var x1 = {a:[{b:[{x:2},{x:3}]},{b:[{x:1},{x:9}]}]};
var x2 = {a:[{b:[{y:2},{x:3}]},{b:[{x:1},{y:9}]}]};
var x3 = [{b:[{x:2},{x:3}]},{b:[{x:1},{y:9}]}];
var x4 = {a:[{b:{c:10}},{b:{c:20}}]};
_getSplat(x1, 'a*.b') === [[{x:2},{x:3}],[{x:1},{x:9}]];
_getSplat(x1, 'a*.b*.x') === [[2, 3], [1, 9]];
_getSplat(x1, 'a*.b*.x*.z') === [[[undefined], [undefined]], [[undefined], [undefined]]];
_getSplat(x2, 'a*.b*.x') === [[undefined, 3], [1, undefined]];
_getSplat(x3, '*.b*.x') === [[2, 3], [1, undefined]];
_getSplat(x3, '*.b*.y'); === [[undefined, undefined], [undefined, 9]];
_getSplat(x3, '*.b*.y*.z*.q', true) === [[[true], [true]], [[true], [true]]];
_getSplat(x4, 'a*.b.c') === [10, 20];
// eg. path = 'a.b*.x*.z'
function _getSplat(obj, path, _default) {
if (!_.isString(path)) return obj;
var paths = path.split('*.');
//console.log('get:', obj, paths);
if (paths[0]) {
obj = _.get(obj, paths[0], _default);
//console.log('obj:', obj);
}
if (paths[1]) {
if (!_.isObject(obj)) {
return [_default];
}
//console.log('paths[1]:', paths[1]);
var _obj = obj;
obj = [];
for (var prop in _obj) {
//console.log('val:', _obj[prop], paths.slice(1).join('*.'));
var recurseResult = _getSplat(_obj[prop], paths.slice(1).join('*.'), _default);
//console.log('recurse:', recurseResult);
obj.push(recurseResult);
}
}
return obj;
}
// eg. path = 'a.b[].x[0].z'
function _getPath(obj, path, _default) {
if (!_.isString(path)) return obj;
var paths = path.match(/(.*?)(?:\[(-?\d*)\]\.?)/);
//eg. paths = ["a.b[0]", "a.b", "0"]
//console.log('get:', obj, paths);
if (!Array.isArray(paths)) {
//console.log('not-parsable:', path);
return _.get(obj, path, _default);
}
if (paths[1]) {
obj = _.get(obj, paths[1], _default);
//console.log('obj:', obj);
}
path = path.slice(paths[0].length);
if (path) {
// _getPath the rest of the path...
if (!_.isObject(obj)) {
return [_default];
}
// recursively!
//console.log('path:', path);
var _obj = obj;
obj = [];
for (var prop in _obj) {
if (!_obj.hasOwnProperty(prop)) continue;
//console.log('val:', _obj[prop], path);
var recurseResult = _getPath(_obj[prop], path, _default);
//console.log('recurse:', recurseResult);
obj.push(recurseResult);
}
}
if (paths[2]) {
var idx = +paths[2] >= 0 ? +paths[2] : obj.length + +paths[2];
return obj[idx];
}
return obj;
}