json-p3 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/json-p3.cjs.js +218 -42
- package/dist/json-p3.esm.js +218 -42
- package/dist/json-p3.iife.js +218 -42
- package/dist/json-p3.iife.min.js +1 -1
- package/dist/json-p3.iife.min.js.map +1 -1
- package/dist/path/environment.d.ts +18 -4
- package/dist/path/expression.d.ts +1 -0
- package/dist/path/extra/expression.d.ts +6 -0
- package/dist/path/extra/index.d.ts +0 -0
- package/dist/path/extra/selectors.d.ts +16 -0
- package/dist/path/lex.d.ts +6 -3
- package/dist/path/parse.d.ts +2 -0
- package/dist/path/selectors.d.ts +3 -1
- package/dist/path/token.d.ts +2 -0
- package/dist/path/types.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/json-p3.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* json-p3 version 1.
|
|
2
|
+
* json-p3 version 1.2.0
|
|
3
3
|
* https://github.com/jg-rp/json-p3
|
|
4
4
|
*
|
|
5
5
|
* MIT License
|
|
@@ -862,12 +862,13 @@ class InfixExpression extends FilterExpression {
|
|
|
862
862
|
this.left = left;
|
|
863
863
|
this.operator = operator;
|
|
864
864
|
this.right = right;
|
|
865
|
+
this.logical = operator === "&&" || operator === "||";
|
|
865
866
|
}
|
|
866
867
|
evaluate(context) {
|
|
867
868
|
let left = this.left.evaluate(context);
|
|
868
|
-
if (left instanceof JSONPathNodeList && left.nodes.length === 1) left = left.nodes[0].value;
|
|
869
|
+
if (!this.logical && left instanceof JSONPathNodeList && left.nodes.length === 1) left = left.nodes[0].value;
|
|
869
870
|
let right = this.right.evaluate(context);
|
|
870
|
-
if (right instanceof JSONPathNodeList && right.nodes.length === 1) right = right.nodes[0].value;
|
|
871
|
+
if (!this.logical && right instanceof JSONPathNodeList && right.nodes.length === 1) right = right.nodes[0].value;
|
|
871
872
|
if (this.operator === "&&") {
|
|
872
873
|
return isTruthy(left) && isTruthy(right);
|
|
873
874
|
}
|
|
@@ -877,7 +878,7 @@ class InfixExpression extends FilterExpression {
|
|
|
877
878
|
return compare(left, this.operator, right);
|
|
878
879
|
}
|
|
879
880
|
toString() {
|
|
880
|
-
if (this.
|
|
881
|
+
if (this.logical) {
|
|
881
882
|
return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`;
|
|
882
883
|
}
|
|
883
884
|
return `${this.left.toString()} ${this.operator} ${this.right.toString()}`;
|
|
@@ -1181,6 +1182,8 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1181
1182
|
TokenKind["GE"] = "TOKEN_GE";
|
|
1182
1183
|
TokenKind["GT"] = "TOKEN_GT";
|
|
1183
1184
|
TokenKind["INDEX"] = "TOKEN_INDEX";
|
|
1185
|
+
TokenKind["KEY"] = "TOKEN_KEY";
|
|
1186
|
+
TokenKind["KEYS"] = "TOKEN_KEYS";
|
|
1184
1187
|
TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
|
|
1185
1188
|
TokenKind["LE"] = "TOKEN_LE";
|
|
1186
1189
|
TokenKind["LG"] = "TOKEN_LG";
|
|
@@ -1250,6 +1253,9 @@ class TokenStream {
|
|
|
1250
1253
|
}
|
|
1251
1254
|
}
|
|
1252
1255
|
|
|
1256
|
+
/** A lexer that accepts additional, non-standard tokens. */
|
|
1257
|
+
|
|
1258
|
+
|
|
1253
1259
|
// These regular expressions are to be used with Lexer.acceptMatchRun(),
|
|
1254
1260
|
// which expects the sticky flag to be set.
|
|
1255
1261
|
const exponentPattern = /e[+-]?\d+/y;
|
|
@@ -1289,7 +1295,8 @@ class Lexer {
|
|
|
1289
1295
|
/**
|
|
1290
1296
|
* @param path - A JSONPath query.
|
|
1291
1297
|
*/
|
|
1292
|
-
constructor(path) {
|
|
1298
|
+
constructor(environment, path) {
|
|
1299
|
+
this.environment = environment;
|
|
1293
1300
|
this.path = path;
|
|
1294
1301
|
}
|
|
1295
1302
|
get pos() {
|
|
@@ -1389,8 +1396,8 @@ class Lexer {
|
|
|
1389
1396
|
* @returns A two-tuple containing a lexer for _path_ and an array to populate
|
|
1390
1397
|
* with tokens.
|
|
1391
1398
|
*/
|
|
1392
|
-
function lex(path) {
|
|
1393
|
-
const lexer = new Lexer(path);
|
|
1399
|
+
function lex(environment, path) {
|
|
1400
|
+
const lexer = new Lexer(environment, path);
|
|
1394
1401
|
return [lexer, lexer.tokens];
|
|
1395
1402
|
}
|
|
1396
1403
|
|
|
@@ -1399,8 +1406,8 @@ function lex(path) {
|
|
|
1399
1406
|
* @param path - A JSONPath query.
|
|
1400
1407
|
* @returns Tokens to be parsed by the parser.
|
|
1401
1408
|
*/
|
|
1402
|
-
function tokenize(path) {
|
|
1403
|
-
const [lexer, tokens] = lex(path);
|
|
1409
|
+
function tokenize(environment, path) {
|
|
1410
|
+
const [lexer, tokens] = lex(environment, path);
|
|
1404
1411
|
lexer.run();
|
|
1405
1412
|
if (tokens.length && tokens[tokens.length - 1].kind === TokenKind.ERROR) {
|
|
1406
1413
|
throw new JSONPathSyntaxError(tokens[tokens.length - 1].value, tokens[tokens.length - 1]);
|
|
@@ -1453,6 +1460,16 @@ function lexSegment(l) {
|
|
|
1453
1460
|
* @returns -
|
|
1454
1461
|
*/
|
|
1455
1462
|
function lexDescendantSelection(l) {
|
|
1463
|
+
if (l.acceptMatchRun(namePattern)) {
|
|
1464
|
+
// Shorthand name
|
|
1465
|
+
l.emit(TokenKind.NAME);
|
|
1466
|
+
return lexSegment;
|
|
1467
|
+
}
|
|
1468
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1469
|
+
// Non-standard keys selector
|
|
1470
|
+
l.emit(TokenKind.KEYS);
|
|
1471
|
+
return lexSegment;
|
|
1472
|
+
}
|
|
1456
1473
|
const ch = l.next();
|
|
1457
1474
|
switch (ch) {
|
|
1458
1475
|
case "":
|
|
@@ -1466,13 +1483,8 @@ function lexDescendantSelection(l) {
|
|
|
1466
1483
|
return lexInsideBracketedSelection;
|
|
1467
1484
|
default:
|
|
1468
1485
|
l.backup();
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
return lexSegment;
|
|
1472
|
-
} else {
|
|
1473
|
-
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1474
|
-
return null;
|
|
1475
|
-
}
|
|
1486
|
+
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1487
|
+
return null;
|
|
1476
1488
|
}
|
|
1477
1489
|
}
|
|
1478
1490
|
function lexDotSelector(l) {
|
|
@@ -1481,23 +1493,34 @@ function lexDotSelector(l) {
|
|
|
1481
1493
|
l.error("unexpected whitespace after dot");
|
|
1482
1494
|
return null;
|
|
1483
1495
|
}
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
l.emit(TokenKind.WILD);
|
|
1496
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1497
|
+
l.emit(TokenKind.KEYS);
|
|
1487
1498
|
return lexSegment;
|
|
1488
1499
|
}
|
|
1489
|
-
l.backup();
|
|
1490
1500
|
if (l.acceptMatchRun(namePattern)) {
|
|
1491
1501
|
l.emit(TokenKind.NAME);
|
|
1492
1502
|
return lexSegment;
|
|
1493
|
-
} else {
|
|
1494
|
-
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1495
|
-
return null;
|
|
1496
1503
|
}
|
|
1504
|
+
const ch = l.next();
|
|
1505
|
+
if (ch === "*") {
|
|
1506
|
+
l.emit(TokenKind.WILD);
|
|
1507
|
+
return lexSegment;
|
|
1508
|
+
}
|
|
1509
|
+
l.backup();
|
|
1510
|
+
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1511
|
+
return null;
|
|
1497
1512
|
}
|
|
1498
1513
|
function lexInsideBracketedSelection(l) {
|
|
1499
1514
|
for (;;) {
|
|
1500
1515
|
l.ignoreWhitespace();
|
|
1516
|
+
if (l.acceptMatchRun(indexPattern)) {
|
|
1517
|
+
l.emit(TokenKind.INDEX);
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1521
|
+
l.emit(TokenKind.KEYS);
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1501
1524
|
const ch = l.next();
|
|
1502
1525
|
switch (ch) {
|
|
1503
1526
|
case "]":
|
|
@@ -1526,10 +1549,6 @@ function lexInsideBracketedSelection(l) {
|
|
|
1526
1549
|
return lexDoubleQuoteStringInsideBracketSelection;
|
|
1527
1550
|
default:
|
|
1528
1551
|
l.backup();
|
|
1529
|
-
if (l.acceptMatchRun(indexPattern)) {
|
|
1530
|
-
l.emit(TokenKind.INDEX);
|
|
1531
|
-
continue;
|
|
1532
|
-
}
|
|
1533
1552
|
l.error(`unexpected token '${ch}' in bracketed selection`);
|
|
1534
1553
|
return null;
|
|
1535
1554
|
}
|
|
@@ -1543,6 +1562,8 @@ function lexInsideFilter(l) {
|
|
|
1543
1562
|
const ch = l.next();
|
|
1544
1563
|
switch (ch) {
|
|
1545
1564
|
case "":
|
|
1565
|
+
l.error("unclosed bracketed selection");
|
|
1566
|
+
return null;
|
|
1546
1567
|
case "]":
|
|
1547
1568
|
l.filterLevel -= 1;
|
|
1548
1569
|
if (l.parenStack.length === 1) {
|
|
@@ -1584,6 +1605,9 @@ function lexInsideFilter(l) {
|
|
|
1584
1605
|
case "@":
|
|
1585
1606
|
l.emit(TokenKind.CURRENT);
|
|
1586
1607
|
return lexSegment;
|
|
1608
|
+
case "#":
|
|
1609
|
+
l.emit(TokenKind.KEY);
|
|
1610
|
+
return lexSegment;
|
|
1587
1611
|
case ".":
|
|
1588
1612
|
l.backup();
|
|
1589
1613
|
return lexSegment;
|
|
@@ -1961,12 +1985,22 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1961
1985
|
}
|
|
1962
1986
|
resolve(nodes) {
|
|
1963
1987
|
const rv = [];
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1988
|
+
if (this.environment.nondeterministic) {
|
|
1989
|
+
for (const root of nodes) {
|
|
1990
|
+
for (const node of this.nondeterministicVisitor(root)) {
|
|
1991
|
+
rv.push(node);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
} else {
|
|
1995
|
+
for (const node of nodes) {
|
|
1996
|
+
rv.push(node);
|
|
1997
|
+
for (const _node of this.visitor(node)) {
|
|
1998
|
+
rv.push(_node);
|
|
1999
|
+
}
|
|
1968
2000
|
}
|
|
1969
2001
|
}
|
|
2002
|
+
|
|
2003
|
+
// console.log(JSON.stringify(rv.map((n: any) => n.value)));
|
|
1970
2004
|
return this.selector.resolve(rv);
|
|
1971
2005
|
}
|
|
1972
2006
|
*lazyResolve(nodes) {
|
|
@@ -2019,7 +2053,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2019
2053
|
toString() {
|
|
2020
2054
|
return `..${this.selector.toString()}`;
|
|
2021
2055
|
}
|
|
2022
|
-
|
|
2056
|
+
visitor(node) {
|
|
2023
2057
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2024
2058
|
if (depth >= this.environment.maxRecursionDepth) {
|
|
2025
2059
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
@@ -2030,7 +2064,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2030
2064
|
for (let i = 0; i < node.value.length; i++) {
|
|
2031
2065
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
2032
2066
|
rv.push(_node);
|
|
2033
|
-
for (const __node of this.
|
|
2067
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2034
2068
|
rv.push(__node);
|
|
2035
2069
|
}
|
|
2036
2070
|
}
|
|
@@ -2038,13 +2072,52 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2038
2072
|
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2039
2073
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2040
2074
|
rv.push(_node);
|
|
2041
|
-
for (const __node of this.
|
|
2075
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2042
2076
|
rv.push(__node);
|
|
2043
2077
|
}
|
|
2044
2078
|
}
|
|
2045
2079
|
}
|
|
2046
2080
|
return rv;
|
|
2047
2081
|
}
|
|
2082
|
+
nondeterministicVisitor(root) {
|
|
2083
|
+
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2084
|
+
const rv = [root];
|
|
2085
|
+
let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
|
|
2086
|
+
while (queue.length) {
|
|
2087
|
+
const [node, _depth] = queue.shift();
|
|
2088
|
+
rv.push(node);
|
|
2089
|
+
if (_depth >= this.environment.maxRecursionDepth) {
|
|
2090
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// Visit child nodes now or queue them for later?
|
|
2094
|
+
const visitChildren = Math.random() < 0.5;
|
|
2095
|
+
for (const child of this.nondeterministicChildren(node)) {
|
|
2096
|
+
if (visitChildren) {
|
|
2097
|
+
rv.push(child);
|
|
2098
|
+
const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
|
|
2099
|
+
queue = interleave(queue, grandchildren);
|
|
2100
|
+
} else {
|
|
2101
|
+
queue.push([child, _depth + 1]);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
return rv;
|
|
2106
|
+
}
|
|
2107
|
+
nondeterministicChildren(node) {
|
|
2108
|
+
const _rv = [];
|
|
2109
|
+
if (node.value instanceof String) return _rv;
|
|
2110
|
+
if (isArray(node.value)) {
|
|
2111
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
2112
|
+
_rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
|
|
2113
|
+
}
|
|
2114
|
+
} else if (isObject(node.value)) {
|
|
2115
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2116
|
+
_rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
return _rv;
|
|
2120
|
+
}
|
|
2048
2121
|
}
|
|
2049
2122
|
class FilterSelector extends JSONPathSelector {
|
|
2050
2123
|
constructor(environment, token, expression) {
|
|
@@ -2065,7 +2138,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2065
2138
|
const filterContext = {
|
|
2066
2139
|
environment: this.environment,
|
|
2067
2140
|
currentValue: value,
|
|
2068
|
-
rootValue: node.root
|
|
2141
|
+
rootValue: node.root,
|
|
2142
|
+
currentKey: i
|
|
2069
2143
|
};
|
|
2070
2144
|
if (this.expression.evaluate(filterContext)) {
|
|
2071
2145
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
@@ -2076,7 +2150,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2076
2150
|
const filterContext = {
|
|
2077
2151
|
environment: this.environment,
|
|
2078
2152
|
currentValue: value,
|
|
2079
|
-
rootValue: node.root
|
|
2153
|
+
rootValue: node.root,
|
|
2154
|
+
currentKey: key
|
|
2080
2155
|
};
|
|
2081
2156
|
if (this.expression.evaluate(filterContext)) {
|
|
2082
2157
|
rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
@@ -2098,7 +2173,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2098
2173
|
environment: this.environment,
|
|
2099
2174
|
currentValue: value,
|
|
2100
2175
|
rootValue: node.root,
|
|
2101
|
-
lazy: true
|
|
2176
|
+
lazy: true,
|
|
2177
|
+
currentKey: i
|
|
2102
2178
|
};
|
|
2103
2179
|
if (this.expression.evaluate(filterContext)) {
|
|
2104
2180
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
@@ -2110,7 +2186,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2110
2186
|
environment: this.environment,
|
|
2111
2187
|
currentValue: value,
|
|
2112
2188
|
rootValue: node.root,
|
|
2113
|
-
lazy: true
|
|
2189
|
+
lazy: true,
|
|
2190
|
+
currentKey: key
|
|
2114
2191
|
};
|
|
2115
2192
|
if (this.expression.evaluate(filterContext)) {
|
|
2116
2193
|
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
@@ -2153,6 +2230,41 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
2153
2230
|
}
|
|
2154
2231
|
}
|
|
2155
2232
|
|
|
2233
|
+
/**
|
|
2234
|
+
* Randomly interleave elements from two arrays while maintaining relative
|
|
2235
|
+
* order of each input array.
|
|
2236
|
+
*
|
|
2237
|
+
* If _arrayA_ is empty, _arrayB_ is returned, and vice versa.
|
|
2238
|
+
*/
|
|
2239
|
+
function interleave(arrayA, arrayB) {
|
|
2240
|
+
if (arrayA.length === 0) {
|
|
2241
|
+
return arrayB;
|
|
2242
|
+
}
|
|
2243
|
+
if (arrayB.length === 0) {
|
|
2244
|
+
return arrayA;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// An array of iterators
|
|
2248
|
+
const iterators = [];
|
|
2249
|
+
const itA = arrayA[Symbol.iterator]();
|
|
2250
|
+
const itB = arrayB[Symbol.iterator]();
|
|
2251
|
+
for (let i = 0; i < arrayA.length; i++) {
|
|
2252
|
+
iterators.push(itA);
|
|
2253
|
+
}
|
|
2254
|
+
for (let i = 0; i < arrayB.length; i++) {
|
|
2255
|
+
iterators.push(itB);
|
|
2256
|
+
}
|
|
2257
|
+
shuffle(iterators);
|
|
2258
|
+
return iterators.map(it => it.next().value);
|
|
2259
|
+
}
|
|
2260
|
+
function shuffle(entries) {
|
|
2261
|
+
for (let i = entries.length - 1; i > 0; i--) {
|
|
2262
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
2263
|
+
[entries[i], entries[j]] = [entries[j], entries[i]];
|
|
2264
|
+
}
|
|
2265
|
+
return entries;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2156
2268
|
var selectors = /*#__PURE__*/Object.freeze({
|
|
2157
2269
|
__proto__: null,
|
|
2158
2270
|
BracketedSelection: BracketedSelection,
|
|
@@ -2236,6 +2348,57 @@ class JSONPath {
|
|
|
2236
2348
|
}
|
|
2237
2349
|
}
|
|
2238
2350
|
|
|
2351
|
+
class CurrentKey extends FilterExpression {
|
|
2352
|
+
evaluate(context) {
|
|
2353
|
+
return context.currentKey ?? Nothing;
|
|
2354
|
+
}
|
|
2355
|
+
toString() {
|
|
2356
|
+
return "#";
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
/**
|
|
2361
|
+
* Object property name selector or array index selector.
|
|
2362
|
+
*/
|
|
2363
|
+
class KeysSelector extends JSONPathSelector {
|
|
2364
|
+
constructor(environment, token) {
|
|
2365
|
+
let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
2366
|
+
super(environment, token);
|
|
2367
|
+
this.environment = environment;
|
|
2368
|
+
this.token = token;
|
|
2369
|
+
this.shorthand = shorthand;
|
|
2370
|
+
}
|
|
2371
|
+
resolve(nodes) {
|
|
2372
|
+
const rv = [];
|
|
2373
|
+
for (const node of nodes) {
|
|
2374
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2375
|
+
if (isObject(node.value)) {
|
|
2376
|
+
let i = 0;
|
|
2377
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2378
|
+
rv.push(new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root));
|
|
2379
|
+
i++;
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
return rv;
|
|
2384
|
+
}
|
|
2385
|
+
*lazyResolve(nodes) {
|
|
2386
|
+
for (const node of nodes) {
|
|
2387
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2388
|
+
if (isObject(node.value)) {
|
|
2389
|
+
let i = 0;
|
|
2390
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2391
|
+
yield new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root);
|
|
2392
|
+
i++;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
toString() {
|
|
2398
|
+
return this.shorthand ? "[~]" : "~";
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2239
2402
|
const PRECEDENCE_LOWEST = 1;
|
|
2240
2403
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
2241
2404
|
const PRECEDENCE_LOGICAL_AND = 5;
|
|
@@ -2251,7 +2414,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2251
2414
|
class Parser {
|
|
2252
2415
|
constructor(environment) {
|
|
2253
2416
|
this.environment = environment;
|
|
2254
|
-
this.tokenMap = new Map([[TokenKind.FALSE, this.parseBoolean], [TokenKind.NUMBER, this.parseNumber], [TokenKind.LPAREN, this.parseGroupedExpression], [TokenKind.NOT, this.parsePrefixExpression], [TokenKind.NULL, this.parseNull], [TokenKind.ROOT, this.parseRootQuery], [TokenKind.CURRENT, this.parseRelativeQuery], [TokenKind.SINGLE_QUOTE_STRING, this.parseString], [TokenKind.DOUBLE_QUOTE_STRING, this.parseString], [TokenKind.TRUE, this.parseBoolean], [TokenKind.FUNCTION, this.parseFunction]]);
|
|
2417
|
+
this.tokenMap = new Map([[TokenKind.FALSE, this.parseBoolean], [TokenKind.NUMBER, this.parseNumber], [TokenKind.LPAREN, this.parseGroupedExpression], [TokenKind.NOT, this.parsePrefixExpression], [TokenKind.NULL, this.parseNull], [TokenKind.ROOT, this.parseRootQuery], [TokenKind.CURRENT, this.parseRelativeQuery], [TokenKind.SINGLE_QUOTE_STRING, this.parseString], [TokenKind.DOUBLE_QUOTE_STRING, this.parseString], [TokenKind.TRUE, this.parseBoolean], [TokenKind.FUNCTION, this.parseFunction], [TokenKind.KEY, this.parseCurrentKey], [TokenKind.KEY, this.parseCurrentKey]]);
|
|
2255
2418
|
}
|
|
2256
2419
|
parse(stream) {
|
|
2257
2420
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2283,6 +2446,8 @@ class Parser {
|
|
|
2283
2446
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2284
2447
|
case TokenKind.WILD:
|
|
2285
2448
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2449
|
+
case TokenKind.KEYS:
|
|
2450
|
+
return new KeysSelector(this.environment, stream.current, true);
|
|
2286
2451
|
case TokenKind.DDOT:
|
|
2287
2452
|
{
|
|
2288
2453
|
const segmentToken = stream.current;
|
|
@@ -2376,6 +2541,9 @@ class Parser {
|
|
|
2376
2541
|
case TokenKind.WILD:
|
|
2377
2542
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2378
2543
|
break;
|
|
2544
|
+
case TokenKind.KEYS:
|
|
2545
|
+
items.push(new KeysSelector(this.environment, stream.current));
|
|
2546
|
+
break;
|
|
2379
2547
|
case TokenKind.EOF:
|
|
2380
2548
|
throw new JSONPathSyntaxError("unexpected end of query", stream.current);
|
|
2381
2549
|
default:
|
|
@@ -2456,6 +2624,9 @@ class Parser {
|
|
|
2456
2624
|
const tok = stream.next();
|
|
2457
2625
|
return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
|
|
2458
2626
|
}
|
|
2627
|
+
parseCurrentKey(stream) {
|
|
2628
|
+
return new CurrentKey(stream.current);
|
|
2629
|
+
}
|
|
2459
2630
|
parseFunction(stream) {
|
|
2460
2631
|
const args = [];
|
|
2461
2632
|
const tok = stream.next();
|
|
@@ -2572,6 +2743,10 @@ class JSONPathEnvironment {
|
|
|
2572
2743
|
* If `true`, enable nondeterministic ordering when iterating JSON object data.
|
|
2573
2744
|
*/
|
|
2574
2745
|
|
|
2746
|
+
/**
|
|
2747
|
+
* The pattern to use for the non-standard _keys selector_.
|
|
2748
|
+
*/
|
|
2749
|
+
|
|
2575
2750
|
/**
|
|
2576
2751
|
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2577
2752
|
* interface. You are free to set or delete custom filter functions directly.
|
|
@@ -2587,6 +2762,7 @@ class JSONPathEnvironment {
|
|
|
2587
2762
|
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2588
2763
|
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2589
2764
|
this.nondeterministic = options.nondeterministic ?? false;
|
|
2765
|
+
this.keysPattern = options.keysPattern ?? /~/y;
|
|
2590
2766
|
this.parser = new Parser(this);
|
|
2591
2767
|
this.setupFilterFunctions();
|
|
2592
2768
|
}
|
|
@@ -2596,7 +2772,7 @@ class JSONPathEnvironment {
|
|
|
2596
2772
|
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2597
2773
|
*/
|
|
2598
2774
|
compile(path) {
|
|
2599
|
-
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
2775
|
+
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
|
|
2600
2776
|
}
|
|
2601
2777
|
|
|
2602
2778
|
/**
|
|
@@ -2678,7 +2854,7 @@ class JSONPathEnvironment {
|
|
|
2678
2854
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2679
2855
|
switch (typ) {
|
|
2680
2856
|
case FunctionExpressionType.ValueType:
|
|
2681
|
-
if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2857
|
+
if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2682
2858
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2683
2859
|
}
|
|
2684
2860
|
break;
|
|
@@ -3306,7 +3482,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3306
3482
|
apply: apply
|
|
3307
3483
|
});
|
|
3308
3484
|
|
|
3309
|
-
const version = "1.
|
|
3485
|
+
const version = "1.2.0";
|
|
3310
3486
|
|
|
3311
3487
|
exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
|
|
3312
3488
|
exports.FunctionExpressionType = FunctionExpressionType;
|