/node_modules/mpath/lib/index.js

https://bitbucket.org/coleman333/smartsite · JavaScript · 280 lines · 177 code · 41 blank · 62 comment · 82 complexity · 03894b38579834b76f634c7bce16812a MD5 · raw file

  1. /**
  2. * Returns the value of object `o` at the given `path`.
  3. *
  4. * ####Example:
  5. *
  6. * var obj = {
  7. * comments: [
  8. * { title: 'exciting!', _doc: { title: 'great!' }}
  9. * , { title: 'number dos' }
  10. * ]
  11. * }
  12. *
  13. * mpath.get('comments.0.title', o) // 'exciting!'
  14. * mpath.get('comments.0.title', o, '_doc') // 'great!'
  15. * mpath.get('comments.title', o) // ['exciting!', 'number dos']
  16. *
  17. * // summary
  18. * mpath.get(path, o)
  19. * mpath.get(path, o, special)
  20. * mpath.get(path, o, map)
  21. * mpath.get(path, o, special, map)
  22. *
  23. * @param {String} path
  24. * @param {Object} o
  25. * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property.
  26. * @param {Function} [map] Optional function which receives each individual found value. The value returned from `map` is used in the original values place.
  27. */
  28. exports.get = function (path, o, special, map) {
  29. var lookup;
  30. if ('function' == typeof special) {
  31. if (special.length < 2) {
  32. map = special;
  33. special = undefined;
  34. } else {
  35. lookup = special;
  36. special = undefined;
  37. }
  38. }
  39. map || (map = K);
  40. var parts = 'string' == typeof path
  41. ? path.split('.')
  42. : path
  43. if (!Array.isArray(parts)) {
  44. throw new TypeError('Invalid `path`. Must be either string or array');
  45. }
  46. var obj = o
  47. , part;
  48. for (var i = 0; i < parts.length; ++i) {
  49. part = parts[i];
  50. if (Array.isArray(obj) && !/^\d+$/.test(part)) {
  51. // reading a property from the array items
  52. var paths = parts.slice(i);
  53. return obj.map(function (item) {
  54. return item
  55. ? exports.get(paths, item, special || lookup, map)
  56. : map(undefined);
  57. });
  58. }
  59. if (lookup) {
  60. obj = lookup(obj, part);
  61. } else {
  62. var _from = special && obj[special] ? obj[special] : obj;
  63. obj = _from instanceof Map ?
  64. _from.get(part) :
  65. _from[part];
  66. }
  67. if (!obj) return map(obj);
  68. }
  69. return map(obj);
  70. };
  71. /**
  72. * Returns true if `in` returns true for every piece of the path
  73. *
  74. * @param {String} path
  75. * @param {Object} o
  76. */
  77. exports.has = function (path, o) {
  78. var parts = typeof path === 'string' ?
  79. path.split('.') :
  80. path;
  81. if (!Array.isArray(parts)) {
  82. throw new TypeError('Invalid `path`. Must be either string or array');
  83. }
  84. var len = parts.length;
  85. var cur = o;
  86. for (var i = 0; i < len; ++i) {
  87. if (cur == null || typeof cur !== 'object' || !(parts[i] in cur)) {
  88. return false;
  89. }
  90. cur = cur[parts[i]];
  91. }
  92. return true;
  93. };
  94. /**
  95. * Deletes the last piece of `path`
  96. *
  97. * @param {String} path
  98. * @param {Object} o
  99. */
  100. exports.unset = function (path, o) {
  101. var parts = typeof path === 'string' ?
  102. path.split('.') :
  103. path;
  104. if (!Array.isArray(parts)) {
  105. throw new TypeError('Invalid `path`. Must be either string or array');
  106. }
  107. var len = parts.length;
  108. var cur = o;
  109. for (var i = 0; i < len; ++i) {
  110. if (cur == null || typeof cur !== 'object' || !(parts[i] in cur)) {
  111. return false;
  112. }
  113. if (i === len - 1) {
  114. delete cur[parts[i]];
  115. return true;
  116. }
  117. cur = cur instanceof Map ? cur.get(parts[i]) : cur[parts[i]];
  118. }
  119. return true;
  120. };
  121. /**
  122. * Sets the `val` at the given `path` of object `o`.
  123. *
  124. * @param {String} path
  125. * @param {Anything} val
  126. * @param {Object} o
  127. * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property.
  128. * @param {Function} [map] Optional function which is passed each individual value before setting it. The value returned from `map` is used in the original values place.
  129. */
  130. exports.set = function (path, val, o, special, map, _copying) {
  131. var lookup;
  132. if ('function' == typeof special) {
  133. if (special.length < 2) {
  134. map = special;
  135. special = undefined;
  136. } else {
  137. lookup = special;
  138. special = undefined;
  139. }
  140. }
  141. map || (map = K);
  142. var parts = 'string' == typeof path
  143. ? path.split('.')
  144. : path
  145. if (!Array.isArray(parts)) {
  146. throw new TypeError('Invalid `path`. Must be either string or array');
  147. }
  148. if (null == o) return;
  149. // the existance of $ in a path tells us if the user desires
  150. // the copying of an array instead of setting each value of
  151. // the array to the one by one to matching positions of the
  152. // current array. Unless the user explicitly opted out by passing
  153. // false, see Automattic/mongoose#6273
  154. var copy = _copying || (/\$/.test(path) && _copying !== false)
  155. , obj = o
  156. , part
  157. for (var i = 0, len = parts.length - 1; i < len; ++i) {
  158. part = parts[i];
  159. if ('$' == part) {
  160. if (i == len - 1) {
  161. break;
  162. } else {
  163. continue;
  164. }
  165. }
  166. if (Array.isArray(obj) && !/^\d+$/.test(part)) {
  167. var paths = parts.slice(i);
  168. if (!copy && Array.isArray(val)) {
  169. for (var j = 0; j < obj.length && j < val.length; ++j) {
  170. // assignment of single values of array
  171. exports.set(paths, val[j], obj[j], special || lookup, map, copy);
  172. }
  173. } else {
  174. for (var j = 0; j < obj.length; ++j) {
  175. // assignment of entire value
  176. exports.set(paths, val, obj[j], special || lookup, map, copy);
  177. }
  178. }
  179. return;
  180. }
  181. if (lookup) {
  182. obj = lookup(obj, part);
  183. } else {
  184. var _to = special && obj[special] ? obj[special] : obj;
  185. obj = _to instanceof Map ?
  186. _to.get(part) :
  187. _to[part];
  188. }
  189. if (!obj) return;
  190. }
  191. // process the last property of the path
  192. part = parts[len];
  193. // use the special property if exists
  194. if (special && obj[special]) {
  195. obj = obj[special];
  196. }
  197. // set the value on the last branch
  198. if (Array.isArray(obj) && !/^\d+$/.test(part)) {
  199. if (!copy && Array.isArray(val)) {
  200. for (var item, j = 0; j < obj.length && j < val.length; ++j) {
  201. item = obj[j];
  202. if (item) {
  203. if (lookup) {
  204. lookup(item, part, map(val[j]));
  205. } else {
  206. if (item[special]) item = item[special];
  207. item[part] = map(val[j]);
  208. }
  209. }
  210. }
  211. } else {
  212. for (var j = 0; j < obj.length; ++j) {
  213. item = obj[j];
  214. if (item) {
  215. if (lookup) {
  216. lookup(item, part, map(val));
  217. } else {
  218. if (item[special]) item = item[special];
  219. item[part] = map(val);
  220. }
  221. }
  222. }
  223. }
  224. } else {
  225. if (lookup) {
  226. lookup(obj, part, map(val));
  227. } else if (obj instanceof Map) {
  228. obj.set(part, map(val));
  229. } else {
  230. obj[part] = map(val);
  231. }
  232. }
  233. }
  234. /*!
  235. * Returns the value passed to it.
  236. */
  237. function K (v) {
  238. return v;
  239. }