json-p3 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * json-p3 version 0.1.1
2
+ * json-p3 version 0.2.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
@@ -124,6 +124,20 @@ class JSONPathSyntaxError extends JSONPathError {
124
124
  }
125
125
  }
126
126
 
127
+ /**
128
+ * Error thrown when the maximum recursion depth is reached.
129
+ */
130
+ class JSONPathRecursionLimitError extends JSONPathError {
131
+ constructor(message, token) {
132
+ super(message, token);
133
+ this.message = message;
134
+ this.token = token;
135
+ Object.setPrototypeOf(this, new.target.prototype);
136
+ this.name = "JSONPathRecursionLimitError";
137
+ this.message = withErrorContext(message, token);
138
+ }
139
+ }
140
+
127
141
  /**
128
142
  * Common types and type predicates.
129
143
  */
@@ -232,6 +246,10 @@ class JSONPointerError extends Error {
232
246
  this.name = "JSONPointerError";
233
247
  }
234
248
  }
249
+
250
+ /**
251
+ * Base class for JSON Pointer resolution errors.
252
+ */
235
253
  class JSONPointerResolutionError extends JSONPointerError {
236
254
  constructor(message) {
237
255
  super(message);
@@ -240,6 +258,10 @@ class JSONPointerResolutionError extends JSONPointerError {
240
258
  this.name = "JSONPointerResolutionError";
241
259
  }
242
260
  }
261
+
262
+ /**
263
+ * Error thrown due to an out of range index when resolving a JSON Pointer.
264
+ */
243
265
  class JSONPointerIndexError extends JSONPointerResolutionError {
244
266
  constructor(message) {
245
267
  super(message);
@@ -248,6 +270,10 @@ class JSONPointerIndexError extends JSONPointerResolutionError {
248
270
  this.name = "JSONPointerIndexError";
249
271
  }
250
272
  }
273
+
274
+ /**
275
+ * Error thrown due to a missing property when resolving a JSON Pointer.
276
+ */
251
277
  class JSONPointerKeyError extends JSONPointerResolutionError {
252
278
  constructor(message) {
253
279
  super(message);
@@ -256,6 +282,10 @@ class JSONPointerKeyError extends JSONPointerResolutionError {
256
282
  this.name = "JSONPointerKeyError";
257
283
  }
258
284
  }
285
+
286
+ /**
287
+ * Error thrown due to invalid JSON Pointer syntax.
288
+ */
259
289
  class JSONPointerSyntaxError extends JSONPointerError {
260
290
  constructor(message) {
261
291
  super(message);
@@ -264,6 +294,10 @@ class JSONPointerSyntaxError extends JSONPointerError {
264
294
  this.name = "JSONPointerSyntaxError";
265
295
  }
266
296
  }
297
+
298
+ /**
299
+ * Error thrown when trying to resolve a property or index against a primitive value.
300
+ */
267
301
  class JSONPointerTypeError extends JSONPointerResolutionError {
268
302
  constructor(message) {
269
303
  super(message);
@@ -323,8 +357,6 @@ class JSONPointer {
323
357
  }
324
358
  }
325
359
 
326
- // TODO: add `resolveWithFallback` to handle explicit `undefined`
327
-
328
360
  /**
329
361
  *
330
362
  * @param value -
@@ -363,6 +395,8 @@ class JSONPointer {
363
395
  }
364
396
  return pointer.split("/").map(token => token.replaceAll("~1", "/").replaceAll("~0", "~")).slice(1);
365
397
  }
398
+
399
+ // eslint-disable-next-line sonarjs/cognitive-complexity
366
400
  getItem(val, token, idx) {
367
401
  // NOTE:
368
402
  // - string primitives "have own" indices and `length`.
@@ -372,12 +406,23 @@ class JSONPointer {
372
406
  if (isArray(val)) {
373
407
  if (token !== "length" && Object.hasOwn(val, token)) {
374
408
  return val[Number(token)];
409
+ } else if (token.startsWith("#")) {
410
+ // handle non-standard '#' from relative json pointer
411
+ const maybeIndex = token.slice(1);
412
+ if (RE_INT.test(maybeIndex) && Object.hasOwn(val, maybeIndex)) {
413
+ return Number(maybeIndex);
414
+ } else {
415
+ throw new JSONPointerIndexError(`index out of range '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
416
+ }
375
417
  } else {
376
418
  throw new JSONPointerIndexError(`index out of range '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
377
419
  }
378
420
  } else if (isObject(val)) {
379
421
  if (Object.hasOwn(val, token)) {
380
422
  return val[token];
423
+ } else if (token.startsWith("#") && Object.hasOwn(val, token.slice(1))) {
424
+ // handle non-standard '#' from relative json pointer
425
+ return token.slice(1);
381
426
  } else {
382
427
  throw new JSONPointerKeyError(`no such property '${JSONPointer.encode(this.tokens.slice(0, idx + 1))}'`);
383
428
  }
@@ -452,8 +497,111 @@ class JSONPointer {
452
497
  }
453
498
  return new JSONPointer(JSONPointer.encode(this.tokens.slice(0, this.tokens.length - 1)));
454
499
  }
500
+ to(rel) {
501
+ const relativePointer = isString(rel) ? new RelativeJSONPointer(rel) : rel;
502
+ return relativePointer.to(this);
503
+ }
504
+ }
505
+ const RE_RELATIVE_POINTER = /(?<ORIGIN>\d+)(?<INDEX_G>(?<SIGN>[+-])(?<INDEX>\d))?(?<POINTER>.*)/s;
506
+ const RE_INT = /(0|[1-9][0-9]*)/;
507
+
508
+ /**
509
+ * A relative JSON Pointer.
510
+ *
511
+ * See https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html
512
+ */
513
+ class RelativeJSONPointer {
514
+ /**
515
+ *
516
+ * @param rel -
517
+ */
518
+ constructor(rel) {
519
+ [this.origin, this.index, this.pointer] = this.parse(rel);
520
+ }
521
+
522
+ /**
523
+ *
524
+ * @returns
525
+ */
526
+ toString() {
527
+ const sign = this.index > 0 ? "+" : "";
528
+ const index = this.index === 0 ? "" : `${sign}${this.index}`;
529
+ return `${this.origin}${index}${this.pointer}`;
530
+ }
531
+
532
+ /**
533
+ *
534
+ * @param pointer -
535
+ */
536
+ to(pointer) {
537
+ const p = isString(pointer) ? new JSONPointer(pointer) : pointer;
538
+
539
+ // move to origin
540
+ if (this.origin > p.tokens.length) {
541
+ throw new JSONPointerIndexError(`origin (${this.origin}) exceeds root (${p.tokens.length})`);
542
+ }
543
+ const tokens = this.origin < 1 ? p.tokens.slice() : p.tokens.slice(0, -this.origin);
544
+
545
+ // array index offset
546
+ if (this.index && tokens.length && this.isIntLike(tokens.at(-1))) {
547
+ const newIndex = Number(tokens.at(-1)) + this.index;
548
+ if (newIndex < 0) {
549
+ throw new JSONPointerIndexError(`index offset out of range (${newIndex})`);
550
+ }
551
+ tokens[tokens.length - 1] = String(newIndex);
552
+ }
553
+
554
+ // pointer or index/property
555
+ if (this.pointer instanceof JSONPointer) {
556
+ tokens.push(...this.pointer.tokens);
557
+ } else {
558
+ tokens[tokens.length - 1] = `#${tokens[tokens.length - 1]}`;
559
+ }
560
+ return new JSONPointer(JSONPointer.encode(tokens));
561
+ }
562
+ parse(rel) {
563
+ const match = RE_RELATIVE_POINTER.exec(rel);
564
+ if (!match || !match.groups) {
565
+ throw new JSONPointerSyntaxError("failed to parse relative pointer");
566
+ }
567
+
568
+ // steps to move
569
+ const origin = this.parseInt(match.groups.ORIGIN);
455
570
 
456
- // TODO: to (relative pointer)
571
+ // optional index manipulation
572
+ let index = 0;
573
+ if (match.groups["INDEX_G"]) {
574
+ index = this.parseInt(match.groups.INDEX);
575
+ if (index === 0) {
576
+ throw new JSONPointerSyntaxError("index offset can't be zero");
577
+ }
578
+ if (match.groups.SIGN === "-") {
579
+ index = -index;
580
+ }
581
+ }
582
+
583
+ // pointer or '#'. an empty string is OK.
584
+ if (match.groups.POINTER === "#") {
585
+ return [origin, index, "#"];
586
+ }
587
+ return [origin, index, new JSONPointer(match.groups.POINTER)];
588
+ }
589
+ parseInt(s) {
590
+ if (s.startsWith("0") && s.length > 1) {
591
+ throw new JSONPointerSyntaxError("unexpected leading zero");
592
+ }
593
+ if (RE_INT.test(s)) {
594
+ return Number(s);
595
+ }
596
+ throw new JSONPointerSyntaxError(`expected an integer, found '${s}'`);
597
+ }
598
+ isIntLike(value) {
599
+ if (value === undefined || isNumber(value)) {
600
+ return true;
601
+ } else {
602
+ return RE_INT.test(value);
603
+ }
604
+ }
457
605
  }
458
606
 
459
607
  /**
@@ -488,6 +636,7 @@ var index$3 = /*#__PURE__*/Object.freeze({
488
636
  JSONPointerResolutionError: JSONPointerResolutionError,
489
637
  JSONPointerSyntaxError: JSONPointerSyntaxError,
490
638
  JSONPointerTypeError: JSONPointerTypeError,
639
+ RelativeJSONPointer: RelativeJSONPointer,
491
640
  UNDEFINED: UNDEFINED,
492
641
  resolve: resolve
493
642
  });
@@ -785,7 +934,7 @@ class FunctionExtension extends FilterExpression {
785
934
  this.args = args;
786
935
  }
787
936
  evaluate(context) {
788
- const func = context.environment.filterRegister.get(this.name);
937
+ const func = context.environment.functionRegister.get(this.name);
789
938
  if (!func) {
790
939
  throw new UndefinedFilterFunctionError(`filter function '${this.name}' is undefined`, this.token);
791
940
  }
@@ -805,13 +954,6 @@ function isTruthy(value) {
805
954
  if (value instanceof JSONPathNodeList && value.empty()) return false;
806
955
  return !(typeof value === "boolean" && value === false);
807
956
  }
808
-
809
- /**
810
- *
811
- * @param left -
812
- * @param operator -
813
- * @param right -
814
- */
815
957
  function compare(left, operator, right) {
816
958
  switch (operator) {
817
959
  case "==":
@@ -865,7 +1007,8 @@ var expression = /*#__PURE__*/Object.freeze({
865
1007
  PrefixExpression: PrefixExpression,
866
1008
  RelativeQuery: RelativeQuery,
867
1009
  RootQuery: RootQuery,
868
- StringLiteral: StringLiteral
1010
+ StringLiteral: StringLiteral,
1011
+ compare: compare
869
1012
  });
870
1013
 
871
1014
  class Count {
@@ -1389,6 +1532,10 @@ function lexInsideFilter(l) {
1389
1532
  case "":
1390
1533
  case "]":
1391
1534
  l.filterLevel -= 1;
1535
+ if (l.parenStack.length === 1) {
1536
+ l.error("unbalanced parentheses");
1537
+ return null;
1538
+ }
1392
1539
  l.backup();
1393
1540
  return lexInsideBracketedSelection;
1394
1541
  case ",":
@@ -1618,7 +1765,7 @@ class IndexSelector extends JSONPathSelector {
1618
1765
  this.environment = environment;
1619
1766
  this.token = token;
1620
1767
  this.index = index;
1621
- if (index < this.environment.options.minIntIndex || index > this.environment.options.maxIntIndex) {
1768
+ if (index < this.environment.minIntIndex || index > this.environment.maxIntIndex) {
1622
1769
  throw new JSONPathIndexError("index out of range", this.token);
1623
1770
  }
1624
1771
  }
@@ -1673,15 +1820,11 @@ class SliceSelector extends JSONPathSelector {
1673
1820
  indices[_key] = arguments[_key];
1674
1821
  }
1675
1822
  for (const index of indices) {
1676
- if (index !== undefined && (index < this.environment.options.minIntIndex || index > this.environment.options.maxIntIndex)) {
1823
+ if (index !== undefined && (index < this.environment.minIntIndex || index > this.environment.maxIntIndex)) {
1677
1824
  throw new JSONPathIndexError("index out of range", this.token);
1678
1825
  }
1679
1826
  }
1680
1827
  }
1681
- normalizedIndex(length, index) {
1682
- if (index < 0 && length >= Math.abs(index)) return Math.min(length + index, length - 1);
1683
- return Math.min(index, length - 1);
1684
- }
1685
1828
 
1686
1829
  // eslint-disable-next-line sonarjs/cognitive-complexity
1687
1830
  slice(arr, start, stop, step) {
@@ -1765,17 +1908,21 @@ class RecursiveDescentSegment extends JSONPathSelector {
1765
1908
  return "..";
1766
1909
  }
1767
1910
  visit(node) {
1911
+ let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
1912
+ if (depth >= this.environment.maxRecursionDepth) {
1913
+ throw new JSONPathRecursionLimitError("recursion limit reached", this.token);
1914
+ }
1768
1915
  const rv = [];
1769
1916
  if (node.value instanceof String) return new JSONPathNodeList(rv);
1770
1917
  if (isArray(node.value)) {
1771
1918
  for (let i = 0; i < node.value.length; i++) {
1772
1919
  const _node = new JSONPathNode(node.value[i], node.location.concat(i), node.root);
1773
- rv.push(_node, ...this.visit(_node));
1920
+ rv.push(_node, ...this.visit(_node, depth + 1));
1774
1921
  }
1775
1922
  } else if (isObject(node.value)) {
1776
1923
  for (const [key, value] of Object.entries(node.value)) {
1777
1924
  const _node = new JSONPathNode(value, node.location.concat(key), node.root);
1778
- rv.push(_node, ...this.visit(_node));
1925
+ rv.push(_node, ...this.visit(_node, depth + 1));
1779
1926
  }
1780
1927
  }
1781
1928
  return new JSONPathNodeList(rv);
@@ -1885,6 +2032,18 @@ class JSONPath {
1885
2032
  return nodes;
1886
2033
  }
1887
2034
 
2035
+ /**
2036
+ * Return a {@link JSONPathNode} instance for the first object found in
2037
+ * _value_ matching this query.
2038
+ *
2039
+ * @param value - JSON-like data to which this query will be applied.
2040
+ * @returns The first node in _value_ matching this query, or `undefined` if
2041
+ * there are no matches.
2042
+ */
2043
+ match(value) {
2044
+ return this.query(value).nodes.at(0);
2045
+ }
2046
+
1888
2047
  /**
1889
2048
  *
1890
2049
  */
@@ -2046,7 +2205,7 @@ class Parser {
2046
2205
  const tok = stream.next();
2047
2206
  const expr = this.parseFilterExpression(stream);
2048
2207
  if (expr instanceof FunctionExtension) {
2049
- const func = this.environment.filterRegister.get(expr.name);
2208
+ const func = this.environment.functionRegister.get(expr.name);
2050
2209
  if (func && func.returnType === FunctionExpressionType.ValueType) {
2051
2210
  throw new JSONPathTypeError(`result of ${expr.name}() must be compared`, expr.token);
2052
2211
  }
@@ -2116,7 +2275,16 @@ class Parser {
2116
2275
  if (!func) {
2117
2276
  throw new JSONPathSyntaxError(`unexpected '${stream.current.value}'`, stream.current);
2118
2277
  }
2119
- args.push(func.bind(this)(stream));
2278
+ let expr = func.bind(this)(stream);
2279
+
2280
+ // Could be a comparison/logical expression
2281
+ let peekKind = stream.peek.kind;
2282
+ while (BINARY_OPERATORS.has(peekKind)) {
2283
+ stream.next();
2284
+ expr = this.parseInfixExpression(stream, expr);
2285
+ peekKind = stream.peek.kind;
2286
+ }
2287
+ args.push(expr);
2120
2288
  if (stream.peek.kind !== TokenKind.RPAREN) {
2121
2289
  if (stream.peek.kind === TokenKind.RBRACKET) break;
2122
2290
  stream.expectPeek(TokenKind.COMMA);
@@ -2124,6 +2292,7 @@ class Parser {
2124
2292
  }
2125
2293
  stream.next();
2126
2294
  }
2295
+ stream.expect(TokenKind.RPAREN);
2127
2296
  return new FunctionExtension(tok, tok.value, this.environment.checkWellTypedness(tok, args));
2128
2297
  }
2129
2298
  parseFilterExpression(stream) {
@@ -2168,7 +2337,7 @@ class Parser {
2168
2337
  }
2169
2338
  throwForNonComparableFunction(expr) {
2170
2339
  if (!(expr instanceof FunctionExtension)) return;
2171
- const func = this.environment.filterRegister.get(expr.name);
2340
+ const func = this.environment.functionRegister.get(expr.name);
2172
2341
  if (func && func.returnType !== FunctionExpressionType.ValueType) {
2173
2342
  throw new JSONPathTypeError(`result of ${expr.name}() is not comparable`, expr.token);
2174
2343
  }
@@ -2176,30 +2345,53 @@ class Parser {
2176
2345
  }
2177
2346
 
2178
2347
  /**
2179
- *
2348
+ * JSONPath environment options. The defaults are in compliance with JSONPath
2349
+ * standards.
2180
2350
  */
2181
2351
 
2182
- const defaultOptions = {
2183
- strict: true,
2184
- maxIntIndex: Math.pow(2, 53) - 1,
2185
- minIntIndex: -Math.pow(2, 53) - 1
2186
- };
2187
-
2188
2352
  /**
2189
2353
  *
2190
2354
  */
2191
2355
  class JSONPathEnvironment {
2192
2356
  /**
2357
+ * Indicates if the environment should to be strict about its compliance with
2358
+ * JSONPath standards.
2193
2359
  *
2360
+ * Defaults to `true`. Setting `strict` to `false` currently has no effect.
2361
+ * If/when we add non-standard features, the environment's strictness will
2362
+ * control their availability.
2194
2363
  */
2195
- filterRegister = new Map();
2364
+
2365
+ /**
2366
+ * The maximum number allowed when indexing or slicing an array. Defaults to
2367
+ * 2**53 -1.
2368
+ */
2369
+
2370
+ /**
2371
+ * The minimum number allowed when indexing or slicing an array. Defaults to
2372
+ * -(2**53) -1.
2373
+ */
2374
+
2375
+ /**
2376
+ * The maximum number of objects and/or arrays the recursive descent selector
2377
+ * can visit before a `JSONPathRecursionLimitError` is thrown.
2378
+ */
2379
+
2380
+ /**
2381
+ * A map of function names to objects implementing the {@link FilterFunction}
2382
+ * interface. You are free to set or delete custom filter functions directly.
2383
+ */
2384
+ functionRegister = new Map();
2196
2385
  /**
2197
2386
  *
2198
2387
  * @param options -
2199
2388
  */
2200
2389
  constructor() {
2201
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultOptions;
2202
- this.options = options;
2390
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2391
+ this.strict = options.strict ?? true;
2392
+ this.maxIntIndex = options.maxIntIndex ?? Math.pow(2, 53) - 1;
2393
+ this.minIntIndex = options.maxIntIndex ?? -Math.pow(2, 53) - 1;
2394
+ this.maxRecursionDepth = options.maxRecursionDepth ?? 50;
2203
2395
  this.parser = new Parser(this);
2204
2396
  this.setupFilterFunctions();
2205
2397
  }
@@ -2222,12 +2414,25 @@ class JSONPathEnvironment {
2222
2414
  query(path, value) {
2223
2415
  return this.compile(path).query(value);
2224
2416
  }
2417
+
2418
+ /**
2419
+ * Return a {@link JSONPathNode} instance for the first object found in
2420
+ * _value_ matching _path_.
2421
+ *
2422
+ * @param path - A JSONPath query.
2423
+ * @param value - JSON-like data to which the query _path_ will be applied.
2424
+ * @returns The first node in _value_ matching _path_, or `undefined` if
2425
+ * there are no matches.
2426
+ */
2427
+ match(path, value) {
2428
+ return this.compile(path).match(value);
2429
+ }
2225
2430
  setupFilterFunctions() {
2226
- this.filterRegister.set("count", new Count());
2227
- this.filterRegister.set("length", new Length());
2228
- this.filterRegister.set("search", new Search());
2229
- this.filterRegister.set("match", new Match());
2230
- this.filterRegister.set("value", new Value());
2431
+ this.functionRegister.set("count", new Count());
2432
+ this.functionRegister.set("length", new Length());
2433
+ this.functionRegister.set("search", new Search());
2434
+ this.functionRegister.set("match", new Match());
2435
+ this.functionRegister.set("value", new Value());
2231
2436
  }
2232
2437
 
2233
2438
  /**
@@ -2237,7 +2442,7 @@ class JSONPathEnvironment {
2237
2442
  */
2238
2443
  // eslint-disable-next-line sonarjs/cognitive-complexity
2239
2444
  checkWellTypedness(token, args) {
2240
- const func = this.filterRegister.get(token.value);
2445
+ const func = this.functionRegister.get(token.value);
2241
2446
  if (!func) {
2242
2447
  throw new UndefinedFilterFunctionError(`no such function '${token.value}'`, token);
2243
2448
  }
@@ -2251,17 +2456,17 @@ class JSONPathEnvironment {
2251
2456
  for (const [typ, arg, idx] of func.argTypes.map((t, i) => [t, args[i], i])) {
2252
2457
  switch (typ) {
2253
2458
  case FunctionExpressionType.ValueType:
2254
- if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery())) {
2459
+ if (!(arg instanceof FilterExpressionLiteral || arg instanceof JSONPathQuery && arg.path.singularQuery() || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.ValueType)) {
2255
2460
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of ValueType`, arg.token);
2256
2461
  }
2257
2462
  break;
2258
2463
  case FunctionExpressionType.LogicalType:
2259
- if (!(arg instanceof BooleanLiteral)) {
2464
+ if (!(arg instanceof JSONPathQuery || arg instanceof InfixExpression)) {
2260
2465
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of LogicalType`, arg.token);
2261
2466
  }
2262
2467
  break;
2263
2468
  case FunctionExpressionType.NodesType:
2264
- if (!(arg instanceof JSONPathQuery)) {
2469
+ if (!(arg instanceof JSONPathQuery || arg instanceof FunctionExtension && this.functionRegister.get(arg.name)?.returnType === FunctionExpressionType.NodesType)) {
2265
2470
  throw new JSONPathTypeError(`${token.value}() argument ${idx} must be of NodesType`, arg.token);
2266
2471
  }
2267
2472
  }
@@ -2316,6 +2521,19 @@ function compile(path) {
2316
2521
  return DEFAULT_ENVIRONMENT.compile(path);
2317
2522
  }
2318
2523
 
2524
+ /**
2525
+ * Return a {@link JSONPathNode} instance for the first object found in
2526
+ * _value_ matching _path_.
2527
+ *
2528
+ * @param path - A JSONPath query.
2529
+ * @param value - JSON-like data to which the query _path_ will be applied.
2530
+ * @returns The first node in _value_ matching _path_, or `undefined` if
2531
+ * there are no matches.
2532
+ */
2533
+ function match(path, value) {
2534
+ return DEFAULT_ENVIRONMENT.match(path, value);
2535
+ }
2536
+
2319
2537
  var index$1 = /*#__PURE__*/Object.freeze({
2320
2538
  __proto__: null,
2321
2539
  DEFAULT_ENVIRONMENT: DEFAULT_ENVIRONMENT,
@@ -2327,6 +2545,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
2327
2545
  JSONPathLexerError: JSONPathLexerError,
2328
2546
  JSONPathNode: JSONPathNode,
2329
2547
  JSONPathNodeList: JSONPathNodeList,
2548
+ JSONPathRecursionLimitError: JSONPathRecursionLimitError,
2330
2549
  JSONPathSyntaxError: JSONPathSyntaxError,
2331
2550
  JSONPathTypeError: JSONPathTypeError,
2332
2551
  Nothing: Nothing,
@@ -2335,6 +2554,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
2335
2554
  compile: compile,
2336
2555
  expressions: expression,
2337
2556
  functions: index$2,
2557
+ match: match,
2338
2558
  query: query,
2339
2559
  selectors: selectors
2340
2560
  });
@@ -2635,6 +2855,15 @@ class JSONPatch {
2635
2855
  }
2636
2856
  }
2637
2857
 
2858
+ /**
2859
+ * @returns an iterator over ops in this patch.
2860
+ */
2861
+ *[Symbol.iterator]() {
2862
+ for (const op of this.ops) {
2863
+ yield op.toObject();
2864
+ }
2865
+ }
2866
+
2638
2867
  /**
2639
2868
  *
2640
2869
  * @param path -
@@ -2810,8 +3039,9 @@ var index = /*#__PURE__*/Object.freeze({
2810
3039
  apply: apply
2811
3040
  });
2812
3041
 
2813
- const version = "0.1.1";
3042
+ const version = "0.2.0";
2814
3043
 
3044
+ exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
2815
3045
  exports.FunctionExpressionType = FunctionExpressionType;
2816
3046
  exports.JSONPatch = JSONPatch;
2817
3047
  exports.JSONPatchError = JSONPatchError;
@@ -2823,10 +3053,12 @@ exports.JSONPathIndexError = JSONPathIndexError;
2823
3053
  exports.JSONPathLexerError = JSONPathLexerError;
2824
3054
  exports.JSONPathNode = JSONPathNode;
2825
3055
  exports.JSONPathNodeList = JSONPathNodeList;
3056
+ exports.JSONPathRecursionLimitError = JSONPathRecursionLimitError;
2826
3057
  exports.JSONPathSyntaxError = JSONPathSyntaxError;
2827
3058
  exports.JSONPathTypeError = JSONPathTypeError;
2828
3059
  exports.JSONPointer = JSONPointer;
2829
3060
  exports.Nothing = Nothing;
3061
+ exports.RelativeJSONPointer = RelativeJSONPointer;
2830
3062
  exports.Token = Token;
2831
3063
  exports.TokenKind = TokenKind;
2832
3064
  exports.UNDEFINED = UNDEFINED;