json-p3 2.1.1 → 2.2.1

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.1
2
+ * json-p3 version 2.2.1
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,9 +1230,18 @@ 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
- * iregexp-check version 0.1.1
1244
+ * iregexp-check version 0.1.2
1236
1245
  * https://github.com/jg-rp/js-iregexp
1237
1246
  *
1238
1247
  * MIT License
@@ -1675,7 +1684,7 @@ function peg$parse(input, options) {
1675
1684
  return s0;
1676
1685
  }
1677
1686
  function peg$parserange_quantifier() {
1678
- var s0, s1, s2, s3, s4, s5;
1687
+ var s0, s1, s2, s3, s4, s5, s6;
1679
1688
  s0 = peg$currPos;
1680
1689
  if (input.charCodeAt(peg$currPos) === 123) {
1681
1690
  s1 = peg$c1;
@@ -1687,15 +1696,32 @@ function peg$parse(input, options) {
1687
1696
  }
1688
1697
  }
1689
1698
  if (s1 !== peg$FAILED) {
1690
- s2 = input.charAt(peg$currPos);
1691
- if (peg$r1.test(s2)) {
1699
+ s2 = [];
1700
+ s3 = input.charAt(peg$currPos);
1701
+ if (peg$r1.test(s3)) {
1692
1702
  peg$currPos++;
1693
1703
  } else {
1694
- s2 = peg$FAILED;
1704
+ s3 = peg$FAILED;
1695
1705
  if (peg$silentFails === 0) {
1696
1706
  peg$fail(peg$e3);
1697
1707
  }
1698
1708
  }
1709
+ if (s3 !== peg$FAILED) {
1710
+ while (s3 !== peg$FAILED) {
1711
+ s2.push(s3);
1712
+ s3 = input.charAt(peg$currPos);
1713
+ if (peg$r1.test(s3)) {
1714
+ peg$currPos++;
1715
+ } else {
1716
+ s3 = peg$FAILED;
1717
+ if (peg$silentFails === 0) {
1718
+ peg$fail(peg$e3);
1719
+ }
1720
+ }
1721
+ }
1722
+ } else {
1723
+ s2 = peg$FAILED;
1724
+ }
1699
1725
  if (s2 !== peg$FAILED) {
1700
1726
  s3 = peg$currPos;
1701
1727
  if (input.charCodeAt(peg$currPos) === 44) {
@@ -1708,17 +1734,27 @@ function peg$parse(input, options) {
1708
1734
  }
1709
1735
  }
1710
1736
  if (s4 !== peg$FAILED) {
1711
- s5 = input.charAt(peg$currPos);
1712
- if (peg$r1.test(s5)) {
1737
+ s5 = [];
1738
+ s6 = input.charAt(peg$currPos);
1739
+ if (peg$r1.test(s6)) {
1713
1740
  peg$currPos++;
1714
1741
  } else {
1715
- s5 = peg$FAILED;
1742
+ s6 = peg$FAILED;
1716
1743
  if (peg$silentFails === 0) {
1717
1744
  peg$fail(peg$e3);
1718
1745
  }
1719
1746
  }
1720
- if (s5 === peg$FAILED) {
1721
- s5 = null;
1747
+ while (s6 !== peg$FAILED) {
1748
+ s5.push(s6);
1749
+ s6 = input.charAt(peg$currPos);
1750
+ if (peg$r1.test(s6)) {
1751
+ peg$currPos++;
1752
+ } else {
1753
+ s6 = peg$FAILED;
1754
+ if (peg$silentFails === 0) {
1755
+ peg$fail(peg$e3);
1756
+ }
1757
+ }
1722
1758
  }
1723
1759
  s4 = [s4, s5];
1724
1760
  s3 = s4;
@@ -2480,7 +2516,7 @@ class Match {
2480
2516
  return false;
2481
2517
  }
2482
2518
  try {
2483
- const re = new RegExp(this.fullMatch(pattern), "u");
2519
+ const re = new RegExp(fullMatch(pattern), "u");
2484
2520
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2485
2521
  return re.test(s);
2486
2522
  } catch (error) {
@@ -2488,15 +2524,6 @@ class Match {
2488
2524
  return false;
2489
2525
  }
2490
2526
  }
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
2527
  }
2501
2528
 
2502
2529
  class Search {
@@ -3070,6 +3097,11 @@ function lexInsideFilter(l) {
3070
3097
  l.emit(TokenKind.CURRENT);
3071
3098
  return lexSegment;
3072
3099
  case "#":
3100
+ if (l.environment.strict) {
3101
+ l.backup();
3102
+ l.error(`unexpected filter selector token '${ch}'`);
3103
+ return null;
3104
+ }
3073
3105
  l.emit(TokenKind.CURRENT_KEY);
3074
3106
  return lexSegment;
3075
3107
  case ".":
@@ -4609,10 +4641,71 @@ class JSONPathEnvironment {
4609
4641
  }
4610
4642
  }
4611
4643
 
4644
+ /**
4645
+ * A function extension that returns `true` if the first argument is an object
4646
+ * value and it contains a property matching the second argument.
4647
+ */
4648
+ class Has {
4649
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4650
+ returnType = (() => FunctionExpressionType.LogicalType)();
4651
+ #cache;
4652
+ constructor() {
4653
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4654
+ this.options = options;
4655
+ this.cacheSize = options.cacheSize ?? 10;
4656
+ this.throwErrors = options.throwErrors ?? false;
4657
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4658
+ this.search = options.search ?? true;
4659
+ this.#cache = new LRUCache(this.cacheSize);
4660
+ }
4661
+
4662
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4663
+ call(value, pattern) {
4664
+ if (this.cacheSize > 0) {
4665
+ const re = this.#cache.get(pattern);
4666
+ if (re) {
4667
+ try {
4668
+ if (isObject(value)) {
4669
+ return Object.keys(value).some(k => !!k.match(re));
4670
+ }
4671
+ return false;
4672
+ } catch (error) {
4673
+ if (this.throwErrors) throw error;
4674
+ return false;
4675
+ }
4676
+ }
4677
+ }
4678
+ if (!isString(pattern)) {
4679
+ if (this.throwErrors) {
4680
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4681
+ }
4682
+ return false;
4683
+ }
4684
+ if (this.iRegexpCheck && !check$1(pattern)) {
4685
+ if (this.throwErrors) {
4686
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4687
+ }
4688
+ return false;
4689
+ }
4690
+ try {
4691
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4692
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4693
+ if (isObject(value)) {
4694
+ return Object.keys(value).some(k => !!k.match(re));
4695
+ }
4696
+ return false;
4697
+ } catch (error) {
4698
+ if (this.throwErrors) throw error;
4699
+ return false;
4700
+ }
4701
+ }
4702
+ }
4703
+
4612
4704
  var index$2 = /*#__PURE__*/Object.freeze({
4613
4705
  __proto__: null,
4614
4706
  Count: Count,
4615
4707
  FunctionExpressionType: FunctionExpressionType,
4708
+ Has: Has,
4616
4709
  Length: Length,
4617
4710
  Match: Match,
4618
4711
  Search: Search,
@@ -5206,7 +5299,7 @@ var index = /*#__PURE__*/Object.freeze({
5206
5299
  apply: apply
5207
5300
  });
5208
5301
 
5209
- const version = "2.1.1";
5302
+ const version = "2.2.1";
5210
5303
 
5211
5304
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
5212
5305
  exports.FunctionExpressionType = FunctionExpressionType;
@@ -1,10 +1,10 @@
1
1
  /*
2
- * json-p3 version 2.1.1
2
+ * json-p3 version 2.2.1
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,9 +1228,18 @@ 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
- * iregexp-check version 0.1.1
1242
+ * iregexp-check version 0.1.2
1234
1243
  * https://github.com/jg-rp/js-iregexp
1235
1244
  *
1236
1245
  * MIT License
@@ -1673,7 +1682,7 @@ function peg$parse(input, options) {
1673
1682
  return s0;
1674
1683
  }
1675
1684
  function peg$parserange_quantifier() {
1676
- var s0, s1, s2, s3, s4, s5;
1685
+ var s0, s1, s2, s3, s4, s5, s6;
1677
1686
  s0 = peg$currPos;
1678
1687
  if (input.charCodeAt(peg$currPos) === 123) {
1679
1688
  s1 = peg$c1;
@@ -1685,15 +1694,32 @@ function peg$parse(input, options) {
1685
1694
  }
1686
1695
  }
1687
1696
  if (s1 !== peg$FAILED) {
1688
- s2 = input.charAt(peg$currPos);
1689
- if (peg$r1.test(s2)) {
1697
+ s2 = [];
1698
+ s3 = input.charAt(peg$currPos);
1699
+ if (peg$r1.test(s3)) {
1690
1700
  peg$currPos++;
1691
1701
  } else {
1692
- s2 = peg$FAILED;
1702
+ s3 = peg$FAILED;
1693
1703
  if (peg$silentFails === 0) {
1694
1704
  peg$fail(peg$e3);
1695
1705
  }
1696
1706
  }
1707
+ if (s3 !== peg$FAILED) {
1708
+ while (s3 !== peg$FAILED) {
1709
+ s2.push(s3);
1710
+ s3 = input.charAt(peg$currPos);
1711
+ if (peg$r1.test(s3)) {
1712
+ peg$currPos++;
1713
+ } else {
1714
+ s3 = peg$FAILED;
1715
+ if (peg$silentFails === 0) {
1716
+ peg$fail(peg$e3);
1717
+ }
1718
+ }
1719
+ }
1720
+ } else {
1721
+ s2 = peg$FAILED;
1722
+ }
1697
1723
  if (s2 !== peg$FAILED) {
1698
1724
  s3 = peg$currPos;
1699
1725
  if (input.charCodeAt(peg$currPos) === 44) {
@@ -1706,17 +1732,27 @@ function peg$parse(input, options) {
1706
1732
  }
1707
1733
  }
1708
1734
  if (s4 !== peg$FAILED) {
1709
- s5 = input.charAt(peg$currPos);
1710
- if (peg$r1.test(s5)) {
1735
+ s5 = [];
1736
+ s6 = input.charAt(peg$currPos);
1737
+ if (peg$r1.test(s6)) {
1711
1738
  peg$currPos++;
1712
1739
  } else {
1713
- s5 = peg$FAILED;
1740
+ s6 = peg$FAILED;
1714
1741
  if (peg$silentFails === 0) {
1715
1742
  peg$fail(peg$e3);
1716
1743
  }
1717
1744
  }
1718
- if (s5 === peg$FAILED) {
1719
- s5 = null;
1745
+ while (s6 !== peg$FAILED) {
1746
+ s5.push(s6);
1747
+ s6 = input.charAt(peg$currPos);
1748
+ if (peg$r1.test(s6)) {
1749
+ peg$currPos++;
1750
+ } else {
1751
+ s6 = peg$FAILED;
1752
+ if (peg$silentFails === 0) {
1753
+ peg$fail(peg$e3);
1754
+ }
1755
+ }
1720
1756
  }
1721
1757
  s4 = [s4, s5];
1722
1758
  s3 = s4;
@@ -2478,7 +2514,7 @@ class Match {
2478
2514
  return false;
2479
2515
  }
2480
2516
  try {
2481
- const re = new RegExp(this.fullMatch(pattern), "u");
2517
+ const re = new RegExp(fullMatch(pattern), "u");
2482
2518
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2483
2519
  return re.test(s);
2484
2520
  } catch (error) {
@@ -2486,15 +2522,6 @@ class Match {
2486
2522
  return false;
2487
2523
  }
2488
2524
  }
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
2525
  }
2499
2526
 
2500
2527
  class Search {
@@ -3068,6 +3095,11 @@ function lexInsideFilter(l) {
3068
3095
  l.emit(TokenKind.CURRENT);
3069
3096
  return lexSegment;
3070
3097
  case "#":
3098
+ if (l.environment.strict) {
3099
+ l.backup();
3100
+ l.error(`unexpected filter selector token '${ch}'`);
3101
+ return null;
3102
+ }
3071
3103
  l.emit(TokenKind.CURRENT_KEY);
3072
3104
  return lexSegment;
3073
3105
  case ".":
@@ -4607,10 +4639,71 @@ class JSONPathEnvironment {
4607
4639
  }
4608
4640
  }
4609
4641
 
4642
+ /**
4643
+ * A function extension that returns `true` if the first argument is an object
4644
+ * value and it contains a property matching the second argument.
4645
+ */
4646
+ class Has {
4647
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4648
+ returnType = (() => FunctionExpressionType.LogicalType)();
4649
+ #cache;
4650
+ constructor() {
4651
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4652
+ this.options = options;
4653
+ this.cacheSize = options.cacheSize ?? 10;
4654
+ this.throwErrors = options.throwErrors ?? false;
4655
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4656
+ this.search = options.search ?? true;
4657
+ this.#cache = new LRUCache(this.cacheSize);
4658
+ }
4659
+
4660
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4661
+ call(value, pattern) {
4662
+ if (this.cacheSize > 0) {
4663
+ const re = this.#cache.get(pattern);
4664
+ if (re) {
4665
+ try {
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
+ if (!isString(pattern)) {
4677
+ if (this.throwErrors) {
4678
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4679
+ }
4680
+ return false;
4681
+ }
4682
+ if (this.iRegexpCheck && !check$1(pattern)) {
4683
+ if (this.throwErrors) {
4684
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4685
+ }
4686
+ return false;
4687
+ }
4688
+ try {
4689
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4690
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4691
+ if (isObject(value)) {
4692
+ return Object.keys(value).some(k => !!k.match(re));
4693
+ }
4694
+ return false;
4695
+ } catch (error) {
4696
+ if (this.throwErrors) throw error;
4697
+ return false;
4698
+ }
4699
+ }
4700
+ }
4701
+
4610
4702
  var index$2 = /*#__PURE__*/Object.freeze({
4611
4703
  __proto__: null,
4612
4704
  Count: Count,
4613
4705
  FunctionExpressionType: FunctionExpressionType,
4706
+ Has: Has,
4614
4707
  Length: Length,
4615
4708
  Match: Match,
4616
4709
  Search: Search,
@@ -5204,6 +5297,6 @@ var index = /*#__PURE__*/Object.freeze({
5204
5297
  apply: apply
5205
5298
  });
5206
5299
 
5207
- const version = "2.1.1";
5300
+ const version = "2.2.1";
5208
5301
 
5209
5302
  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.1
2
+ * json-p3 version 2.2.1
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,9 +1231,18 @@ 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
- * iregexp-check version 0.1.1
1245
+ * iregexp-check version 0.1.2
1237
1246
  * https://github.com/jg-rp/js-iregexp
1238
1247
  *
1239
1248
  * MIT License
@@ -1676,7 +1685,7 @@ var json_p3 = (function (exports) {
1676
1685
  return s0;
1677
1686
  }
1678
1687
  function peg$parserange_quantifier() {
1679
- var s0, s1, s2, s3, s4, s5;
1688
+ var s0, s1, s2, s3, s4, s5, s6;
1680
1689
  s0 = peg$currPos;
1681
1690
  if (input.charCodeAt(peg$currPos) === 123) {
1682
1691
  s1 = peg$c1;
@@ -1688,15 +1697,32 @@ var json_p3 = (function (exports) {
1688
1697
  }
1689
1698
  }
1690
1699
  if (s1 !== peg$FAILED) {
1691
- s2 = input.charAt(peg$currPos);
1692
- if (peg$r1.test(s2)) {
1700
+ s2 = [];
1701
+ s3 = input.charAt(peg$currPos);
1702
+ if (peg$r1.test(s3)) {
1693
1703
  peg$currPos++;
1694
1704
  } else {
1695
- s2 = peg$FAILED;
1705
+ s3 = peg$FAILED;
1696
1706
  if (peg$silentFails === 0) {
1697
1707
  peg$fail(peg$e3);
1698
1708
  }
1699
1709
  }
1710
+ if (s3 !== peg$FAILED) {
1711
+ while (s3 !== peg$FAILED) {
1712
+ s2.push(s3);
1713
+ s3 = input.charAt(peg$currPos);
1714
+ if (peg$r1.test(s3)) {
1715
+ peg$currPos++;
1716
+ } else {
1717
+ s3 = peg$FAILED;
1718
+ if (peg$silentFails === 0) {
1719
+ peg$fail(peg$e3);
1720
+ }
1721
+ }
1722
+ }
1723
+ } else {
1724
+ s2 = peg$FAILED;
1725
+ }
1700
1726
  if (s2 !== peg$FAILED) {
1701
1727
  s3 = peg$currPos;
1702
1728
  if (input.charCodeAt(peg$currPos) === 44) {
@@ -1709,17 +1735,27 @@ var json_p3 = (function (exports) {
1709
1735
  }
1710
1736
  }
1711
1737
  if (s4 !== peg$FAILED) {
1712
- s5 = input.charAt(peg$currPos);
1713
- if (peg$r1.test(s5)) {
1738
+ s5 = [];
1739
+ s6 = input.charAt(peg$currPos);
1740
+ if (peg$r1.test(s6)) {
1714
1741
  peg$currPos++;
1715
1742
  } else {
1716
- s5 = peg$FAILED;
1743
+ s6 = peg$FAILED;
1717
1744
  if (peg$silentFails === 0) {
1718
1745
  peg$fail(peg$e3);
1719
1746
  }
1720
1747
  }
1721
- if (s5 === peg$FAILED) {
1722
- s5 = null;
1748
+ while (s6 !== peg$FAILED) {
1749
+ s5.push(s6);
1750
+ s6 = input.charAt(peg$currPos);
1751
+ if (peg$r1.test(s6)) {
1752
+ peg$currPos++;
1753
+ } else {
1754
+ s6 = peg$FAILED;
1755
+ if (peg$silentFails === 0) {
1756
+ peg$fail(peg$e3);
1757
+ }
1758
+ }
1723
1759
  }
1724
1760
  s4 = [s4, s5];
1725
1761
  s3 = s4;
@@ -2481,7 +2517,7 @@ var json_p3 = (function (exports) {
2481
2517
  return false;
2482
2518
  }
2483
2519
  try {
2484
- const re = new RegExp(this.fullMatch(pattern), "u");
2520
+ const re = new RegExp(fullMatch(pattern), "u");
2485
2521
  if (this.cacheSize > 0) this.#cache.set(pattern, re);
2486
2522
  return re.test(s);
2487
2523
  } catch (error) {
@@ -2489,15 +2525,6 @@ var json_p3 = (function (exports) {
2489
2525
  return false;
2490
2526
  }
2491
2527
  }
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
2528
  }
2502
2529
 
2503
2530
  class Search {
@@ -3071,6 +3098,11 @@ var json_p3 = (function (exports) {
3071
3098
  l.emit(TokenKind.CURRENT);
3072
3099
  return lexSegment;
3073
3100
  case "#":
3101
+ if (l.environment.strict) {
3102
+ l.backup();
3103
+ l.error(`unexpected filter selector token '${ch}'`);
3104
+ return null;
3105
+ }
3074
3106
  l.emit(TokenKind.CURRENT_KEY);
3075
3107
  return lexSegment;
3076
3108
  case ".":
@@ -4610,10 +4642,71 @@ var json_p3 = (function (exports) {
4610
4642
  }
4611
4643
  }
4612
4644
 
4645
+ /**
4646
+ * A function extension that returns `true` if the first argument is an object
4647
+ * value and it contains a property matching the second argument.
4648
+ */
4649
+ class Has {
4650
+ argTypes = (() => [FunctionExpressionType.ValueType, FunctionExpressionType.ValueType])();
4651
+ returnType = (() => FunctionExpressionType.LogicalType)();
4652
+ #cache;
4653
+ constructor() {
4654
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
4655
+ this.options = options;
4656
+ this.cacheSize = options.cacheSize ?? 10;
4657
+ this.throwErrors = options.throwErrors ?? false;
4658
+ this.iRegexpCheck = options.iRegexpCheck ?? true;
4659
+ this.search = options.search ?? true;
4660
+ this.#cache = new LRUCache(this.cacheSize);
4661
+ }
4662
+
4663
+ // eslint-disable-next-line sonarjs/cognitive-complexity
4664
+ call(value, pattern) {
4665
+ if (this.cacheSize > 0) {
4666
+ const re = this.#cache.get(pattern);
4667
+ if (re) {
4668
+ try {
4669
+ if (isObject(value)) {
4670
+ return Object.keys(value).some(k => !!k.match(re));
4671
+ }
4672
+ return false;
4673
+ } catch (error) {
4674
+ if (this.throwErrors) throw error;
4675
+ return false;
4676
+ }
4677
+ }
4678
+ }
4679
+ if (!isString(pattern)) {
4680
+ if (this.throwErrors) {
4681
+ throw new IRegexpError(`match() expected a string pattern, found ${pattern}`);
4682
+ }
4683
+ return false;
4684
+ }
4685
+ if (this.iRegexpCheck && !check$1(pattern)) {
4686
+ if (this.throwErrors) {
4687
+ throw new IRegexpError(`pattern ${pattern} is not a valid I-Regexp pattern`);
4688
+ }
4689
+ return false;
4690
+ }
4691
+ try {
4692
+ const re = this.search ? new RegExp(mapRegexp(pattern), "u") : new RegExp(mapRegexp(fullMatch(pattern)), "u");
4693
+ if (this.cacheSize > 0) this.#cache.set(pattern, re);
4694
+ if (isObject(value)) {
4695
+ return Object.keys(value).some(k => !!k.match(re));
4696
+ }
4697
+ return false;
4698
+ } catch (error) {
4699
+ if (this.throwErrors) throw error;
4700
+ return false;
4701
+ }
4702
+ }
4703
+ }
4704
+
4613
4705
  var index$2 = /*#__PURE__*/Object.freeze({
4614
4706
  __proto__: null,
4615
4707
  Count: Count,
4616
4708
  FunctionExpressionType: FunctionExpressionType,
4709
+ Has: Has,
4617
4710
  Length: Length,
4618
4711
  Match: Match,
4619
4712
  Search: Search,
@@ -5207,7 +5300,7 @@ var json_p3 = (function (exports) {
5207
5300
  apply: apply
5208
5301
  });
5209
5302
 
5210
- const version = "2.1.1";
5303
+ const version = "2.2.1";
5211
5304
 
5212
5305
  exports.DEFAULT_ENVIRONMENT = DEFAULT_ENVIRONMENT;
5213
5306
  exports.FunctionExpressionType = FunctionExpressionType;