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.esm.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
|
|
@@ -1180,6 +1180,8 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1180
1180
|
TokenKind["GE"] = "TOKEN_GE";
|
|
1181
1181
|
TokenKind["GT"] = "TOKEN_GT";
|
|
1182
1182
|
TokenKind["INDEX"] = "TOKEN_INDEX";
|
|
1183
|
+
TokenKind["KEY"] = "TOKEN_KEY";
|
|
1184
|
+
TokenKind["KEYS"] = "TOKEN_KEYS";
|
|
1183
1185
|
TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
|
|
1184
1186
|
TokenKind["LE"] = "TOKEN_LE";
|
|
1185
1187
|
TokenKind["LG"] = "TOKEN_LG";
|
|
@@ -1249,6 +1251,9 @@ class TokenStream {
|
|
|
1249
1251
|
}
|
|
1250
1252
|
}
|
|
1251
1253
|
|
|
1254
|
+
/** A lexer that accepts additional, non-standard tokens. */
|
|
1255
|
+
|
|
1256
|
+
|
|
1252
1257
|
// These regular expressions are to be used with Lexer.acceptMatchRun(),
|
|
1253
1258
|
// which expects the sticky flag to be set.
|
|
1254
1259
|
const exponentPattern = /e[+-]?\d+/y;
|
|
@@ -1288,7 +1293,8 @@ class Lexer {
|
|
|
1288
1293
|
/**
|
|
1289
1294
|
* @param path - A JSONPath query.
|
|
1290
1295
|
*/
|
|
1291
|
-
constructor(path) {
|
|
1296
|
+
constructor(environment, path) {
|
|
1297
|
+
this.environment = environment;
|
|
1292
1298
|
this.path = path;
|
|
1293
1299
|
}
|
|
1294
1300
|
get pos() {
|
|
@@ -1388,8 +1394,8 @@ class Lexer {
|
|
|
1388
1394
|
* @returns A two-tuple containing a lexer for _path_ and an array to populate
|
|
1389
1395
|
* with tokens.
|
|
1390
1396
|
*/
|
|
1391
|
-
function lex(path) {
|
|
1392
|
-
const lexer = new Lexer(path);
|
|
1397
|
+
function lex(environment, path) {
|
|
1398
|
+
const lexer = new Lexer(environment, path);
|
|
1393
1399
|
return [lexer, lexer.tokens];
|
|
1394
1400
|
}
|
|
1395
1401
|
|
|
@@ -1398,8 +1404,8 @@ function lex(path) {
|
|
|
1398
1404
|
* @param path - A JSONPath query.
|
|
1399
1405
|
* @returns Tokens to be parsed by the parser.
|
|
1400
1406
|
*/
|
|
1401
|
-
function tokenize(path) {
|
|
1402
|
-
const [lexer, tokens] = lex(path);
|
|
1407
|
+
function tokenize(environment, path) {
|
|
1408
|
+
const [lexer, tokens] = lex(environment, path);
|
|
1403
1409
|
lexer.run();
|
|
1404
1410
|
if (tokens.length && tokens[tokens.length - 1].kind === TokenKind.ERROR) {
|
|
1405
1411
|
throw new JSONPathSyntaxError(tokens[tokens.length - 1].value, tokens[tokens.length - 1]);
|
|
@@ -1452,6 +1458,16 @@ function lexSegment(l) {
|
|
|
1452
1458
|
* @returns -
|
|
1453
1459
|
*/
|
|
1454
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
|
+
}
|
|
1455
1471
|
const ch = l.next();
|
|
1456
1472
|
switch (ch) {
|
|
1457
1473
|
case "":
|
|
@@ -1465,13 +1481,8 @@ function lexDescendantSelection(l) {
|
|
|
1465
1481
|
return lexInsideBracketedSelection;
|
|
1466
1482
|
default:
|
|
1467
1483
|
l.backup();
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
return lexSegment;
|
|
1471
|
-
} else {
|
|
1472
|
-
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1473
|
-
return null;
|
|
1474
|
-
}
|
|
1484
|
+
l.error(`unexpected descendent selection token '${ch}'`);
|
|
1485
|
+
return null;
|
|
1475
1486
|
}
|
|
1476
1487
|
}
|
|
1477
1488
|
function lexDotSelector(l) {
|
|
@@ -1480,23 +1491,34 @@ function lexDotSelector(l) {
|
|
|
1480
1491
|
l.error("unexpected whitespace after dot");
|
|
1481
1492
|
return null;
|
|
1482
1493
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
l.emit(TokenKind.WILD);
|
|
1494
|
+
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1495
|
+
l.emit(TokenKind.KEYS);
|
|
1486
1496
|
return lexSegment;
|
|
1487
1497
|
}
|
|
1488
|
-
l.backup();
|
|
1489
1498
|
if (l.acceptMatchRun(namePattern)) {
|
|
1490
1499
|
l.emit(TokenKind.NAME);
|
|
1491
1500
|
return lexSegment;
|
|
1492
|
-
} else {
|
|
1493
|
-
l.error(`unexpected shorthand selector '${ch}'`);
|
|
1494
|
-
return null;
|
|
1495
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;
|
|
1496
1510
|
}
|
|
1497
1511
|
function lexInsideBracketedSelection(l) {
|
|
1498
1512
|
for (;;) {
|
|
1499
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
|
+
}
|
|
1500
1522
|
const ch = l.next();
|
|
1501
1523
|
switch (ch) {
|
|
1502
1524
|
case "]":
|
|
@@ -1525,10 +1547,6 @@ function lexInsideBracketedSelection(l) {
|
|
|
1525
1547
|
return lexDoubleQuoteStringInsideBracketSelection;
|
|
1526
1548
|
default:
|
|
1527
1549
|
l.backup();
|
|
1528
|
-
if (l.acceptMatchRun(indexPattern)) {
|
|
1529
|
-
l.emit(TokenKind.INDEX);
|
|
1530
|
-
continue;
|
|
1531
|
-
}
|
|
1532
1550
|
l.error(`unexpected token '${ch}' in bracketed selection`);
|
|
1533
1551
|
return null;
|
|
1534
1552
|
}
|
|
@@ -1542,6 +1560,8 @@ function lexInsideFilter(l) {
|
|
|
1542
1560
|
const ch = l.next();
|
|
1543
1561
|
switch (ch) {
|
|
1544
1562
|
case "":
|
|
1563
|
+
l.error("unclosed bracketed selection");
|
|
1564
|
+
return null;
|
|
1545
1565
|
case "]":
|
|
1546
1566
|
l.filterLevel -= 1;
|
|
1547
1567
|
if (l.parenStack.length === 1) {
|
|
@@ -1583,6 +1603,9 @@ function lexInsideFilter(l) {
|
|
|
1583
1603
|
case "@":
|
|
1584
1604
|
l.emit(TokenKind.CURRENT);
|
|
1585
1605
|
return lexSegment;
|
|
1606
|
+
case "#":
|
|
1607
|
+
l.emit(TokenKind.KEY);
|
|
1608
|
+
return lexSegment;
|
|
1586
1609
|
case ".":
|
|
1587
1610
|
l.backup();
|
|
1588
1611
|
return lexSegment;
|
|
@@ -1761,7 +1784,7 @@ class NameSelector extends JSONPathSelector {
|
|
|
1761
1784
|
resolve(nodes) {
|
|
1762
1785
|
const rv = [];
|
|
1763
1786
|
for (const node of nodes) {
|
|
1764
|
-
if (hasStringKey(node.value, this.name)) {
|
|
1787
|
+
if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
|
|
1765
1788
|
rv.push(new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root));
|
|
1766
1789
|
}
|
|
1767
1790
|
}
|
|
@@ -1769,7 +1792,7 @@ class NameSelector extends JSONPathSelector {
|
|
|
1769
1792
|
}
|
|
1770
1793
|
*lazyResolve(nodes) {
|
|
1771
1794
|
for (const node of nodes) {
|
|
1772
|
-
if (hasStringKey(node.value, this.name)) {
|
|
1795
|
+
if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
|
|
1773
1796
|
yield new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root);
|
|
1774
1797
|
}
|
|
1775
1798
|
}
|
|
@@ -1845,7 +1868,7 @@ class SliceSelector extends JSONPathSelector {
|
|
|
1845
1868
|
*lazyResolve(nodes) {
|
|
1846
1869
|
for (const node of nodes) {
|
|
1847
1870
|
if (!isArray(node.value)) continue;
|
|
1848
|
-
for (const [i, value] of this.
|
|
1871
|
+
for (const [i, value] of this.lazySlice(node.value, this.start, this.stop, this.step)) {
|
|
1849
1872
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
1850
1873
|
}
|
|
1851
1874
|
}
|
|
@@ -1908,6 +1931,45 @@ class SliceSelector extends JSONPathSelector {
|
|
|
1908
1931
|
}
|
|
1909
1932
|
return slicedArray;
|
|
1910
1933
|
}
|
|
1934
|
+
|
|
1935
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
1936
|
+
*lazySlice(arr, start, stop, step) {
|
|
1937
|
+
if (!arr.length) return;
|
|
1938
|
+
|
|
1939
|
+
// Handle negative and undefined start values
|
|
1940
|
+
if (start === undefined || start === null) {
|
|
1941
|
+
start = step && step < 0 ? arr.length - 1 : 0;
|
|
1942
|
+
} else if (start < 0) {
|
|
1943
|
+
start = Math.max(arr.length + start, 0);
|
|
1944
|
+
} else {
|
|
1945
|
+
start = Math.min(start, arr.length - 1);
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
// Handle negative and undefined stop values
|
|
1949
|
+
if (stop === undefined || stop === null) {
|
|
1950
|
+
stop = step && step < 0 ? -1 : arr.length;
|
|
1951
|
+
} else if (stop < 0) {
|
|
1952
|
+
stop = Math.max(arr.length + stop, -1);
|
|
1953
|
+
} else {
|
|
1954
|
+
stop = Math.min(stop, arr.length);
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// Perform the slice
|
|
1958
|
+
if (step === undefined) {
|
|
1959
|
+
// Default to a step of 1
|
|
1960
|
+
for (let i = start; i < stop; i += 1) {
|
|
1961
|
+
yield [i, arr[i]];
|
|
1962
|
+
}
|
|
1963
|
+
} else if (step > 0) {
|
|
1964
|
+
for (let i = start; i < stop; i += step) {
|
|
1965
|
+
yield [i, arr[i]];
|
|
1966
|
+
}
|
|
1967
|
+
} else if (step < 0) {
|
|
1968
|
+
for (let i = start; i > stop; i += step) {
|
|
1969
|
+
yield [i, arr[i]];
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1911
1973
|
}
|
|
1912
1974
|
class WildcardSelector extends JSONPathSelector {
|
|
1913
1975
|
constructor(environment, token) {
|
|
@@ -1960,10 +2022,18 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
1960
2022
|
}
|
|
1961
2023
|
resolve(nodes) {
|
|
1962
2024
|
const rv = [];
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
2025
|
+
if (this.environment.nondeterministic) {
|
|
2026
|
+
for (const root of nodes) {
|
|
2027
|
+
for (const node of this.nondeterministicVisitor(root)) {
|
|
2028
|
+
rv.push(node);
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
} else {
|
|
2032
|
+
for (const node of nodes) {
|
|
2033
|
+
rv.push(node);
|
|
2034
|
+
for (const _node of this.visitor(node)) {
|
|
2035
|
+
rv.push(_node);
|
|
2036
|
+
}
|
|
1967
2037
|
}
|
|
1968
2038
|
}
|
|
1969
2039
|
return this.selector.resolve(rv);
|
|
@@ -2018,7 +2088,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2018
2088
|
toString() {
|
|
2019
2089
|
return `..${this.selector.toString()}`;
|
|
2020
2090
|
}
|
|
2021
|
-
|
|
2091
|
+
visitor(node) {
|
|
2022
2092
|
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2023
2093
|
if (depth >= this.environment.maxRecursionDepth) {
|
|
2024
2094
|
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
@@ -2029,7 +2099,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2029
2099
|
for (let i = 0; i < node.value.length; i++) {
|
|
2030
2100
|
const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
|
|
2031
2101
|
rv.push(_node);
|
|
2032
|
-
for (const __node of this.
|
|
2102
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2033
2103
|
rv.push(__node);
|
|
2034
2104
|
}
|
|
2035
2105
|
}
|
|
@@ -2037,13 +2107,52 @@ class RecursiveDescentSegment extends JSONPathSelector {
|
|
|
2037
2107
|
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2038
2108
|
const _node = new JSONPathNode(value, node.location.concat(key), node.root);
|
|
2039
2109
|
rv.push(_node);
|
|
2040
|
-
for (const __node of this.
|
|
2110
|
+
for (const __node of this.visitor(_node, depth + 1)) {
|
|
2041
2111
|
rv.push(__node);
|
|
2042
2112
|
}
|
|
2043
2113
|
}
|
|
2044
2114
|
}
|
|
2045
2115
|
return rv;
|
|
2046
2116
|
}
|
|
2117
|
+
nondeterministicVisitor(root) {
|
|
2118
|
+
let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
2119
|
+
const rv = [root];
|
|
2120
|
+
let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
|
|
2121
|
+
while (queue.length) {
|
|
2122
|
+
const [node, _depth] = queue.shift();
|
|
2123
|
+
rv.push(node);
|
|
2124
|
+
if (_depth >= this.environment.maxRecursionDepth) {
|
|
2125
|
+
throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
// Visit child nodes now or queue them for later?
|
|
2129
|
+
const visitChildren = Math.random() < 0.5;
|
|
2130
|
+
for (const child of this.nondeterministicChildren(node)) {
|
|
2131
|
+
if (visitChildren) {
|
|
2132
|
+
rv.push(child);
|
|
2133
|
+
const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
|
|
2134
|
+
queue = interleave(queue, grandchildren);
|
|
2135
|
+
} else {
|
|
2136
|
+
queue.push([child, _depth + 1]);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
return rv;
|
|
2141
|
+
}
|
|
2142
|
+
nondeterministicChildren(node) {
|
|
2143
|
+
const _rv = [];
|
|
2144
|
+
if (node.value instanceof String) return _rv;
|
|
2145
|
+
if (isArray(node.value)) {
|
|
2146
|
+
for (let i = 0; i < node.value.length; i++) {
|
|
2147
|
+
_rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
|
|
2148
|
+
}
|
|
2149
|
+
} else if (isObject(node.value)) {
|
|
2150
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2151
|
+
_rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
return _rv;
|
|
2155
|
+
}
|
|
2047
2156
|
}
|
|
2048
2157
|
class FilterSelector extends JSONPathSelector {
|
|
2049
2158
|
constructor(environment, token, expression) {
|
|
@@ -2064,7 +2173,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2064
2173
|
const filterContext = {
|
|
2065
2174
|
environment: this.environment,
|
|
2066
2175
|
currentValue: value,
|
|
2067
|
-
rootValue: node.root
|
|
2176
|
+
rootValue: node.root,
|
|
2177
|
+
currentKey: i
|
|
2068
2178
|
};
|
|
2069
2179
|
if (this.expression.evaluate(filterContext)) {
|
|
2070
2180
|
rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
|
|
@@ -2075,7 +2185,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2075
2185
|
const filterContext = {
|
|
2076
2186
|
environment: this.environment,
|
|
2077
2187
|
currentValue: value,
|
|
2078
|
-
rootValue: node.root
|
|
2188
|
+
rootValue: node.root,
|
|
2189
|
+
currentKey: key
|
|
2079
2190
|
};
|
|
2080
2191
|
if (this.expression.evaluate(filterContext)) {
|
|
2081
2192
|
rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
|
|
@@ -2097,7 +2208,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2097
2208
|
environment: this.environment,
|
|
2098
2209
|
currentValue: value,
|
|
2099
2210
|
rootValue: node.root,
|
|
2100
|
-
lazy: true
|
|
2211
|
+
lazy: true,
|
|
2212
|
+
currentKey: i
|
|
2101
2213
|
};
|
|
2102
2214
|
if (this.expression.evaluate(filterContext)) {
|
|
2103
2215
|
yield new JSONPathNode(value, node.location.concat(i), node.root);
|
|
@@ -2109,7 +2221,8 @@ class FilterSelector extends JSONPathSelector {
|
|
|
2109
2221
|
environment: this.environment,
|
|
2110
2222
|
currentValue: value,
|
|
2111
2223
|
rootValue: node.root,
|
|
2112
|
-
lazy: true
|
|
2224
|
+
lazy: true,
|
|
2225
|
+
currentKey: key
|
|
2113
2226
|
};
|
|
2114
2227
|
if (this.expression.evaluate(filterContext)) {
|
|
2115
2228
|
yield new JSONPathNode(value, node.location.concat(key), node.root);
|
|
@@ -2152,6 +2265,41 @@ class BracketedSelection extends JSONPathSelector {
|
|
|
2152
2265
|
}
|
|
2153
2266
|
}
|
|
2154
2267
|
|
|
2268
|
+
/**
|
|
2269
|
+
* Randomly interleave elements from two arrays while maintaining relative
|
|
2270
|
+
* order of each input array.
|
|
2271
|
+
*
|
|
2272
|
+
* If _arrayA_ is empty, _arrayB_ is returned, and vice versa.
|
|
2273
|
+
*/
|
|
2274
|
+
function interleave(arrayA, arrayB) {
|
|
2275
|
+
if (arrayA.length === 0) {
|
|
2276
|
+
return arrayB;
|
|
2277
|
+
}
|
|
2278
|
+
if (arrayB.length === 0) {
|
|
2279
|
+
return arrayA;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
// An array of iterators
|
|
2283
|
+
const iterators = [];
|
|
2284
|
+
const itA = arrayA[Symbol.iterator]();
|
|
2285
|
+
const itB = arrayB[Symbol.iterator]();
|
|
2286
|
+
for (let i = 0; i < arrayA.length; i++) {
|
|
2287
|
+
iterators.push(itA);
|
|
2288
|
+
}
|
|
2289
|
+
for (let i = 0; i < arrayB.length; i++) {
|
|
2290
|
+
iterators.push(itB);
|
|
2291
|
+
}
|
|
2292
|
+
shuffle(iterators);
|
|
2293
|
+
return iterators.map(it => it.next().value);
|
|
2294
|
+
}
|
|
2295
|
+
function shuffle(entries) {
|
|
2296
|
+
for (let i = entries.length - 1; i > 0; i--) {
|
|
2297
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
2298
|
+
[entries[i], entries[j]] = [entries[j], entries[i]];
|
|
2299
|
+
}
|
|
2300
|
+
return entries;
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2155
2303
|
var selectors = /*#__PURE__*/Object.freeze({
|
|
2156
2304
|
__proto__: null,
|
|
2157
2305
|
BracketedSelection: BracketedSelection,
|
|
@@ -2235,6 +2383,57 @@ class JSONPath {
|
|
|
2235
2383
|
}
|
|
2236
2384
|
}
|
|
2237
2385
|
|
|
2386
|
+
class CurrentKey extends FilterExpression {
|
|
2387
|
+
evaluate(context) {
|
|
2388
|
+
return context.currentKey ?? Nothing;
|
|
2389
|
+
}
|
|
2390
|
+
toString() {
|
|
2391
|
+
return "#";
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
/**
|
|
2396
|
+
* Object property name selector or array index selector.
|
|
2397
|
+
*/
|
|
2398
|
+
class KeysSelector extends JSONPathSelector {
|
|
2399
|
+
constructor(environment, token) {
|
|
2400
|
+
let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
2401
|
+
super(environment, token);
|
|
2402
|
+
this.environment = environment;
|
|
2403
|
+
this.token = token;
|
|
2404
|
+
this.shorthand = shorthand;
|
|
2405
|
+
}
|
|
2406
|
+
resolve(nodes) {
|
|
2407
|
+
const rv = [];
|
|
2408
|
+
for (const node of nodes) {
|
|
2409
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2410
|
+
if (isObject(node.value)) {
|
|
2411
|
+
let i = 0;
|
|
2412
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2413
|
+
rv.push(new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root));
|
|
2414
|
+
i++;
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
return rv;
|
|
2419
|
+
}
|
|
2420
|
+
*lazyResolve(nodes) {
|
|
2421
|
+
for (const node of nodes) {
|
|
2422
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2423
|
+
if (isObject(node.value)) {
|
|
2424
|
+
let i = 0;
|
|
2425
|
+
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2426
|
+
yield new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root);
|
|
2427
|
+
i++;
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
toString() {
|
|
2433
|
+
return this.shorthand ? "[~]" : "~";
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2238
2437
|
const PRECEDENCE_LOWEST = 1;
|
|
2239
2438
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
2240
2439
|
const PRECEDENCE_LOGICAL_AND = 5;
|
|
@@ -2250,7 +2449,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2250
2449
|
class Parser {
|
|
2251
2450
|
constructor(environment) {
|
|
2252
2451
|
this.environment = environment;
|
|
2253
|
-
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]]);
|
|
2452
|
+
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]]);
|
|
2254
2453
|
}
|
|
2255
2454
|
parse(stream) {
|
|
2256
2455
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2282,6 +2481,8 @@ class Parser {
|
|
|
2282
2481
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2283
2482
|
case TokenKind.WILD:
|
|
2284
2483
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2484
|
+
case TokenKind.KEYS:
|
|
2485
|
+
return new KeysSelector(this.environment, stream.current, true);
|
|
2285
2486
|
case TokenKind.DDOT:
|
|
2286
2487
|
{
|
|
2287
2488
|
const segmentToken = stream.current;
|
|
@@ -2375,6 +2576,9 @@ class Parser {
|
|
|
2375
2576
|
case TokenKind.WILD:
|
|
2376
2577
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2377
2578
|
break;
|
|
2579
|
+
case TokenKind.KEYS:
|
|
2580
|
+
items.push(new KeysSelector(this.environment, stream.current));
|
|
2581
|
+
break;
|
|
2378
2582
|
case TokenKind.EOF:
|
|
2379
2583
|
throw new JSONPathSyntaxError("unexpected end of query", stream.current);
|
|
2380
2584
|
default:
|
|
@@ -2435,13 +2639,20 @@ class Parser {
|
|
|
2435
2639
|
return new InfixExpression(tok, left, operator, right);
|
|
2436
2640
|
}
|
|
2437
2641
|
parseGroupedExpression(stream) {
|
|
2438
|
-
stream.
|
|
2642
|
+
if (stream.peek.kind === TokenKind.RPAREN) {
|
|
2643
|
+
throw new JSONPathSyntaxError(`empty paren expression`, stream.current);
|
|
2644
|
+
}
|
|
2645
|
+
stream.next(); // eat open paren
|
|
2646
|
+
|
|
2439
2647
|
let expr = this.parseFilterExpression(stream);
|
|
2440
2648
|
stream.next();
|
|
2441
2649
|
while (stream.current.kind !== TokenKind.RPAREN) {
|
|
2442
2650
|
if (stream.current.kind === TokenKind.EOF) {
|
|
2443
2651
|
throw new JSONPathSyntaxError("unbalanced parentheses", stream.current);
|
|
2444
2652
|
}
|
|
2653
|
+
if (!BINARY_OPERATORS.has(stream.current.kind)) {
|
|
2654
|
+
throw new JSONPathSyntaxError(`expected an expression, found '${stream.current.value}'`, stream.current);
|
|
2655
|
+
}
|
|
2445
2656
|
expr = this.parseInfixExpression(stream, expr);
|
|
2446
2657
|
}
|
|
2447
2658
|
stream.expect(TokenKind.RPAREN);
|
|
@@ -2455,6 +2666,9 @@ class Parser {
|
|
|
2455
2666
|
const tok = stream.next();
|
|
2456
2667
|
return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
|
|
2457
2668
|
}
|
|
2669
|
+
parseCurrentKey(stream) {
|
|
2670
|
+
return new CurrentKey(stream.current);
|
|
2671
|
+
}
|
|
2458
2672
|
parseFunction(stream) {
|
|
2459
2673
|
const args = [];
|
|
2460
2674
|
const tok = stream.next();
|
|
@@ -2494,7 +2708,7 @@ class Parser {
|
|
|
2494
2708
|
msg = "end of expression";
|
|
2495
2709
|
break;
|
|
2496
2710
|
default:
|
|
2497
|
-
msg = `'${stream.current.value}`;
|
|
2711
|
+
msg = `'${stream.current.value}'`;
|
|
2498
2712
|
}
|
|
2499
2713
|
throw new JSONPathSyntaxError(`unexpected ${msg}`, stream.current);
|
|
2500
2714
|
}
|
|
@@ -2571,6 +2785,10 @@ class JSONPathEnvironment {
|
|
|
2571
2785
|
* If `true`, enable nondeterministic ordering when iterating JSON object data.
|
|
2572
2786
|
*/
|
|
2573
2787
|
|
|
2788
|
+
/**
|
|
2789
|
+
* The pattern to use for the non-standard _keys selector_.
|
|
2790
|
+
*/
|
|
2791
|
+
|
|
2574
2792
|
/**
|
|
2575
2793
|
* A map of function names to objects implementing the {@link FilterFunction}
|
|
2576
2794
|
* interface. You are free to set or delete custom filter functions directly.
|
|
@@ -2586,6 +2804,7 @@ class JSONPathEnvironment {
|
|
|
2586
2804
|
this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
|
|
2587
2805
|
this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
|
|
2588
2806
|
this.nondeterministic = options.nondeterministic ?? false;
|
|
2807
|
+
this.keysPattern = options.keysPattern ?? /~/y;
|
|
2589
2808
|
this.parser = new Parser(this);
|
|
2590
2809
|
this.setupFilterFunctions();
|
|
2591
2810
|
}
|
|
@@ -2595,7 +2814,7 @@ class JSONPathEnvironment {
|
|
|
2595
2814
|
* @returns A new {@link JSONPath} object, bound to this environment.
|
|
2596
2815
|
*/
|
|
2597
2816
|
compile(path) {
|
|
2598
|
-
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
|
|
2817
|
+
return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
|
|
2599
2818
|
}
|
|
2600
2819
|
|
|
2601
2820
|
/**
|
|
@@ -2677,7 +2896,7 @@ class JSONPathEnvironment {
|
|
|
2677
2896
|
for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
|
|
2678
2897
|
switch (typ) {
|
|
2679
2898
|
case FunctionExpressionType.ValueType:
|
|
2680
|
-
if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2899
|
+
if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
|
|
2681
2900
|
throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
|
|
2682
2901
|
}
|
|
2683
2902
|
break;
|
|
@@ -3305,6 +3524,6 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3305
3524
|
apply: apply
|
|
3306
3525
|
});
|
|
3307
3526
|
|
|
3308
|
-
const version = "1.
|
|
3527
|
+
const version = "1.2.1";
|
|
3309
3528
|
|
|
3310
3529
|
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 };
|