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.esm.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
|
|
@@ -860,12 +860,13 @@ class InfixExpression extends FilterExpression {
|
|
|
860
860
|
this.left = left;
|
|
861
861
|
this.operator = operator;
|
|
862
862
|
this.right = right;
|
|
863
|
+
this.logical = operator === "&&" || operator === "||";
|
|
863
864
|
}
|
|
864
865
|
evaluate(context) {
|
|
865
866
|
let left = this.left.evaluate(context);
|
|
866
|
-
if (left instanceof JSONPathNodeList && left.nodes.length === 1) left = left.nodes[0].value;
|
|
867
|
+
if (!this.logical && left instanceof JSONPathNodeList && left.nodes.length === 1) left = left.nodes[0].value;
|
|
867
868
|
let right = this.right.evaluate(context);
|
|
868
|
-
if (right instanceof JSONPathNodeList && right.nodes.length === 1) right = right.nodes[0].value;
|
|
869
|
+
if (!this.logical && right instanceof JSONPathNodeList && right.nodes.length === 1) right = right.nodes[0].value;
|
|
869
870
|
if (this.operator === "&&") {
|
|
870
871
|
return isTruthy(left) && isTruthy(right);
|
|
871
872
|
}
|
|
@@ -875,7 +876,7 @@ class InfixExpression extends FilterExpression {
|
|
|
875
876
|
return compare(left, this.operator, right);
|
|
876
877
|
}
|
|
877
878
|
toString() {
|
|
878
|
-
if (this.
|
|
879
|
+
if (this.logical) {
|
|
879
880
|
return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`;
|
|
880
881
|
}
|
|
881
882
|
return `${this.left.toString()} ${this.operator} ${this.right.toString()}`;
|
|
@@ -1179,6 +1180,8 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1179
1180
|
TokenKind["GE"] = "TOKEN_GE";
|
|
1180
1181
|
TokenKind["GT"] = "TOKEN_GT";
|
|
1181
1182
|
TokenKind["INDEX"] = "TOKEN_INDEX";
|
|
1183
|
+
TokenKind["KEY"] = "TOKEN_KEY";
|
|
1184
|
+
TokenKind["KEYS"] = "TOKEN_KEYS";
|
|
1182
1185
|
TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
|
|
1183
1186
|
TokenKind["LE"] = "TOKEN_LE";
|
|
1184
1187
|
TokenKind["LG"] = "TOKEN_LG";
|
|
@@ -1248,6 +1251,9 @@ class TokenStream {
|
|
|
1248
1251
|
}
|
|
1249
1252
|
}
|
|
1250
1253
|
|
|
1254
|
+
/** A lexer that accepts additional, non-standard tokens. */
|
|
1255
|
+
|
|
1256
|
+
|
|
1251
1257
|
// These regular expressions are to be used with Lexer.acceptMatchRun(),
|
|
1252
1258
|
// which expects the sticky flag to be set.
|
|
1253
1259
|
const exponentPattern = /e[+-]?\d+/y;
|
|
@@ -1287,7 +1293,8 @@ class Lexer {
|
|
|
1287
1293
|
/**
|
|
1288
1294
|
* @param path - A JSONPath query.
|
|
1289
1295
|
*/
|
|
1290
|
-
constructor(path) {
|
|
1296
|
+
constructor(environment, path) {
|
|
1297
|
+
this.environment = environment;
|
|
1291
1298
|
this.path = path;
|
|
1292
1299
|
}
|
|
1293
1300
|
get pos() {
|
|
@@ -1387,8 +1394,8 @@ class Lexer {
|
|
|
1387
1394
|
* @returns A two-tuple containing a lexer for _path_ and an array to populate
|
|
1388
1395
|
* with tokens.
|
|
1389
1396
|
*/
|
|
1390
|
-
function lex(path) {
|
|
1391
|
-
const lexer = new Lexer(path);
|
|
1397
|
+
function lex(environment, path) {
|
|
1398
|
+
const lexer = new Lexer(environment, path);
|
|
1392
1399
|
return [lexer, lexer.tokens];
|
|
1393
1400
|
}
|
|
1394
1401
|
|
|
@@ -1397,8 +1404,8 @@ function lex(path) {
|
|
|
1397
1404
|
* @param path - A JSONPath query.
|
|
1398
1405
|
* @returns Tokens to be parsed by the parser.
|
|
1399
1406
|
*/
|
|
1400
|
-
function tokenize(path) {
|
|
1401
|
-
const [lexer, tokens] = lex(path);
|
|
1407
|
+
function tokenize(environment, path) {
|
|
1408
|
+
const [lexer, tokens] = lex(environment, path);
|
|
1402
1409
|
lexer.run();
|
|
1403
1410
|
if (tokens.length && tokens[tokens.length - 1].kind === TokenKind.ERROR) {
|
|
1404
1411
|
throw new JSONPathSyntaxError(tokens[tokens.length - 1].value, tokens[tokens.length - 1]);
|
|
@@ -1451,6 +1458,16 @@ function lexSegment(l) {
|
|
|
1451
1458
|
* @returns -
|
|
1452
1459
|
*/
|
|
1453
1460
|
function lexDescendantSelection(l) {
|
|
1461
|
+
if (l.acceptMatchRun(namePattern)) {
|
|
1462
|
+
// Shorthand name
|
|
1463
|
+
l.emit(TokenKind.NAME);
|
|
1464
|
+
return lexSegment;
|
|
1465
|
+
}
|
|
1466
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1467
|
+
// Non-standard keys selector
|
|
1468
|
+
l.emit(TokenKind.KEYS);
|
|
1469
|
+
return lexSegment;
|
|
1470
|
+
}
|
|
1454
1471
|
const ch = l.next();
|
|
1455
1472
|
switch (ch) {
|
|
1456
1473
|
case "":
|
|
@@ -1464,13 +1481,8 @@ function lexDescendantSelection(l) {
|
|
|
1464
1481
|
return lexInsideBracketedSelection;
|
|
1465
1482
|
default:
|
|
1466
1483
|
l.backup();
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
return lexSegment;
|
|
1470
|
-
} else {
|
|
1471
|
-
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1472
|
-
return null;
|
|
1473
|
-
}
|
|
1484
|
+
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1485
|
+
return null;
|
|
1474
1486
|
}
|
|
1475
1487
|
}
|
|
1476
1488
|
function lexDotSelector(l) {
|
|
@@ -1479,23 +1491,34 @@ function lexDotSelector(l) {
|
|
|
1479
1491
|
l.error("unexpected whitespace after dot");
|
|
1480
1492
|
return null;
|
|
1481
1493
|
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
l.emit(TokenKind.WILD);
|
|
1494
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1495
|
+
l.emit(TokenKind.KEYS);
|
|
1485
1496
|
return lexSegment;
|
|
1486
1497
|
}
|
|
1487
|
-
l.backup();
|
|
1488
1498
|
if (l.acceptMatchRun(namePattern)) {
|
|
1489
1499
|
l.emit(TokenKind.NAME);
|
|
1490
1500
|
return lexSegment;
|
|
1491
|
-
} else {
|
|
1492
|
-
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1493
|
-
return null;
|
|
1494
1501
|
}
|
|
1502
|
+
const ch = l.next();
|
|
1503
|
+
if (ch === "*") {
|
|
1504
|
+
l.emit(TokenKind.WILD);
|
|
1505
|
+
return lexSegment;
|
|
1506
|
+
}
|
|
1507
|
+
l.backup();
|
|
1508
|
+
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1509
|
+
return null;
|
|
1495
1510
|
}
|
|
1496
1511
|
function lexInsideBracketedSelection(l) {
|
|
1497
1512
|
for (;;) {
|
|
1498
1513
|
l.ignoreWhitespace();
|
|
1514
|
+
if (l.acceptMatchRun(indexPattern)) {
|
|
1515
|
+
l.emit(TokenKind.INDEX);
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1519
|
+
l.emit(TokenKind.KEYS);
|
|
1520
|
+
continue;
|
|
1521
|
+
}
|
|
1499
1522
|
const ch = l.next();
|
|
1500
1523
|
switch (ch) {
|
|
1501
1524
|
case "]":
|
|
@@ -1524,10 +1547,6 @@ function lexInsideBracketedSelection(l) {
|
|
|
1524
1547
|
return lexDoubleQuoteStringInsideBracketSelection;
|
|
1525
1548
|
default:
|
|
1526
1549
|
l.backup();
|
|
1527
|
-
if (l.acceptMatchRun(indexPattern)) {
|
|
1528
|
-
l.emit(TokenKind.INDEX);
|
|
1529
|
-
continue;
|
|
1530
|
-
}
|
|
1531
1550
|
l.error(`unexpected token '${ch}' in bracketed selection`);
|
|
1532
1551
|
return null;
|
|
1533
1552
|
}
|
|
@@ -1541,6 +1560,8 @@ function lexInsideFilter(l) {
|
|
|
1541
1560
|
const ch = l.next();
|
|
1542
1561
|
switch (ch) {
|
|
1543
1562
|
case "":
|
|
1563
|
+
l.error("unclosed bracketed selection");
|
|
1564
|
+
return null;
|
|
1544
1565
|
case "]":
|
|
1545
1566
|
l.filterLevel -= 1;
|
|
1546
1567
|
if (l.parenStack.length === 1) {
|
|
@@ -1582,6 +1603,9 @@ function lexInsideFilter(l) {
|
|
|
1582
1603
|
case "@":
|
|
1583
1604
|
l.emit(TokenKind.CURRENT);
|
|
1584
1605
|
return lexSegment;
|
|
1606
|
+
case "#":
|
|
1607
|
+
l.emit(TokenKind.KEY);
|
|
1608
|
+
return lexSegment;
|
|
1585
1609
|
case ".":
|
|
1586
1610
|
l.backup();
|
|
1587
1611
|
return lexSegment;
|
|
@@ -1959,12 +1983,22 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1959
1983
|
}
|
|
1960
1984
|
resolve(nodes) {
|
|
1961
1985
|
const rv = [];
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1986
|
+
if (this.environment.nondeterministic) {
|
|
1987
|
+
for (const root of nodes) {
|
|
1988
|
+
for (const node of this.nondeterministicVisitor(root)) {
|
|
1989
|
+
rv.push(node);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
} else {
|
|
1993
|
+
for (const node of nodes) {
|
|
1994
|
+
rv.push(node);
|
|
1995
|
+
for (const _node of this.visitor(node)) {
|
|
1996
|
+
rv.push(_node);
|
|
1997
|
+
}
|
|
1966
1998
|
}
|
|
1967
1999
|
}
|
|
2000
|
+
|
|
2001
|
+
// console.log(JSON.stringify(rv.map((n: any) => n.value)));
|
|
1968
2002
|
return this.selector.resolve(rv);
|
|
1969
2003
|
}
|
|
1970
2004
|
*lazyResolve(nodes) {
|
|
@@ -2017,7 +2051,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2017
2051
|
toString() {
|
|
2018
2052
|
return `..${this.selector.toString()}`;
|
|
2019
2053
|
}
|
|
2020
|
-
|
|
2054
|
+
visitor(node) {
|
|
2021
2055
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2022
2056
|
if (depth >= this.environment.maxRecursionDepth) {
|
|
2023
2057
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
@@ -2028,7 +2062,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2028
2062
|
for (let i = 0; i < node.value.length; i++) {
|
|
2029
2063
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
2030
2064
|
rv.push(_node);
|
|
2031
|
-
for (const __node of this.
|
|
2065
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2032
2066
|
rv.push(__node);
|
|
2033
2067
|
}
|
|
2034
2068
|
}
|
|
@@ -2036,13 +2070,52 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2036
2070
|
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2037
2071
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2038
2072
|
rv.push(_node);
|
|
2039
|
-
for (const __node of this.
|
|
2073
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2040
2074
|
rv.push(__node);
|
|
2041
2075
|
}
|
|
2042
2076
|
}
|
|
2043
2077
|
}
|
|
2044
2078
|
return rv;
|
|
2045
2079
|
}
|
|
2080
|
+
nondeterministicVisitor(root) {
|
|
2081
|
+
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2082
|
+
const rv = [root];
|
|
2083
|
+
let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
|
|
2084
|
+
while (queue.length) {
|
|
2085
|
+
const [node, _depth] = queue.shift();
|
|
2086
|
+
rv.push(node);
|
|
2087
|
+
if (_depth >= this.environment.maxRecursionDepth) {
|
|
2088
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// Visit child nodes now or queue them for later?
|
|
2092
|
+
const visitChildren = Math.random() < 0.5;
|
|
2093
|
+
for (const child of this.nondeterministicChildren(node)) {
|
|
2094
|
+
if (visitChildren) {
|
|
2095
|
+
rv.push(child);
|
|
2096
|
+
const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
|
|
2097
|
+
queue = interleave(queue, grandchildren);
|
|
2098
|
+
} else {
|
|
2099
|
+
queue.push([child, _depth + 1]);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
return rv;
|
|
2104
|
+
}
|
|
2105
|
+
nondeterministicChildren(node) {
|
|
2106
|
+
const _rv = [];
|
|
2107
|
+
if (node.value instanceof String) return _rv;
|
|
2108
|
+
if (isArray(node.value)) {
|
|
2109
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
2110
|
+
_rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
|
|
2111
|
+
}
|
|
2112
|
+
} else if (isObject(node.value)) {
|
|
2113
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2114
|
+
_rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
return _rv;
|
|
2118
|
+
}
|
|
2046
2119
|
}
|
|
2047
2120
|
class FilterSelector extends JSONPathSelector {
|
|
2048
2121
|
constructor(environment, token, expression) {
|
|
@@ -2063,7 +2136,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2063
2136
|
const filterContext = {
|
|
2064
2137
|
environment: this.environment,
|
|
2065
2138
|
currentValue: value,
|
|
2066
|
-
rootValue: node.root
|
|
2139
|
+
rootValue: node.root,
|
|
2140
|
+
currentKey: i
|
|
2067
2141
|
};
|
|
2068
2142
|
if (this.expression.evaluate(filterContext)) {
|
|
2069
2143
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
@@ -2074,7 +2148,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2074
2148
|
const filterContext = {
|
|
2075
2149
|
environment: this.environment,
|
|
2076
2150
|
currentValue: value,
|
|
2077
|
-
rootValue: node.root
|
|
2151
|
+
rootValue: node.root,
|
|
2152
|
+
currentKey: key
|
|
2078
2153
|
};
|
|
2079
2154
|
if (this.expression.evaluate(filterContext)) {
|
|
2080
2155
|
rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
@@ -2096,7 +2171,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2096
2171
|
environment: this.environment,
|
|
2097
2172
|
currentValue: value,
|
|
2098
2173
|
rootValue: node.root,
|
|
2099
|
-
lazy: true
|
|
2174
|
+
lazy: true,
|
|
2175
|
+
currentKey: i
|
|
2100
2176
|
};
|
|
2101
2177
|
if (this.expression.evaluate(filterContext)) {
|
|
2102
2178
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
@@ -2108,7 +2184,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2108
2184
|
environment: this.environment,
|
|
2109
2185
|
currentValue: value,
|
|
2110
2186
|
rootValue: node.root,
|
|
2111
|
-
lazy: true
|
|
2187
|
+
lazy: true,
|
|
2188
|
+
currentKey: key
|
|
2112
2189
|
};
|
|
2113
2190
|
if (this.expression.evaluate(filterContext)) {
|
|
2114
2191
|
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
@@ -2151,6 +2228,41 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
2151
2228
|
}
|
|
2152
2229
|
}
|
|
2153
2230
|
|
|
2231
|
+
/**
|
|
2232
|
+
* Randomly interleave elements from two arrays while maintaining relative
|
|
2233
|
+
* order of each input array.
|
|
2234
|
+
*
|
|
2235
|
+
* If _arrayA_ is empty, _arrayB_ is returned, and vice versa.
|
|
2236
|
+
*/
|
|
2237
|
+
function interleave(arrayA, arrayB) {
|
|
2238
|
+
if (arrayA.length === 0) {
|
|
2239
|
+
return arrayB;
|
|
2240
|
+
}
|
|
2241
|
+
if (arrayB.length === 0) {
|
|
2242
|
+
return arrayA;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
// An array of iterators
|
|
2246
|
+
const iterators = [];
|
|
2247
|
+
const itA = arrayA[Symbol.iterator]();
|
|
2248
|
+
const itB = arrayB[Symbol.iterator]();
|
|
2249
|
+
for (let i = 0; i < arrayA.length; i++) {
|
|
2250
|
+
iterators.push(itA);
|
|
2251
|
+
}
|
|
2252
|
+
for (let i = 0; i < arrayB.length; i++) {
|
|
2253
|
+
iterators.push(itB);
|
|
2254
|
+
}
|
|
2255
|
+
shuffle(iterators);
|
|
2256
|
+
return iterators.map(it => it.next().value);
|
|
2257
|
+
}
|
|
2258
|
+
function shuffle(entries) {
|
|
2259
|
+
for (let i = entries.length - 1; i > 0; i--) {
|
|
2260
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
2261
|
+
[entries[i], entries[j]] = [entries[j], entries[i]];
|
|
2262
|
+
}
|
|
2263
|
+
return entries;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2154
2266
|
var selectors = /*#__PURE__*/Object.freeze({
|
|
2155
2267
|
__proto__: null,
|
|
2156
2268
|
BracketedSelection: BracketedSelection,
|
|
@@ -2234,6 +2346,57 @@ class JSONPath {
|
|
|
2234
2346
|
}
|
|
2235
2347
|
}
|
|
2236
2348
|
|
|
2349
|
+
class CurrentKey extends FilterExpression {
|
|
2350
|
+
evaluate(context) {
|
|
2351
|
+
return context.currentKey ?? Nothing;
|
|
2352
|
+
}
|
|
2353
|
+
toString() {
|
|
2354
|
+
return "#";
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
/**
|
|
2359
|
+
* Object property name selector or array index selector.
|
|
2360
|
+
*/
|
|
2361
|
+
class KeysSelector extends JSONPathSelector {
|
|
2362
|
+
constructor(environment, token) {
|
|
2363
|
+
let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
2364
|
+
super(environment, token);
|
|
2365
|
+
this.environment = environment;
|
|
2366
|
+
this.token = token;
|
|
2367
|
+
this.shorthand = shorthand;
|
|
2368
|
+
}
|
|
2369
|
+
resolve(nodes) {
|
|
2370
|
+
const rv = [];
|
|
2371
|
+
for (const node of nodes) {
|
|
2372
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2373
|
+
if (isObject(node.value)) {
|
|
2374
|
+
let i = 0;
|
|
2375
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2376
|
+
rv.push(new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root));
|
|
2377
|
+
i++;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
return rv;
|
|
2382
|
+
}
|
|
2383
|
+
*lazyResolve(nodes) {
|
|
2384
|
+
for (const node of nodes) {
|
|
2385
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2386
|
+
if (isObject(node.value)) {
|
|
2387
|
+
let i = 0;
|
|
2388
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2389
|
+
yield new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root);
|
|
2390
|
+
i++;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
toString() {
|
|
2396
|
+
return this.shorthand ? "[~]" : "~";
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2237
2400
|
const PRECEDENCE_LOWEST = 1;
|
|
2238
2401
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
2239
2402
|
const PRECEDENCE_LOGICAL_AND = 5;
|
|
@@ -2249,7 +2412,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2249
2412
|
class Parser {
|
|
2250
2413
|
constructor(environment) {
|
|
2251
2414
|
this.environment = environment;
|
|
2252
|
-
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]]);
|
|
2415
|
+
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]]);
|
|
2253
2416
|
}
|
|
2254
2417
|
parse(stream) {
|
|
2255
2418
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2281,6 +2444,8 @@ class Parser {
|
|
|
2281
2444
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2282
2445
|
case TokenKind.WILD:
|
|
2283
2446
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2447
|
+
case TokenKind.KEYS:
|
|
2448
|
+
return new KeysSelector(this.environment, stream.current, true);
|
|
2284
2449
|
case TokenKind.DDOT:
|
|
2285
2450
|
{
|
|
2286
2451
|
const segmentToken = stream.current;
|
|
@@ -2374,6 +2539,9 @@ class Parser {
|
|
|
2374
2539
|
case TokenKind.WILD:
|
|
2375
2540
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2376
2541
|
break;
|
|
2542
|
+
case TokenKind.KEYS:
|
|
2543
|
+
items.push(new KeysSelector(this.environment, stream.current));
|
|
2544
|
+
break;
|
|
2377
2545
|
case TokenKind.EOF:
|
|
2378
2546
|
throw new JSONPathSyntaxError("unexpected end of query", stream.current);
|
|
2379
2547
|
default:
|
|
@@ -2454,6 +2622,9 @@ class Parser {
|
|
|
2454
2622
|
const tok = stream.next();
|
|
2455
2623
|
return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
|
|
2456
2624
|
}
|
|
2625
|
+
parseCurrentKey(stream) {
|
|
2626
|
+
return new CurrentKey(stream.current);
|
|
2627
|
+
}
|
|
2457
2628
|
parseFunction(stream) {
|
|
2458
2629
|
const args = [];
|
|
2459
2630
|
const tok = stream.next();
|
|
@@ -2570,6 +2741,10 @@ class JSONPathEnvironment {
|
|
|
2570
2741
|
* If `true`, enable nondeterministic ordering when iterating JSON object data.
|
|
2571
2742
|
*/
|
|
2572
2743
|
|
|
2744
|
+
/**
|
|
2745
|
+
* The pattern to use for the non-standard _keys selector_.
|
|
2746
|
+
*/
|
|
2747
|
+
|
|
2573
2748
|
/**
|
|
2574
2749
|
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2575
2750
|
* interface. You are free to set or delete custom filter functions directly.
|
|
@@ -2585,6 +2760,7 @@ class JSONPathEnvironment {
|
|
|
2585
2760
|
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2586
2761
|
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2587
2762
|
this.nondeterministic = options.nondeterministic ?? false;
|
|
2763
|
+
this.keysPattern = options.keysPattern ?? /~/y;
|
|
2588
2764
|
this.parser = new Parser(this);
|
|
2589
2765
|
this.setupFilterFunctions();
|
|
2590
2766
|
}
|
|
@@ -2594,7 +2770,7 @@ class JSONPathEnvironment {
|
|
|
2594
2770
|
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2595
2771
|
*/
|
|
2596
2772
|
compile(path) {
|
|
2597
|
-
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
2773
|
+
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
|
|
2598
2774
|
}
|
|
2599
2775
|
|
|
2600
2776
|
/**
|
|
@@ -2676,7 +2852,7 @@ class JSONPathEnvironment {
|
|
|
2676
2852
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2677
2853
|
switch (typ) {
|
|
2678
2854
|
case FunctionExpressionType.ValueType:
|
|
2679
|
-
if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2855
|
+
if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2680
2856
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2681
2857
|
}
|
|
2682
2858
|
break;
|
|
@@ -3304,6 +3480,6 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3304
3480
|
apply: apply
|
|
3305
3481
|
});
|
|
3306
3482
|
|
|
3307
|
-
const version = "1.
|
|
3483
|
+
const version = "1.2.0";
|
|
3308
3484
|
|
|
3309
3485
|
export { DEFAULT_ENVIRONMENT, FunctionExpressionType, JSONPatch, JSONPatchError, JSONPatchTestFailure, JSONPath, JSONPathEnvironment, JSONPathError, JSONPathIndexError, JSONPathLexerError, JSONPathNode, JSONPathNodeList, JSONPathRecursionLimitError, JSONPathSyntaxError, JSONPathTypeError, JSONPointer, Nothing, RelativeJSONPointer, Token, TokenKind, UNDEFINED, apply, compile, index as jsonpatch, index$1 as jsonpath, index$3 as jsonpointer, lazyQuery, query, resolve, version };
|