json-p3 1.1.1 → 1.2.1
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 +263 -44
- package/dist/json-p3.esm.js +263 -44
- package/dist/json-p3.iife.js +263 -44
- 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 +4 -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.1
|
|
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;
|
|
@@ -1763,7 +1786,7 @@ class NameSelector extends JSONPathSelector {
|
|
|
1763
1786
|
resolve(nodes) {
|
|
1764
1787
|
const rv = [];
|
|
1765
1788
|
for (const node of nodes) {
|
|
1766
|
-
if (hasStringKey(node.value, this.name)) {
|
|
1789
|
+
if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
|
|
1767
1790
|
rv.push(new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root));
|
|
1768
1791
|
}
|
|
1769
1792
|
}
|
|
@@ -1771,7 +1794,7 @@ class NameSelector extends JSONPathSelector {
|
|
|
1771
1794
|
}
|
|
1772
1795
|
*lazyResolve(nodes) {
|
|
1773
1796
|
for (const node of nodes) {
|
|
1774
|
-
if (hasStringKey(node.value, this.name)) {
|
|
1797
|
+
if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
|
|
1775
1798
|
yield new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root);
|
|
1776
1799
|
}
|
|
1777
1800
|
}
|
|
@@ -1847,7 +1870,7 @@ class SliceSelector extends JSONPathSelector {
|
|
|
1847
1870
|
*lazyResolve(nodes) {
|
|
1848
1871
|
for (const node of nodes) {
|
|
1849
1872
|
if (!isArray(node.value)) continue;
|
|
1850
|
-
for (const [i, value] of this.
|
|
1873
|
+
for (const [i, value] of this.lazySlice(node.value, this.start, this.stop, this.step)) {
|
|
1851
1874
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
1852
1875
|
}
|
|
1853
1876
|
}
|
|
@@ -1910,6 +1933,45 @@ class SliceSelector extends JSONPathSelector {
|
|
|
1910
1933
|
}
|
|
1911
1934
|
return slicedArray;
|
|
1912
1935
|
}
|
|
1936
|
+
|
|
1937
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
1938
|
+
*lazySlice(arr, start, stop, step) {
|
|
1939
|
+
if (!arr.length) return;
|
|
1940
|
+
|
|
1941
|
+
// Handle negative and undefined start values
|
|
1942
|
+
if (start === undefined || start === null) {
|
|
1943
|
+
start = step && step < 0 ? arr.length - 1 : 0;
|
|
1944
|
+
} else if (start < 0) {
|
|
1945
|
+
start = Math.max(arr.length + start, 0);
|
|
1946
|
+
} else {
|
|
1947
|
+
start = Math.min(start, arr.length - 1);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
// Handle negative and undefined stop values
|
|
1951
|
+
if (stop === undefined || stop === null) {
|
|
1952
|
+
stop = step && step < 0 ? -1 : arr.length;
|
|
1953
|
+
} else if (stop < 0) {
|
|
1954
|
+
stop = Math.max(arr.length + stop, -1);
|
|
1955
|
+
} else {
|
|
1956
|
+
stop = Math.min(stop, arr.length);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
// Perform the slice
|
|
1960
|
+
if (step === undefined) {
|
|
1961
|
+
// Default to a step of 1
|
|
1962
|
+
for (let i = start; i < stop; i += 1) {
|
|
1963
|
+
yield [i, arr[i]];
|
|
1964
|
+
}
|
|
1965
|
+
} else if (step > 0) {
|
|
1966
|
+
for (let i = start; i < stop; i += step) {
|
|
1967
|
+
yield [i, arr[i]];
|
|
1968
|
+
}
|
|
1969
|
+
} else if (step < 0) {
|
|
1970
|
+
for (let i = start; i > stop; i += step) {
|
|
1971
|
+
yield [i, arr[i]];
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1913
1975
|
}
|
|
1914
1976
|
class WildcardSelector extends JSONPathSelector {
|
|
1915
1977
|
constructor(environment, token) {
|
|
@@ -1962,10 +2024,18 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1962
2024
|
}
|
|
1963
2025
|
resolve(nodes) {
|
|
1964
2026
|
const rv = [];
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2027
|
+
if (this.environment.nondeterministic) {
|
|
2028
|
+
for (const root of nodes) {
|
|
2029
|
+
for (const node of this.nondeterministicVisitor(root)) {
|
|
2030
|
+
rv.push(node);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
} else {
|
|
2034
|
+
for (const node of nodes) {
|
|
2035
|
+
rv.push(node);
|
|
2036
|
+
for (const _node of this.visitor(node)) {
|
|
2037
|
+
rv.push(_node);
|
|
2038
|
+
}
|
|
1969
2039
|
}
|
|
1970
2040
|
}
|
|
1971
2041
|
return this.selector.resolve(rv);
|
|
@@ -2020,7 +2090,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2020
2090
|
toString() {
|
|
2021
2091
|
return `..${this.selector.toString()}`;
|
|
2022
2092
|
}
|
|
2023
|
-
|
|
2093
|
+
visitor(node) {
|
|
2024
2094
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2025
2095
|
if (depth >= this.environment.maxRecursionDepth) {
|
|
2026
2096
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
@@ -2031,7 +2101,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2031
2101
|
for (let i = 0; i < node.value.length; i++) {
|
|
2032
2102
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
2033
2103
|
rv.push(_node);
|
|
2034
|
-
for (const __node of this.
|
|
2104
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2035
2105
|
rv.push(__node);
|
|
2036
2106
|
}
|
|
2037
2107
|
}
|
|
@@ -2039,13 +2109,52 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2039
2109
|
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2040
2110
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2041
2111
|
rv.push(_node);
|
|
2042
|
-
for (const __node of this.
|
|
2112
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2043
2113
|
rv.push(__node);
|
|
2044
2114
|
}
|
|
2045
2115
|
}
|
|
2046
2116
|
}
|
|
2047
2117
|
return rv;
|
|
2048
2118
|
}
|
|
2119
|
+
nondeterministicVisitor(root) {
|
|
2120
|
+
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2121
|
+
const rv = [root];
|
|
2122
|
+
let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
|
|
2123
|
+
while (queue.length) {
|
|
2124
|
+
const [node, _depth] = queue.shift();
|
|
2125
|
+
rv.push(node);
|
|
2126
|
+
if (_depth >= this.environment.maxRecursionDepth) {
|
|
2127
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
// Visit child nodes now or queue them for later?
|
|
2131
|
+
const visitChildren = Math.random() < 0.5;
|
|
2132
|
+
for (const child of this.nondeterministicChildren(node)) {
|
|
2133
|
+
if (visitChildren) {
|
|
2134
|
+
rv.push(child);
|
|
2135
|
+
const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
|
|
2136
|
+
queue = interleave(queue, grandchildren);
|
|
2137
|
+
} else {
|
|
2138
|
+
queue.push([child, _depth + 1]);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return rv;
|
|
2143
|
+
}
|
|
2144
|
+
nondeterministicChildren(node) {
|
|
2145
|
+
const _rv = [];
|
|
2146
|
+
if (node.value instanceof String) return _rv;
|
|
2147
|
+
if (isArray(node.value)) {
|
|
2148
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
2149
|
+
_rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
|
|
2150
|
+
}
|
|
2151
|
+
} else if (isObject(node.value)) {
|
|
2152
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2153
|
+
_rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
return _rv;
|
|
2157
|
+
}
|
|
2049
2158
|
}
|
|
2050
2159
|
class FilterSelector extends JSONPathSelector {
|
|
2051
2160
|
constructor(environment, token, expression) {
|
|
@@ -2066,7 +2175,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2066
2175
|
const filterContext = {
|
|
2067
2176
|
environment: this.environment,
|
|
2068
2177
|
currentValue: value,
|
|
2069
|
-
rootValue: node.root
|
|
2178
|
+
rootValue: node.root,
|
|
2179
|
+
currentKey: i
|
|
2070
2180
|
};
|
|
2071
2181
|
if (this.expression.evaluate(filterContext)) {
|
|
2072
2182
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
@@ -2077,7 +2187,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2077
2187
|
const filterContext = {
|
|
2078
2188
|
environment: this.environment,
|
|
2079
2189
|
currentValue: value,
|
|
2080
|
-
rootValue: node.root
|
|
2190
|
+
rootValue: node.root,
|
|
2191
|
+
currentKey: key
|
|
2081
2192
|
};
|
|
2082
2193
|
if (this.expression.evaluate(filterContext)) {
|
|
2083
2194
|
rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
@@ -2099,7 +2210,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2099
2210
|
environment: this.environment,
|
|
2100
2211
|
currentValue: value,
|
|
2101
2212
|
rootValue: node.root,
|
|
2102
|
-
lazy: true
|
|
2213
|
+
lazy: true,
|
|
2214
|
+
currentKey: i
|
|
2103
2215
|
};
|
|
2104
2216
|
if (this.expression.evaluate(filterContext)) {
|
|
2105
2217
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
@@ -2111,7 +2223,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2111
2223
|
environment: this.environment,
|
|
2112
2224
|
currentValue: value,
|
|
2113
2225
|
rootValue: node.root,
|
|
2114
|
-
lazy: true
|
|
2226
|
+
lazy: true,
|
|
2227
|
+
currentKey: key
|
|
2115
2228
|
};
|
|
2116
2229
|
if (this.expression.evaluate(filterContext)) {
|
|
2117
2230
|
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
@@ -2154,6 +2267,41 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
2154
2267
|
}
|
|
2155
2268
|
}
|
|
2156
2269
|
|
|
2270
|
+
/**
|
|
2271
|
+
* Randomly interleave elements from two arrays while maintaining relative
|
|
2272
|
+
* order of each input array.
|
|
2273
|
+
*
|
|
2274
|
+
* If _arrayA_ is empty, _arrayB_ is returned, and vice versa.
|
|
2275
|
+
*/
|
|
2276
|
+
function interleave(arrayA, arrayB) {
|
|
2277
|
+
if (arrayA.length === 0) {
|
|
2278
|
+
return arrayB;
|
|
2279
|
+
}
|
|
2280
|
+
if (arrayB.length === 0) {
|
|
2281
|
+
return arrayA;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
// An array of iterators
|
|
2285
|
+
const iterators = [];
|
|
2286
|
+
const itA = arrayA[Symbol.iterator]();
|
|
2287
|
+
const itB = arrayB[Symbol.iterator]();
|
|
2288
|
+
for (let i = 0; i < arrayA.length; i++) {
|
|
2289
|
+
iterators.push(itA);
|
|
2290
|
+
}
|
|
2291
|
+
for (let i = 0; i < arrayB.length; i++) {
|
|
2292
|
+
iterators.push(itB);
|
|
2293
|
+
}
|
|
2294
|
+
shuffle(iterators);
|
|
2295
|
+
return iterators.map(it => it.next().value);
|
|
2296
|
+
}
|
|
2297
|
+
function shuffle(entries) {
|
|
2298
|
+
for (let i = entries.length - 1; i > 0; i--) {
|
|
2299
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
2300
|
+
[entries[i], entries[j]] = [entries[j], entries[i]];
|
|
2301
|
+
}
|
|
2302
|
+
return entries;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2157
2305
|
var selectors = /*#__PURE__*/Object.freeze({
|
|
2158
2306
|
__proto__: null,
|
|
2159
2307
|
BracketedSelection: BracketedSelection,
|
|
@@ -2237,6 +2385,57 @@ class JSONPath {
|
|
|
2237
2385
|
}
|
|
2238
2386
|
}
|
|
2239
2387
|
|
|
2388
|
+
class CurrentKey extends FilterExpression {
|
|
2389
|
+
evaluate(context) {
|
|
2390
|
+
return context.currentKey ?? Nothing;
|
|
2391
|
+
}
|
|
2392
|
+
toString() {
|
|
2393
|
+
return "#";
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
/**
|
|
2398
|
+
* Object property name selector or array index selector.
|
|
2399
|
+
*/
|
|
2400
|
+
class KeysSelector extends JSONPathSelector {
|
|
2401
|
+
constructor(environment, token) {
|
|
2402
|
+
let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
2403
|
+
super(environment, token);
|
|
2404
|
+
this.environment = environment;
|
|
2405
|
+
this.token = token;
|
|
2406
|
+
this.shorthand = shorthand;
|
|
2407
|
+
}
|
|
2408
|
+
resolve(nodes) {
|
|
2409
|
+
const rv = [];
|
|
2410
|
+
for (const node of nodes) {
|
|
2411
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2412
|
+
if (isObject(node.value)) {
|
|
2413
|
+
let i = 0;
|
|
2414
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2415
|
+
rv.push(new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root));
|
|
2416
|
+
i++;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
return rv;
|
|
2421
|
+
}
|
|
2422
|
+
*lazyResolve(nodes) {
|
|
2423
|
+
for (const node of nodes) {
|
|
2424
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2425
|
+
if (isObject(node.value)) {
|
|
2426
|
+
let i = 0;
|
|
2427
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2428
|
+
yield new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root);
|
|
2429
|
+
i++;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
toString() {
|
|
2435
|
+
return this.shorthand ? "[~]" : "~";
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2240
2439
|
const PRECEDENCE_LOWEST = 1;
|
|
2241
2440
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
2242
2441
|
const PRECEDENCE_LOGICAL_AND = 5;
|
|
@@ -2252,7 +2451,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2252
2451
|
class Parser {
|
|
2253
2452
|
constructor(environment) {
|
|
2254
2453
|
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]]);
|
|
2454
|
+
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
2455
|
}
|
|
2257
2456
|
parse(stream) {
|
|
2258
2457
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2284,6 +2483,8 @@ class Parser {
|
|
|
2284
2483
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2285
2484
|
case TokenKind.WILD:
|
|
2286
2485
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2486
|
+
case TokenKind.KEYS:
|
|
2487
|
+
return new KeysSelector(this.environment, stream.current, true);
|
|
2287
2488
|
case TokenKind.DDOT:
|
|
2288
2489
|
{
|
|
2289
2490
|
const segmentToken = stream.current;
|
|
@@ -2377,6 +2578,9 @@ class Parser {
|
|
|
2377
2578
|
case TokenKind.WILD:
|
|
2378
2579
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2379
2580
|
break;
|
|
2581
|
+
case TokenKind.KEYS:
|
|
2582
|
+
items.push(new KeysSelector(this.environment, stream.current));
|
|
2583
|
+
break;
|
|
2380
2584
|
case TokenKind.EOF:
|
|
2381
2585
|
throw new JSONPathSyntaxError("unexpected end of query", stream.current);
|
|
2382
2586
|
default:
|
|
@@ -2437,13 +2641,20 @@ class Parser {
|
|
|
2437
2641
|
return new InfixExpression(tok, left, operator, right);
|
|
2438
2642
|
}
|
|
2439
2643
|
parseGroupedExpression(stream) {
|
|
2440
|
-
stream.
|
|
2644
|
+
if (stream.peek.kind === TokenKind.RPAREN) {
|
|
2645
|
+
throw new JSONPathSyntaxError(`empty paren expression`, stream.current);
|
|
2646
|
+
}
|
|
2647
|
+
stream.next(); // eat open paren
|
|
2648
|
+
|
|
2441
2649
|
let expr = this.parseFilterExpression(stream);
|
|
2442
2650
|
stream.next();
|
|
2443
2651
|
while (stream.current.kind !== TokenKind.RPAREN) {
|
|
2444
2652
|
if (stream.current.kind === TokenKind.EOF) {
|
|
2445
2653
|
throw new JSONPathSyntaxError("unbalanced parentheses", stream.current);
|
|
2446
2654
|
}
|
|
2655
|
+
if (!BINARY_OPERATORS.has(stream.current.kind)) {
|
|
2656
|
+
throw new JSONPathSyntaxError(`expected an expression, found '${stream.current.value}'`, stream.current);
|
|
2657
|
+
}
|
|
2447
2658
|
expr = this.parseInfixExpression(stream, expr);
|
|
2448
2659
|
}
|
|
2449
2660
|
stream.expect(TokenKind.RPAREN);
|
|
@@ -2457,6 +2668,9 @@ class Parser {
|
|
|
2457
2668
|
const tok = stream.next();
|
|
2458
2669
|
return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
|
|
2459
2670
|
}
|
|
2671
|
+
parseCurrentKey(stream) {
|
|
2672
|
+
return new CurrentKey(stream.current);
|
|
2673
|
+
}
|
|
2460
2674
|
parseFunction(stream) {
|
|
2461
2675
|
const args = [];
|
|
2462
2676
|
const tok = stream.next();
|
|
@@ -2496,7 +2710,7 @@ class Parser {
|
|
|
2496
2710
|
msg = "end of expression";
|
|
2497
2711
|
break;
|
|
2498
2712
|
default:
|
|
2499
|
-
msg = `'${stream.current.value}`;
|
|
2713
|
+
msg = `'${stream.current.value}'`;
|
|
2500
2714
|
}
|
|
2501
2715
|
throw new JSONPathSyntaxError(`unexpected ${msg}`, stream.current);
|
|
2502
2716
|
}
|
|
@@ -2573,6 +2787,10 @@ class JSONPathEnvironment {
|
|
|
2573
2787
|
* If `true`, enable nondeterministic ordering when iterating JSON object data.
|
|
2574
2788
|
*/
|
|
2575
2789
|
|
|
2790
|
+
/**
|
|
2791
|
+
* The pattern to use for the non-standard _keys selector_.
|
|
2792
|
+
*/
|
|
2793
|
+
|
|
2576
2794
|
/**
|
|
2577
2795
|
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2578
2796
|
* interface. You are free to set or delete custom filter functions directly.
|
|
@@ -2588,6 +2806,7 @@ class JSONPathEnvironment {
|
|
|
2588
2806
|
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2589
2807
|
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2590
2808
|
this.nondeterministic = options.nondeterministic ?? false;
|
|
2809
|
+
this.keysPattern = options.keysPattern ?? /~/y;
|
|
2591
2810
|
this.parser = new Parser(this);
|
|
2592
2811
|
this.setupFilterFunctions();
|
|
2593
2812
|
}
|
|
@@ -2597,7 +2816,7 @@ class JSONPathEnvironment {
|
|
|
2597
2816
|
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2598
2817
|
*/
|
|
2599
2818
|
compile(path) {
|
|
2600
|
-
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
2819
|
+
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
|
|
2601
2820
|
}
|
|
2602
2821
|
|
|
2603
2822
|
/**
|
|
@@ -2679,7 +2898,7 @@ class JSONPathEnvironment {
|
|
|
2679
2898
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2680
2899
|
switch (typ) {
|
|
2681
2900
|
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)) {
|
|
2901
|
+
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
2902
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2684
2903
|
}
|
|
2685
2904
|
break;
|
|
@@ -3307,7 +3526,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3307
3526
|
apply: apply
|
|
3308
3527
|
});
|
|
3309
3528
|
|
|
3310
|
-
const version = "1.
|
|
3529
|
+
const version = "1.2.1";
|
|
3311
3530
|
|
|
3312
3531
|
exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
|
|
3313
3532
|
exports.FunctionExpressionType = FunctionExpressionType;
|