json-p3 0.3.1 → 1.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.
package/LICENCE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 James Prior
3
+ Copyright (c) 2024 James Prior
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  <p align="center">
4
4
  JSONPath, JSON Patch and JSON Pointer for JavaScript.
5
+ <br>
6
+ We follow <a href="https://datatracker.ietf.org/doc/html/rfc9535">RFC 9535</a> and test against the <a href="https://github.com/jsonpath-standard/jsonpath-compliance-test-suite">JSONPath Compliance Test Suite</a>.
5
7
  </p>
6
8
 
7
9
  <p align="center">
@@ -59,6 +61,15 @@ JSON P3 has zero runtime dependencies.
59
61
  | `json-p3-iife.js` | A bundle formatted as an Immediately Invoked Function Expression. |
60
62
  | `json-p3-iife.min.js` | A minified bundle formatted as an Immediately Invoked Function Expression. |
61
63
 
64
+ ## Compliance Environment Variables
65
+
66
+ These environment variables control the location of the compliance test suite under test and if nondeterministic object iteration is enabled for those tests.
67
+
68
+ | Environment Variable | Description |
69
+ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------- |
70
+ | `JSONP3_CTS_PATH` | The path to `cts.json` used by `compliance.test.ts`. Defaults to `tests/path/cts/cts.json`. |
71
+ | `JSONP3_CTS_NONDETERMINISTIC` | When set to `true`, enables nondeterministic iteration of JSON objects for `compliance.test.ts`. Defaults to `false`. |
72
+
62
73
  ## Contributing
63
74
 
