json-p3 1.3.5 → 2.1.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.3.5
2
+ * json-p3 version 2.1.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
@@ -654,6 +654,30 @@ var json_p3 = (function (exports) {
654
654
  resolve: resolve
655
655
  });
656
656
 
657
+ /**
658
+ * An identifier that is allowed in both JS and JSONPath.
659
+ * JSONPath identifiers are generally much more permissive than JS ones, but
660
+ * they don't allow the character "$", so we take the intersection of the two
661
+ * when deciding whether to use dot shorthand for canonical serialization of
662
+ * simple names.
663
+ */
664
+ const SHORTHAND_COMPATIBLE_IDENTIFIER = /^[\p{ID_Start}_]\p{ID_Continue}*$/u;
665
+
666
+ /** Usable in a quoted path. */
667
+ function toQuoted(name) {
668
+ return name.includes("'") && !name.includes('"') ? JSON.stringify(name) : toCanonical(name);
669
+ }
670
+
671
+ /** Usable in a normalized path. */
672
+ function toCanonical(name) {
673
+ return `'${JSON.stringify(name).slice(1, -1).replaceAll('\\"', '"').replaceAll("'", "\\'")}'`;
674
+ }
675
+
676
+ /** Usable in a shorthand path. */
677
+ function toShorthand(name) {
678
+ return SHORTHAND_COMPATIBLE_IDENTIFIER.test(name) ? name : null;
679
+ }
680
+
657
681
  const Nothing = Symbol.for("jsonpath.nothing");
658
682
 
659
683
  /**
@@ -661,7 +685,7 @@ var json_p3 = (function (exports) {
661
685
  */
662
686
 
663
687
  /**
664
- * Object passed to FilterExpression.evaluate().
688
+ * Object passed to `FilterExpression.evaluate()`.
665
689
  */
666
690
 
667
691
  /**
@@ -672,6 +696,14 @@ var json_p3 = (function (exports) {
672
696
  }
673
697
  const KEY_MARK = "\x02";
674
698
 
699
+ /**
700
+ * Options for serializing paths.
701
+ */
702
+
703
+ const defaultSerializationOptions = {
704
+ form: "pretty"
705
+ };
706
+
675
707
  /**
676
708
  * The pair of a JSON value and its location found in the target JSON value.
677
709
  */
