json-p3 1.1.1 → 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 +214 -39
- package/dist/json-p3.esm.js +214 -39
- package/dist/json-p3.iife.js +214 -39
- 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/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
|
|
@@ -1182,6 +1182,8 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1182
1182
|
TokenKind["GE"] = "TOKEN_GE";
|
|
1183
1183
|
TokenKind["GT"] = "TOKEN_GT";
|
|
1184
1184
|
TokenKind["INDEX"] = "TOKEN_INDEX";
|
|
1185
|
+
TokenKind["KEY"] = "TOKEN_KEY";
|
|
1186
|
+
TokenKind["KEYS"] = "TOKEN_KEYS";
|
|
1185
1187
|
TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
|
|
1186
1188
|
TokenKind["LE"] = "TOKEN_LE";
|
|
1187
1189
|
TokenKind["LG"] = "TOKEN_LG";
|
|
@@ -1251,6 +1253,9 @@ class TokenStream {
|
|
|
1251
1253
|
}
|
|
1252
1254
|
}
|
|
1253
1255
|
|
|
1256
|
+
/** A lexer that accepts additional, non-standard tokens. */
|
|
1257
|
+
|
|
1258
|
+
|
|
1254
1259
|
// These regular expressions are to be used with Lexer.acceptMatchRun(),
|
|
1255
1260
|
// which expects the sticky flag to be set.
|
|
1256
1261
|
const exponentPattern = /e[+-]?\d+/y;
|
|
@@ -1290,7 +1295,8 @@ class Lexer {
|
|
|
1290
1295
|
/**
|
|
1291
1296
|
* @param path - A JSONPath query.
|
|
1292
1297
|
*/
|
|
1293
|
-
constructor(path) {
|
|
1298
|
+
constructor(environment, path) {
|
|
1299
|
+
this.environment = environment;
|
|
1294
1300
|
this.path = path;
|
|
1295
1301
|
}
|
|
1296
1302
|
get pos() {
|
|
@@ -1390,8 +1396,8 @@ class Lexer {
|
|
|
1390
1396
|
* @returns A two-tuple containing a lexer for _path_ and an array to populate
|
|
1391
1397
|
* with tokens.
|
|
1392
1398
|
*/
|
|
1393
|
-
function lex(path) {
|
|
1394
|
-
const lexer = new Lexer(path);
|
|
1399
|
+
function lex(environment, path) {
|
|
1400
|
+
const lexer = new Lexer(environment, path);
|
|
1395
1401
|
return [lexer, lexer.tokens];
|
|
1396
1402
|
}
|
|
1397
1403
|
|
|
@@ -1400,8 +1406,8 @@ function lex(path) {
|
|
|
1400
1406
|
* @param path - A JSONPath query.
|
|
1401
1407
|
* @returns Tokens to be parsed by the parser.
|
|
1402
1408
|
*/
|
|
1403
|
-
function tokenize(path) {
|
|
1404
|
-
const [lexer, tokens] = lex(path);
|
|
1409
|
+
function tokenize(environment, path) {
|
|
1410
|
+
const [lexer, tokens] = lex(environment, path);
|
|
1405
1411
|
lexer.run();
|
|
1406
1412
|
if (tokens.length && tokens[tokens.length - 1].kind === TokenKind.ERROR) {
|
|
1407
1413
|
throw new JSONPathSyntaxError(tokens[tokens.length - 1].value, tokens[tokens.length - 1]);
|
|
@@ -1454,6 +1460,16 @@ function lexSegment(l) {
|
|
|
1454
1460
|
* @returns -
|
|
1455
1461
|
*/
|
|
1456
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
|
+
}
|
|
1457
1473
|
const ch = l.next();
|
|
1458
1474
|
switch (ch) {
|
|
1459
1475
|
case "":
|
|
@@ -1467,13 +1483,8 @@ function lexDescendantSelection(l) {
|
|
|
1467
1483
|
return lexInsideBracketedSelection;
|
|
1468
1484
|
default:
|
|
1469
1485
|
l.backup();
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
return lexSegment;
|
|
1473
|
-
} else {
|
|
1474
|
-
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1475
|
-
return null;
|
|
1476
|
-
}
|
|
1486
|
+
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1487
|
+
return null;
|
|
1477
1488
|
}
|
|
1478
1489
|
}
|
|
1479
1490
|
function lexDotSelector(l) {
|
|
@@ -1482,23 +1493,34 @@ function lexDotSelector(l) {
|
|
|
1482
1493
|
l.error("unexpected whitespace after dot");
|
|
1483
1494
|
return null;
|
|
1484
1495
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
l.emit(TokenKind.WILD);
|
|
1496
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1497
|
+
l.emit(TokenKind.KEYS);
|
|
1488
1498
|
return lexSegment;
|
|
1489
1499
|
}
|
|
1490
|
-
l.backup();
|
|
1491
1500
|
if (l.acceptMatchRun(namePattern)) {
|
|
1492
1501
|
l.emit(TokenKind.NAME);
|
|
1493
1502
|
return lexSegment;
|
|
1494
|
-
} else {
|
|
1495
|
-
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1496
|
-
return null;
|
|
1497
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;
|
|
1498
1512
|
}
|
|
1499
1513
|
function lexInsideBracketedSelection(l) {
|
|
1500
1514
|
for (;;) {
|
|
1501
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
|
+
}
|
|
1502
1524
|
const ch = l.next();
|
|
1503
1525
|
switch (ch) {
|
|
1504
1526
|
case "]":
|
|
@@ -1527,10 +1549,6 @@ function lexInsideBracketedSelection(l) {
|
|
|
1527
1549
|
return lexDoubleQuoteStringInsideBracketSelection;
|
|
1528
1550
|
default:
|
|
1529
1551
|
l.backup();
|
|
1530
|
-
if (l.acceptMatchRun(indexPattern)) {
|
|
1531
|
-
l.emit(TokenKind.INDEX);
|
|
1532
|
-
continue;
|
|
1533
|
-
}
|
|
1534
1552
|
l.error(`unexpected token '${ch}' in bracketed selection`);
|
|
1535
1553
|
return null;
|
|
1536
1554
|
}
|
|
@@ -1544,6 +1562,8 @@ function lexInsideFilter(l) {
|
|
|
1544
1562
|
const ch = l.next();
|
|
1545
1563
|
switch (ch) {
|
|
1546
1564
|
case "":
|
|
1565
|
+
l.error("unclosed bracketed selection");
|
|
1566
|
+
return null;
|
|
1547
1567
|
case "]":
|
|
1548
1568
|
l.filterLevel -= 1;
|
|
1549
1569
|
if (l.parenStack.length === 1) {
|
|
@@ -1585,6 +1605,9 @@ function lexInsideFilter(l) {
|
|
|
1585
1605
|
case "@":
|
|
1586
1606
|
l.emit(TokenKind.CURRENT);
|
|
1587
1607
|
return lexSegment;
|
|
1608
|
+
case "#":
|
|
1609
|
+
l.emit(TokenKind.KEY);
|
|
1610
|
+
return lexSegment;
|
|
1588
1611
|
case ".":
|
|
1589
1612
|
l.backup();
|
|
1590
1613
|
return lexSegment;
|
|
@@ -1962,12 +1985,22 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1962
1985
|
}
|
|
1963
1986
|
resolve(nodes) {
|
|
1964
1987
|
const rv = [];
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
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
|
+
}
|
|
1969
2000
|
}
|
|
1970
2001
|
}
|
|
2002
|
+
|
|
2003
|
+
// console.log(JSON.stringify(rv.map((n: any) => n.value)));
|
|
1971
2004
|
return this.selector.resolve(rv);
|
|
1972
2005
|
}
|
|
1973
2006
|
*lazyResolve(nodes) {
|
|
@@ -2020,7 +2053,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2020
2053
|
toString() {
|
|
2021
2054
|
return `..${this.selector.toString()}`;
|
|
2022
2055
|
}
|
|
2023
|
-
|
|
2056
|
+
visitor(node) {
|
|
2024
2057
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2025
2058
|
if (depth >= this.environment.maxRecursionDepth) {
|
|
2026
2059
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
@@ -2031,7 +2064,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2031
2064
|
for (let i = 0; i < node.value.length; i++) {
|
|
2032
2065
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
2033
2066
|
rv.push(_node);
|
|
2034
|
-
for (const __node of this.
|
|
2067
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2035
2068
|
rv.push(__node);
|
|
2036
2069
|
}
|
|
2037
2070
|
}
|
|
@@ -2039,13 +2072,52 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2039
2072
|
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2040
2073
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2041
2074
|
rv.push(_node);
|
|
2042
|
-
for (const __node of this.
|
|
2075
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2043
2076
|
rv.push(__node);
|
|
2044
2077
|
}
|
|
2045
2078
|
}
|
|
2046
2079
|
}
|
|
2047
2080
|
return rv;
|
|
2048
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
|
+
}
|
|
2049
2121
|
}
|
|
2050
2122
|
class FilterSelector extends JSONPathSelector {
|
|
2051
2123
|
constructor(environment, token, expression) {
|
|
@@ -2066,7 +2138,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2066
2138
|
const filterContext = {
|
|
2067
2139
|
environment: this.environment,
|
|
2068
2140
|
currentValue: value,
|
|
2069
|
-
rootValue: node.root
|
|
2141
|
+
rootValue: node.root,
|
|
2142
|
+
currentKey: i
|
|
2070
2143
|
};
|
|
2071
2144
|
if (this.expression.evaluate(filterContext)) {
|
|
2072
2145
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
@@ -2077,7 +2150,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2077
2150
|
const filterContext = {
|
|
2078
2151
|
environment: this.environment,
|
|
2079
2152
|
currentValue: value,
|
|
2080
|
-
rootValue: node.root
|
|
2153
|
+
rootValue: node.root,
|
|
2154
|
+
currentKey: key
|
|
2081
2155
|
};
|
|
2082
2156
|
if (this.expression.evaluate(filterContext)) {
|
|
2083
2157
|
rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
@@ -2099,7 +2173,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2099
2173
|
environment: this.environment,
|
|
2100
2174
|
currentValue: value,
|
|
2101
2175
|
rootValue: node.root,
|
|
2102
|
-
lazy: true
|
|
2176
|
+
lazy: true,
|
|
2177
|
+
currentKey: i
|
|
2103
2178
|
};
|
|
2104
2179
|
if (this.expression.evaluate(filterContext)) {
|
|
2105
2180
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
@@ -2111,7 +2186,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2111
2186
|
environment: this.environment,
|
|
2112
2187
|
currentValue: value,
|
|
2113
2188
|
rootValue: node.root,
|
|
2114
|
-
lazy: true
|
|
2189
|
+
lazy: true,
|
|
2190
|
+
currentKey: key
|
|
2115
2191
|
};
|
|
2116
2192
|
if (this.expression.evaluate(filterContext)) {
|
|
2117
2193
|
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
@@ -2154,6 +2230,41 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
2154
2230
|
}
|
|
2155
2231
|
}
|
|
2156
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
|
+
|
|
2157
2268
|
var selectors = /*#__PURE__*/Object.freeze({
|
|
2158
2269
|
__proto__: null,
|
|
2159
2270
|
BracketedSelection: BracketedSelection,
|
|
@@ -2237,6 +2348,57 @@ class JSONPath {
|
|
|
2237
2348
|
}
|
|
2238
2349
|
}
|
|
2239
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
|
+
|
|
2240
2402
|
const PRECEDENCE_LOWEST = 1;
|
|
2241
2403
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
2242
2404
|
const PRECEDENCE_LOGICAL_AND = 5;
|
|
@@ -2252,7 +2414,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2252
2414
|
class Parser {
|
|
2253
2415
|
constructor(environment) {
|
|
2254
2416
|
this.environment = environment;
|
|
2255
|
-
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]]);
|
|
2256
2418
|
}
|
|
2257
2419
|
parse(stream) {
|
|
2258
2420
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2284,6 +2446,8 @@ class Parser {
|
|
|
2284
2446
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2285
2447
|
case TokenKind.WILD:
|
|
2286
2448
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2449
|
+
case TokenKind.KEYS:
|
|
2450
|
+
return new KeysSelector(this.environment, stream.current, true);
|
|
2287
2451
|
case TokenKind.DDOT:
|
|
2288
2452
|
{
|
|
2289
2453
|
const segmentToken = stream.current;
|
|
@@ -2377,6 +2541,9 @@ class Parser {
|
|
|
2377
2541
|
case TokenKind.WILD:
|
|
2378
2542
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2379
2543
|
break;
|
|
2544
|
+
case TokenKind.KEYS:
|
|
2545
|
+
items.push(new KeysSelector(this.environment, stream.current));
|
|
2546
|
+
break;
|
|
2380
2547
|
case TokenKind.EOF:
|
|
2381
2548
|
throw new JSONPathSyntaxError("unexpected end of query", stream.current);
|
|
2382
2549
|
default:
|
|
@@ -2457,6 +2624,9 @@ class Parser {
|
|
|
2457
2624
|
const tok = stream.next();
|
|
2458
2625
|
return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
|
|
2459
2626
|
}
|
|
2627
|
+
parseCurrentKey(stream) {
|
|
2628
|
+
return new CurrentKey(stream.current);
|
|
2629
|
+
}
|
|
2460
2630
|
parseFunction(stream) {
|
|
2461
2631
|
const args = [];
|
|
2462
2632
|
const tok = stream.next();
|
|
@@ -2573,6 +2743,10 @@ class JSONPathEnvironment {
|
|
|
2573
2743
|
* If `true`, enable nondeterministic ordering when iterating JSON object data.
|
|
2574
2744
|
*/
|
|
2575
2745
|
|
|
2746
|
+
/**
|
|
2747
|
+
* The pattern to use for the non-standard _keys selector_.
|
|
2748
|
+
*/
|
|
2749
|
+
|
|
2576
2750
|
/**
|
|
2577
2751
|
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2578
2752
|
* interface. You are free to set or delete custom filter functions directly.
|
|
@@ -2588,6 +2762,7 @@ class JSONPathEnvironment {
|
|
|
2588
2762
|
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2589
2763
|
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2590
2764
|
this.nondeterministic = options.nondeterministic ?? false;
|
|
2765
|
+
this.keysPattern = options.keysPattern ?? /~/y;
|
|
2591
2766
|
this.parser = new Parser(this);
|
|
2592
2767
|
this.setupFilterFunctions();
|
|
2593
2768
|
}
|
|
@@ -2597,7 +2772,7 @@ class JSONPathEnvironment {
|
|
|
2597
2772
|
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2598
2773
|
*/
|
|
2599
2774
|
compile(path) {
|
|
2600
|
-
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
2775
|
+
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
|
|
2601
2776
|
}
|
|
2602
2777
|
|
|
2603
2778
|
/**
|
|
@@ -2679,7 +2854,7 @@ class JSONPathEnvironment {
|
|
|
2679
2854
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2680
2855
|
switch (typ) {
|
|
2681
2856
|
case FunctionExpressionType.ValueType:
|
|
2682
|
-
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)) {
|
|
2683
2858
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2684
2859
|
}
|
|
2685
2860
|
break;
|
|
@@ -3307,7 +3482,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3307
3482
|
apply: apply
|
|
3308
3483
|
});
|
|
3309
3484
|
|
|
3310
|
-
const version = "1.
|
|
3485
|
+
const version = "1.2.0";
|
|
3311
3486
|
|
|
3312
3487
|
exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
|
|
3313
3488
|
exports.FunctionExpressionType = FunctionExpressionType;
|