64
75
  Please see [Contributing to JSON P3](https://github.com/jg-rp/json-p3/blob/main/CONTRIBUTING.md)
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 0.3.1
2
+ * json-p3 version 1.1.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2023 James Prior
7
+ * Copyright (c) 2024 James Prior
8
8
  *
9
9
  * Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  * of this software and associated documentation files (the "Software"), to deal
@@ -222,7 +222,7 @@ function deepEquals(a, b) {
222
222
 
223
223
  /**
224
224
  * The type of a JSONPath filter function parameter or return value, as
225
- * described in See section 2.4.1 of draft-ietf-jsonpath-base-20.
225
+ * described in See section 2.4.1 of RFC 9535.
226
226
  */
227
227
  let FunctionExpressionType = /*#__PURE__*/function (FunctionExpressionType) {
228
228
  FunctionExpressionType["ValueType"] = "ValueType";
@@ -508,7 +508,7 @@ const RE_INT = /(0|[1-9][0-9]*)/;
508
508
  /**
509
509
  * A relative JSON Pointer.
510
510
  *
511
- * See https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html
511
+ * See https://datatracker.ietf.org/doc/html/draft-hha-relative-json-pointer
512
512
  */
513
513
  class RelativeJSONPointer {
514
514
  /**
@@ -1927,7 +1927,7 @@ class WildcardSelector extends JSONPathSelector {
1927
1927
  rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
1928
1928
  }
1929
1929
  } else if (isObject(node.value)) {
1930
- for (const [key, value] of Object.entries(node.value)) {
1930
+ for (const [key, value] of this.environment.entries(node.value)) {
1931
1931
  rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
1932
1932
  }
1933
1933
  }
@@ -1942,7 +1942,7 @@ class WildcardSelector extends JSONPathSelector {
1942
1942
  yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
1943
1943
  }
1944
1944
  } else if (isObject(node.value)) {
1945
- for (const [key, value] of Object.entries(node.value)) {
1945
+ for (const [key, value] of this.environment.entries(node.value)) {
1946
1946
  yield new JSONPathNode(value, node.location.concat(key), node.root);
1947
1947
  }
1948
1948
  }
@@ -2002,7 +2002,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
2002
2002
  }
2003
2003
  }
2004
2004
  } else if (isObject(currentNode.value)) {
2005
- for (const [key, value] of Object.entries(currentNode.value)) {
2005
+ for (const [key, value] of this.environment.entries(currentNode.value)) {
2006
2006
  const __node = new JSONPathNode(value, currentNode.location.concat(key), currentNode.root);
2007
2007
  yield __node;
2008
2008
  if (isObject(__node.value)) {
@@ -2035,7 +2035,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
2035
2035
  }
2036
2036
  }
2037
2037
  } else if (isObject(node.value)) {
2038
- for (const [key, value] of Object.entries(node.value)) {
2038
+ for (const [key, value] of this.environment.entries(node.value)) {
2039
2039
  const _node = new JSONPathNode(value, node.location.concat(key), node.root);
2040
2040
  rv.push(_node);
2041
2041
  for (const __node of this.visit(_node, depth + 1)) {
@@ -2072,7 +2072,7 @@ class FilterSelector extends JSONPathSelector {
2072
2072
  }
2073
2073
  }
2074
2074
  } else if (isObject(node.value)) {
2075
- for (const [key, value] of Object.entries(node.value)) {
2075
+ for (const [key, value] of this.environment.entries(node.value)) {
2076
2076
  const filterContext = {
2077
2077
  environment: this.environment,
2078
2078
  currentValue: value,
@@ -2105,7 +2105,7 @@ class FilterSelector extends JSONPathSelector {
2105
2105
  }
2106
2106
  }
2107
2107
  } else if (isObject(node.value)) {
2108
- for (const [key, value] of Object.entries(node.value)) {
2108
+ for (const [key, value] of this.environment.entries(node.value)) {
2109
2109
  const filterContext = {
2110
2110
  environment: this.environment,
2111
2111
  currentValue: value,
@@ -2237,8 +2237,8 @@ class JSONPath {
2237
2237
  }
2238
2238
 
2239
2239
  const PRECEDENCE_LOWEST = 1;
2240
- const PRECEDENCE_LOGICAL_AND = 4;
2241
- const PRECEDENCE_LOGICAL_OR = 5;
2240
+ const PRECEDENCE_LOGICAL_OR = 4;
2241
+ const PRECEDENCE_LOGICAL_AND = 5;
2242
2242
  const PRECEDENCE_COMPARISON = 6;
2243
2243
  const PRECEDENCE_PREFIX = 7;
2244
2244
  const PRECEDENCES = new Map([[TokenKind.AND, PRECEDENCE_LOGICAL_AND], [TokenKind.EQ, PRECEDENCE_COMPARISON], [TokenKind.GE, PRECEDENCE_COMPARISON], [TokenKind.GT, PRECEDENCE_COMPARISON], [TokenKind.LE, PRECEDENCE_COMPARISON], [TokenKind.LT, PRECEDENCE_COMPARISON], [TokenKind.NE, PRECEDENCE_COMPARISON], [TokenKind.NOT, PRECEDENCE_PREFIX], [TokenKind.OR, PRECEDENCE_LOGICAL_OR], [TokenKind.RPAREN, PRECEDENCE_LOWEST]]);
@@ -2568,6 +2568,10 @@ class JSONPathEnvironment {
2568
2568
  * can visit before a `JSONPathRecursionLimitError` is thrown.
2569
2569
  */
2570
2570
 
2571
+ /**
2572
+ * If `true`, enable nondeterministic ordering when iterating JSON object data.
2573
+ */
2574
+
2571
2575
  /**
2572
2576
  * A map of function names to objects implementing the {@link FilterFunction}
2573
2577
  * interface. You are free to set or delete custom filter functions directly.
@@ -2582,6 +2586,7 @@ class JSONPathEnvironment {
2582
2586
  this.maxIntIndex = options.maxIntIndex ?? Math.pow(2, 53) - 1;
2583
2587
  this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
2584
2588
  this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
2589
+ this.nondeterministic = options.nondeterministic ?? false;
2585
2590
  this.parser = new Parser(this);
2586
2591
  this.setupFilterFunctions();
2587
2592
  }
@@ -2690,6 +2695,29 @@ class JSONPathEnvironment {
2690
2695
  }
2691
2696
  return args;
2692
2697
  }
2698
+
2699
+ /**
2700
+ * Return an array of key/values of the enumerable properties in _obj_.
2701
+ *
2702
+ * If you want to introduce some nondeterminism to iterating JSON-like
2703
+ * objects, do it here. The wildcard selector, descendent segment and
2704
+ * filter selector all use `this.environment.entries`.
2705
+ *
2706
+ * @param obj - A JSON-like object.
2707
+ */
2708
+ entries(obj) {
2709
+ function shuffle(entries) {
2710
+ for (let i = entries.length - 1; i > 0; i--) {
2711
+ const j = Math.floor(Math.random() * (i + 1));
2712
+ [entries[i], entries[j]] = [entries[j], entries[i]];
2713
+ }
2714
+ return entries;
2715
+ }
2716
+ if (this.nondeterministic) {
2717
+ return shuffle(Object.entries(obj));
2718
+ }
2719
+ return Object.entries(obj);
2720
+ }
2693
2721
  }
2694
2722
 
2695
2723
  var index$2 = /*#__PURE__*/Object.freeze({
@@ -3278,7 +3306,7 @@ var index = /*#__PURE__*/Object.freeze({
3278
3306
  apply: apply
3279
3307
  });
3280
3308
 
3281
- const version = "0.3.1";
3309
+ const version = "1.1.0";
3282
3310
 
3283
3311
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
3284
3312
  exports.FunctionExpressionType = FunctionExpressionType;
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 0.3.1
2
+ * json-p3 version 1.1.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2023 James Prior
7
+ * Copyright (c) 2024 James Prior
8
8
  *
9
9
  * Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  * of this software and associated documentation files (the "Software"), to deal
@@ -220,7 +220,7 @@ function deepEquals(a, b) {
220
220
 
221
221
  /**
222
222
  * The type of a JSONPath filter function parameter or return value, as
223
- * described in See section 2.4.1 of draft-ietf-jsonpath-base-20.
223
+ * described in See section 2.4.1 of RFC 9535.
224
224
  */
225
225
  let FunctionExpressionType = /*#__PURE__*/function (FunctionExpressionType) {
226
226
  FunctionExpressionType["ValueType"] = "ValueType";
@@ -506,7 +506,7 @@ const RE_INT = /(0|[1-9][0-9]*)/;
506
506
  /**
507
507
  * A relative JSON Pointer.
508
508
  *
509
- * See https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html
509
+ * See https://datatracker.ietf.org/doc/html/draft-hha-relative-json-pointer
510
510
  */
511
511
  class RelativeJSONPointer {
512
512
  /**
@@ -1925,7 +1925,7 @@ class WildcardSelector extends JSONPathSelector {
1925
1925
  rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
1926
1926
  }
1927
1927
  } else if (isObject(node.value)) {
1928
- for (const [key, value] of Object.entries(node.value)) {
1928
+ for (const [key, value] of this.environment.entries(node.value)) {
1929
1929
  rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
1930
1930
  }
1931
1931
  }
@@ -1940,7 +1940,7 @@ class WildcardSelector extends JSONPathSelector {
1940
1940
  yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
1941
1941
  }
1942
1942
  } else if (isObject(node.value)) {
1943
- for (const [key, value] of Object.entries(node.value)) {
1943
+ for (const [key, value] of this.environment.entries(node.value)) {
1944
1944
  yield new JSONPathNode(value, node.location.concat(key), node.root);
1945
1945
  }
1946
1946
  }
@@ -2000,7 +2000,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
2000
2000
  }
2001
2001
  }
2002
2002
  } else if (isObject(currentNode.value)) {
2003
- for (const [key, value] of Object.entries(currentNode.value)) {
2003
+ for (const [key, value] of this.environment.entries(currentNode.value)) {
2004
2004
  const __node = new JSONPathNode(value, currentNode.location.concat(key), currentNode.root);
2005
2005
  yield __node;
2006
2006
  if (isObject(__node.value)) {
@@ -2033,7 +2033,7 @@ class RecursiveDescentSegment extends JSONPathSelector {
2033
2033
  }
2034
2034
  }
2035
2035
  } else if (isObject(node.value)) {
2036
- for (const [key, value] of Object.entries(node.value)) {
2036
+ for (const [key, value] of this.environment.entries(node.value)) {
2037
2037
  const _node = new JSONPathNode(value, node.location.concat(key), node.root);
2038
2038
  rv.push(_node);
2039
2039
  for (const __node of this.visit(_node, depth + 1)) {
@@ -2070,7 +2070,7 @@ class FilterSelector extends JSONPathSelector {
2070
2070
  }
2071
2071
  }
2072
2072
  } else if (isObject(node.value)) {
2073
- for (const [key, value] of Object.entries(node.value)) {
2073
+ for (const [key, value] of this.environment.entries(node.value)) {
2074
2074
  const filterContext = {
2075
2075
  environment: this.environment,
2076
2076
  currentValue: value,
@@ -2103,7 +2103,7 @@ class FilterSelector extends JSONPathSelector {
2103
2103
  }
2104
2104
  }
2105
2105
  } else if (isObject(node.value)) {
2106
- for (const [key, value] of Object.entries(node.value)) {
2106
+ for (const [key, value] of this.environment.entries(node.value)) {
2107
2107
  const filterContext = {
2108
2108
  environment: this.environment,
2109
2109
  currentValue: value,
@@ -2235,8 +2235,8 @@ class JSONPath {
2235
2235
  }
2236
2236
 
2237
2237
  const PRECEDENCE_LOWEST = 1;
2238
- const PRECEDENCE_LOGICAL_AND = 4;
2239
- const PRECEDENCE_LOGICAL_OR = 5;
2238
+ const PRECEDENCE_LOGICAL_OR = 4;
2239
+ const PRECEDENCE_LOGICAL_AND = 5;
2240
2240
  const PRECEDENCE_COMPARISON = 6;
2241
2241
  const PRECEDENCE_PREFIX = 7;
2242
2242
  const PRECEDENCES = new Map([[TokenKind.AND, PRECEDENCE_LOGICAL_AND], [TokenKind.EQ, PRECEDENCE_COMPARISON], [TokenKind.GE, PRECEDENCE_COMPARISON], [TokenKind.GT, PRECEDENCE_COMPARISON], [TokenKind.LE, PRECEDENCE_COMPARISON], [TokenKind.LT, PRECEDENCE_COMPARISON], [TokenKind.NE, PRECEDENCE_COMPARISON], [TokenKind.NOT, PRECEDENCE_PREFIX], [TokenKind.OR, PRECEDENCE_LOGICAL_OR], [TokenKind.RPAREN, PRECEDENCE_LOWEST]]);
@@ -2566,6 +2566,10 @@ class JSONPathEnvironment {
2566
2566
  * can visit before a `JSONPathRecursionLimitError` is thrown.
2567
2567
  */
2568
2568
 
2569
+ /**
2570
+ * If `true`, enable nondeterministic ordering when iterating JSON object data.
2571
+ */
2572
+
2569
2573
  /**
2570
2574
  * A map of function names to objects implementing the {@link FilterFunction}
2571
2575
  * interface. You are free to set or delete custom filter functions directly.
@@ -2580,6 +2584,7 @@ class JSONPathEnvironment {
2580
2584
  this.maxIntIndex = options.maxIntIndex ?? Math.pow(2, 53) - 1;
2581
2585
  this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
2582
2586
  this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
2587
+ this.nondeterministic = options.nondeterministic ?? false;
2583
2588
  this.parser = new Parser(this);
2584
2589
  this.setupFilterFunctions();
2585
2590
  }
@@ -2688,6 +2693,29 @@ class JSONPathEnvironment {
2688
2693
  }
2689
2694
  return args;
2690
2695
  }
2696
+
2697
+ /**
2698
+ * Return an array of key/values of the enumerable properties in _obj_.
2699
+ *
2700
+ * If you want to introduce some nondeterminism to iterating JSON-like
2701
+ * objects, do it here. The wildcard selector, descendent segment and
2702
+ * filter selector all use `this.environment.entries`.
2703
+ *
2704
+ * @param obj - A JSON-like object.
2705
+ */
2706
+ entries(obj) {
2707
+ function shuffle(entries) {
2708
+ for (let i = entries.length - 1; i > 0; i--) {
2709
+ const j = Math.floor(Math.random() * (i + 1));
2710
+ [entries[i], entries[j]] = [entries[j], entries[i]];
2711
+ }
2712
+ return entries;
2713
+ }
2714
+ if (this.nondeterministic) {
2715
+ return shuffle(Object.entries(obj));
2716
+ }
2717
+ return Object.entries(obj);
2718
+ }
2691
2719
  }
2692
2720
 
2693
2721
  var index$2 = /*#__PURE__*/Object.freeze({
@@ -3276,6 +3304,6 @@ var index = /*#__PURE__*/Object.freeze({
3276
3304
  apply: apply
3277
3305
  });
3278
3306
 
3279
- const version = "0.3.1";
3307
+ const version = "1.1.0";
3280
3308
 
3281
3309
  export { DEFAULT_ENVIRONMENT, FunctionExpressionType, JSONPatch, JSONPatchError, JSONPatchTestFailure, JSONPath, JSONPathEnvironment, JSONPathError, JSONPathIndexError, JSONPathLexerError, JSONPathNode, JSONPathNodeList, JSONPathRecursionLimitError, JSONPathSyntaxError, JSONPathTypeError, JSONPointer, Nothing, RelativeJSONPointer, Token, TokenKind, UNDEFINED, apply, compile, index as jsonpatch, index$1 as jsonpath, index$3 as jsonpointer, lazyQuery, query, resolve, version };
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 0.3.1
2
+ * json-p3 version 1.1.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2023 James Prior
7
+ * Copyright (c) 2024 James Prior
8
8
  *
9
9
  * Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  * of this software and associated documentation files (the "Software"), to deal
@@ -223,7 +223,7 @@ var json_p3 = (function (exports) {
223
223
 
224
224
  /**
225
225
  * The type of a JSONPath filter function parameter or return value, as
226
- * described in See section 2.4.1 of draft-ietf-jsonpath-base-20.
226
+ * described in See section 2.4.1 of RFC 9535.
227
227
  */
228
228
  let FunctionExpressionType = /*#__PURE__*/function (FunctionExpressionType) {
229
229
  FunctionExpressionType["ValueType"] = "ValueType";
@@ -509,7 +509,7 @@ var json_p3 = (function (exports) {
509
509
  /**
510
510
  * A relative JSON Pointer.
511
511
  *
512
- * See https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html
512
+ * See https://datatracker.ietf.org/doc/html/draft-hha-relative-json-pointer
513
513
  */
514
514
  class RelativeJSONPointer {
515
515
  /**
@@ -1928,7 +1928,7 @@ var json_p3 = (function (exports) {
1928
1928
  rv.push(new JSONPathNode(node.value[i], node.location.concat(i), node.root));
1929
1929
  }
1930
1930
  } else if (isObject(node.value)) {
1931
- for (const [key, value] of Object.entries(node.value)) {
1931
+ for (const [key, value] of this.environment.entries(node.value)) {
1932
1932
  rv.push(new JSONPathNode(value, node.location.concat(key), node.root));
1933
1933
  }
1934
1934
  }
@@ -1943,7 +1943,7 @@ var json_p3 = (function (exports) {
1943
1943
  yield new JSONPathNode(node.value[i], node.location.concat(i), node.root);
1944
1944
  }
1945
1945
  } else if (isObject(node.value)) {
1946
- for (const [key, value] of Object.entries(node.value)) {
1946
+ for (const [key, value] of this.environment.entries(node.value)) {
1947
1947
  yield new JSONPathNode(value, node.location.concat(key), node.root);
1948
1948
  }
1949
1949
  }
@@ -2003,7 +2003,7 @@ var json_p3 = (function (exports) {
2003
2003
  }
2004
2004
  }
2005
2005
  } else if (isObject(currentNode.value)) {
2006
- for (const [key, value] of Object.entries(currentNode.value)) {
2006
+ for (const [key, value] of this.environment.entries(currentNode.value)) {
2007
2007
  const __node = new JSONPathNode(value, currentNode.location.concat(key), currentNode.root);
2008
2008
  yield __node;
2009
2009
  if (isObject(__node.value)) {
@@ -2036,7 +2036,7 @@ var json_p3 = (function (exports) {
2036
2036
  }
2037
2037
  }
2038
2038
  } else if (isObject(node.value)) {
2039
- for (const [key, value] of Object.entries(node.value)) {
2039
+ for (const [key, value] of this.environment.entries(node.value)) {
2040
2040
  const _node = new JSONPathNode(value, node.location.concat(key), node.root);
2041
2041
  rv.push(_node);
2042
2042
  for (const __node of this.visit(_node, depth + 1)) {
@@ -2073,7 +2073,7 @@ var json_p3 = (function (exports) {
2073
2073
  }
2074
2074
  }
2075
2075
  } else if (isObject(node.value)) {
2076
- for (const [key, value] of Object.entries(node.value)) {
2076
+ for (const [key, value] of this.environment.entries(node.value)) {
2077
2077
  const filterContext = {
2078
2078
  environment: this.environment,
2079
2079
  currentValue: value,
@@ -2106,7 +2106,7 @@ var json_p3 = (function (exports) {
2106
2106
  }
2107
2107
  }
2108
2108
  } else if (isObject(node.value)) {
2109
- for (const [key, value] of Object.entries(node.value)) {
2109
+ for (const [key, value] of this.environment.entries(node.value)) {
2110
2110
  const filterContext = {
2111
2111
  environment: this.environment,
2112
2112
  currentValue: value,
@@ -2238,8 +2238,8 @@ var json_p3 = (function (exports) {
2238
2238
  }
2239
2239
 
2240
2240
  const PRECEDENCE_LOWEST = 1;
2241
- const PRECEDENCE_LOGICAL_AND = 4;
2242
- const PRECEDENCE_LOGICAL_OR = 5;
2241
+ const PRECEDENCE_LOGICAL_OR = 4;
2242
+ const PRECEDENCE_LOGICAL_AND = 5;
2243
2243
  const PRECEDENCE_COMPARISON = 6;
2244
2244
  const PRECEDENCE_PREFIX = 7;
2245
2245
  const PRECEDENCES = new Map([[TokenKind.AND, PRECEDENCE_LOGICAL_AND], [TokenKind.EQ, PRECEDENCE_COMPARISON], [TokenKind.GE, PRECEDENCE_COMPARISON], [TokenKind.GT, PRECEDENCE_COMPARISON], [TokenKind.LE, PRECEDENCE_COMPARISON], [TokenKind.LT, PRECEDENCE_COMPARISON], [TokenKind.NE, PRECEDENCE_COMPARISON], [TokenKind.NOT, PRECEDENCE_PREFIX], [TokenKind.OR, PRECEDENCE_LOGICAL_OR], [TokenKind.RPAREN, PRECEDENCE_LOWEST]]);
@@ -2569,6 +2569,10 @@ var json_p3 = (function (exports) {
2569
2569
  * can visit before a `JSONPathRecursionLimitError` is thrown.
2570
2570
  */
2571
2571
 
2572
+ /**
2573
+ * If `true`, enable nondeterministic ordering when iterating JSON object data.
2574
+ */
2575
+
2572
2576
  /**
2573
2577
  * A map of function names to objects implementing the {@link FilterFunction}
2574
2578
  * interface. You are free to set or delete custom filter functions directly.
@@ -2583,6 +2587,7 @@ var json_p3 = (function (exports) {
2583
2587
  this.maxIntIndex = options.maxIntIndex ?? Math.pow(2, 53) - 1;
2584
2588
  this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
2585
2589
  this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
2590
+ this.nondeterministic = options.nondeterministic ?? false;
2586
2591
  this.parser = new Parser(this);
2587
2592
  this.setupFilterFunctions();
2588
2593
  }
@@ -2691,6 +2696,29 @@ var json_p3 = (function (exports) {
2691
2696
  }
2692
2697
  return args;
2693
2698
  }
2699
+
2700
+ /**
2701
+ * Return an array of key/values of the enumerable properties in _obj_.
2702
+ *
2703
+ * If you want to introduce some nondeterminism to iterating JSON-like
2704
+ * objects, do it here. The wildcard selector, descendent segment and
2705
+ * filter selector all use `this.environment.entries`.
2706
+ *
2707
+ * @param obj - A JSON-like object.
2708
+ */
2709
+ entries(obj) {
2710
+ function shuffle(entries) {
2711
+ for (let i = entries.length - 1; i > 0; i--) {
2712
+ const j = Math.floor(Math.random() * (i + 1));
2713
+ [entries[i], entries[j]] = [entries[j], entries[i]];
2714
+ }
2715
+ return entries;
2716
+ }
2717
+ if (this.nondeterministic) {
2718
+ return shuffle(Object.entries(obj));
2719
+ }
2720
+ return Object.entries(obj);
2721
+ }
2694
2722
  }
2695
2723
 
2696
2724
  var index$2 = /*#__PURE__*/Object.freeze({
@@ -3279,7 +3307,7 @@ var json_p3 = (function (exports) {
3279
3307
  apply: apply
3280
3308
  });
3281
3309
 
3282
- const version = "0.3.1";
3310
+ const version = "1.1.0";
3283
3311
 
3284
3312
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
3285
3313
  exports.FunctionExpressionType = FunctionExpressionType;