@@ -686,10 +718,31 @@ var json_p3 = (function (exports) {
686
718
  this.location = location;
687
719
  this.root = root;
688
720
  }
721
+
722
+ /**
723
+ * @deprecated Use {@link getPath} with `options.form` set to `canonical` instead.
724
+ */
689
725
  get path() {
726
+ return this.getPath({
727
+ form: "canonical"
728
+ });
729
+ }
730
+
731
+ /**
732
+ * Get the path to this node in the target JSON value.
733
+ *
734
+ * Given that the path refers to the singular current node, the returned path
735
+ * will always be a normalized path if `options.form` is set to `canonical`,
736
+ * following section 2.7 of RFC 9535.
737
+ */
738
+ getPath(options) {
739
+ const opts = {
740
+ ...defaultSerializationOptions,
741
+ ...options
742
+ };
690
743
  return (
691
744
  // eslint-disable-next-line prefer-template
692
- "$" + this.location.map(s => isString(s) ? this.decode_name_location(s) : `[${s}]`).join("")
745
+ "$" + this.location.map(s => isString(s) ? this.decodeNameLocation(s, opts) : `[${s}]`).join("")
693
746
  );
694
747
  }
695
748
 
@@ -702,8 +755,16 @@ var json_p3 = (function (exports) {
702
755
  }
703
756
  return new JSONPointer(JSONPointer.encode(this.location.map(String)));
704
757
  }
705
- decode_name_location(name) {
706
- return name.startsWith(KEY_MARK) ? `[~'${name.slice(1).replaceAll("'", "\\'")}']` : `['${name.replaceAll("'", "\\'")}']`;
758
+ decodeNameLocation(name, options) {
759
+ const normalized = options.form === "canonical";
760
+ const serialize = normalized ? toCanonical : toQuoted;
761
+ const hasKeyMark = name.startsWith(KEY_MARK);
762
+ if (hasKeyMark) name = name.slice(1);
763
+ const shorthand = toShorthand(name);
764
+ if (hasKeyMark) {
765
+ return normalized || shorthand == null ? `[~${serialize(name)}]` : `.~${shorthand}`;
766
+ }
767
+ return normalized || shorthand == null ? `[${serialize(name)}]` : `.${shorthand}`;
707
768
  }
708
769
  }
709
770
 
@@ -764,8 +825,8 @@ var json_p3 = (function (exports) {
764
825
  * A normalized path contains only property name and index selectors, and
765
826
  * always uses bracketed segments, never shorthand selectors.
766
827
  */
767
- paths() {
768
- return this.nodes.map(node => node.path);
828
+ paths(options) {
829
+ return this.nodes.map(node => node.getPath(options));
769
830
  }
770
831
 
771
832
  /**
@@ -837,7 +898,7 @@ var json_p3 = (function (exports) {
837
898
  return this.value;
838
899
  }
839
900
  toString() {
840
- return JSON.stringify(this.value);
901
+ return toCanonical(this.value);
841
902
  }
842
903
  }
843
904
  class NumberLiteral extends FilterExpressionLiteral {
@@ -868,10 +929,13 @@ var json_p3 = (function (exports) {
868
929
  }
869
930
  throw new JSONPathTypeError(`unknown operator '${this.operator}'`, this.token);
870
931
  }
871
- toString() {
872
- return `${this.operator}${this.right.toString()}`;
932
+ toString(options) {
933
+ return `${this.operator}${this.right.toString(options)}`;
873
934
  }
874
935
  }
936
+ const PRECEDENCE_LOGICAL_OR$1 = 4;
937
+ const PRECEDENCE_LOGICAL_AND$1 = 5;
938
+ const PRECEDENCE_PREFIX$1 = 7;
875
939
  class InfixExpression extends FilterExpression {
876
940
  constructor(token, left, operator, right) {
877
941
  super(token);
@@ -894,11 +958,12 @@ var json_p3 = (function (exports) {
894
958
  }
895
959
  return compare(left, this.operator, right);
896
960
  }
897
- toString() {
961
+ toString(options) {
962
+ // Note that `LogicalExpression.toString()` does not call this.
898
963
  if (this.logical) {
899
- return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`;
964
+ return `(${this.left.toString(options)} ${this.operator} ${this.right.toString(options)})`;
900
965
  }
901
- return `${this.left.toString()} ${this.operator} ${this.right.toString()}`;
966
+ return `${this.left.toString(options)} ${this.operator} ${this.right.toString(options)}`;
902
967
  }
903
968
  }
904
969
  class LogicalExpression extends FilterExpression {
@@ -912,35 +977,65 @@ var json_p3 = (function (exports) {
912
977
  if (value instanceof JSONPathNodeList) return value.nodes.length > 0; // existence
913
978
  return isTruthy(value);
914
979
  }
915
- toString() {
916
- return this.expression.toString();
980
+ toString(options) {
981
+ // Minimize parentheses in logical expressions.
982
+ function _toString(expression, parentPrecedence) {
983
+ if (expression instanceof InfixExpression) {
984
+ let precedence;
985
+ let op;
986
+ let left;
987
+ let right;
988
+ if (expression.operator === "&&") {
989
+ precedence = PRECEDENCE_LOGICAL_AND$1;
990
+ op = "&&";
991
+ left = _toString(expression.left, precedence);
992
+ right = _toString(expression.right, precedence);
993
+ } else if (expression.operator === "||") {
994
+ precedence = PRECEDENCE_LOGICAL_OR$1;
995
+ op = "||";
996
+ left = _toString(expression.left, precedence);
997
+ right = _toString(expression.right, precedence);
998
+ } else {
999
+ return expression.toString(options);
1000
+ }
1001
+ const expr = `${left} ${op} ${right}`;
1002
+ return precedence < parentPrecedence ? `(${expr})` : expr;
1003
+ }
1004
+ if (expression instanceof PrefixExpression) {
1005
+ const operand = _toString(expression.right, PRECEDENCE_PREFIX$1);
1006
+ const expr = `!${operand}`;
1007
+ return parentPrecedence > PRECEDENCE_PREFIX$1 ? `(${expr})` : expr;
1008
+ }
1009
+ return expression.toString(options);
1010
+ }
1011
+ return _toString(this.expression, 0);
917
1012
  }
918
1013
  }
919
1014
 
920
1015
  /**
921
1016
  * Base class for relative and absolute JSONPath query expressions.
922
1017
  */
923
- class JSONPathQuery extends FilterExpression {
1018
+ class FilterQuery extends FilterExpression {
924
1019
  constructor(token, path) {
925
1020
  super(token);
926
1021
  this.token = token;
927
1022
  this.path = path;
928
1023
  }
929
1024
  }
930
- class RelativeQuery extends JSONPathQuery {
1025
+ class RelativeQuery extends FilterQuery {
931
1026
  evaluate(context) {
932
1027
  return context.lazy ? new JSONPathNodeList(Array.from(this.path.lazyQuery(context.currentValue))) : this.path.query(context.currentValue);
933
1028
  }
934
- toString() {
935
- return `@${this.path.toString().slice(1)}`;
1029
+ toString(options) {
1030
+ return `@${this.path.toString(options).slice(1)}`;
936
1031
  }
937
1032
  }
938
- class RootQuery extends JSONPathQuery {
1033
+ class RootQuery extends FilterQuery {
939
1034
  evaluate(context) {
940
1035
  return context.lazy ? new JSONPathNodeList(Array.from(this.path.lazyQuery(context.rootValue))) : this.path.query(context.rootValue);
941
1036
  }
942
- toString() {
943
- return this.path.toString();
1037
+ toString(options) {
1038
+ return this.path.toString(options);
944
1039
  }
945
1040
  }
946
1041
  class FunctionExtension extends FilterExpression {
@@ -958,8 +1053,8 @@ var json_p3 = (function (exports) {
958
1053
  const args = this.args.map(arg => arg.evaluate(context)).map((arg, idx) => func.argTypes[idx] !== FunctionExpressionType.NodesType && arg instanceof JSONPathNodeList ? this.unpack_node_list(arg) : arg);
959
1054
  return func.call(...args);
960
1055
  }
961
- toString() {
962
- return `${this.name}(${this.args.map(e => e.toString()).join(", ")})`;
1056
+ toString(options) {
1057
+ return `${this.name}(${this.args.map(e => e.toString(options)).join(", ")})`;
963
1058
  }
964
1059
  unpack_node_list(arg) {
965
1060
  switch (arg.length) {
@@ -1029,9 +1124,9 @@ var json_p3 = (function (exports) {
1029
1124
  BooleanLiteral: BooleanLiteral,
1030
1125
  FilterExpression: FilterExpression,
1031
1126
  FilterExpressionLiteral: FilterExpressionLiteral,
1127
+ FilterQuery: FilterQuery,
1032
1128
  FunctionExtension: FunctionExtension,
1033
1129
  InfixExpression: InfixExpression,
1034
- JSONPathQuery: JSONPathQuery,
1035
1130
  LogicalExpression: LogicalExpression,
1036
1131
  NullLiteral: NullLiteral,
1037
1132
  NumberLiteral: NumberLiteral,
@@ -3132,11 +3227,11 @@ var json_p3 = (function (exports) {
3132
3227
  }
3133
3228
 
3134
3229
  /**
3135
- * @param nodes - Nodes matched by preceding selectors.
3230
+ * @param node - Nodes matched by preceding selectors.
3136
3231
  */
3137
3232
 
3138
3233
  /**
3139
- * @param nodes - Nodes matched by preceding selectors.
3234
+ * @param node - Nodes matched by preceding selectors.
3140
3235
  */
3141
3236
 
3142
3237
  /**
@@ -3148,31 +3243,35 @@ var json_p3 = (function (exports) {
3148
3243
  * Shorthand and quoted name selector.
3149
3244
  */
3150
3245
  class NameSelector extends JSONPathSelector {
3151
- constructor(environment, token, name, shorthand) {
3246
+ constructor(environment, token, name) {
3152
3247
  super(environment, token);
3153
3248
  this.environment = environment;
3154
3249
  this.token = token;
3155
3250
  this.name = name;
3156
- this.shorthand = shorthand;
3157
3251
  }
3158
- resolve(nodes) {
3252
+ resolve(node) {
3159
3253
  const rv = [];
3160
- for (const node of nodes) {
3161
- if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
3162
- rv.push(new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root));
3163
- }
3254
+ if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
3255
+ rv.push(new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root));
3164
3256
  }
3165
3257
  return rv;
3166
3258
  }
3167
- *lazyResolve(nodes) {
3168
- for (const node of nodes) {
3169
- if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
3170
- yield new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root);
3171
- }
3259
+ *lazyResolve(node) {
3260
+ if (!isArray(node.value) && hasStringKey(node.value, this.name)) {
3261
+ yield new JSONPathNode(node.value[this.name], node.location.concat(this.name), node.root);
3172
3262
  }
3173
3263
  }
3174
- toString() {
3175
- return this.shorthand ? `['${this.name}']` : `'${this.name}'`;
3264
+ toString(options) {
3265
+ const {
3266
+ form
3267
+ } = {
3268
+ ...defaultSerializationOptions,
3269
+ ...options
3270
+ };
3271
+ return form === "canonical" ? toCanonical(this.name) : toQuoted(this.name);
3272
+ }
3273
+ shorthand() {
3274
+ return toShorthand(this.name);
3176
3275
  }
3177
3276
  }
3178
3277
 
@@ -3189,25 +3288,21 @@ var json_p3 = (function (exports) {
3189
3288
  throw new JSONPathIndexError("index out of range", this.token);
3190
3289
  }
3191
3290
  }
3192
- resolve(nodes) {
3291
+ resolve(node) {
3193
3292
  const rv = [];
3194
- for (const node of nodes) {
3195
- if (isArray(node.value)) {
3196
- const normIndex = this.normalizedIndex(node.value.length);
3197
- if (normIndex in node.value) {
3198
- rv.push(new JSONPathNode(node.value[normIndex], node.location.concat(normIndex), node.root));
3199
- }
3293
+ if (isArray(node.value)) {
3294
+ const normIndex = this.normalizedIndex(node.value.length);
3295
+ if (normIndex in node.value) {
3296
+ rv.push(new JSONPathNode(node.value[normIndex], node.location.concat(normIndex), node.root));
3200
3297
  }
3201
3298
  }
3202
3299
  return rv;
3203
3300
  }
3204
- *lazyResolve(nodes) {
3205
- for (const node of nodes) {
3206
- if (isArray(node.value)) {
3207
- const normIndex = this.normalizedIndex(node.value.length);
3208
- if (normIndex in node.value) {
3209
- yield new JSONPathNode(node.value[normIndex], node.location.concat(normIndex), node.root);
3210
- }
3301
+ *lazyResolve(node) {
3302
+ if (isArray(node.value)) {
3303
+ const normIndex = this.normalizedIndex(node.value.length);
3304
+ if (normIndex in node.value) {
3305
+ yield new JSONPathNode(node.value[normIndex], node.location.concat(normIndex), node.root);
3211
3306
  }
3212
3307
  }
3213
3308
  }
@@ -3229,19 +3324,16 @@ var json_p3 = (function (exports) {
3229
3324
  this.step = step;
3230
3325
  this.checkRange(start, stop, step);
3231
3326
  }
3232
- resolve(nodes) {
3327
+ resolve(node) {
3233
3328
  const rv = [];
3234
- for (const node of nodes) {
3235
- if (!isArray(node.value)) continue;
3236
- for (const [i, value] of this.slice(node.value, this.start, this.stop, this.step)) {
3237
- rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
3238
- }
3329
+ if (!isArray(node.value)) return rv;
3330
+ for (const [i, value] of this.slice(node.value, this.start, this.stop, this.step)) {
3331
+ rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
3239
3332
  }
3240
3333
  return rv;
3241
3334
  }
3242
- *lazyResolve(nodes) {
3243
- for (const node of nodes) {
3244
- if (!isArray(node.value)) continue;
3335
+ *lazyResolve(node) {
3336
+ if (isArray(node.value)) {
3245
3337
  for (const [i, value] of this.lazySlice(node.value, this.start, this.stop, this.step)) {
3246
3338
  yield new JSONPathNode(value, node.location.concat(i), node.root);
3247
3339
  }
@@ -3347,281 +3439,185 @@ var json_p3 = (function (exports) {
3347
3439
  }
3348
3440
  class WildcardSelector extends JSONPathSelector {
3349
3441
  constructor(environment, token) {
3350
- let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3351
3442
  super(environment, token);
3352
3443
  this.environment = environment;
3353
3444
  this.token = token;
3354
- this.shorthand = shorthand;
3355
3445
  }
3356
- resolve(nodes) {
3446
+ resolve(node) {
3357
3447
  const rv = [];
3358
- for (const node of nodes) {
3359
- if (node.value instanceof String) continue;
3360
- if (isArray(node.value)) {
3361
- for (let i = 0; i < node.value.length; i++) {
3362
- rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
3363
- }
3364
- } else if (isObject(node.value)) {
3365
- for (const [key, value] of this.environment.entries(node.value)) {
3366
- rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
3367
- }
3448
+ if (node.value instanceof String) return rv;
3449
+ if (isArray(node.value)) {
3450
+ for (let i = 0; i < node.value.length; i++) {
3451
+ rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
3452
+ }
3453
+ } else if (isObject(node.value)) {
3454
+ for (const [key, value] of this.environment.entries(node.value)) {
3455
+ rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
3368
3456
  }
3369
3457
  }
3370
3458
  return rv;
3371
3459
  }
3372
- *lazyResolve(nodes) {
3373
- for (const node of nodes) {
3374
- if (node.value instanceof String) continue;
3375
- if (isArray(node.value)) {
3376
- for (let i = 0; i < node.value.length; i++) {
3377
- yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
3378
- }
3379
- } else if (isObject(node.value)) {
3380
- for (const [key, value] of this.environment.entries(node.value)) {
3381
- yield new JSONPathNode(value, node.location.concat(key), node.root);
3382
- }
3460
+ *lazyResolve(node) {
3461
+ if (isArray(node.value)) {
3462
+ for (let i = 0; i < node.value.length; i++) {
3463
+ yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
3464
+ }
3465
+ } else if (isObject(node.value) && !isString(node.value)) {
3466
+ for (const [key, value] of this.environment.entries(node.value)) {
3467
+ yield new JSONPathNode(value, node.location.concat(key), node.root);
3383
3468
  }
3384
3469
  }
3385
3470
  }
3386
3471
  toString() {
3387
- return this.shorthand ? "[*]" : "*";
3472
+ return "*";
3388
3473
  }
3389
3474
  }
3390
- class RecursiveDescentSegment extends JSONPathSelector {
3391
- constructor(environment, token, selector) {
3475
+ class FilterSelector extends JSONPathSelector {
3476
+ constructor(environment, token, expression) {
3392
3477
  super(environment, token);
3393
3478
  this.environment = environment;
3394
3479
  this.token = token;
3395
- this.selector = selector;
3396
- }
3397
- resolve(nodes) {
3398
- const rv = [];
3399
- if (this.environment.nondeterministic) {
3400
- for (const root of nodes) {
3401
- for (const node of this.nondeterministicVisitor(root)) {
3402
- rv.push(node);
3403
- }
3404
- }
3405
- } else {
3406
- for (const node of nodes) {
3407
- rv.push(node);
3408
- for (const _node of this.visitor(node)) {
3409
- rv.push(_node);
3410
- }
3411
- }
3412
- }
3413
- return this.selector.resolve(rv);
3414
- }
3415
- *lazyResolve(nodes) {
3416
- yield* this.selector.lazyResolve(this._lazyResolve(nodes));
3417
- }
3418
-
3419
- // eslint-disable-next-line sonarjs/cognitive-complexity
3420
- *_lazyResolve(nodes) {
3421
- for (const _node of nodes) {
3422
- const stack = [{
3423
- node: _node,
3424
- depth: 0
3425
- }];
3426
- yield _node;
3427
- while (stack.length) {
3428
- const {
3429
- node: currentNode,
3430
- depth
3431
- } = stack.pop();
3432
- if (depth >= this.environment.maxRecursionDepth) {
3433
- throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
3434
- }
3435
- if (currentNode.value instanceof String) continue;
3436
- if (isArray(currentNode.value)) {
3437
- for (let i = 0; i < currentNode.value.length; i++) {
3438
- const __node = new JSONPathNode(currentNode.value[i], currentNode.location.concat(i), currentNode.root);
3439
- yield __node;
3440
- if (isObject(__node.value)) {
3441
- stack.push({
3442
- node: __node,
3443
- depth: depth + 1
3444
- });
3445
- }
3446
- }
3447
- } else if (isObject(currentNode.value)) {
3448
- for (const [key, value] of this.environment.entries(currentNode.value)) {
3449
- const __node = new JSONPathNode(value, currentNode.location.concat(key), currentNode.root);
3450
- yield __node;
3451
- if (isObject(__node.value)) {
3452
- stack.push({
3453
- node: __node,
3454
- depth: depth + 1
3455
- });
3456
- }
3457
- }
3458
- }
3459
- }
3460
- }
3461
- }
3462
- toString() {
3463
- return `..${this.selector.toString()}`;
3480
+ this.expression = expression;
3464
3481
  }
3465
- visitor(node) {
3466
- let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
3467
- if (depth >= this.environment.maxRecursionDepth) {
3468
- throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
3469
- }
3482
+ resolve(node) {
3470
3483
  const rv = [];
3471
3484
  if (node.value instanceof String) return rv;
3472
3485
  if (isArray(node.value)) {
3473
3486
  for (let i = 0; i < node.value.length; i++) {
3474
- const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
3475
- rv.push(_node);
3476
- for (const __node of this.visitor(_node, depth + 1)) {
3477
- rv.push(__node);
3487
+ const value = node.value[i];
3488
+ const filterContext = {
3489
+ environment: this.environment,
3490
+ currentValue: value,
3491
+ rootValue: node.root,
3492
+ currentKey: i
3493
+ };
3494
+ if (this.expression.evaluate(filterContext)) {
3495
+ rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
3478
3496
  }
3479
3497
  }
3480
3498
  } else if (isObject(node.value)) {
3481
3499
  for (const [key, value] of this.environment.entries(node.value)) {
3482
- const _node = new JSONPathNode(value, node.location.concat(key), node.root);
3483
- rv.push(_node);
3484
- for (const __node of this.visitor(_node, depth + 1)) {
3485
- rv.push(__node);
3486
- }
3487
- }
3488
- }
3489
- return rv;
3490
- }
3491
- nondeterministicVisitor(root) {
3492
- let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
3493
- const rv = [root];
3494
- let queue = this.nondeterministicChildren(root).map(node => [node, depth]);
3495
- while (queue.length) {
3496
- const [node, _depth] = queue.shift();
3497
- rv.push(node);
3498
- if (_depth >= this.environment.maxRecursionDepth) {
3499
- throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
3500
- }
3501
-
3502
- // Visit child nodes now or queue them for later?
3503
- const visitChildren = Math.random() < 0.5;
3504
- for (const child of this.nondeterministicChildren(node)) {
3505
- if (visitChildren) {
3506
- rv.push(child);
3507
- const grandchildren = this.nondeterministicChildren(child).map(n => [n, _depth + 2]);
3508
- queue = interleave(queue, grandchildren);
3509
- } else {
3510
- queue.push([child, _depth + 1]);
3500
+ const filterContext = {
3501
+ environment: this.environment,
3502
+ currentValue: value,
3503
+ rootValue: node.root,
3504
+ currentKey: key
3505
+ };
3506
+ if (this.expression.evaluate(filterContext)) {
3507
+ rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
3511
3508
  }
3512
3509
  }
3513
3510
  }
3514
3511
  return rv;
3515
3512
  }
3516
- nondeterministicChildren(node) {
3517
- const _rv = [];
3518
- if (node.value instanceof String) return _rv;
3513
+ *lazyResolve(node) {
3519
3514
  if (isArray(node.value)) {
3520
3515
  for (let i = 0; i < node.value.length; i++) {
3521
- _rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
3516
+ const value = node.value[i];
3517
+ const filterContext = {
3518
+ environment: this.environment,
3519
+ currentValue: value,
3520
+ rootValue: node.root,
3521
+ lazy: true,
3522
+ currentKey: i
3523
+ };
3524
+ if (this.expression.evaluate(filterContext)) {
3525
+ yield new JSONPathNode(value, node.location.concat(i), node.root);
3526
+ }
3522
3527
  }
3523
- } else if (isObject(node.value)) {
3528
+ } else if (isObject(node.value) && !isString(node.value)) {
3524
3529
  for (const [key, value] of this.environment.entries(node.value)) {
3525
- _rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
3530
+ const filterContext = {
3531
+ environment: this.environment,
3532
+ currentValue: value,
3533
+ rootValue: node.root,
3534
+ lazy: true,
3535
+ currentKey: key
3536
+ };
3537
+ if (this.expression.evaluate(filterContext)) {
3538
+ yield new JSONPathNode(value, node.location.concat(key), node.root);
3539
+ }
3526
3540
  }
3527
3541
  }
3528
- return _rv;
3542
+ }
3543
+ toString(options) {
3544
+ return `?${this.expression.toString(options)}`;
3529
3545
  }
3530
3546
  }
3531
- class FilterSelector extends JSONPathSelector {
3532
- constructor(environment, token, expression) {
3533
- super(environment, token);
3547
+
3548
+ var selectors = /*#__PURE__*/Object.freeze({
3549
+ __proto__: null,
3550
+ FilterSelector: FilterSelector,
3551
+ IndexSelector: IndexSelector,
3552
+ JSONPathSelector: JSONPathSelector,
3553
+ NameSelector: NameSelector,
3554
+ SliceSelector: SliceSelector,
3555
+ WildcardSelector: WildcardSelector
3556
+ });
3557
+
3558
+ /** Base class for all JSONPath segments. Both shorthand and bracketed. */
3559
+ class JSONPathSegment {
3560
+ constructor(environment, token, selectors) {
3534
3561
  this.environment = environment;
3535
3562
  this.token = token;
3536
- this.expression = expression;
3563
+ this.selectors = selectors;
3537
3564
  }
3538
3565
 
3539
- // eslint-disable-next-line sonarjs/cognitive-complexity
3566
+ /**
3567
+ * @param nodes - Nodes matched by preceding segments.
3568
+ */
3569
+
3570
+ /**
3571
+ * @param nodes - Nodes matched by preceding segments.
3572
+ */
3573
+
3574
+ /**
3575
+ * Return a string representation of this segment.
3576
+ */
3577
+ }
3578
+
3579
+ /** The child selection segment. */
3580
+ class ChildSegment extends JSONPathSegment {
3540
3581
  resolve(nodes) {
3541
3582
  const rv = [];
3542
3583
  for (const node of nodes) {
3543
- if (node.value instanceof String) continue;
3544
- if (isArray(node.value)) {
3545
- for (let i = 0; i < node.value.length; i++) {
3546
- const value = node.value[i];
3547
- const filterContext = {
3548
- environment: this.environment,
3549
- currentValue: value,
3550
- rootValue: node.root,
3551
- currentKey: i
3552
- };
3553
- if (this.expression.evaluate(filterContext)) {
3554
- rv.push(new JSONPathNode(value, node.location.concat(i), node.root));
3555
- }
3556
- }
3557
- } else if (isObject(node.value)) {
3558
- for (const [key, value] of this.environment.entries(node.value)) {
3559
- const filterContext = {
3560
- environment: this.environment,
3561
- currentValue: value,
3562
- rootValue: node.root,
3563
- currentKey: key
3564
- };
3565
- if (this.expression.evaluate(filterContext)) {
3566
- rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
3567
- }
3568
- }
3584
+ for (const selector of this.selectors) {
3585
+ rv.push(...selector.resolve(node));
3569
3586
  }
3570
3587
  }
3571
3588
  return rv;
3572
3589
  }
3573
-
3574
- // eslint-disable-next-line sonarjs/cognitive-complexity
3575
3590
  *lazyResolve(nodes) {
3576
3591
  for (const node of nodes) {
3577
- if (node.value instanceof String) continue;
3578
- if (isArray(node.value)) {
3579
- for (let i = 0; i < node.value.length; i++) {
3580
- const value = node.value[i];
3581
- const filterContext = {
3582
- environment: this.environment,
3583
- currentValue: value,
3584
- rootValue: node.root,
3585
- lazy: true,
3586
- currentKey: i
3587
- };
3588
- if (this.expression.evaluate(filterContext)) {
3589
- yield new JSONPathNode(value, node.location.concat(i), node.root);
3590
- }
3591
- }
3592
- } else if (isObject(node.value)) {
3593
- for (const [key, value] of this.environment.entries(node.value)) {
3594
- const filterContext = {
3595
- environment: this.environment,
3596
- currentValue: value,
3597
- rootValue: node.root,
3598
- lazy: true,
3599
- currentKey: key
3600
- };
3601
- if (this.expression.evaluate(filterContext)) {
3602
- yield new JSONPathNode(value, node.location.concat(key), node.root);
3603
- }
3604
- }
3592
+ for (const selector of this.selectors) {
3593
+ yield* selector.resolve(node);
3605
3594
  }
3606
3595
  }
3607
3596
  }
3608
- toString() {
3609
- return `?${this.expression.toString()}`;
3597
+ toString(options) {
3598
+ const {
3599
+ form
3600
+ } = {
3601
+ ...defaultSerializationOptions,
3602
+ ...options
3603
+ };
3604
+ if (form === "pretty" && this.selectors.length === 1 && this.selectors[0] instanceof NameSelector) {
3605
+ const shorthand = this.selectors[0].shorthand();
3606
+ if (shorthand != null) return `.${shorthand}`;
3607
+ }
3608
+ return `[${this.selectors.map(s => s.toString(options)).join(", ")}]`;
3610
3609
  }
3611
3610
  }
3612
- class BracketedSelection extends JSONPathSelector {
3613
- constructor(environment, token, items) {
3614
- super(environment, token);
3615
- this.environment = environment;
3616
- this.token = token;
3617
- this.items = items;
3618
- }
3611
+
3612
+ /** The recursive descent segment. */
3613
+ class DescendantSegment extends JSONPathSegment {
3619
3614
  resolve(nodes) {
3620
3615
  const rv = [];
3616
+ const visitor = (this.environment.nondeterministic ? this.nondeterministicVisit : this.visit).bind(this);
3621
3617
  for (const node of nodes) {
3622
- for (const item of this.items) {
3623
- for (const _node of item.resolve([node])) {
3624
- rv.push(_node);
3618
+ for (const _node of visitor(node)) {
3619
+ for (const selector of this.selectors) {
3620
+ rv.push(...selector.resolve(_node));
3625
3621
  }
3626
3622
  }
3627
3623
  }
@@ -3629,13 +3625,75 @@ var json_p3 = (function (exports) {
3629
3625
  }
3630
3626
  *lazyResolve(nodes) {
3631
3627
  for (const node of nodes) {
3632
- for (const item of this.items) {
3633
- yield* item.lazyResolve([node]);
3628
+ for (const _node of this.visit(node)) {
3629
+ for (const selector of this.selectors) {
3630
+ yield* selector.resolve(_node);
3631
+ }
3634
3632
  }
3635
3633
  }
3636
3634
  }
3637
- toString() {
3638
- return `[${this.items.map(itm => itm.toString()).join(", ")}]`;
3635
+ toString(options) {
3636
+ return `..[${this.selectors.map(s => s.toString(options)).join(", ")}]`;
3637
+ }
3638
+ visit(node) {
3639
+ var _this = this;
3640
+ let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
3641
+ return function* () {
3642
+ if (depth >= _this.environment.maxRecursionDepth) {
3643
+ throw new JSONPathRecursionLimitError("recursion limit reached", _this.token);
3644
+ }
3645
+ yield node;
3646
+ if (isArray(node.value)) {
3647
+ for (let i = 0; i < node.value.length; i++) {
3648
+ const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
3649
+ yield* _this.visit(_node, depth + 1);
3650
+ }
3651
+ } else if (isObject(node.value)) {
3652
+ for (const [key, value] of _this.environment.entries(node.value)) {
3653
+ const _node = new JSONPathNode(value, node.location.concat(key), node.root);
3654
+ yield* _this.visit(_node, depth + 1);
3655
+ }
3656
+ }
3657
+ }();
3658
+ }
3659
+ nondeterministicVisit(root) {
3660
+ var _this2 = this;
3661
+ let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
3662
+ return function* () {
3663
+ let queue = Array.from(_this2.nondeterministicChildren(root)).map(node => [node, depth]);
3664
+ yield root;
3665
+ while (queue.length) {
3666
+ const [node, _depth] = queue.shift();
3667
+ yield node;
3668
+ if (_depth >= _this2.environment.maxRecursionDepth) {
3669
+ throw new JSONPathRecursionLimitError("recursion limit reached", _this2.token);
3670
+ }
3671
+
3672
+ // Visit child nodes now or queue them for later?
3673
+ const visitChildren = Math.random() < 0.5;
3674
+ for (const child of _this2.nondeterministicChildren(node)) {
3675
+ if (visitChildren) {
3676
+ yield child;
3677
+ const grandchildren = Array.from(_this2.nondeterministicChildren(child)).map(n => [n, _depth + 2]);
3678
+ queue = interleave(queue, grandchildren);
3679
+ } else {
3680
+ queue.push([child, _depth + 1]);
3681
+ }
3682
+ }
3683
+ }
3684
+ }();
3685
+ }
3686
+ *nondeterministicChildren(node) {
3687
+ if (isString(node.value)) return;
3688
+ if (isArray(node.value)) {
3689
+ for (let i = 0; i < node.value.length; i++) {
3690
+ yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
3691
+ }
3692
+ } else if (isObject(node.value)) {
3693
+ for (const [key, value] of this.environment.entries(node.value)) {
3694
+ yield new JSONPathNode(value, node.location.concat(key), node.root);
3695
+ }
3696
+ }
3639
3697
  }
3640
3698
  }
3641
3699
 
@@ -3674,54 +3732,37 @@ var json_p3 = (function (exports) {
3674
3732
  return entries;
3675
3733
  }
3676
3734
 
3677
- var selectors = /*#__PURE__*/Object.freeze({
3678
- __proto__: null,
3679
- BracketedSelection: BracketedSelection,
3680
- FilterSelector: FilterSelector,
3681
- IndexSelector: IndexSelector,
3682
- JSONPathSelector: JSONPathSelector,
3683
- NameSelector: NameSelector,
3684
- RecursiveDescentSegment: RecursiveDescentSegment,
3685
- SliceSelector: SliceSelector,
3686
- WildcardSelector: WildcardSelector
3687
- });
3688
-
3689
3735
  /**
3690
- *
3736
+ * A compiled JSONPath query ready to be applied to different data repeatedly.
3691
3737
  */
3692
- class JSONPath {
3693
- /**
3694
- *
3695
- * @param environment -
3696
- * @param selectors -
3697
- */
3698
- constructor(environment, selectors) {
3738
+ class JSONPathQuery {
3739
+ constructor(environment, segments) {
3699
3740
  this.environment = environment;
3700
- this.selectors = selectors;
3741
+ this.segments = segments;
3701
3742
  }
3702
3743
 
3703
3744
  /**
3704
- *
3705
- * @param value -
3706
- * @returns
3745
+ * Apply this JSONPath query to _value_.
3746
+ * @param value - A JSON-like object to apply this query to.
3747
+ * @returns Nodes matched by applying this query to _value_.
3707
3748
  */
3708
3749
  query(value) {
3709
3750
  let nodes = [new JSONPathNode(value, [], value)];
3710
- for (const selector of this.selectors) {
3711
- nodes = selector.resolve(nodes);
3751
+ for (const segment of this.segments) {
3752
+ nodes = segment.resolve(nodes);
3712
3753
  }
3713
3754
  return new JSONPathNodeList(nodes);
3714
3755
  }
3715
3756
 
3716
3757
  /**
3717
- *
3718
- * @param value -
3719
- * @returns
3758
+ * Apply this JSONPath query to _value_.
3759
+ * @param value - A JSON-like object to apply this query to.
3760
+ * @returns An iterator over nodes matched by applying this query to _value_.
3720
3761
  */
3721
3762
  lazyQuery(value) {
3722
3763
  let nodes = [new JSONPathNode(value, [], value)][Symbol.iterator]();
3723
- for (const selector of this.selectors) {
3724
- nodes = selector.lazyResolve(nodes);
3764
+ for (const segment of this.segments) {
3765
+ nodes = segment.lazyResolve(nodes);
3725
3766
  }
3726
3767
  return nodes;
3727
3768
  }
@@ -3742,15 +3783,21 @@ var json_p3 = (function (exports) {
3742
3783
  }
3743
3784
 
3744
3785
  /**
3745
- *
3786
+ * Return a string representation of this query.
3746
3787
  */
3747
- toString() {
3748
- return `$${this.selectors.map(s => s.toString()).join("")}`;
3788
+ toString(options) {
3789
+ return `$${this.segments.map(s => s.toString(options)).join("")}`;
3749
3790
  }
3791
+
3792
+ /**
3793
+ * Return `true` if this query is a _singular query_, or `false` otherwise.
3794
+ */
3750
3795
  singularQuery() {
3751
- for (const selector of this.selectors) {
3752
- if (selector instanceof NameSelector) continue;
3753
- if (selector instanceof BracketedSelection && selector.items.length === 1 && (selector.items[0] instanceof NameSelector || selector.items[0] instanceof IndexSelector)) continue;
3796
+ for (const segment of this.segments) {
3797
+ if (segment instanceof DescendantSegment) return false;
3798
+ if (segment.selectors.length === 1 && (segment.selectors[0] instanceof NameSelector || segment.selectors[0] instanceof IndexSelector)) {
3799
+ continue;
3800
+ }
3754
3801
  return false;
3755
3802
  }
3756
3803
  return true;
@@ -3768,33 +3815,33 @@ var json_p3 = (function (exports) {
3768
3815
 
3769
3816
  class KeySelector extends JSONPathSelector {
3770
3817
  constructor(environment, token, key) {
3771
- let shorthand = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
3772
3818
  super(environment, token);
3773
3819
  this.environment = environment;
3774
3820
  this.token = token;
3775
3821
  this.key = key;
3776
- this.shorthand = shorthand;
3777
3822
  }
3778
- resolve(nodes) {
3823
+ resolve(node) {
3779
3824
  const rv = [];
3780
- for (const node of nodes) {
3781
- if (node.value instanceof String || isArray(node.value)) continue;
3782
- if (isObject(node.value) && hasStringKey(node.value, this.key)) {
3783
- rv.push(new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root));
3784
- }
3825
+ if (node.value instanceof String || isArray(node.value)) return rv;
3826
+ if (isObject(node.value) && hasStringKey(node.value, this.key)) {
3827
+ rv.push(new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root));
3785
3828
  }
3786
3829
  return rv;
3787
3830
  }
3788
- *lazyResolve(nodes) {
3789
- for (const node of nodes) {
3790
- if (node.value instanceof String || isArray(node.value)) continue;
3791
- if (isObject(node.value) && hasStringKey(node.value, this.key)) {
3792
- yield new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root);
3793
- }
3831
+ *lazyResolve(node) {
3832
+ if (!isString(node.value) && isObject(node.value) && hasStringKey(node.value, this.key)) {
3833
+ yield new JSONPathNode(this.key, node.location.concat(`${KEY_MARK}${this.key}`), node.root);
3794
3834
  }
3795
3835
  }
3796
- toString() {
3797
- return this.shorthand ? `[~'${this.key.replaceAll("'", "\\'")}']` : `~'${this.key.replaceAll("'", "\\'")}'`;
3836
+ toString(options) {
3837
+ const {
3838
+ form
3839
+ } = {
3840
+ ...defaultSerializationOptions,
3841
+ ...options
3842
+ };
3843
+ const serialize = form === "canonical" ? toCanonical : toQuoted;
3844
+ return `~${serialize(this.key)}`;
3798
3845
  }
3799
3846
  }
3800
3847
 
@@ -3803,36 +3850,29 @@ var json_p3 = (function (exports) {
3803
3850
  */
3804
3851
  class KeysSelector extends JSONPathSelector {
3805
3852
  constructor(environment, token) {
3806
- let shorthand = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3807
3853
  super(environment, token);
3808
3854
  this.environment = environment;
3809
3855
  this.token = token;
3810
- this.shorthand = shorthand;
3811
3856
  }
3812
- resolve(nodes) {
3857
+ resolve(node) {
3813
3858
  const rv = [];
3814
- for (const node of nodes) {
3815
- if (node.value instanceof String || isArray(node.value)) continue;
3816
- if (isObject(node.value)) {
3817
- for (const [key, _] of this.environment.entries(node.value)) {
3818
- rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
3819
- }
3859
+ if (node.value instanceof String || isArray(node.value)) return rv;
3860
+ if (isObject(node.value)) {
3861
+ for (const [key, _] of this.environment.entries(node.value)) {
3862
+ rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
3820
3863
  }
3821
3864
  }
3822
3865
  return rv;
3823
3866
  }
3824
- *lazyResolve(nodes) {
3825
- for (const node of nodes) {
3826
- if (node.value instanceof String || isArray(node.value)) continue;
3827
- if (isObject(node.value)) {
3828
- for (const [key, _] of this.environment.entries(node.value)) {
3829
- yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
3830
- }
3867
+ *lazyResolve(node) {
3868
+ if (isObject(node.value) && !isString(node.value) && !isArray(node.value)) {
3869
+ for (const [key, _] of this.environment.entries(node.value)) {
3870
+ yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
3831
3871
  }
3832
3872
  }
3833
3873
  }
3834
3874
  toString() {
3835
- return this.shorthand ? "[~]" : "~";
3875
+ return "~";
3836
3876
  }
3837
3877
  }
3838
3878
  class KeysFilterSelector extends JSONPathSelector {
@@ -3842,47 +3882,43 @@ var json_p3 = (function (exports) {
3842
3882
  this.token = token;
3843
3883
  this.expression = expression;
3844
3884
  }
3845
- resolve(nodes) {
3885
+ resolve(node) {
3846
3886
  const rv = [];
3847
- for (const node of nodes) {
3848
- if (node.value instanceof String || isArray(node.value)) continue;
3849
- if (isObject(node.value)) {
3850
- for (const [key, value] of this.environment.entries(node.value)) {
3851
- const filterContext = {
3852
- environment: this.environment,
3853
- currentValue: value,
3854
- rootValue: node.root,
3855
- currentKey: key
3856
- };
3857
- if (this.expression.evaluate(filterContext)) {
3858
- rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
3859
- }
3887
+ if (node.value instanceof String || isArray(node.value)) return rv;
3888
+ if (isObject(node.value)) {
3889
+ for (const [key, value] of this.environment.entries(node.value)) {
3890
+ const filterContext = {
3891
+ environment: this.environment,
3892
+ currentValue: value,
3893
+ rootValue: node.root,
3894
+ currentKey: key
3895
+ };
3896
+ if (this.expression.evaluate(filterContext)) {
3897
+ rv.push(new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root));
3860
3898
  }
3861
3899
  }
3862
3900
  }
3863
3901
  return rv;
3864
3902
  }
3865
- *lazyResolve(nodes) {
3866
- for (const node of nodes) {
3867
- if (node.value instanceof String || isArray(node.value)) continue;
3868
- if (isObject(node.value)) {
3869
- for (const [key, value] of this.environment.entries(node.value)) {
3870
- const filterContext = {
3871
- environment: this.environment,
3872
- currentValue: value,
3873
- rootValue: node.root,
3874
- lazy: true,
3875
- currentKey: key
3876
- };
3877
- if (this.expression.evaluate(filterContext)) {
3878
- yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
3879
- }
3903
+ *lazyResolve(node) {
3904
+ if (node.value instanceof String || isArray(node.value)) return;
3905
+ if (isObject(node.value)) {
3906
+ for (const [key, value] of this.environment.entries(node.value)) {
3907
+ const filterContext = {
3908
+ environment: this.environment,
3909
+ currentValue: value,
3910
+ rootValue: node.root,
3911
+ lazy: true,
3912
+ currentKey: key
3913
+ };
3914
+ if (this.expression.evaluate(filterContext)) {
3915
+ yield new JSONPathNode(key, node.location.concat(`${KEY_MARK}${key}`), node.root);
3880
3916
  }
3881
3917
  }
3882
3918
  }
3883
3919
  }
3884
- toString() {
3885
- return `~?${this.expression.toString()}`;
3920
+ toString(options) {
3921
+ return `~?${this.expression.toString(options)}`;
3886
3922
  }
3887
3923
  }
3888
3924
 
@@ -3905,52 +3941,59 @@ var json_p3 = (function (exports) {
3905
3941
  }
3906
3942
  parse(stream) {
3907
3943
  if (stream.current.kind === TokenKind.ROOT) stream.next();
3908
- const selectors = this.parsePath(stream);
3944
+ const segments = this.parseQuery(stream);
3909
3945
  if (stream.current.kind !== TokenKind.EOF) {
3910
3946
  throw new JSONPathSyntaxError(`unexpected token '${stream.current.kind}'`, stream.current);
3911
3947
  }
3912
- return selectors;
3948
+ return segments;
3913
3949
  }
3914
- parsePath(stream) {
3950
+ parseQuery(stream) {
3915
3951
  let inFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3916
- const selectors = [];
3917
- for (;;) {
3918
- const selector = this.parseSegment(stream);
3919
- if (!selector) {
3920
- if (inFilter) {
3921
- stream.backup();
3922
- }
3923
- break;
3952
+ const segments = [];
3953
+ loop: for (;;) {
3954
+ switch (stream.current.kind) {
3955
+ case TokenKind.DDOT:
3956
+ {
3957
+ const token = stream.next();
3958
+ const selectors = this.parseSelectors(stream);
3959
+ segments.push(new DescendantSegment(this.environment, token, selectors));
3960
+ break;
3961
+ }
3962
+ case TokenKind.LBRACKET:
3963
+ case TokenKind.KEY:
3964
+ case TokenKind.KEYS:
3965
+ case TokenKind.NAME:
3966
+ case TokenKind.WILD:
3967
+ {
3968
+ const token = stream.current;
3969
+ const selectors = this.parseSelectors(stream);
3970
+ segments.push(new ChildSegment(this.environment, token, selectors));
3971
+ break;
3972
+ }
3973
+ default:
3974
+ {
3975
+ if (inFilter) stream.backup();
3976
+ break loop;
3977
+ }
3924
3978
  }
3925
- selectors.push(selector);
3926
3979
  stream.next();
3927
3980
  }
3928
- return selectors;
3981
+ return segments;
3929
3982
  }
3930
- parseSegment(stream) {
3983
+ parseSelectors(stream) {
3931
3984
  switch (stream.current.kind) {
3932
3985
  case TokenKind.NAME:
3933
- return new NameSelector(this.environment, stream.current, stream.current.value, true);
3986
+ return [new NameSelector(this.environment, stream.current, stream.current.value)];
3934
3987
  case TokenKind.WILD:
3935
- return new WildcardSelector(this.environment, stream.current, true);
3988
+ return [new WildcardSelector(this.environment, stream.current)];
3936
3989
  case TokenKind.KEY:
3937
- return new KeySelector(this.environment, stream.current, stream.current.value, true);
3990
+ return [new KeySelector(this.environment, stream.current, stream.current.value)];
3938
3991
  case TokenKind.KEYS:
3939
- return new KeysSelector(this.environment, stream.current, true);
3940
- case TokenKind.DDOT:
3941
- {
3942
- const segmentToken = stream.current;
3943
- stream.next();
3944
- const selector = this.parseSegment(stream);
3945
- if (!selector) {
3946
- throw new JSONPathSyntaxError("bald descendant segment", stream.current);
3947
- }
3948
- return new RecursiveDescentSegment(this.environment, segmentToken, selector);
3949
- }
3992
+ return [new KeysSelector(this.environment, stream.current)];
3950
3993
  case TokenKind.LBRACKET:
3951
3994
  return this.parseBracketedSelection(stream);
3952
3995
  default:
3953
- return null;
3996
+ return [];
3954
3997
  }
3955
3998
  }
3956
3999
  parseIndex(stream) {
@@ -4007,38 +4050,38 @@ var json_p3 = (function (exports) {
4007
4050
  }
4008
4051
  parseBracketedSelection(stream) {
4009
4052
  const token = stream.next();
4010
- const items = [];
4053
+ const selectors = [];
4011
4054
  while (stream.current.kind !== TokenKind.RBRACKET) {
4012
4055
  switch (stream.current.kind) {
4013
4056
  case TokenKind.SINGLE_QUOTE_STRING:
4014
4057
  case TokenKind.DOUBLE_QUOTE_STRING:
4015
- items.push(new NameSelector(this.environment, stream.current, this.decodeString(stream.current), false));
4058
+ selectors.push(new NameSelector(this.environment, stream.current, this.decodeString(stream.current)));
4016
4059
  break;
4017
4060
  case TokenKind.FILTER:
4018
- items.push(this.parseFilter(stream));
4061
+ selectors.push(this.parseFilter(stream));
4019
4062
  break;
4020
4063
  case TokenKind.INDEX:
4021
4064
  if (stream.peek.kind === TokenKind.COLON) {
4022
- items.push(this.parseSlice(stream));
4065
+ selectors.push(this.parseSlice(stream));
4023
4066
  } else {
4024
- items.push(this.parseIndex(stream));
4067
+ selectors.push(this.parseIndex(stream));
4025
4068
  }
4026
4069
  break;
4027
4070
  case TokenKind.COLON:
4028
- items.push(this.parseSlice(stream));
4071
+ selectors.push(this.parseSlice(stream));
4029
4072
  break;
4030
4073
  case TokenKind.WILD:
4031
- items.push(new WildcardSelector(this.environment, stream.current));
4074
+ selectors.push(new WildcardSelector(this.environment, stream.current));
4032
4075
  break;
4033
4076
  case TokenKind.KEY_SINGLE_QUOTE_STRING:
4034
4077
  case TokenKind.KEY_DOUBLE_QUOTE_STRING:
4035
- items.push(new KeySelector(this.environment, stream.current, this.decodeString(stream.current), false));
4078
+ selectors.push(new KeySelector(this.environment, stream.current, this.decodeString(stream.current)));
4036
4079
  break;
4037
4080
  case TokenKind.KEYS_FILTER:
4038
- items.push(this.parseFilter(stream, true));
4081
+ selectors.push(this.parseFilter(stream, true));
4039
4082
  break;
4040
4083
  case TokenKind.KEYS:
4041
- items.push(new KeysSelector(this.environment, stream.current));
4084
+ selectors.push(new KeysSelector(this.environment, stream.current));
4042
4085
  break;
4043
4086
  case TokenKind.EOF:
4044
4087
  throw new JSONPathSyntaxError("unexpected end of query", stream.current);
@@ -4052,10 +4095,10 @@ var json_p3 = (function (exports) {
4052
4095
  }
4053
4096
  stream.next();
4054
4097
  }
4055
- if (!items.length) {
4098
+ if (!selectors.length) {
4056
4099
  throw new JSONPathSyntaxError("empty bracketed segment", token);
4057
4100
  }
4058
- return new BracketedSelection(this.environment, token, items);
4101
+ return selectors;
4059
4102
  }
4060
4103
  parseFilter(stream) {
4061
4104
  let keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
@@ -4135,11 +4178,11 @@ var json_p3 = (function (exports) {
4135
4178
  }
4136
4179
  parseRootQuery(stream) {
4137
4180
  const tok = stream.next();
4138
- return new RootQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
4181
+ return new RootQuery(tok, new JSONPathQuery(this.environment, this.parseQuery(stream, true)));
4139
4182
  }
4140
4183
  parseRelativeQuery(stream) {
4141
4184
  const tok = stream.next();
4142
- return new RelativeQuery(tok, new JSONPath(this.environment, this.parsePath(stream, true)));
4185
+ return new RelativeQuery(tok, new JSONPathQuery(this.environment, this.parseQuery(stream, true)));
4143
4186
  }
4144
4187
  parseCurrentKey(stream) {
4145
4188
  return new CurrentKey(stream.current);
@@ -4441,10 +4484,10 @@ var json_p3 = (function (exports) {
4441
4484
 
4442
4485
  /**
4443
4486
  * @param path - A JSONPath query to parse.
4444
- * @returns A new {@link JSONPath} object, bound to this environment.
4487
+ * @returns A new {@link JSONPathQuery} object, bound to this environment.
4445
4488
  */
4446
4489
  compile(path) {
4447
- return new JSONPath(this, this.parser.parse(new TokenStream(tokenize(this, path))));
4490
+ return new JSONPathQuery(this, this.parser.parse(new TokenStream(tokenize(this, path))));
4448
4491
  }
4449
4492
 
4450
4493
  /**
@@ -4499,7 +4542,7 @@ var json_p3 = (function (exports) {
4499
4542
  /**
4500
4543
  * Check the well-typedness of a function's arguments at compile-time.
4501
4544
  *
4502
- * This method is called by the {@link Parser} when parsing function calls.
4545
+ * This method is called by the parser when parsing function calls.
4503
4546
  * It is expected to throw a {@link JSONPathTypeError} if the function's
4504
4547
  * parameters are not well-typed.
4505
4548
  *
@@ -4526,17 +4569,17 @@ var json_p3 = (function (exports) {
4526
4569
  for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
4527
4570
  switch (typ) {
4528
4571
  case FunctionExpressionType.ValueType:
4529
- if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
4572
+ if (!(arg instanceof FilterExpressionLiteral || arg instanceof CurrentKey || arg instanceof FilterQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
4530
4573
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
4531
4574
  }
4532
4575
  break;
4533
4576
  case FunctionExpressionType.LogicalType:
4534
- if (!(arg instanceof JSONPathQuery || arg instanceof InfixExpression)) {
4577
+ if (!(arg instanceof FilterQuery || arg instanceof InfixExpression)) {
4535
4578
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of LogicalType`, arg.token);
4536
4579
  }
4537
4580
  break;
4538
4581
  case FunctionExpressionType.NodesType:
4539
- if (!(arg instanceof JSONPathQuery || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.NodesType)) {
4582
+ if (!(arg instanceof FilterQuery || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.NodesType)) {
4540
4583
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of NodesType`, arg.token);
4541
4584
  }
4542
4585
  }
@@ -4652,14 +4695,16 @@ var json_p3 = (function (exports) {
4652
4695
  __proto__: null,
4653
4696
  DEFAULT_ENVIRONMENT: DEFAULT_ENVIRONMENT,
4654
4697
  FunctionExpressionType: FunctionExpressionType,
4655
- JSONPath: JSONPath,
4656
4698
  JSONPathEnvironment: JSONPathEnvironment,
4657
4699
  JSONPathError: JSONPathError,
4658
4700
  JSONPathIndexError: JSONPathIndexError,
4659
4701
  JSONPathLexerError: JSONPathLexerError,
4660
4702
  JSONPathNode: JSONPathNode,
4661
4703
  JSONPathNodeList: JSONPathNodeList,
4704
+ JSONPathQuery: JSONPathQuery,
4662
4705
  JSONPathRecursionLimitError: JSONPathRecursionLimitError,
4706
+ JSONPathSegment: JSONPathSegment,
4707
+ JSONPathSelector: JSONPathSelector,
4663
4708
  JSONPathSyntaxError: JSONPathSyntaxError,
4664
4709
  JSONPathTypeError: JSONPathTypeError,
4665
4710
  KEY_MARK: KEY_MARK,
@@ -5163,20 +5208,20 @@ var json_p3 = (function (exports) {
5163
5208
  apply: apply
5164
5209
  });
5165
5210
 
5166
- const version = "1.3.5";
5211
+ const version = "2.1.0";
5167
5212
 
5168
5213
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
5169
5214
  exports.FunctionExpressionType = FunctionExpressionType;
5170
5215
  exports.JSONPatch = JSONPatch;
5171
5216
  exports.JSONPatchError = JSONPatchError;
5172
5217
  exports.JSONPatchTestFailure = JSONPatchTestFailure;
5173
- exports.JSONPath = JSONPath;
5174
5218
  exports.JSONPathEnvironment = JSONPathEnvironment;
5175
5219
  exports.JSONPathError = JSONPathError;
5176
5220
  exports.JSONPathIndexError = JSONPathIndexError;
5177
5221
  exports.JSONPathLexerError = JSONPathLexerError;
5178
5222
  exports.JSONPathNode = JSONPathNode;
5179
5223
  exports.JSONPathNodeList = JSONPathNodeList;
5224
+ exports.JSONPathQuery = JSONPathQuery;
5180
5225
  exports.JSONPathRecursionLimitError = JSONPathRecursionLimitError;
5181
5226
  exports.JSONPathSyntaxError = JSONPathSyntaxError;
5182
5227
  exports.JSONPathTypeError = JSONPathTypeError;