json-p3 1.2.1 → 1.3.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 +290 -50
- package/dist/json-p3.esm.js +290 -50
- package/dist/json-p3.iife.js +290 -50
- package/dist/json-p3.iife.min.js +1 -1
- package/dist/json-p3.iife.min.js.map +1 -1
- package/dist/path/extra/selectors.d.ts +20 -0
- package/dist/path/functions/match.d.ts +1 -0
- package/dist/path/functions/search.d.ts +1 -0
- package/dist/path/index.d.ts +1 -1
- package/dist/path/lex.d.ts +1 -0
- package/dist/path/node.d.ts +1 -0
- package/dist/path/parse.d.ts +1 -1
- package/dist/path/token.d.ts +7 -3
- 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.3.1
|
|
3
3
|
* https://github.com/jg-rp/json-p3
|
|
4
4
|
*
|
|
5
5
|
* MIT License
|
|
@@ -639,6 +639,24 @@ var index$3 = /*#__PURE__*/Object.freeze({
|
|
|
639
639
|
resolve: resolve
|
|
640
640
|
});
|
|
641
641
|
|
|
642
|
+
const Nothing = Symbol.for("jsonpath.nothing");
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* ValueType for JSONPath function expression tye system.
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Object passed to FilterExpression.evaluate().
|
|
650
|
+
*/
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* A type predicate for an object with a string property.
|
|
654
|
+
*/
|
|
655
|
+
function hasStringKey(value, key) {
|
|
656
|
+
return isObject(value) && Object.hasOwn(value, key);
|
|
657
|
+
}
|
|
658
|
+
const KEY_MARK = "\x02";
|
|
659
|
+
|
|
642
660
|
/**
|
|
643
661
|
* The pair of a JSON value and its location found in the target JSON value.
|
|
644
662
|
*/
|
|
@@ -656,7 +674,7 @@ class JSONPathNode {
|
|
|
656
674
|
get path() {
|
|
657
675
|
return (
|
|
658
676
|
// eslint-disable-next-line prefer-template
|
|
659
|
-
"$" + this.location.map(s => isString(s) ?
|
|
677
|
+
"$" + this.location.map(s => isString(s) ? this.decode_name_location(s) : `[${s}]`).join("")
|
|
660
678
|
);
|
|
661
679
|
}
|
|
662
680
|
|
|
@@ -669,6 +687,9 @@ class JSONPathNode {
|
|
|
669
687
|
}
|
|
670
688
|
return new JSONPointer(JSONPointer.encode(this.location.map(String)));
|
|
671
689
|
}
|
|
690
|
+
decode_name_location(name) {
|
|
691
|
+
return name.startsWith(KEY_MARK) ? `[~'${name.slice(1).replaceAll("'", "\\'")}']` : `['${name.replaceAll("'", "\\'")}']`;
|
|
692
|
+
}
|
|
672
693
|
}
|
|
673
694
|
|
|
674
695
|
/**
|
|
@@ -748,23 +769,6 @@ class JSONPathNodeList {
|
|
|
748
769
|
}
|
|
749
770
|
}
|
|
750
771
|
|
|
751
|
-
const Nothing = Symbol.for("jsonpath.nothing");
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* ValueType for JSONPath function expression tye system.
|
|
755
|
-
*/
|
|
756
|
-
|
|
757
|
-
/**
|
|
758
|
-
* Object passed to FilterExpression.evaluate().
|
|
759
|
-
*/
|
|
760
|
-
|
|
761
|
-
/**
|
|
762
|
-
* A type predicate for an object with a string property.
|
|
763
|
-
*/
|
|
764
|
-
function hasStringKey(value, key) {
|
|
765
|
-
return isObject(value) && Object.hasOwn(value, key);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
772
|
/**
|
|
769
773
|
* Base class for all filter expressions.
|
|
770
774
|
*/
|
|
@@ -1110,9 +1114,53 @@ class Match {
|
|
|
1110
1114
|
}
|
|
1111
1115
|
fullMatch(pattern) {
|
|
1112
1116
|
const parts = [];
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1117
|
+
let nonCaptureGroup = false;
|
|
1118
|
+
if (!pattern.startsWith("^") && !pattern.startsWith("^(")) {
|
|
1119
|
+
nonCaptureGroup = true;
|
|
1120
|
+
parts.push("^(?:");
|
|
1121
|
+
}
|
|
1122
|
+
parts.push(this.mapRegexp(pattern));
|
|
1123
|
+
if (nonCaptureGroup && !pattern.endsWith("$") && !pattern.endsWith(")$")) {
|
|
1124
|
+
parts.push(")$");
|
|
1125
|
+
}
|
|
1126
|
+
return parts.join("");
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// See https://datatracker.ietf.org/doc/html/rfc9485#name-ecmascript-regexps
|
|
1130
|
+
mapRegexp(pattern) {
|
|
1131
|
+
let escaped = false;
|
|
1132
|
+
let charClass = false;
|
|
1133
|
+
const parts = [];
|
|
1134
|
+
for (const ch of pattern) {
|
|
1135
|
+
switch (ch) {
|
|
1136
|
+
case ".":
|
|
1137
|
+
if (!escaped && !charClass) {
|
|
1138
|
+
parts.push("(?:(?![\r\n])\\P{Cs}|\\p{Cs}\\p{Cs})");
|
|
1139
|
+
} else {
|
|
1140
|
+
parts.push(ch);
|
|
1141
|
+
escaped = false;
|
|
1142
|
+
}
|
|
1143
|
+
break;
|
|
1144
|
+
case "\\":
|
|
1145
|
+
escaped = true;
|
|
1146
|
+
parts.push(ch);
|
|
1147
|
+
break;
|
|
1148
|
+
case "[":
|
|
1149
|
+
charClass = true;
|
|
1150
|
+
escaped = false;
|
|
1151
|
+
parts.push(ch);
|
|
1152
|
+
break;
|
|
1153
|
+
case "]":
|
|
1154
|
+
charClass = false;
|
|
1155
|
+
escaped = false;
|
|
1156
|
+
parts.push(ch);
|
|
1157
|
+
break;
|
|
1158
|
+
default:
|
|
1159
|
+
escaped = false;
|
|
1160
|
+
parts.push(ch);
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1116
1164
|
return parts.join("");
|
|
1117
1165
|
}
|
|
1118
1166
|
}
|
|
@@ -1141,7 +1189,7 @@ class Search {
|
|
|
1141
1189
|
}
|
|
1142
1190
|
}
|
|
1143
1191
|
try {
|
|
1144
|
-
const re = new RegExp(pattern, "u");
|
|
1192
|
+
const re = new RegExp(this.mapRegexp(pattern), "u");
|
|
1145
1193
|
if (this.cacheSize > 0) this.#cache.set(pattern, re);
|
|
1146
1194
|
return !!s.match(re);
|
|
1147
1195
|
} catch (error) {
|
|
@@ -1149,6 +1197,44 @@ class Search {
|
|
|
1149
1197
|
return false;
|
|
1150
1198
|
}
|
|
1151
1199
|
}
|
|
1200
|
+
|
|
1201
|
+
// See https://datatracker.ietf.org/doc/html/rfc9485#name-ecmascript-regexps
|
|
1202
|
+
mapRegexp(pattern) {
|
|
1203
|
+
let escaped = false;
|
|
1204
|
+
let charClass = false;
|
|
1205
|
+
const parts = [];
|
|
1206
|
+
for (const ch of pattern) {
|
|
1207
|
+
switch (ch) {
|
|
1208
|
+
case ".":
|
|
1209
|
+
if (!escaped && !charClass) {
|
|
1210
|
+
parts.push("(?:(?![\r\n])\\P{Cs}|\\p{Cs}\\p{Cs})");
|
|
1211
|
+
} else {
|
|
1212
|
+
parts.push(ch);
|
|
1213
|
+
escaped = false;
|
|
1214
|
+
}
|
|
1215
|
+
break;
|
|
1216
|
+
case "\\":
|
|
1217
|
+
escaped = true;
|
|
1218
|
+
parts.push(ch);
|
|
1219
|
+
break;
|
|
1220
|
+
case "[":
|
|
1221
|
+
charClass = true;
|
|
1222
|
+
escaped = false;
|
|
1223
|
+
parts.push(ch);
|
|
1224
|
+
break;
|
|
1225
|
+
case "]":
|
|
1226
|
+
charClass = false;
|
|
1227
|
+
escaped = false;
|
|
1228
|
+
parts.push(ch);
|
|
1229
|
+
break;
|
|
1230
|
+
default:
|
|
1231
|
+
escaped = false;
|
|
1232
|
+
parts.push(ch);
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return parts.join("");
|
|
1237
|
+
}
|
|
1152
1238
|
}
|
|
1153
1239
|
|
|
1154
1240
|
class Value {
|
|
@@ -1167,7 +1253,8 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1167
1253
|
TokenKind["AND"] = "TOKEN_AND";
|
|
1168
1254
|
TokenKind["COLON"] = "TOKEN_COLON";
|
|
1169
1255
|
TokenKind["COMMA"] = "TOKEN_COMMA";
|
|
1170
|
-
TokenKind["CURRENT"] = "
|
|
1256
|
+
TokenKind["CURRENT"] = "TOKEN_CURRENT_VALUE";
|
|
1257
|
+
TokenKind["CURRENT_KEY"] = "TOKEN_CURRENT_KEY";
|
|
1171
1258
|
TokenKind["DDOT"] = "TOKEN_DDOT";
|
|
1172
1259
|
TokenKind["DOT"] = "TOKEN_DOT";
|
|
1173
1260
|
TokenKind["DOUBLE_QUOTE_STRING"] = "TOKEN_DOUBLE_QUOTE_STRING";
|
|
@@ -1181,7 +1268,10 @@ let TokenKind = /*#__PURE__*/function (TokenKind) {
|
|
|
1181
1268
|
TokenKind["GT"] = "TOKEN_GT";
|
|
1182
1269
|
TokenKind["INDEX"] = "TOKEN_INDEX";
|
|
1183
1270
|
TokenKind["KEY"] = "TOKEN_KEY";
|
|
1271
|
+
TokenKind["KEY_DOUBLE_QUOTE_STRING"] = "TOKEN_KEY_DOUBLE_QUOTE_STRING";
|
|
1272
|
+
TokenKind["KEY_SINGLE_QUOTE_STRING"] = "TOKEN_KEY_SINGLE_QUOTE_STRING";
|
|
1184
1273
|
TokenKind["KEYS"] = "TOKEN_KEYS";
|
|
1274
|
+
TokenKind["KEYS_FILTER"] = "TOKEN_KEYS_FILTER";
|
|
1185
1275
|
TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
|
|
1186
1276
|
TokenKind["LE"] = "TOKEN_LE";
|
|
1187
1277
|
TokenKind["LG"] = "TOKEN_LG";
|
|
@@ -1262,6 +1352,7 @@ const indexPattern = /-?\d+/y;
|
|
|
1262
1352
|
const intPattern = /-?[0-9]+/y;
|
|
1263
1353
|
const namePattern = /[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*/y;
|
|
1264
1354
|
const whitespace = new Set([" ", "\n", "\t", "\r"]);
|
|
1355
|
+
const nameFirstPattern = /[\u0080-\uFFFFa-zA-Z_]/; // don't set sticky bit
|
|
1265
1356
|
|
|
1266
1357
|
/**
|
|
1267
1358
|
* JSONPath lexical scanner.
|
|
@@ -1334,6 +1425,11 @@ class Lexer {
|
|
|
1334
1425
|
if (ch) this.backup();
|
|
1335
1426
|
return ch;
|
|
1336
1427
|
}
|
|
1428
|
+
peekMatch(pattern) {
|
|
1429
|
+
const ch = this.next();
|
|
1430
|
+
if (ch) this.backup();
|
|
1431
|
+
return pattern.test(ch);
|
|
1432
|
+
}
|
|
1337
1433
|
accept(valid) {
|
|
1338
1434
|
const ch = this.next();
|
|
1339
1435
|
if (valid.has(ch)) return true;
|
|
@@ -1463,10 +1559,28 @@ function lexDescendantSelection(l) {
|
|
|
1463
1559
|
l.emit(TokenKind.NAME);
|
|
1464
1560
|
return lexSegment;
|
|
1465
1561
|
}
|
|
1466
|
-
if (!l.environment.strict
|
|
1467
|
-
//
|
|
1468
|
-
|
|
1469
|
-
|
|
1562
|
+
if (!l.environment.strict) {
|
|
1563
|
+
// We're effectively disabling the _key selector_ and _keys filter selector_ if a
|
|
1564
|
+
// custom _keys selector_ is set.
|
|
1565
|
+
if (l.environment.keysPattern.source === "~" && l.peek() === "~") {
|
|
1566
|
+
l.next();
|
|
1567
|
+
if (l.peekMatch(nameFirstPattern)) {
|
|
1568
|
+
// Non-standard key selector
|
|
1569
|
+
l.ignore(); // ignore ~
|
|
1570
|
+
l.acceptMatchRun(namePattern);
|
|
1571
|
+
l.emit(TokenKind.KEY);
|
|
1572
|
+
return lexSegment;
|
|
1573
|
+
} else {
|
|
1574
|
+
// Non-standard keys selector
|
|
1575
|
+
l.emit(TokenKind.KEYS);
|
|
1576
|
+
return lexSegment;
|
|
1577
|
+
}
|
|
1578
|
+
} else if (l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1579
|
+
// NOTE: A custom keys pattern does not play well with other non-standard key selectors.
|
|
1580
|
+
// We leave this here for backwards compatibility.
|
|
1581
|
+
l.emit(TokenKind.KEYS);
|
|
1582
|
+
return lexSegment;
|
|
1583
|
+
}
|
|
1470
1584
|
}
|
|
1471
1585
|
const ch = l.next();
|
|
1472
1586
|
switch (ch) {
|
|
@@ -1491,9 +1605,28 @@ function lexDotSelector(l) {
|
|
|
1491
1605
|
l.error("unexpected whitespace after dot");
|
|
1492
1606
|
return null;
|
|
1493
1607
|
}
|
|
1494
|
-
if (!l.environment.strict
|
|
1495
|
-
|
|
1496
|
-
|
|
1608
|
+
if (!l.environment.strict) {
|
|
1609
|
+
// We're effectively disabling the _key selector_ and _keys filter selector_ if a
|
|
1610
|
+
// custom _keys selector_ is set.
|
|
1611
|
+
if (l.environment.keysPattern.source === "~" && l.peek() === "~") {
|
|
1612
|
+
l.next();
|
|
1613
|
+
if (l.peekMatch(nameFirstPattern)) {
|
|
1614
|
+
// Non-standard key selector
|
|
1615
|
+
l.ignore(); // ignore ~
|
|
1616
|
+
l.acceptMatchRun(namePattern);
|
|
1617
|
+
l.emit(TokenKind.KEY);
|
|
1618
|
+
return lexSegment;
|
|
1619
|
+
} else {
|
|
1620
|
+
// Non-standard keys selector
|
|
1621
|
+
l.emit(TokenKind.KEYS);
|
|
1622
|
+
return lexSegment;
|
|
1623
|
+
}
|
|
1624
|
+
} else if (l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1625
|
+
// NOTE: A custom keys pattern does not play well with other non-standard key selectors.
|
|
1626
|
+
// We leave this here for backwards compatibility.
|
|
1627
|
+
l.emit(TokenKind.KEYS);
|
|
1628
|
+
return lexSegment;
|
|
1629
|
+
}
|
|
1497
1630
|
}
|
|
1498
1631
|
if (l.acceptMatchRun(namePattern)) {
|
|
1499
1632
|
l.emit(TokenKind.NAME);
|
|
@@ -1516,8 +1649,25 @@ function lexInsideBracketedSelection(l) {
|
|
|
1516
1649
|
continue;
|
|
1517
1650
|
}
|
|
1518
1651
|
if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
|
|
1519
|
-
|
|
1520
|
-
|
|
1652
|
+
// FIXME: fall back to legacy behavior if keysPattern is not the default
|
|
1653
|
+
switch (l.peek()) {
|
|
1654
|
+
case "'":
|
|
1655
|
+
l.ignore(); // ~
|
|
1656
|
+
l.next();
|
|
1657
|
+
return lexSingleQuoteKeyString(l);
|
|
1658
|
+
case '"':
|
|
1659
|
+
l.ignore(); // ~
|
|
1660
|
+
l.next();
|
|
1661
|
+
return lexDoubleQuoteKeyString(l);
|
|
1662
|
+
case "?":
|
|
1663
|
+
l.next();
|
|
1664
|
+
l.emit(TokenKind.KEYS_FILTER);
|
|
1665
|
+
l.filterLevel += 1;
|
|
1666
|
+
return lexInsideFilter;
|
|
1667
|
+
default:
|
|
1668
|
+
l.emit(TokenKind.KEYS);
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1521
1671
|
}
|
|
1522
1672
|
const ch = l.next();
|
|
1523
1673
|
switch (ch) {
|
|
@@ -1604,7 +1754,7 @@ function lexInsideFilter(l) {
|
|
|
1604
1754
|
l.emit(TokenKind.CURRENT);
|
|
1605
1755
|
return lexSegment;
|
|
1606
1756
|
case "#":
|
|
1607
|
-
l.emit(TokenKind.
|
|
1757
|
+
l.emit(TokenKind.CURRENT_KEY);
|
|
1608
1758
|
return lexSegment;
|
|
1609
1759
|
case ".":
|
|
1610
1760
|
l.backup();
|
|
@@ -1704,8 +1854,7 @@ function lexInsideFilter(l) {
|
|
|
1704
1854
|
* @param state - The state function to return control to.
|
|
1705
1855
|
* @returns String tokenizing state function.
|
|
1706
1856
|
*/
|
|
1707
|
-
function makeLexString(quote, state) {
|
|
1708
|
-
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
1857
|
+
function makeLexString(quote, state, token_kind) {
|
|
1709
1858
|
function _lexString(l) {
|
|
1710
1859
|
l.ignore();
|
|
1711
1860
|
if (l.peek() === quote) {
|
|
@@ -1731,7 +1880,7 @@ function makeLexString(quote, state) {
|
|
|
1731
1880
|
}
|
|
1732
1881
|
if (ch === quote) {
|
|
1733
1882
|
l.backup();
|
|
1734
|
-
l.emit(
|
|
1883
|
+
l.emit(token_kind);
|
|
1735
1884
|
l.next();
|
|
1736
1885
|
l.ignore();
|
|
1737
1886
|
return state;
|
|
@@ -1740,10 +1889,12 @@ function makeLexString(quote, state) {
|
|
|
1740
1889
|
}
|
|
1741
1890
|
return _lexString;
|
|
1742
1891
|
}
|
|
1743
|
-
const lexSingleQuoteStringInsideBracketSelection = makeLexString("'", lexInsideBracketedSelection);
|
|
1744
|
-
const lexDoubleQuoteStringInsideBracketSelection = makeLexString('"', lexInsideBracketedSelection);
|
|
1745
|
-
const lexSingleQuoteStringInsideFilterExpression = makeLexString("'", lexInsideFilter);
|
|
1746
|
-
const lexDoubleQuoteStringInsideFilterExpression = makeLexString('"', lexInsideFilter);
|
|
1892
|
+
const lexSingleQuoteStringInsideBracketSelection = makeLexString("'", lexInsideBracketedSelection, TokenKind.SINGLE_QUOTE_STRING);
|
|
1893
|
+
const lexDoubleQuoteStringInsideBracketSelection = makeLexString('"', lexInsideBracketedSelection, TokenKind.DOUBLE_QUOTE_STRING);
|
|
1894
|
+
const lexSingleQuoteStringInsideFilterExpression = makeLexString("'", lexInsideFilter, TokenKind.SINGLE_QUOTE_STRING);
|
|
1895
|
+
const lexDoubleQuoteStringInsideFilterExpression = makeLexString('"', lexInsideFilter, TokenKind.DOUBLE_QUOTE_STRING);
|
|
1896
|
+
const lexSingleQuoteKeyString = makeLexString("'", lexInsideBracketedSelection, TokenKind.KEY_SINGLE_QUOTE_STRING);
|
|
1897
|
+
const lexDoubleQuoteKeyString = makeLexString('"', lexInsideBracketedSelection, TokenKind.KEY_DOUBLE_QUOTE_STRING);
|
|
1747
1898
|
|
|
1748
1899
|
/**
|
|
1749
1900
|
* Base class for all JSONPath segments and selectors.
|
|
@@ -2392,6 +2543,38 @@ class CurrentKey extends FilterExpression {
|
|
|
2392
2543
|
}
|
|
2393
2544
|
}
|
|
2394
2545
|
|
|
2546
|
+
class KeySelector extends JSONPathSelector {
|
|
2547
|
+
constructor(environment, token, key) {
|
|
2548
|
+
let shorthand = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
2549
|
+
super(environment, token);
|
|
2550
|
+
this.environment = environment;
|
|
2551
|
+
this.token = token;
|
|
2552
|
+
this.key = key;
|
|
2553
|
+
this.shorthand = shorthand;
|
|
2554
|
+
}
|
|
2555
|
+
resolve(nodes) {
|
|
2556
|
+
const rv = [];
|
|
2557
|
+
for (const node of nodes) {
|
|
2558
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2559
|
+
if (isObject(node.value) && hasStringKey(node.value, this.key)) {
|
|
2560
|
+
rv.push(new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root));
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
return rv;
|
|
2564
|
+
}
|
|
2565
|
+
*lazyResolve(nodes) {
|
|
2566
|
+
for (const node of nodes) {
|
|
2567
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2568
|
+
if (isObject(node.value) && hasStringKey(node.value, this.key)) {
|
|
2569
|
+
yield new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
toString() {
|
|
2574
|
+
return this.shorthand ? `[~'${this.key.replaceAll("'", "\\'")}']` : `~'${this.key.replaceAll("'", "\\'")}'`;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2395
2578
|
/**
|
|
2396
2579
|
* Object property name selector or array index selector.
|
|
2397
2580
|
*/
|
|
@@ -2408,10 +2591,8 @@ class KeysSelector extends JSONPathSelector {
|
|
|
2408
2591
|
for (const node of nodes) {
|
|
2409
2592
|
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2410
2593
|
if (isObject(node.value)) {
|
|
2411
|
-
let i = 0;
|
|
2412
2594
|
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2413
|
-
rv.push(new JSONPathNode(key, node.location.concat(
|
|
2414
|
-
i++;
|
|
2595
|
+
rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
|
|
2415
2596
|
}
|
|
2416
2597
|
}
|
|
2417
2598
|
}
|
|
@@ -2421,10 +2602,8 @@ class KeysSelector extends JSONPathSelector {
|
|
|
2421
2602
|
for (const node of nodes) {
|
|
2422
2603
|
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2423
2604
|
if (isObject(node.value)) {
|
|
2424
|
-
let i = 0;
|
|
2425
2605
|
for (const [key, _] of this.environment.entries(node.value)) {
|
|
2426
|
-
yield new JSONPathNode(key, node.location.concat(
|
|
2427
|
-
i++;
|
|
2606
|
+
yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
|
|
2428
2607
|
}
|
|
2429
2608
|
}
|
|
2430
2609
|
}
|
|
@@ -2433,6 +2612,56 @@ class KeysSelector extends JSONPathSelector {
|
|
|
2433
2612
|
return this.shorthand ? "[~]" : "~";
|
|
2434
2613
|
}
|
|
2435
2614
|
}
|
|
2615
|
+
class KeysFilterSelector extends JSONPathSelector {
|
|
2616
|
+
constructor(environment, token, expression) {
|
|
2617
|
+
super(environment, token);
|
|
2618
|
+
this.environment = environment;
|
|
2619
|
+
this.token = token;
|
|
2620
|
+
this.expression = expression;
|
|
2621
|
+
}
|
|
2622
|
+
resolve(nodes) {
|
|
2623
|
+
const rv = [];
|
|
2624
|
+
for (const node of nodes) {
|
|
2625
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2626
|
+
if (isObject(node.value)) {
|
|
2627
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2628
|
+
const filterContext = {
|
|
2629
|
+
environment: this.environment,
|
|
2630
|
+
currentValue: value,
|
|
2631
|
+
rootValue: node.root,
|
|
2632
|
+
currentKey: key
|
|
2633
|
+
};
|
|
2634
|
+
if (this.expression.evaluate(filterContext)) {
|
|
2635
|
+
rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
return rv;
|
|
2641
|
+
}
|
|
2642
|
+
*lazyResolve(nodes) {
|
|
2643
|
+
for (const node of nodes) {
|
|
2644
|
+
if (node.value instanceof String || isArray(node.value)) continue;
|
|
2645
|
+
if (isObject(node.value)) {
|
|
2646
|
+
for (const [key, value] of this.environment.entries(node.value)) {
|
|
2647
|
+
const filterContext = {
|
|
2648
|
+
environment: this.environment,
|
|
2649
|
+
currentValue: value,
|
|
2650
|
+
rootValue: node.root,
|
|
2651
|
+
lazy: true,
|
|
2652
|
+
currentKey: key
|
|
2653
|
+
};
|
|
2654
|
+
if (this.expression.evaluate(filterContext)) {
|
|
2655
|
+
yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
toString() {
|
|
2662
|
+
return `~?${this.expression.toString()}`;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2436
2665
|
|
|
2437
2666
|
const PRECEDENCE_LOWEST = 1;
|
|
2438
2667
|
const PRECEDENCE_LOGICAL_OR = 4;
|
|
@@ -2449,7 +2678,7 @@ const COMPARISON_OPERATORS = new Set(["==", ">=", ">", "<=", "<", "!="]);
|
|
|
2449
2678
|
class Parser {
|
|
2450
2679
|
constructor(environment) {
|
|
2451
2680
|
this.environment = environment;
|
|
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.
|
|
2681
|
+
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.CURRENT_KEY, this.parseCurrentKey]]);
|
|
2453
2682
|
}
|
|
2454
2683
|
parse(stream) {
|
|
2455
2684
|
if (stream.current.kind === TokenKind.ROOT) stream.next();
|
|
@@ -2481,6 +2710,8 @@ class Parser {
|
|
|
2481
2710
|
return new NameSelector(this.environment, stream.current, stream.current.value, true);
|
|
2482
2711
|
case TokenKind.WILD:
|
|
2483
2712
|
return new WildcardSelector(this.environment, stream.current, true);
|
|
2713
|
+
case TokenKind.KEY:
|
|
2714
|
+
return new KeySelector(this.environment, stream.current, stream.current.value, true);
|
|
2484
2715
|
case TokenKind.KEYS:
|
|
2485
2716
|
return new KeysSelector(this.environment, stream.current, true);
|
|
2486
2717
|
case TokenKind.DDOT:
|
|
@@ -2576,6 +2807,13 @@ class Parser {
|
|
|
2576
2807
|
case TokenKind.WILD:
|
|
2577
2808
|
items.push(new WildcardSelector(this.environment, stream.current));
|
|
2578
2809
|
break;
|
|
2810
|
+
case TokenKind.KEY_SINGLE_QUOTE_STRING:
|
|
2811
|
+
case TokenKind.KEY_DOUBLE_QUOTE_STRING:
|
|
2812
|
+
items.push(new KeySelector(this.environment, stream.current, this.decodeString(stream.current, true), false));
|
|
2813
|
+
break;
|
|
2814
|
+
case TokenKind.KEYS_FILTER:
|
|
2815
|
+
items.push(this.parseFilter(stream, true));
|
|
2816
|
+
break;
|
|
2579
2817
|
case TokenKind.KEYS:
|
|
2580
2818
|
items.push(new KeysSelector(this.environment, stream.current));
|
|
2581
2819
|
break;
|
|
@@ -2596,6 +2834,7 @@ class Parser {
|
|
|
2596
2834
|
return new BracketedSelection(this.environment, token, items);
|
|
2597
2835
|
}
|
|
2598
2836
|
parseFilter(stream) {
|
|
2837
|
+
let keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
2599
2838
|
const tok = stream.next();
|
|
2600
2839
|
const expr = this.parseFilterExpression(stream);
|
|
2601
2840
|
if (expr instanceof FunctionExtension) {
|
|
@@ -2604,7 +2843,7 @@ class Parser {
|
|
|
2604
2843
|
throw new JSONPathTypeError(`result of ${expr.name}() must be compared`, expr.token);
|
|
2605
2844
|
}
|
|
2606
2845
|
}
|
|
2607
|
-
return new FilterSelector(this.environment, tok, new LogicalExpression(tok, expr));
|
|
2846
|
+
return keys ? new KeysFilterSelector(this.environment, tok, new LogicalExpression(tok, expr)) : new FilterSelector(this.environment, tok, new LogicalExpression(tok, expr));
|
|
2608
2847
|
}
|
|
2609
2848
|
parseBoolean(stream) {
|
|
2610
2849
|
if (stream.current.kind === TokenKind.FALSE) return new BooleanLiteral(stream.current, false);
|
|
@@ -3032,6 +3271,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
|
|
|
3032
3271
|
JSONPathRecursionLimitError: JSONPathRecursionLimitError,
|
|
3033
3272
|
JSONPathSyntaxError: JSONPathSyntaxError,
|
|
3034
3273
|
JSONPathTypeError: JSONPathTypeError,
|
|
3274
|
+
KEY_MARK: KEY_MARK,
|
|
3035
3275
|
Nothing: Nothing,
|
|
3036
3276
|
Token: Token,
|
|
3037
3277
|
TokenKind: TokenKind,
|
|
@@ -3524,6 +3764,6 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
3524
3764
|
apply: apply
|
|
3525
3765
|
});
|
|
3526
3766
|
|
|
3527
|
-
const version = "1.
|
|
3767
|
+
const version = "1.3.1";
|
|
3528
3768
|
|
|
3529
3769
|
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 };
|