json-p3 2.1.0 → 2.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.
package/LICENCE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 James Prior
3
+ Copyright (c) 2025 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
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 2.1.0
2
+ * json-p3 version 2.2.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2024 James Prior
7
+ * Copyright (c) 2025 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
@@ -1230,6 +1230,15 @@ function mapRegexp(pattern) {
1230
1230
  }
1231
1231
  return parts.join("");
1232
1232
  }
1233
+ function fullMatch(pattern) {
1234
+ const parts = [];
1235
+ const explicitCaret = pattern.startsWith("^");
1236
+ const explicitDollar = pattern.endsWith("$");
1237
+ if (!explicitCaret && !explicitDollar) parts.push("^(?:");
1238
+ parts.push(mapRegexp(pattern));
1239
+ if (!explicitCaret && !explicitDollar) parts.push(")$");
1240
+ return parts.join("");
1241
+ }
1233
1242
 
1234
1243
  /*
1235
1244
  * iregexp-check version 0.1.1
@@ -2480,7 +2489,7 @@ class Match {
2480
2489
  return false;
2481
2490
  }
2482
2491
  try {
2483
- const re = new RegExp(this.fullMatch(pattern), "u");
2492
+ const re = new RegExp(fullMatch(pattern), "u");
2484
2493
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2485
2494
  return re.test(s);
2486
2495
  } catch (error) {
@@ -2488,15 +2497,6 @@ class Match {
2488
2497
  return false;
2489
2498
  }
2490
2499
  }
2491
- fullMatch(pattern) {
2492
- const parts = [];
2493
- const explicitCaret = pattern.startsWith("^");
2494
- const explicitDollar = pattern.endsWith("$");
2495
- if (!explicitCaret && !explicitDollar) parts.push("^(?:");
2496
- parts.push(mapRegexp(pattern));
2497
- if (!explicitCaret && !explicitDollar) parts.push(")$");
2498
- return parts.join("");
2499
- }
2500
2500
  }
2501
2501
 
2502
2502
  class Search {
@@ -2990,7 +2990,6 @@ function lexInsideBracketedSelection(l) {
2990
2990
  switch (ch) {
2991
2991
  case "]":
2992
2992
  l.emit(TokenKind.RBRACKET);
2993
- if (l.filterLevel) return lexInsideFilter;
2994
2993
  return lexSegment;
2995
2994
  case "":
2996
2995
  l.error("unclosed bracketed selection");
@@ -3071,6 +3070,11 @@ function lexInsideFilter(l) {
3071
3070
  l.emit(TokenKind.CURRENT);
3072
3071
  return lexSegment;
3073
3072
  case "#":
3073
+ if (l.environment.strict) {
3074
+ l.backup();
3075
+ l.error(`unexpected filter selector token '${ch}'`);
3076
+ return null;
3077
+ }
3074
3078
  l.emit(TokenKind.CURRENT_KEY);
3075
3079
  return lexSegment;
3076
3080
  case ".":
@@ -4610,10 +4614,71 @@ class JSONPathEnvironment {
4610
4614
  }
4611
4615
  }
4612
4616
 
4617
+ /**
4618
+ * A function extension that returns `true` if the first argument is an object
4619
+ * value and it contains a property matching the second argument.
4620
+ */
4621
+ class Has {
4622
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4623
+ returnType = (() => FunctionExpressionType.LogicalType)();
4624
+ #cache;
4625
+ constructor() {
4626
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4627
+ this.options = options;
4628
+ this.cacheSize = options.cacheSize ?? 10;
4629
+ this.throwErrors = options.throwErrors ?? false;
4630
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4631
+ this.search = options.search ?? true;
4632
+ this.#cache = new LRUCache(this.cacheSize);
4633
+ }
4634
+
4635
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4636
+ call(value, pattern) {
4637
+ if (this.cacheSize > 0) {
4638
+ const re = this.#cache.get(pattern);
4639
+ if (re) {
4640
+ try {
4641
+ if (isObject(value)) {
4642
+ return Object.keys(value).some(k => !!k.match(re));
4643
+ }
4644
+ return false;
4645
+ } catch (error) {
4646
+ if (this.throwErrors) throw error;
4647
+ return false;
4648
+ }
4649
+ }
4650
+ }
4651
+ if (!isString(pattern)) {
4652
+ if (this.throwErrors) {
4653
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4654
+ }
4655
+ return false;
4656
+ }
4657
+ if (this.iRegexpCheck && !check$1(pattern)) {
4658
+ if (this.throwErrors) {
4659
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4660
+ }
4661
+ return false;
4662
+ }
4663
+ try {
4664
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4665
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4666
+ if (isObject(value)) {
4667
+ return Object.keys(value).some(k => !!k.match(re));
4668
+ }
4669
+ return false;
4670
+ } catch (error) {
4671
+ if (this.throwErrors) throw error;
4672
+ return false;
4673
+ }
4674
+ }
4675
+ }
4676
+
4613
4677
  var index$2 = /*#__PURE__*/Object.freeze({
4614
4678
  __proto__: null,
4615
4679
  Count: Count,
4616
4680
  FunctionExpressionType: FunctionExpressionType,
4681
+ Has: Has,
4617
4682
  Length: Length,
4618
4683
  Match: Match,
4619
4684
  Search: Search,
@@ -5207,7 +5272,7 @@ var index = /*#__PURE__*/Object.freeze({
5207
5272
  apply: apply
5208
5273
  });
5209
5274
 
5210
- const version = "2.1.0";
5275
+ const version = "2.2.0";
5211
5276
 
5212
5277
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
5213
5278
  exports.FunctionExpressionType = FunctionExpressionType;
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 2.1.0
2
+ * json-p3 version 2.2.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2024 James Prior
7
+ * Copyright (c) 2025 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
@@ -1228,6 +1228,15 @@ function mapRegexp(pattern) {
1228
1228
  }
1229
1229
  return parts.join("");
1230
1230
  }
1231
+ function fullMatch(pattern) {
1232
+ const parts = [];
1233
+ const explicitCaret = pattern.startsWith("^");
1234
+ const explicitDollar = pattern.endsWith("$");
1235
+ if (!explicitCaret && !explicitDollar) parts.push("^(?:");
1236
+ parts.push(mapRegexp(pattern));
1237
+ if (!explicitCaret && !explicitDollar) parts.push(")$");
1238
+ return parts.join("");
1239
+ }
1231
1240
 
1232
1241
  /*
1233
1242
  * iregexp-check version 0.1.1
@@ -2478,7 +2487,7 @@ class Match {
2478
2487
  return false;
2479
2488
  }
2480
2489
  try {
2481
- const re = new RegExp(this.fullMatch(pattern), "u");
2490
+ const re = new RegExp(fullMatch(pattern), "u");
2482
2491
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2483
2492
  return re.test(s);
2484
2493
  } catch (error) {
@@ -2486,15 +2495,6 @@ class Match {
2486
2495
  return false;
2487
2496
  }
2488
2497
  }
2489
- fullMatch(pattern) {
2490
- const parts = [];
2491
- const explicitCaret = pattern.startsWith("^");
2492
- const explicitDollar = pattern.endsWith("$");
2493
- if (!explicitCaret && !explicitDollar) parts.push("^(?:");
2494
- parts.push(mapRegexp(pattern));
2495
- if (!explicitCaret && !explicitDollar) parts.push(")$");
2496
- return parts.join("");
2497
- }
2498
2498
  }
2499
2499
 
2500
2500
  class Search {
@@ -2988,7 +2988,6 @@ function lexInsideBracketedSelection(l) {
2988
2988
  switch (ch) {
2989
2989
  case "]":
2990
2990
  l.emit(TokenKind.RBRACKET);
2991
- if (l.filterLevel) return lexInsideFilter;
2992
2991
  return lexSegment;
2993
2992
  case "":
2994
2993
  l.error("unclosed bracketed selection");
@@ -3069,6 +3068,11 @@ function lexInsideFilter(l) {
3069
3068
  l.emit(TokenKind.CURRENT);
3070
3069
  return lexSegment;
3071
3070
  case "#":
3071
+ if (l.environment.strict) {
3072
+ l.backup();
3073
+ l.error(`unexpected filter selector token '${ch}'`);
3074
+ return null;
3075
+ }
3072
3076
  l.emit(TokenKind.CURRENT_KEY);
3073
3077
  return lexSegment;
3074
3078
  case ".":
@@ -4608,10 +4612,71 @@ class JSONPathEnvironment {
4608
4612
  }
4609
4613
  }
4610
4614
 
4615
+ /**
4616
+ * A function extension that returns `true` if the first argument is an object
4617
+ * value and it contains a property matching the second argument.
4618
+ */
4619
+ class Has {
4620
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4621
+ returnType = (() => FunctionExpressionType.LogicalType)();
4622
+ #cache;
4623
+ constructor() {
4624
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4625
+ this.options = options;
4626
+ this.cacheSize = options.cacheSize ?? 10;
4627
+ this.throwErrors = options.throwErrors ?? false;
4628
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4629
+ this.search = options.search ?? true;
4630
+ this.#cache = new LRUCache(this.cacheSize);
4631
+ }
4632
+
4633
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4634
+ call(value, pattern) {
4635
+ if (this.cacheSize > 0) {
4636
+ const re = this.#cache.get(pattern);
4637
+ if (re) {
4638
+ try {
4639
+ if (isObject(value)) {
4640
+ return Object.keys(value).some(k => !!k.match(re));
4641
+ }
4642
+ return false;
4643
+ } catch (error) {
4644
+ if (this.throwErrors) throw error;
4645
+ return false;
4646
+ }
4647
+ }
4648
+ }
4649
+ if (!isString(pattern)) {
4650
+ if (this.throwErrors) {
4651
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4652
+ }
4653
+ return false;
4654
+ }
4655
+ if (this.iRegexpCheck && !check$1(pattern)) {
4656
+ if (this.throwErrors) {
4657
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4658
+ }
4659
+ return false;
4660
+ }
4661
+ try {
4662
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4663
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4664
+ if (isObject(value)) {
4665
+ return Object.keys(value).some(k => !!k.match(re));
4666
+ }
4667
+ return false;
4668
+ } catch (error) {
4669
+ if (this.throwErrors) throw error;
4670
+ return false;
4671
+ }
4672
+ }
4673
+ }
4674
+
4611
4675
  var index$2 = /*#__PURE__*/Object.freeze({
4612
4676
  __proto__: null,
4613
4677
  Count: Count,
4614
4678
  FunctionExpressionType: FunctionExpressionType,
4679
+ Has: Has,
4615
4680
  Length: Length,
4616
4681
  Match: Match,
4617
4682
  Search: Search,
@@ -5205,6 +5270,6 @@ var index = /*#__PURE__*/Object.freeze({
5205
5270
  apply: apply
5206
5271
  });
5207
5272
 
5208
- const version = "2.1.0";
5273
+ const version = "2.2.0";
5209
5274
 
5210
5275
  export { DEFAULT_ENVIRONMENT, FunctionExpressionType, JSONPatch, JSONPatchError, JSONPatchTestFailure, JSONPathEnvironment, JSONPathError, JSONPathIndexError, JSONPathLexerError, JSONPathNode, JSONPathNodeList, JSONPathQuery, 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 2.1.0
2
+ * json-p3 version 2.2.0
3
3
  * https://github.com/jg-rp/json-p3
4
4
  *
5
5
  * MIT License
6
6
  *
7
- * Copyright (c) 2024 James Prior
7
+ * Copyright (c) 2025 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
@@ -1231,6 +1231,15 @@ var json_p3 = (function (exports) {
1231
1231
  }
1232
1232
  return parts.join("");
1233
1233
  }
1234
+ function fullMatch(pattern) {
1235
+ const parts = [];
1236
+ const explicitCaret = pattern.startsWith("^");
1237
+ const explicitDollar = pattern.endsWith("$");
1238
+ if (!explicitCaret && !explicitDollar) parts.push("^(?:");
1239
+ parts.push(mapRegexp(pattern));
1240
+ if (!explicitCaret && !explicitDollar) parts.push(")$");
1241
+ return parts.join("");
1242
+ }
1234
1243
 
1235
1244
  /*
1236
1245
  * iregexp-check version 0.1.1
@@ -2481,7 +2490,7 @@ var json_p3 = (function (exports) {
2481
2490
  return false;
2482
2491
  }
2483
2492
  try {
2484
- const re = new RegExp(this.fullMatch(pattern), "u");
2493
+ const re = new RegExp(fullMatch(pattern), "u");
2485
2494
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2486
2495
  return re.test(s);
2487
2496
  } catch (error) {
@@ -2489,15 +2498,6 @@ var json_p3 = (function (exports) {
2489
2498
  return false;
2490
2499
  }
2491
2500
  }
2492
- fullMatch(pattern) {
2493
- const parts = [];
2494
- const explicitCaret = pattern.startsWith("^");
2495
- const explicitDollar = pattern.endsWith("$");
2496
- if (!explicitCaret && !explicitDollar) parts.push("^(?:");
2497
- parts.push(mapRegexp(pattern));
2498
- if (!explicitCaret && !explicitDollar) parts.push(")$");
2499
- return parts.join("");
2500
- }
2501
2501
  }
2502
2502
 
2503
2503
  class Search {
@@ -2991,7 +2991,6 @@ var json_p3 = (function (exports) {
2991
2991
  switch (ch) {
2992
2992
  case "]":
2993
2993
  l.emit(TokenKind.RBRACKET);
2994
- if (l.filterLevel) return lexInsideFilter;
2995
2994
  return lexSegment;
2996
2995
  case "":
2997
2996
  l.error("unclosed bracketed selection");
@@ -3072,6 +3071,11 @@ var json_p3 = (function (exports) {
3072
3071
  l.emit(TokenKind.CURRENT);
3073
3072
  return lexSegment;
3074
3073
  case "#":
3074
+ if (l.environment.strict) {
3075
+ l.backup();
3076
+ l.error(`unexpected filter selector token '${ch}'`);
3077
+ return null;
3078
+ }
3075
3079
  l.emit(TokenKind.CURRENT_KEY);
3076
3080
  return lexSegment;
3077
3081
  case ".":
@@ -4611,10 +4615,71 @@ var json_p3 = (function (exports) {
4611
4615
  }
4612
4616
  }
4613
4617
 
4618
+ /**
4619
+ * A function extension that returns `true` if the first argument is an object
4620
+ * value and it contains a property matching the second argument.
4621
+ */
4622
+ class Has {
4623
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4624
+ returnType = (() => FunctionExpressionType.LogicalType)();
4625
+ #cache;
4626
+ constructor() {
4627
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4628
+ this.options = options;
4629
+ this.cacheSize = options.cacheSize ?? 10;
4630
+ this.throwErrors = options.throwErrors ?? false;
4631
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4632
+ this.search = options.search ?? true;
4633
+ this.#cache = new LRUCache(this.cacheSize);
4634
+ }
4635
+
4636
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4637
+ call(value, pattern) {
4638
+ if (this.cacheSize > 0) {
4639
+ const re = this.#cache.get(pattern);
4640
+ if (re) {
4641
+ try {
4642
+ if (isObject(value)) {
4643
+ return Object.keys(value).some(k => !!k.match(re));
4644
+ }
4645
+ return false;
4646
+ } catch (error) {
4647
+ if (this.throwErrors) throw error;
4648
+ return false;
4649
+ }
4650
+ }
4651
+ }
4652
+ if (!isString(pattern)) {
4653
+ if (this.throwErrors) {
4654
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4655
+ }
4656
+ return false;
4657
+ }
4658
+ if (this.iRegexpCheck && !check$1(pattern)) {
4659
+ if (this.throwErrors) {
4660
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4661
+ }
4662
+ return false;
4663
+ }
4664
+ try {
4665
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4666
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4667
+ if (isObject(value)) {
4668
+ return Object.keys(value).some(k => !!k.match(re));
4669
+ }
4670
+ return false;
4671
+ } catch (error) {
4672
+ if (this.throwErrors) throw error;
4673
+ return false;
4674
+ }
4675
+ }
4676
+ }
4677
+
4614
4678
  var index$2 = /*#__PURE__*/Object.freeze({
4615
4679
  __proto__: null,
4616
4680
  Count: Count,
4617
4681
  FunctionExpressionType: FunctionExpressionType,
4682
+ Has: Has,
4618
4683
  Length: Length,
4619
4684
  Match: Match,
4620
4685
  Search: Search,
@@ -5208,7 +5273,7 @@ var json_p3 = (function (exports) {
5208
5273
  apply: apply
5209
5274
  });
5210
5275
 
5211
- const version = "2.1.0";
5276
+ const version = "2.2.0";
5212
5277
 
5213
5278
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
5214
5279
  exports.FunctionExpressionType = FunctionExpressionType;