dot-wild
Version:
Use powerful dot notation (dot path + wildcard) to manipulate properties of JSON
425 lines (424 loc) • 12.8 kB
JavaScript
;
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Utilities
*/
var clone = require('clone-deep');
var isObj = require('is-plain-object');
var isArray = function (val) { return Array.isArray(val); };
var isString = function (val) { return typeof val === 'string'; };
var isInteger = function (val) { return Number(val) == val && Number(val) % 1 === 0; }; // tslint:disable-line triple-equals
var isNumeric = function (val) { return !isArray(val) && (val - parseFloat(val) + 1) >= 0; };
var isData = function (data) { return isObj(data) || isArray(data); };
var isArrayKey = function (key) { return isInteger(key) && parseInt(key) >= 0; };
var hasProp = function (obj, key) { return obj && obj.hasOwnProperty(key); };
var objKeys = Object.keys;
var isEmpty = function (obj) {
if (isArray(obj))
return obj.length === 0;
if (isObj(obj))
return objKeys(obj).length === 0;
if (isNumeric(obj))
return parseFloat(obj) === 0;
return !obj;
};
var regex = {
dot: /^\./,
prop: /[^[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,
escape: /\\(\\)?/g,
};
var each = function (obj, iteratee) {
if (!obj)
return;
if (isArray(obj)) {
for (var i = 0; i < obj.length; i++) {
if (iteratee(obj[i], i, obj) === false)
break;
}
}
else if (isObj(obj)) {
var keys = objKeys(obj);
for (var i = 0; i < keys.length; i++) {
if (iteratee(obj[keys[i]], keys[i], obj) === false)
break;
}
}
};
var merge = function (obj, source) {
each(source, function (value, key) {
if (hasProp(obj, key) && isData(obj)) {
merge(obj[key], value);
}
else {
obj[key] = value;
}
});
return obj;
};
var splitTokens = function (input) {
var tokens = ("" + input).split('.');
var results = [];
var store = [];
tokens.forEach(function (token) {
if (/^.*\\$/.test(token)) {
store.push(token.slice(0, token.length - 1));
}
else if (store.length > 0) {
results = results.concat([store.join('.') + "." + token]);
store = [];
}
else {
results.push(token);
}
});
return results;
};
var matchToken = function (key, token) {
if (token === '*')
return true;
return isInteger(token) ? key == token : key === token; // tslint:disable-line triple-equals
};
var hasToken = function (path) { return (path.indexOf('.') > -1 || path.indexOf('[') > -1); };
/**
* Tokenize path string
*/
exports.tokenize = function (str) {
var results = [];
splitTokens(str).forEach(function (token) {
token.replace(regex.prop, function (m, n, q, s) {
results.push(q ? s.replace(regex.escape, '$1') : (n || m));
});
});
return results;
};
var defaultGetOptions = {
iterateObject: true,
iterateArray: true,
};
var internalGet = function (data, path, value, options) {
var opts = __assign({}, defaultGetOptions, (options || {}));
if (!path || !isString(path)) {
return {
exist: false,
wildcard: false,
values: [[value, data, []]],
};
}
var key = '__get_item__';
var tokens = exports.tokenize(path);
var length = tokens.length;
var state = {
index: 0,
context: (_a = {}, _a[key] = [[data, data, []]], _a),
wildcard: false,
};
tokens.forEach(function (token) {
var next = [];
each(state.context[key], function (_a) {
var item = _a[0], _ = _a[1], p = _a[2];
each(item, function (v, k) {
if (!matchToken(k, token))
return;
if (token !== '*') {
next.push([v, item, p.concat([k])]);
}
else {
if (!opts.iterateObject && isObj(item))
return;
if (!opts.iterateArray && isArray(item))
return;
state.wildcard = true;
next.push([v, item, p.concat([k])]);
}
});
});
if (next.length > 0) {
state.context = (_a = {}, _a[key] = next, _a);
state.index++;
}
var _a;
});
if (state.index !== length) {
return {
exist: false,
wildcard: state.wildcard,
values: [[value, null, []]],
};
}
return {
exist: true,
wildcard: state.wildcard,
values: state.context[key],
};
var _a;
};
exports.get = function (data, path, value, options) {
if (value === void 0) { value = undefined; }
var _a = internalGet(data, path, value, options), exist = _a.exist, wildcard = _a.wildcard, values = _a.values;
if (!exist)
return values[0][0];
if (wildcard)
return values.map(function (v) { return v[0]; });
return values[0][0] === undefined ? value : values[0][0];
};
/**
* Setter
*/
exports.set = function (data, path, value) {
if (!path || !isString(path))
return data;
var _data = clone(data);
if (!hasToken(path)) {
_data[path] = value;
return _data;
}
var tokens = exports.tokenize(path);
if (tokens.indexOf('*') < 0) {
var res = _data;
each(tokens, function (token, i) {
if (!isObj(_data[token]) && !isArray(_data[token])) {
if (i < tokens.length - 1 && isArrayKey(tokens[i + 1])) {
_data[token] = [];
}
else {
_data[token] = {};
}
}
if (i === tokens.length - 1) {
_data[token] = value;
}
_data = _data[token];
});
return res;
}
else {
var token_1 = tokens.shift();
var nextPath_1 = tokens.map(function (v) { return v.replace('.', '\\.'); }).join('.');
if (token_1 === undefined)
return _data;
each(_data, function (v, k) {
if (matchToken(k, token_1)) {
_data[k] = nextPath_1 ? exports.set(v, nextPath_1, value) : merge(v, value);
}
});
}
return _data;
};
/**
* Deleter
*/
var arrayRemove = function (array, index) { return (array.slice(0, index).concat(array.slice(index + 1))); };
var simpleRemove = function (data, path) {
if (isArray(data) && isArrayKey(path)) {
data = arrayRemove(data, parseInt(path, 10));
}
else {
delete data[path];
}
return data;
};
exports.remove = function (data, path) {
if (!path || !isString(path)) {
return data;
}
var _data = clone(data);
if (!hasToken(path) && path !== '*') {
return simpleRemove(_data, path);
}
var tokens = exports.tokenize(path);
if (tokens.indexOf('*') < 0) {
var result = _data;
each(tokens, function (token, i) {
if (i === tokens.length - 1) {
if (isArray(_data)) {
_data.splice(parseInt(token, 10), 1);
}
else {
delete _data[token];
}
return false;
}
else {
_data = _data[token];
return isObj(_data) || isArray(_data);
}
});
return result;
}
var first = tokens.shift();
var later = tokens.join('.');
var isDataArray = isArray(_data);
var count = 0;
if (first === undefined) {
return _data;
}
each(_data, function (v, k) {
if (!matchToken(k, first)) {
return;
}
if ((!isObj(v) && !isArray(v)) || !later) {
if (!later) {
if (isDataArray) {
_data = arrayRemove(_data, parseInt(k, 10) - count);
count += isDataArray ? 1 : 0;
}
else {
delete _data[k];
}
}
return;
}
_data[k] = exports.remove(v, later);
});
return _data;
};
/**
* Check value
*/
exports.has = function (data, path) {
if (!path || !isString(path))
return false;
var key = '__has__item';
var tokens = exports.tokenize(path);
var context = (_a = {}, _a[key] = [data], _a);
var result = true;
each(tokens, function (token) {
var next = [];
each(context[key], function (item) {
each(item, function (v, k) {
if (matchToken(k, token)) {
next.push(v);
}
});
});
if (next.length === 0) {
result = false;
return false;
}
else {
context = (_a = {}, _a[key] = next, _a);
}
return true;
var _a;
});
return result;
var _a;
};
/**
* Flatten values
*/
var internalFlatten = function (data, currentPath) {
if (currentPath === void 0) { currentPath = null; }
var results = {};
if (isEmpty(data))
return results;
if (isArray(data) && data.length === 0) {
var path = currentPath == null ? 0 : currentPath;
results[path] = data;
return results;
}
each(data, function (val, key) {
var k = ("" + key).split('.').join('\\.');
var p = currentPath == null ? k : currentPath + "." + k;
if (isArray(val) || isObj(val)) {
var children = internalFlatten(val, p);
if (objKeys(children).length > 0) {
results = merge(results, children);
}
}
else {
results[p] = val;
}
});
return results;
};
exports.flatten = function (data) { return internalFlatten(data); };
/**
* Expand vaules
*/
exports.expand = function (data) {
var results = {};
each(data, function (value, flat) {
var keys = exports.tokenize(flat).reverse();
var key = keys.shift();
var child = isArrayKey(key) ? [] : {};
child[key] = value;
each(keys, function (k) {
if (isArrayKey(k)) {
var newChild = [];
newChild[k] = child;
child = newChild;
}
else {
child = (_a = {}, _a[k] = child, _a);
}
var _a;
});
if (isArrayKey(keys[keys.length - 1]) && isEmpty(results)) {
results = [];
}
results = merge(results, child);
});
return results;
};
/**
* Executes a provided function once for each element.
*/
exports.forEach = function (data, path, iteratee, options) {
var _a = internalGet(data, path, null, options), exist = _a.exist, values = _a.values;
if (!exist)
return;
each(values, function (_a) {
var v = _a[0], c = _a[1], p = _a[2];
return iteratee(v, p[p.length - 1], c, p.join('.'), data);
});
};
/**
* Create a new element
* with the results of calling a provided function on every element.
*/
exports.map = function (data, path, iteratee, options) {
var _a = internalGet(data, path, null, options), exist = _a.exist, values = _a.values;
if (!exist)
return [];
return values.map(function (_a) {
var v = _a[0], c = _a[1], p = _a[2];
return iteratee(v, p[p.length - 1], c, p.join('.'), data);
});
};
/**
* Match key
*/
exports.matchPath = function (pathA, pathB) {
if (!isString(pathA) || !isString(pathB))
return false;
if (pathA === pathB)
return true;
var a = exports.tokenize(pathA);
var b = exports.tokenize(pathB);
return a.length !== b.length ? false : a.every(function (t, i) {
return matchToken(t, b[i]) || matchToken(b[i], t);
});
};
/**
* Escape path string
*/
exports.escapePath = function (path) { return (!isString(path) ? '' : exports.tokenize(path).map(function (p) {
return p.split('.').join('\\.');
}).join('\\.')); };
/**
* Build path from Tokens like array
*/
exports.buildPath = function (tokens) { return (tokens.map(function (token) { return exports.escapePath("" + token); }).join('.')); };
/**
* Check contains of wildcard syntax
*/
exports.containWildcardToken = function (path) { return (!isString(path) ? false : exports.tokenize(path).indexOf('*') > -1); };