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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * json-p3 version 1.1.1
2
+ * json-p3 version 1.2.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
@@ -1183,6 +1183,8 @@ var json_p3 = (function (exports) {
1183
1183
  TokenKind["GE"] = "TOKEN_GE";
1184
1184
  TokenKind["GT"] = "TOKEN_GT";
1185
1185
  TokenKind["INDEX"] = "TOKEN_INDEX";
1186
+ TokenKind["KEY"] = "TOKEN_KEY";
1187
+ TokenKind["KEYS"] = "TOKEN_KEYS";
1186
1188
  TokenKind["LBRACKET"] = "TOKEN_LBRACKET";
1187
1189
  TokenKind["LE"] = "TOKEN_LE";
1188
1190
  TokenKind["LG"] = "TOKEN_LG";
@@ -1252,6 +1254,9 @@ var json_p3 = (function (exports) {
1252
1254
  }
1253
1255
  }
1254
1256
 
1257
+ /** A lexer that accepts additional, non-standard tokens. */
1258
+
1259
+
1255
1260
  // These regular expressions are to be used with Lexer.acceptMatchRun(),
1256
1261
  // which expects the sticky flag to be set.
1257
1262
  const exponentPattern = /e[+-]?\d+/y;
@@ -1291,7 +1296,8 @@ var json_p3 = (function (exports) {
1291
1296
  /**
1292
1297
  * @param path - A JSONPath query.
1293
1298
  */
1294
- constructor(path) {
1299
+ constructor(environment, path) {
1300
+ this.environment = environment;
1295
1301
  this.path = path;
1296
1302
  }
1297
1303
  get pos() {
@@ -1391,8 +1397,8 @@ var json_p3 = (function (exports) {
1391
1397
  * @returns A two-tuple containing a lexer for _path_ and an array to populate
1392
1398
  * with tokens.
1393
1399
  */
1394
- function lex(path) {
1395
- const lexer = new Lexer(path);
1400
+ function lex(environment, path) {
1401
+ const lexer = new Lexer(environment, path);
1396
1402
  return [lexer, lexer.tokens];
1397
1403
  }
1398
1404
 
@@ -1401,8 +1407,8 @@ var json_p3 = (function (exports) {
1401
1407
  * @param path - A JSONPath query.
1402
1408
  * @returns Tokens to be parsed by the parser.
1403
1409
  */
1404
- function tokenize(path) {
1405
- const [lexer, tokens] = lex(path);
1410
+ function tokenize(environment, path) {
1411
+ const [lexer, tokens] = lex(environment, path);
1406
1412
  lexer.run();
1407
1413
  if (tokens.length && tokens[tokens.length - 1].kind === TokenKind.ERROR) {
1408
1414
  throw new JSONPathSyntaxError(tokens[tokens.length - 1].value, tokens[tokens.length - 1]);
@@ -1455,6 +1461,16 @@ var json_p3 = (function (exports) {
1455
1461
  * @returns -
1456
1462
  */
1457
1463
  function lexDescendantSelection(l) {
1464
+ if (l.acceptMatchRun(namePattern)) {
1465
+ // Shorthand name
1466
+ l.emit(TokenKind.NAME);
1467
+ return lexSegment;
1468
+ }
1469
+ if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
1470
+ // Non-standard keys selector
1471
+ l.emit(TokenKind.KEYS);
1472
+ return lexSegment;
1473
+ }
1458
1474
  const ch = l.next();
1459
1475
  switch (ch) {
1460
1476
  case "":
@@ -1468,13 +1484,8 @@ var json_p3 = (function (exports) {
1468
1484
  return lexInsideBracketedSelection;
1469
1485
  default:
1470
1486
  l.backup();
1471
- if (l.acceptMatchRun(namePattern)) {
1472
- l.emit(TokenKind.NAME);
1473
- return lexSegment;
1474
- } else {
1475
- l.error(`unexpected descendent selection token '${ch}'`);
1476
- return null;
1477
- }
1487
+ l.error(`unexpected descendent selection token '${ch}'`);
1488
+ return null;
1478
1489
  }
1479
1490
  }
1480
1491
  function lexDotSelector(l) {
@@ -1483,23 +1494,34 @@ var json_p3 = (function (exports) {
1483
1494
  l.error("unexpected whitespace after dot");
1484
1495
  return null;
1485
1496
  }
1486
- const ch = l.next();
1487
- if (ch === "*") {
1488
- l.emit(TokenKind.WILD);
1497
+ if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
1498
+ l.emit(TokenKind.KEYS);
1489
1499
  return lexSegment;
1490
1500
  }
1491
- l.backup();
1492
1501
  if (l.acceptMatchRun(namePattern)) {
1493
1502
  l.emit(TokenKind.NAME);
1494
1503
  return lexSegment;
1495
- } else {
1496
- l.error(`unexpected shorthand selector '${ch}'`);
1497
- return null;
1498
1504
  }
1505
+ const ch = l.next();
1506
+ if (ch === "*") {
1507
+ l.emit(TokenKind.WILD);
1508
+ return lexSegment;
1509
+ }
1510
+ l.backup();
1511
+ l.error(`unexpected shorthand selector '${ch}'`);
1512
+ return null;
1499
1513
  }
1500
1514
  function lexInsideBracketedSelection(l) {
1501
1515
  for (;;) {
1502
1516
  l.ignoreWhitespace();
1517
+ if (l.acceptMatchRun(indexPattern)) {
1518
+ l.emit(TokenKind.INDEX);
1519
+ continue;
1520
+ }
1521
+ if (!l.environment.strict && l.acceptMatchRun(l.environment.keysPattern)) {
1522
+ l.emit(TokenKind.KEYS);
1523
+ continue;
1524
+ }
1503
1525
  const ch = l.next();
1504
1526
  switch (ch) {
1505
1527
  case "]":
@@ -1528,10 +1550,6 @@ var json_p3 = (function (exports) {
1528
1550
  return lexDoubleQuoteStringInsideBracketSelection;
1529
1551
  default:
1530
1552
  l.backup();
1531
- if (l.acceptMatchRun(indexPattern)) {
1532
- l.emit(TokenKind.INDEX);
1533
- continue;
1534
- }
1535
1553
  l.error(`unexpected token '${ch}' in bracketed selection`);
1536
1554
  return null;
1537
1555
  }
@@ -1545,6 +1563,8 @@ var json_p3 = (function (exports) {
1545
1563
  const ch = l.next();
1546
1564
  switch (ch) {
1547
1565
  case "":
1566
+ l.error("unclosed bracketed selection");
1567
+ return null;
1548
1568
  case "]":
1549
1569
  l.filterLevel -= 1;
1550
1570
  if (l.parenStack.length === 1) {
@@ -1586,6 +1606,9 @@ var json_p3 = (function (exports) {
1586
1606
  case "@":
1587
1607
  l.emit(TokenKind.CURRENT);
1588
1608
  return lexSegment;
1609
+ case "#":
1610
+ l.emit(TokenKind.KEY);
1611
+ return lexSegment;
1589
1612
  case ".":
1590
1613
  l.backup();
1591
1614
  return lexSegment;
@@ -1963,12 +1986,22 @@ var json_p3 = (function (exports) {
1963
1986
  }
1964
1987
  resolve(nodes) {
1965
1988
  const rv = [];
1966
- for (const node of nodes) {
1967
- rv.push(node);
1968
- for (const _node of this.visit(node)) {
1969
- rv.push(_node);
1989
+ if (this.environment.nondeterministic) {
1990
+ for (const root of nodes) {
1991
+ for (const node of this.nondeterministicVisitor(root)) {
1992
+ rv.push(node);
1993
+ }
1994
+ }
1995
+ } else {
1996
+ for (const node of nodes) {
1997
+ rv.push(node);
1998
+ for (const _node of this.visitor(node)) {
1999
+ rv.push(_node);
2000
+ }
1970
2001
  }
1971
2002
  }
2003
+
2004
+ // console.log(JSON.stringify(rv.map((n: any) => n.value)));
1972
2005
  return this.selector.resolve(rv);
1973
2006
  }
1974
2007
  *lazyResolve(nodes) {
@@ -2021,7 +2054,7 @@ var json_p3 = (function (exports) {
2021
2054
  toString() {
2022
2055
  return `..${this.selector.toString()}`;
2023
2056
  }
2024
- visit(node) {
2057
+ visitor(node) {
2025
2058
  let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
2026
2059
  if (depth >= this.environment.maxRecursionDepth) {
2027
2060
  throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
@@ -2032,7 +2065,7 @@ var json_p3 = (function (exports) {
2032
2065
  for (let i = 0; i < node.value.length; i++) {
2033
2066
  const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
2034
2067
  rv.push(_node);
2035
- for (const __node of this.visit(_node, depth + 1)) {
2068
+ for (const __node of this.visitor(_node, depth + 1)) {
2036
2069
  rv.push(__node);
2037
2070
  }
2038
2071
  }
@@ -2040,13 +2073,52 @@ var json_p3 = (function (exports) {
2040
2073
  for (const [key, value] of this.environment.entries(node.value)) {
2041
2074
  const _node = new JSONPathNode(value, node.location.concat(key), node.root);
2042
2075
  rv.push(_node);
2043
- for (const __node of this.visit(_node, depth + 1)) {
2076
+ for (const __node of this.visitor(_node, depth + 1)) {
2044
2077
  rv.push(__node);
2045
2078
  }
2046
2079
  }
2047
2080
  }
2048
2081
  return rv;
2049
2082
  }
2083
+ nondeterministicVisitor(root) {
2084
+ let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
2085
+ const rv = [root];
2086
+ let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
2087
+ while (queue.length) {
2088
+ const [node, _depth] = queue.shift();
2089
+ rv.push(node);
2090
+ if (_depth >= this.environment.maxRecursionDepth) {
2091
+ throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
2092
+ }
2093
+
2094
+ // Visit child nodes now or queue them for later?
2095
+ const visitChildren = Math.random() < 0.5;
2096
+ for (const child of this.nondeterministicChildren(node)) {
2097
+ if (visitChildren) {
2098
+ rv.push(child);
2099
+ const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
2100
+ queue = interleave(queue, grandchildren);
2101
+ } else {
2102
+ queue.push([child, _depth + 1]);
2103
+ }
2104
+ }
2105
+ }
2106
+ return rv;
2107
+ }
2108
+ nondeterministicChildren(node) {
2109
+ const _rv = [];
2110
+ if (node.value instanceof String) return _rv;
2111
+ if (isArray(node.value)) {
2112
+ for (let i = 0; i < node.value.length; i++) {
2113
+ _rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
2114
+ }
2115
+ } else if (isObject(node.value)) {
2116
+ for (const [key, value] of this.environment.entries(node.value)) {
2117
+ _rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
2118
+ }
2119
+ }
2120
+ return _rv;
2121
+ }
2050
2122
  }
2051
2123
  class FilterSelector extends JSONPathSelector {
2052
2124
  constructor(environment, token, expression) {
@@ -2067,7 +2139,8 @@ var json_p3 = (function (exports) {
2067
2139
  const filterContext = {
2068
2140
  environment: this.environment,
2069
2141
  currentValue: value,
2070
- rootValue: node.root
2142
+ rootValue: node.root,
2143
+ currentKey: i
2071
2144
  };
2072
2145
  if (this.expression.evaluate(filterContext)) {
2073
2146
  rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
@@ -2078,7 +2151,8 @@ var json_p3 = (function (exports) {
2078
2151
  const filterContext = {
2079
2152
  environment: this.environment,
2080
2153
  currentValue: value,
2081
- rootValue: node.root
2154
+ rootValue: node.root,
2155
+ currentKey: key
2082
2156
  };
2083
2157
  if (this.expression.evaluate(filterContext)) {
2084
2158
  rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
@@ -2100,7 +2174,8 @@ var json_p3 = (function (exports) {
2100
2174
  environment: this.environment,
2101
2175
  currentValue: value,
2102
2176
  rootValue: node.root,
2103
- lazy: true
2177
+ lazy: true,
2178
+ currentKey: i
2104
2179
  };
2105
2180
  if (this.expression.evaluate(filterContext)) {
2106
2181
  yield new JSONPathNode(value, node.location.concat(i), node.root);
@@ -2112,7 +2187,8 @@ var json_p3 = (function (exports) {
2112
2187
  environment: this.environment,
2113
2188
  currentValue: value,
2114
2189
  rootValue: node.root,
2115
- lazy: true
2190
+ lazy: true,
2191
+ currentKey: key
2116
2192
  };
2117
2193
  if (this.expression.evaluate(filterContext)) {
2118
2194
  yield new JSONPathNode(value, node.location.concat(key), node.root);
@@ -2155,6 +2231,41 @@ var json_p3 = (function (exports) {
2155
2231
  }
2156
2232
  }
2157
2233
 
2234
+ /**
2235
+ * Randomly interleave elements from two arrays while maintaining relative
2236
+ * order of each input array.
2237
+ *
2238
+ * If _arrayA_ is empty, _arrayB_ is returned, and vice versa.
2239
+ */
2240
+ function interleave(arrayA, arrayB) {
2241
+ if (arrayA.length === 0) {
2242
+ return arrayB;
2243
+ }
2244
+ if (arrayB.length === 0) {
2245
+ return arrayA;
2246
+ }
2247
+
2248
+ // An array of iterators
2249
+ const iterators = [];
2250
+ const itA = arrayA[Symbol.iterator]();
2251
+ const itB = arrayB[Symbol.iterator]();
2252
+ for (let i = 0; i < arrayA.length; i++) {
2253
+ iterators.push(itA);
2254
+ }
2255
+ for (let i = 0; i < arrayB.length; i++) {
2256
+ iterators.push(itB);
2257
+ }
2258
+ shuffle(iterators);
2259
+ return iterators.map(it => it.next().value);
2260
+ }
2261
+ function shuffle(entries) {
2262
+ for (let i = entries.length - 1; i > 0; i--) {
2263
+ const j = Math.floor(Math.random() * (i + 1));
2264
+ [entries[i], entries[j]] = [entries[j], entries[i]];
2265
+ }
2266
+ return entries;
2267
+ }
2268
+
2158
2269
  var selectors = /*#__PURE__*/Object.freeze({
2159
2270
  __proto__: null,
2160
2271
  BracketedSelection: BracketedSelection,
@@ -2238,6 +2349,57 @@ var json_p3 = (function (exports) {
2238
2349
  }
2239
2350
  }
2240
2351
 
2352
+ class CurrentKey extends FilterExpression {
2353
+ evaluate(context) {
2354
+ return context.currentKey ?? Nothing;
2355
+ }
2356
+ toString() {
2357
+ return "#";
2358
+ }
2359
+ }
2360
+
2361
+ /**
2362
+ * Object property name selector or array index selector.
2363
+ */
2364
+ class KeysSelector extends JSONPathSelector {
2365
+ constructor(environment, token) {
2366
+ let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
2367
+ super(environment, token);
2368
+ this.environment = environment;
2369
+ this.token = token;
2370
+ this.shorthand = shorthand;
2371
+ }
2372
+ resolve(nodes) {
2373
+ const rv = [];
2374
+ for (const node of nodes) {
2375
+ if (node.value instanceof String || isArray(node.value)) continue;
2376
+ if (isObject(node.value)) {
2377
+ let i = 0;
2378
+ for (const [key, _] of this.environment.entries(node.value)) {
2379
+ rv.push(new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root));
2380
+ i++;
2381
+ }
2382
+ }
2383
+ }
2384
+ return rv;
2385
+ }
2386
+ *lazyResolve(nodes) {
2387
+ for (const node of nodes) {
2388
+ if (node.value instanceof String || isArray(node.value)) continue;
2389
+ if (isObject(node.value)) {
2390
+ let i = 0;
2391
+ for (const [key, _] of this.environment.entries(node.value)) {
2392
+ yield new JSONPathNode(key, node.location.concat("[~]", `[${i}]`), node.root);
2393
+ i++;
2394
+ }
2395
+ }
2396
+ }
2397
+ }
2398
+ toString() {
2399
+ return this.shorthand ? "[~]" : "~";
2400
+ }
2401
+ }
2402
+
2241
2403
  const PRECEDENCE_LOWEST = 1;
2242
2404
  const PRECEDENCE_LOGICAL_OR = 4;
2243
2405
  const PRECEDENCE_LOGICAL_AND = 5;
@@ -2253,7 +2415,7 @@ var json_p3 = (function (exports) {
2253
2415
  class Parser {
2254
2416
  constructor(environment) {
2255
2417
  this.environment = environment;
2256
- 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]]);
2418
+ 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]]);
2257
2419
  }
2258
2420
  parse(stream) {
2259
2421
  if (stream.current.kind === TokenKind.ROOT) stream.next();
@@ -2285,6 +2447,8 @@ var json_p3 = (function (exports) {
2285
2447
  return new NameSelector(this.environment, stream.current, stream.current.value, true);
2286
2448
  case TokenKind.WILD:
2287
2449
  return new WildcardSelector(this.environment, stream.current, true);
2450
+ case TokenKind.KEYS:
2451
+ return new KeysSelector(this.environment, stream.current, true);
2288
2452
  case TokenKind.DDOT:
2289
2453
  {
2290
2454
  const segmentToken = stream.current;
@@ -2378,6 +2542,9 @@ var json_p3 = (function (exports) {
2378
2542
  case TokenKind.WILD:
2379
2543
  items.push(new WildcardSelector(this.environment, stream.current));
2380
2544
  break;
2545
+ case TokenKind.KEYS:
2546
+ items.push(new KeysSelector(this.environment, stream.current));
2547
+ break;
2381
2548
  case TokenKind.EOF:
2382
2549
  throw new JSONPathSyntaxError("unexpected end of query", stream.current);
2383
2550
  default:
@@ -2458,6 +2625,9 @@ var json_p3 = (function (exports) {
2458
2625
  const tok = stream.next();
2459
2626
  return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
2460
2627
  }
2628
+ parseCurrentKey(stream) {
2629
+ return new CurrentKey(stream.current);
2630
+ }
2461
2631
  parseFunction(stream) {
2462
2632
  const args = [];
2463
2633
  const tok = stream.next();
@@ -2574,6 +2744,10 @@ var json_p3 = (function (exports) {
2574
2744
  * If `true`, enable nondeterministic ordering when iterating JSON object data.
2575
2745
  */
2576
2746
 
2747
+ /**
2748
+ * The pattern to use for the non-standard _keys selector_.
2749
+ */
2750
+
2577
2751
  /**
2578
2752
  * A map of function names to objects implementing the {@link FilterFunction}
2579
2753
  * interface. You are free to set or delete custom filter functions directly.
@@ -2589,6 +2763,7 @@ var json_p3 = (function (exports) {
2589
2763
  this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
2590
2764
  this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
2591
2765
  this.nondeterministic = options.nondeterministic ?? false;
2766
+ this.keysPattern = options.keysPattern ?? /~/y;
2592
2767
  this.parser = new Parser(this);
2593
2768
  this.setupFilterFunctions();
2594
2769
  }
@@ -2598,7 +2773,7 @@ var json_p3 = (function (exports) {
2598
2773
  * @returns A new {@link JSONPath} object, bound to this environment.
2599
2774
  */
2600
2775
  compile(path) {
2601
- return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(path))));
2776
+ return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
2602
2777
  }
2603
2778
 
2604
2779
  /**
@@ -2680,7 +2855,7 @@ var json_p3 = (function (exports) {
2680
2855
  for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
2681
2856
  switch (typ) {
2682
2857
  case FunctionExpressionType.ValueType:
2683
- if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
2858
+ if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
2684
2859
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
2685
2860
  }
2686
2861
  break;
@@ -3308,7 +3483,7 @@ var json_p3 = (function (exports) {
3308
3483
  apply: apply
3309
3484
  });
3310
3485
 
3311
- const version = "1.1.1";
3486
+ const version = "1.2.0";
3312
3487
 
3313
3488
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
3314
3489
  exports.FunctionExpressionType = FunctionExpressionType;