jsonpath-plus
Advanced tools
Comparing version 0.15.0 to 0.16.0
@@ -1,3 +0,14 @@ | ||
# JSONPath changes | ||
# jsonpath-plus changes | ||
## 0.16.0 (January 14, 2017) | ||
- Breaking change: Give preference to treating special chars in a property | ||
as special (override with backtick operator) | ||
- Breaking feature: Add custom \` operator to allow unambiguous literal | ||
sequences (if an initial backtick is needed, an additional one must | ||
now be added) | ||
- Fix: `toPathArray` caching bug | ||
- Improvements: Performance optimizations | ||
- Dev testing: Rename test file | ||
## 0.15.0 (Mar 15, 2016) | ||
@@ -19,7 +30,8 @@ | ||
- Add `@scalar()` type operator (in JavaScript mode, will also include) | ||
- Feature: Add `@scalar()` type operator (in JavaScript mode, will also | ||
include) | ||
## 0.13.1 (Jan 5, 2016) | ||
- Avoid double-encoding path in results | ||
- Fix: Avoid double-encoding path in results | ||
@@ -50,3 +62,3 @@ ## 0.13.0 (Dec 13, 2015) | ||
- Actually add the warning in the README that problems in npm | ||
- Docs: Actually add the warning in the README that problems in npm | ||
with upper-case letters is causing us to rename to "jsonpath-plus" | ||
@@ -57,3 +69,3 @@ (next version will actually apply the change). | ||
- Give warning in README that problems in npm with upper-case letters | ||
- Docs: Give warning in README that problems in npm with upper-case letters | ||
is causing us to rename to "jsonpath-plus" (next version will actually | ||
@@ -105,10 +117,10 @@ apply the change). | ||
- Support for parent selection via `^` | ||
- Access current path via `@path` in test statements | ||
- Allowing for multi-statement evals | ||
- Performance improvements | ||
- Feature: Support for parent selection via `^` | ||
- Feature: Access current path via `@path` in test statements | ||
- Feature: Allowing for multi-statement evals | ||
- Improvements: Performance | ||
## 0.9.0 (Mar 28, 2012) | ||
- Support a sandbox arg to eval | ||
- Use vm.runInNewContext in place of eval | ||
- Feature: Support a sandbox arg to eval | ||
- Improvements: Use `vm.runInNewContext` in place of eval |
@@ -18,2 +18,13 @@ /*global exports, require*/ | ||
if (!Array.prototype.includes) { | ||
Array.prototype.includes = function (item) { // eslint-disable-line no-extend-native | ||
return this.indexOf(item) > -1; | ||
}; | ||
} | ||
if (!String.prototype.includes) { | ||
String.prototype.includes = function (item) { // eslint-disable-line no-extend-native | ||
return this.indexOf(item) > -1; | ||
}; | ||
} | ||
var moveToAnotherArray = function (source, target, conditionCb) { | ||
@@ -144,3 +155,3 @@ for (var i = 0, kl = source.length; i < kl; i++) { | ||
} | ||
if (!expr || !json || allowedResultTypes.indexOf(this.currResultType) === -1) { | ||
if (!expr || !json || !allowedResultTypes.includes(this.currResultType)) { | ||
return; | ||
@@ -152,2 +163,3 @@ } | ||
if (exprList[0] === '$' && exprList.length > 1) {exprList.shift();} | ||
this._hasParentSelector = null; | ||
var result = this._trace(exprList, json, ['$'], currParent, currParentProperty, callback); | ||
@@ -197,3 +209,3 @@ result = result.filter(function (ea) {return ea && !ea.isParentSelector;}); | ||
JSONPath.prototype._trace = function (expr, val, path, parent, parentPropName, callback) { | ||
JSONPath.prototype._trace = function (expr, val, path, parent, parentPropName, callback, literalPriority) { | ||
// No expr to follow? return path and value as the result of this trace branch | ||
@@ -212,5 +224,14 @@ var retObj, self = this; | ||
var ret = []; | ||
function addRet (elems) {ret = ret.concat(elems);} | ||
function retPush (elem) { | ||
ret.push(elem); | ||
} | ||
function addRet (elems) { | ||
if (Array.isArray(elems)) { | ||
elems.forEach(retPush); | ||
} else { | ||
ret.push(elems); | ||
} | ||
} | ||
if (val && Object.prototype.hasOwnProperty.call(val, loc)) { // simple case--directly follow property | ||
if ((typeof loc !== 'string' || literalPriority) && val && Object.prototype.hasOwnProperty.call(val, loc)) { // simple case--directly follow property | ||
addRet(this._trace(x, val[loc], push(path, loc), val, loc, callback)); | ||
@@ -220,3 +241,3 @@ } | ||
this._walk(loc, x, val, path, parent, parentPropName, callback, function (m, l, x, v, p, par, pr, cb) { | ||
addRet(self._trace(unshift(m, x), v, p, par, pr, cb)); | ||
addRet(self._trace(unshift(m, x), v, p, par, pr, cb, true)); | ||
}); | ||
@@ -233,9 +254,2 @@ } | ||
} | ||
else if (loc[0] === '(') { // [(expr)] (dynamic property/index) | ||
if (this.currPreventEval) { | ||
throw new Error('Eval [(expr)] prevented in JSONPath expression.'); | ||
} | ||
// As this will resolve to a property name (but we don't know it yet), property and parent information is relative to the parent of the property to which this expression will resolve | ||
addRet(this._trace(unshift(this._eval(loc, val, path[path.length - 1], path.slice(0, -1), parent, parentPropName), x), val, path, parent, parentPropName, callback)); | ||
} | ||
// The parent sel computation is handled in the frame above using the | ||
@@ -245,2 +259,3 @@ // ancestor object of val | ||
// This is not a final endpoint, so we do not invoke the callback here | ||
this._hasParentSelector = true; | ||
return path.length ? { | ||
@@ -260,2 +275,5 @@ path: path.slice(0, -1), | ||
} | ||
else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step] Python slice syntax | ||
addRet(this._slice(loc, x, val, path, parent, parentPropName, callback)); | ||
} | ||
else if (loc.indexOf('?(') === 0) { // [?(expr)] (filtering) | ||
@@ -271,7 +289,8 @@ if (this.currPreventEval) { | ||
} | ||
else if (loc.indexOf(',') > -1) { // [name1,name2,...] | ||
var parts, i; | ||
for (parts = loc.split(','), i = 0; i < parts.length; i++) { | ||
addRet(this._trace(unshift(parts[i], x), val, path, parent, parentPropName, callback)); | ||
else if (loc[0] === '(') { // [(expr)] (dynamic property/index) | ||
if (this.currPreventEval) { | ||
throw new Error('Eval [(expr)] prevented in JSONPath expression.'); | ||
} | ||
// As this will resolve to a property name (but we don't know it yet), property and parent information is relative to the parent of the property to which this expression will resolve | ||
addRet(this._trace(unshift(this._eval(loc, val, path[path.length - 1], path.slice(0, -1), parent, parentPropName), x), val, path, parent, parentPropName, callback)); | ||
} | ||
@@ -283,3 +302,3 @@ else if (loc[0] === '@') { // value type: @boolean(), etc. | ||
case 'scalar': | ||
if (!val || (['object', 'function'].indexOf(typeof val) === -1)) { | ||
if (!val || !(['object', 'function'].includes(typeof val))) { | ||
addType = true; | ||
@@ -333,5 +352,15 @@ } | ||
} | ||
else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) { // [start:end:step] Python slice syntax | ||
addRet(this._slice(loc, x, val, path, parent, parentPropName, callback)); | ||
else if (loc[0] === '`' && val && Object.prototype.hasOwnProperty.call(val, loc.slice(1))) { // `-escaped property | ||
var locProp = loc.slice(1); | ||
addRet(this._trace(x, val[locProp], push(path, locProp), val, locProp, callback, true)); | ||
} | ||
else if (loc.includes(',')) { // [name1,name2,...] | ||
var parts, i; | ||
for (parts = loc.split(','), i = 0; i < parts.length; i++) { | ||
addRet(this._trace(unshift(parts[i], x), val, path, parent, parentPropName, callback)); | ||
} | ||
} | ||
else if (!literalPriority && val && Object.prototype.hasOwnProperty.call(val, loc)) { // simple case--directly follow property | ||
addRet(this._trace(x, val[loc], push(path, loc), val, loc, callback, true)); | ||
} | ||
@@ -341,5 +370,20 @@ // We check the resulting values for parent selections. For parent | ||
// current val object | ||
return ret.reduce(function (all, ea) { | ||
return all.concat(ea.isParentSelector ? self._trace(ea.expr, val, ea.path, parent, parentPropName, callback) : ea); | ||
}, []); | ||
if (this._hasParentSelector) { | ||
for (var t = 0; t < ret.length; t++) { | ||
var rett = ret[t]; | ||
if (rett.isParentSelector) { | ||
var tmp = self._trace(rett.expr, val, rett.path, parent, parentPropName, callback); | ||
if (Array.isArray(tmp)) { | ||
ret[t] = tmp[0]; | ||
for (var tt = 1, tl = tmp.length; tt < tl; tt++) { | ||
t++; | ||
ret.splice(t, 0, tmp[tt]); | ||
} | ||
} else { | ||
ret[t] = tmp; | ||
} | ||
} | ||
} | ||
} | ||
return ret; | ||
}; | ||
@@ -374,3 +418,11 @@ | ||
for (i = start; i < end; i += step) { | ||
ret = ret.concat(this._trace(unshift(i, expr), val, path, parent, parentPropName, callback)); | ||
var tmp = this._trace(unshift(i, expr), val, path, parent, parentPropName, callback); | ||
if (Array.isArray(tmp)) { | ||
tmp.forEach(function (t) { | ||
ret.push(t); | ||
}); | ||
} | ||
else { | ||
ret.push(tmp); | ||
} | ||
} | ||
@@ -382,15 +434,15 @@ return ret; | ||
if (!this._obj || !_v) {return false;} | ||
if (code.indexOf('@parentProperty') > -1) { | ||
if (code.includes('@parentProperty')) { | ||
this.currSandbox._$_parentProperty = parentPropName; | ||
code = code.replace(/@parentProperty/g, '_$_parentProperty'); | ||
} | ||
if (code.indexOf('@parent') > -1) { | ||
if (code.includes('@parent')) { | ||
this.currSandbox._$_parent = parent; | ||
code = code.replace(/@parent/g, '_$_parent'); | ||
} | ||
if (code.indexOf('@property') > -1) { | ||
if (code.includes('@property')) { | ||
this.currSandbox._$_property = _vname; | ||
code = code.replace(/@property/g, '_$_property'); | ||
} | ||
if (code.indexOf('@path') > -1) { | ||
if (code.includes('@path')) { | ||
this.currSandbox._$_path = JSONPath.toPathString(path.concat([_vname])); | ||
@@ -441,3 +493,3 @@ code = code.replace(/@path/g, '_$_path'); | ||
var cache = JSONPath.cache; | ||
if (cache[expr]) {return cache[expr];} | ||
if (cache[expr]) {return cache[expr].concat();} | ||
var subx = []; | ||
@@ -451,3 +503,6 @@ var normalized = expr | ||
.replace(/\['([^'\]]*)'\]/g, function ($0, prop) { | ||
return "['" + prop.replace(/\./g, '%@%').replace(/~/g, '%%@@%%') + "']"; | ||
return "['" + prop | ||
.replace(/\./g, '%@%') | ||
.replace(/~/g, '%%@@%%') + | ||
"']"; | ||
}) | ||
@@ -454,0 +509,0 @@ // Properties operator |
@@ -32,3 +32,3 @@ { | ||
"license": "MIT", | ||
"version": "0.15.0", | ||
"version": "0.16.0", | ||
"repository": { | ||
@@ -63,4 +63,5 @@ "type": "git", | ||
"test": "npm run lint && npm run nodeunit", | ||
"browser-test": "npm run lint && node ./test-helpers/nodeunit-server" | ||
"browser-test": "npm run lint && node ./test-helpers/nodeunit-server", | ||
"start": "npm run browser-test" | ||
} | ||
} |
@@ -6,2 +6,8 @@ # JSONPath Plus [![build status](https://secure.travis-ci.org/s3u/JSONPath.png)](http://travis-ci.org/s3u/JSONPath) | ||
**Note that `jsonpath-plus` is currently suffering from [performance problems](https://github.com/s3u/JSONPath/issues/14) | ||
and the maintainers are not currently able to work on resolving. | ||
You may wish to use [jsonpath](https://www.npmjs.com/package/jsonpath) | ||
to avoid this problem (though noting that it does not include the | ||
proprietary features added to `jsonpath-plus`).** | ||
# Install | ||
@@ -83,7 +89,9 @@ | ||
in an array. If `wrap` is set to false, and no results are found, | ||
`undefined` will be returned (as opposed to an empty array with | ||
`wrap` set to true). If `wrap` is set to false and a single result | ||
`undefined` will be returned (as opposed to an empty array when | ||
`wrap` is set to true). If `wrap` is set to false and a single result | ||
is found, that result will be the only item returned (not within | ||
an array). An array will still be returned if multiple results are | ||
found, however. | ||
found, however. To avoid ambiguities (in the case where it is necessary | ||
to distinguish between a result which is a failure and one which is an | ||
empty array), it is recommended to switch the default to `false`. | ||
- ***preventEval*** (**default: false**) - Although JavaScript evaluation | ||
@@ -255,2 +263,3 @@ expressions are allowed by default, for security reasons (if one is | ||
//book/../\*\[. instance of element(\*, xs:decimal)\] (in XPath 2.0) | $..book..\*@number() | Get the numeric values within the book array | @number(), the other basic types (@boolean(), @string()), other low-level derived types (@null(), @object(), @array()), the JSONSchema-added type, @integer(), the compound type @scalar() (which also accepts `undefined` and non-finite numbers for JavaScript objects as well as all of the basic non-object/non-function types), the type, @other(), to be used in conjunction with a user-defined callback (see `otherTypeCallback`) and the following non-JSON types that can nevertheless be used with JSONPath when querying non-JSON JavaScript objects (@undefined(), @function(), @nonFinite()) are not present in the original spec | ||
| | `` ` `` (e.g., `` `$`` to match a property literally named `$`) | Escapes the entire sequence following (to be treated as a literal) | `\`` is not present in the original spec | ||
@@ -295,3 +304,3 @@ Any additional variables supplied as properties on the optional "sandbox" | ||
- Visit [http://localhost:8082/test/test.html](http://localhost:8082/test/test.html). | ||
- Visit [http://localhost:8082/test/](http://localhost:8082/test/). | ||
@@ -298,0 +307,0 @@ # License |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44778
496
306