/** * Returns the value of object `o` at the given `path`. * * ####Example: * * var obj = { * comments: [ * { title: 'exciting!', _doc: { title: 'great!' }} * , { title: 'number dos' } * ] * } * * mpath.get('comments.0.title', o) // 'exciting!' * mpath.get('comments.0.title', o, '_doc') // 'great!' * mpath.get('comments.title', o) // ['exciting!', 'number dos'] * * // summary * mpath.get(path, o) * mpath.get(path, o, special) * mpath.get(path, o, map) * mpath.get(path, o, special, map) * * @param {String} path * @param {Object} o * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property. * @param {Function} [map] Optional function which receives each individual found value. The value returned from `map` is used in the original values place. */ exports.get = function (path, o, special, map) { if ('function' == typeof special) { map = special; special = undefined; } map || (map = K); var parts = 'string' == typeof path ? path.split('.') : path if (!Array.isArray(parts)) { throw new TypeError('Invalid `path`. Must be either string or array'); } var obj = o , part; for (var i = 0; i < parts.length; ++i) { part = parts[i]; if (Array.isArray(obj) && !/^\d+$/.test(part)) { // reading a property from the array items var paths = parts.slice(i); return obj.map(function (item) { return item ? exports.get(paths, item, special, map) : map(undefined); }); } obj = special && obj[special] ? obj[special][part] : obj[part]; if (!obj) return map(obj); } return map(obj); } /** * Sets the `val` at the given `path` of object `o`. * * @param {String} path * @param {Anything} val * @param {Object} o * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property. * @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. */ exports.set = function (path, val, o, special, map, _copying) { if ('function' == typeof special) { map = special; special = undefined; } map || (map = K); var parts = 'string' == typeof path ? path.split('.') : path if (!Array.isArray(parts)) { throw new TypeError('Invalid `path`. Must be either string or array'); } if (null == o) return; // the existance of $ in a path tells us if the user desires // the copying of an array instead of setting each value of // the array to the one by one to matching positions of the // current array. var copy = _copying || /\$/.test(path) , obj = o , part for (var i = 0, len = parts.length - 1; i < len; ++i) { part = parts[i]; if ('$' == part) { if (i == len - 1) { break; } else { continue; } } if (Array.isArray(obj) && !/^\d+$/.test(part)) { var paths = parts.slice(i); if (!copy && Array.isArray(val)) { for (var j = 0; j < obj.length && j < val.length; ++j) { // assignment of single values of array exports.set(paths, val[j], obj[j], special, map, copy); } } else { for (var j = 0; j < obj.length; ++j) { // assignment of entire value exports.set(paths, val, obj[j], special, map, copy); } } return; } obj = special && obj[special] ? obj[special][part] : obj[part]; if (!obj) return; } // process the last property of the path part = parts[len]; // use the special property if exists if (special && obj[special]) { obj = obj[special]; } // set the value on the last branch if (Array.isArray(obj) && !/^\d+$/.test(part)) { if (!copy && Array.isArray(val)) { for (var item, j = 0; j < obj.length && j < val.length; ++j) { item = obj[j]; if (item) { if (item[special]) item = item[special]; item[part] = map(val[j]); } } } else { for (var j = 0; j < obj.length; ++j) { item = obj[j]; if (item) { if (item[special]) item = item[special]; item[part] = map(val); } } } } else { obj[part] = map(val); } } /*! * Returns the value passed to it. */ function K (v) { return v; }