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