@cdk8s/awscdk-resolver 0.0.607 → 0.0.608

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/.jsii CHANGED
@@ -4082,6 +4082,6 @@
4082
4082
  "symbolId": "src/resolve:AwsCdkResolver"
4083
4083
  }
4084
4084
  },
4085
- "version": "0.0.607",
4086
- "fingerprint": "QMRbwfgAbKCnIJW860uqAwgGm+83+QLzz0Vz1Pbs5oI="
4085
+ "version": "0.0.608",
4086
+ "fingerprint": "2OTHYRy6a1IxUxiSmtHE3CovQ9HDuEOLreTUYtITAbI="
4087
4087
  }
package/lib/resolve.js CHANGED
@@ -39,7 +39,7 @@ const child_process_1 = require("child_process");
39
39
  const path = __importStar(require("path"));
40
40
  const aws_cdk_lib_1 = require("aws-cdk-lib");
41
41
  class AwsCdkResolver {
42
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@cdk8s/awscdk-resolver.AwsCdkResolver", version: "0.0.607" };
42
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@cdk8s/awscdk-resolver.AwsCdkResolver", version: "0.0.608" };
43
43
  resolve(context) {
44
44
  if (!aws_cdk_lib_1.Token.isUnresolved(context.value)) {
45
45
  return;
@@ -1,5 +1,9 @@
1
1
  # path-expression-matcher
2
2
 
3
+ [![path-expression-matcher downloads](https://img.shields.io/npm/dw/path-expression-matcher.svg)](https://npm-compare.com/path-expression-matcher)
4
+ [![path-expression-matcher version](https://img.shields.io/npm/v/path-expression-matcher.svg)](https://www.npmjs.com/package/path-expression-matcher)
5
+ [![path-expression-matcher license](https://img.shields.io/npm/l/path-expression-matcher.svg)](https://github.com/NaturalIntelligence/path-expression-matcher)
6
+
3
7
  Efficient path tracking and pattern matching for XML, JSON, YAML or any other parsers.
4
8
 
5
9
  ## 🎯 Purpose
@@ -71,9 +75,10 @@ console.log(matcher.toString()); // "soap:Envelope.soap:Body.ns:UserId"
71
75
  ```javascript
72
76
  "user[id]" // user with "id" attribute
73
77
  "user[type=admin]" // user with type="admin" (current node only)
74
- "root[lang]..user" // user under root that has "lang" attribute
75
78
  ```
76
79
 
80
+ > **Note:** Attribute conditions in expressions only ever look at the **current** (last) node in the path — `..user` matches `user` at any depth, but bracket conditions like `[lang]` still apply to `user` itself, never to an ancestor tag. To check an *ancestor's* attribute (e.g. "is there a `lang` attribute somewhere above this node?"), use `push(..., { keep: [...] })` with `getAnyParentAttr()` / `hasAnyParentAttr()` — see [Ancestor Attributes (`keep`)](#ancestor-attributes-keep) below.
81
+
77
82
  ### Position Selectors
78
83
 
79
84
  ```javascript
@@ -174,7 +179,7 @@ new Matcher(options)
174
179
 
175
180
  #### Path Tracking Methods
176
181
 
177
- ##### `push(tagName, attrValues, namespace)`
182
+ ##### `push(tagName, attrValues, namespace, options)`
178
183
 
179
184
  Add a tag to the current path. Position and counter are automatically calculated.
180
185
 
@@ -182,6 +187,8 @@ Add a tag to the current path. Position and counter are automatically calculated
182
187
  - `tagName` (string): Tag name
183
188
  - `attrValues` (object, optional): Attribute key-value pairs (current node only)
184
189
  - `namespace` (string, optional): Namespace for the tag
190
+ - `options` (object, optional):
191
+ - `keep` (string[], optional): Names of attributes (from `attrValues`) to retain for ancestor lookup via `getAnyParentAttr()` / `hasAnyParentAttr()`, even after this node is no longer the current node. See [Ancestor Attributes (`keep`)](#ancestor-attributes-keep).
185
192
 
186
193
  **Example:**
187
194
  ```javascript
@@ -189,6 +196,7 @@ matcher.push("user", { id: "123", type: "admin" });
189
196
  matcher.push("item"); // No attributes
190
197
  matcher.push("Envelope", null, "soap"); // With namespace
191
198
  matcher.push("Body", { version: "1.1" }, "soap"); // With both
199
+ matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] }); // Retain "version" for descendants
192
200
  ```
193
201
 
194
202
  **Position vs Counter:**
@@ -293,6 +301,29 @@ if (matcher.hasAttr("id")) {
293
301
  }
294
302
  ```
295
303
 
304
+ ##### `getAnyParentAttr(attrName)`
305
+
306
+ Get the value of an attribute that was explicitly **kept** (via `push(..., { keep: [...] })`) by the current node or any ancestor. Unlike `getAttrValue()`, this works regardless of how far the path has descended since the attribute was pushed — but only for names that were marked with `keep` at push time. If the same name was kept at multiple depths, the **nearest** (most recent) one wins.
307
+
308
+ ```javascript
309
+ matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] });
310
+ matcher.push("GetUserRequest");
311
+ matcher.push("UserId");
312
+
313
+ matcher.getAttrValue("version"); // undefined — Body is no longer current
314
+ matcher.getAnyParentAttr("version"); // "1.1" — still reachable, because it was kept
315
+ ```
316
+
317
+ ##### `hasAnyParentAttr(attrName)`
318
+
319
+ Check whether the current node or any ancestor kept the given attribute via `push(..., { keep: [...] })`.
320
+
321
+ ```javascript
322
+ if (matcher.hasAnyParentAttr("version")) {
323
+ // Some node on the path (current or ancestor) kept "version"
324
+ }
325
+ ```
326
+
296
327
  ##### `getPosition()`
297
328
 
298
329
  Get sibling position of current node (child index in parent).
@@ -528,6 +559,32 @@ const expr2 = new Expression("user[type=admin]");
528
559
  console.log(matcher.matches(expr2)); // true
529
560
  ```
530
561
 
562
+ > Need to check an attribute from an *ancestor* node, not just the current one? See [Example 5b](#example-5b-ancestor-attributes-keep) and [Ancestor Attributes (`keep`)](#ancestor-attributes-keep).
563
+
564
+ ### Example 5b: Ancestor Attributes (`keep`)
565
+
566
+ `getAttrValue()` / `hasAttr()` only ever see the **current** node — by design, ancestor attribute values are discarded as soon as you push past them, to keep memory usage low. If you know in advance that a specific attribute (e.g. a SOAP envelope's `version`, or `xml:space`) will matter much deeper in the tree, mark it to be **kept**:
567
+
568
+ ```javascript
569
+ const matcher = new Matcher();
570
+ matcher.push("Envelope", null, "soap");
571
+ matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] });
572
+ matcher.push("GetUserRequest", { id: "42" });
573
+ matcher.push("UserId");
574
+
575
+ // Ordinary attribute access only sees the current node:
576
+ console.log(matcher.getAttrValue("version")); // undefined
577
+
578
+ // getAnyParentAttr/hasAnyParentAttr still see it, however deep we've gone:
579
+ console.log(matcher.hasAnyParentAttr("version")); // true
580
+ console.log(matcher.getAnyParentAttr("version")); // "1.1"
581
+
582
+ matcher.pop(); matcher.pop(); matcher.pop(); // back to Envelope
583
+ console.log(matcher.hasAnyParentAttr("version")); // false — Body (and its kept attrs) was popped
584
+ ```
585
+
586
+ **When to use this:** only for the small number of attributes you specifically know you'll need many levels deeper — not as a general substitute for `getAttrValue()`. Each name passed to `keep` adds a tiny, constant amount of bookkeeping at `push()` time; lookups scan only the kept-attributes list (typically 0-3 entries), never the full path, so cost does not grow with document depth.
587
+
531
588
  ### Example 6: Position vs Counter
532
589
 
533
590
  ```javascript
@@ -634,24 +691,42 @@ console.log(matcher.matches(expr)); // true - matches namespace "ns", tag "first
634
691
 
635
692
  This design minimizes memory usage:
636
693
  - No attribute names stored (derived from values object when needed)
637
- - Attribute values only for current node, not ancestors
638
- - Attribute checking for ancestors is not supported (acceptable trade-off)
694
+ - Attribute values only for current node, not ancestors, **by default**
639
695
  - For 1M nodes with 3 attributes each, saves ~50MB vs storing attribute names
640
696
 
697
+ ### Ancestor Attributes (`keep`)
698
+
699
+ The trade-off above is the right default, but XML/SOAP documents occasionally have a handful of attributes — `xml:space`, a SOAP envelope's `version`, a feature-flag at the document root — that genuinely need to be visible many levels deeper. Rather than retaining *all* attribute values for *every* node (defeating the memory savings above), `push()` accepts an explicit opt-in:
700
+
701
+ ```javascript
702
+ matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] });
703
+ ```
704
+
705
+ Only the named attribute(s) are copied into a small side-stack (`_keptAttrs`), independent of the normal per-node `values`. Reachable later via `getAnyParentAttr(name)` / `hasAnyParentAttr(name)` regardless of depth — see [Example 5b](#example-5b-ancestor-attributes-keep).
706
+
707
+ **Why this stays cheap:**
708
+ - Pushing without `options` costs two extra property reads — no allocation, no measurable overhead (benchmarked: within run-to-run noise vs. plain `push()`).
709
+ - Lookups scan only the kept-attributes stack, not the full path — cost is proportional to *how many distinct attributes are currently kept* (typically 0-3 in real usage), not to document depth.
710
+ - `pop()` truncates kept entries belonging to the popped subtree in the same backward-scan style, so the stack never grows unbounded.
711
+ - The core `matches()` / `_matchSegment` pattern-matching path is completely unaffected — `keep` is a separate, opt-in mechanism with no new expression syntax.
712
+
713
+ This is intentionally a narrow escape hatch, not a general "remember everything" toggle — overusing `keep` (e.g. keeping every attribute on every node) reintroduces the same memory cost this library avoids by default.
714
+
641
715
  ### Matching Strategy
642
716
 
643
717
  Matching is performed **bottom-to-top** (from current node toward root):
644
718
  1. Start at current node
645
719
  2. Match segments from pattern end to start
646
- 3. Attribute checking only works for current node (ancestors have no attribute data)
720
+ 3. Attribute *expression* conditions (`[attr=value]`) only apply to the current node ancestors have no attribute data in the path itself. For genuinely ancestor-scoped checks outside of expression matching, use `keep` (above).
647
721
  4. Position selectors use **counter** (occurrence count), not position (child index)
648
722
 
649
723
  ### Performance
650
724
 
651
725
  - **Expression parsing:** One-time cost when Expression is created
652
726
  - **Expression analysis:** Cached (hasDeepWildcard, hasAttributeCondition, hasPositionSelector)
653
- - **Path tracking:** O(1) for push/pop operations
727
+ - **Path tracking:** O(1) for push/pop operations (O(k) additionally when `options.keep` is used, where k = number of kept attribute names — typically 0-3)
654
728
  - **Pattern matching:** O(n*m) where n = path depth, m = pattern segments
729
+ - **Ancestor attribute lookup:** O(k) where k = number of currently-kept attributes, independent of path depth
655
730
  - **Memory per ancestor node:** ~40-60 bytes (tag, position, counter only)
656
731
  - **Memory per current node:** ~80-120 bytes (adds attribute values)
657
732
 
@@ -869,4 +944,4 @@ MIT
869
944
 
870
945
  ## 🤝 Contributing
871
946
 
872
- Issues and PRs welcome! This package is designed to be used by XML/JSON parsers like fast-xml-parser. But can be used with any formar parser.
947
+ Issues and PRs welcome! This package is designed to be used by XML/JSON parsers like fast-xml-parser. But can be used with any formar parser.
@@ -1 +1 @@
1
- (()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{Expression:()=>s,ExpressionSet:()=>n,Matcher:()=>h,default:()=>r});class s{constructor(t,e={},s){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=s,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let s=0,i="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(i.trim()&&(e.push(this._parseSegment(i.trim())),i=""),e.push({type:"deep-wildcard"}),s+=2):(i.trim()&&e.push(this._parseSegment(i.trim())),i="",s++):(i+=t[s],s++);return i.trim()&&e.push(this._parseSegment(i.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,i=t;const h=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(h&&(i=h[1]+h[3],h[2])){const t=h[2].slice(1,-1);t&&(s=t)}let n,r,a=i;if(i.includes("::")){const e=i.indexOf("::");if(n=i.substring(0,e).trim(),a=i.substring(e+2).trim(),!n)throw new Error(`Invalid namespace in pattern: ${t}`)}let p=null;if(a.includes(":")){const t=a.lastIndexOf(":"),e=a.substring(0,t).trim(),s=a.substring(t+1).trim();["first","last","odd","even"].includes(s)||/^nth\(\d+\)$/.test(s)?(r=e,p=s):r=a}else r=a;if(!r)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=r,n&&(e.namespace=n),s)if(s.includes("=")){const t=s.indexOf("=");e.attrName=s.substring(0,t).trim(),e.attrValue=s.substring(t+1).trim()}else e.attrName=s.trim();if(p){const t=p.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=p}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class i{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const s=e[e.length-1];return void 0!==s.values&&t in s.values}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class h{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new i(this)}push(t,e=null,s=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const i=this.path.length;this.siblingStacks[i]||(this.siblingStacks[i]=new Map);const h=this.siblingStacks[i],n=s?`${s}:${t}`:t,r=h.get(n)||0;let a=0;for(const t of h.values())a+=t;h.set(n,r+1);const p={tag:t,position:a,counter:r};null!=s&&(p.namespace=s),null!=e&&(p.values=e),this.path.push(p)}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();return this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1),t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const s=t||this.separator;if(s===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,s=t.length-1;for(;s>=0&&e>=0;){const i=t[s];if("deep-wildcard"===i.type){if(s--,s<0)return!0;const i=t[s];let h=!1;for(let t=e;t>=0;t--)if(this._matchSegment(i,this.path[t],t===this.path.length-1)){e=t-1,s--,h=!0;break}if(!h)return!1}else{if(!this._matchSegment(i,this.path[e],e===this.path.length-1))return!1;e--,s--}}return s<0}_matchSegment(t,e,s){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!s)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!s)return!1;const i=e.counter??0;if("first"===t.position&&0!==i)return!1;if("odd"===t.position&&i%2!=1)return!1;if("even"===t.position&&i%2!=0)return!1;if("nth"===t.position&&i!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t))}readOnly(){return this._view}}class n{constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard())return this._deepWildcards.push(t),this;const e=t.length,s=t.segments[t.segments.length-1],i=s?.tag;if(i&&"*"!==i){const s=`${e}:${i}`;this._byDepthAndTag.has(s)||this._byDepthAndTag.set(s,[]),this._byDepthAndTag.get(s).push(t)}else this._wildcardByDepth.has(e)||this._wildcardByDepth.set(e,[]),this._wildcardByDepth.get(e).push(t);return this}addAll(t){for(const e of t)this.add(e);return this}has(t){return this._patterns.has(t.pattern)}get size(){return this._patterns.size}seal(){return this._sealed=!0,this}get isSealed(){return this._sealed}matchesAny(t){return null!==this.findMatch(t)}findMatch(t){const e=t.getDepth(),s=`${e}:${t.getCurrentTag()}`,i=this._byDepthAndTag.get(s);if(i)for(let e=0;e<i.length;e++)if(t.matches(i[e]))return i[e];const h=this._wildcardByDepth.get(e);if(h)for(let e=0;e<h.length;e++)if(t.matches(h[e]))return h[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}const r={Expression:s,Matcher:h,ExpressionSet:n};module.exports=e})();
1
+ (()=>{"use strict";var t={d:(e,s)=>{for(var n in s)t.o(s,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:s[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{Expression:()=>s,ExpressionSet:()=>h,Matcher:()=>r,default:()=>i});class s{constructor(t,e={},s){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=s,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let s=0,n="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(n.trim()&&(e.push(this._parseSegment(n.trim())),n=""),e.push({type:"deep-wildcard"}),s+=2):(n.trim()&&e.push(this._parseSegment(n.trim())),n="",s++):(n+=t[s],s++);return n.trim()&&e.push(this._parseSegment(n.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,n=t;const r=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(r&&(n=r[1]+r[3],r[2])){const t=r[2].slice(1,-1);t&&(s=t)}let h,i,a=n;if(n.includes("::")){const e=n.indexOf("::");if(h=n.substring(0,e).trim(),a=n.substring(e+2).trim(),!h)throw new Error(`Invalid namespace in pattern: ${t}`)}let p=null;if(a.includes(":")){const t=a.lastIndexOf(":"),e=a.substring(0,t).trim(),s=a.substring(t+1).trim();["first","last","odd","even"].includes(s)||/^nth\(\d+\)$/.test(s)?(i=e,p=s):i=a}else i=a;if(!i)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=i,h&&(e.namespace=h),s)if(s.includes("=")){const t=s.indexOf("=");e.attrName=s.substring(0,t).trim(),e.attrValue=s.substring(t+1).trim()}else e.attrName=s.trim();if(p){const t=p.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=p}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class n{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const s=e[e.length-1];return void 0!==s.values&&t in s.values}getAnyParentAttr(t){return this._matcher.getAnyParentAttr(t)}hasAnyParentAttr(t){return this._matcher.hasAnyParentAttr(t)}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class r{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new n(this),this._keptAttrs=[]}push(t,e=null,s=null,n=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const r=this.path.length;this.siblingStacks[r]||(this.siblingStacks[r]=new Map);const h=this.siblingStacks[r],i=s?`${s}:${t}`:t,a=h.get(i)||0;let p=0;for(const t of h.values())p+=t;h.set(i,a+1);const l={tag:t,position:p,counter:a};null!=s&&(l.namespace=s),null!=e&&(l.values=e),this.path.push(l);const o=this.path.length,g=null!==n?n.keep:null;if(null!=g&&g.length>0&&e)for(let t=0;t<g.length;t++){const s=g[t];void 0!==e[s]&&this._keptAttrs.push({depth:o,name:s,value:e[s]})}}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1);const e=this.path.length+1;for(;this._keptAttrs.length>0&&this._keptAttrs[this._keptAttrs.length-1].depth>=e;)this._keptAttrs.pop();return t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getAnyParentAttr(t){const e=this._keptAttrs;for(let s=e.length-1;s>=0;s--)if(e[s].name===t)return e[s].value}hasAnyParentAttr(t){const e=this._keptAttrs;for(let s=e.length-1;s>=0;s--)if(e[s].name===t)return!0;return!1}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const s=t||this.separator;if(s===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[],this._keptAttrs=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,s=t.length-1;for(;s>=0&&e>=0;){const n=t[s];if("deep-wildcard"===n.type){if(s--,s<0)return!0;const n=t[s];let r=!1;for(let t=e;t>=0;t--)if(this._matchSegment(n,this.path[t],t===this.path.length-1)){e=t-1,s--,r=!0;break}if(!r)return!1}else{if(!this._matchSegment(n,this.path[e],e===this.path.length-1))return!1;e--,s--}}return s<0}_matchSegment(t,e,s){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!s)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!s)return!1;const n=e.counter??0;if("first"===t.position&&0!==n)return!1;if("odd"===t.position&&n%2!=1)return!1;if("even"===t.position&&n%2!=0)return!1;if("nth"===t.position&&n!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t)),keptAttrs:this._keptAttrs.map(t=>({...t}))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t)),this._keptAttrs=(t.keptAttrs||[]).map(t=>({...t}))}readOnly(){return this._view}}class h{constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._deepByTerminalTag=new Map,this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard()){const e=t.segments[t.segments.length-1];if(e&&"deep-wildcard"!==e.type&&"*"!==e.tag){const s=e.tag;this._deepByTerminalTag.has(s)||this._deepByTerminalTag.set(s,[]),this._deepByTerminalTag.get(s).push(t)}else this._deepWildcards.push(t);return this}const e=t.length,s=t.segments[t.segments.length-1],n=s?.tag;if(n&&"*"!==n){const s=`${e}:${n}`;this._byDepthAndTag.has(s)||this._byDepthAndTag.set(s,[]),this._byDepthAndTag.get(s).push(t)}else this._wildcardByDepth.has(e)||this._wildcardByDepth.set(e,[]),this._wildcardByDepth.get(e).push(t);return this}addAll(t){for(const e of t)this.add(e);return this}has(t){return this._patterns.has(t.pattern)}get size(){return this._patterns.size}seal(){return this._sealed=!0,this}get isSealed(){return this._sealed}matchesAny(t){return null!==this.findMatch(t)}findMatch(t){const e=t.getDepth(),s=t.getCurrentTag(),n=`${e}:${s}`,r=this._byDepthAndTag.get(n);if(r)for(let e=0;e<r.length;e++)if(t.matches(r[e]))return r[e];const h=this._wildcardByDepth.get(e);if(h)for(let e=0;e<h.length;e++)if(t.matches(h[e]))return h[e];const i=this._deepByTerminalTag.get(s);if(i)for(let e=0;e<i.length;e++)if(t.matches(i[e]))return i[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}const i={Expression:s,Matcher:r,ExpressionSet:h};module.exports=e})();
@@ -186,6 +186,42 @@ declare interface MatcherSnapshot {
186
186
  * Copy of sibling tracking maps
187
187
  */
188
188
  siblingStacks: Map<string, number>[];
189
+
190
+ /**
191
+ * Copy of the kept-attrs stack (see {@link PushOptions.keep})
192
+ */
193
+ keptAttrs: KeptAttrEntry[];
194
+ }
195
+
196
+ /**
197
+ * A single entry in the matcher's kept-attrs stack — an attribute value
198
+ * explicitly retained at push time via `{ keep: [...] }` so it remains
199
+ * reachable from descendants after the owning node is no longer current.
200
+ */
201
+ declare interface KeptAttrEntry {
202
+ /** Path depth (1-based) of the node that declared this kept attribute */
203
+ depth: number;
204
+ /** Attribute name */
205
+ name: string;
206
+ /** Attribute value at push time */
207
+ value: any;
208
+ }
209
+
210
+ /**
211
+ * Options for {@link Matcher.push}
212
+ */
213
+ declare interface PushOptions {
214
+ /**
215
+ * Names of attributes (from `attrValues`) to retain for ancestor lookup
216
+ * (`getAnyParentAttr` / `hasAnyParentAttr`) even after this node is no
217
+ * longer the current node.
218
+ *
219
+ * Use sparingly — this is for attributes you know you'll need much deeper
220
+ * in the tree (e.g. `xml:space`, a SOAP envelope's `version`), not a
221
+ * general substitute for `getAttrValue()`. Cost is proportional to
222
+ * `keep.length`, independent of path depth.
223
+ */
224
+ keep?: string[];
189
225
  }
190
226
 
191
227
  /**
@@ -253,6 +289,24 @@ declare interface ReadOnlyMatcher {
253
289
  */
254
290
  hasAttr(attrName: string): boolean;
255
291
 
292
+ /**
293
+ * Get the value of a "kept" attribute from the nearest ancestor (or
294
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
295
+ * Unlike `getAttrValue()`, this works regardless of how deep the path has
296
+ * gone since the attribute was pushed — but only for attribute names that
297
+ * were explicitly marked with `keep` at push time.
298
+ * @param attrName - Attribute name
299
+ * @returns The kept value, or undefined if no ancestor kept this attribute
300
+ */
301
+ getAnyParentAttr(attrName: string): any;
302
+
303
+ /**
304
+ * Check whether any ancestor (or the current node) kept the given
305
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
306
+ * @param attrName - Attribute name
307
+ */
308
+ hasAnyParentAttr(attrName: string): boolean;
309
+
256
310
  /**
257
311
  * Get current node's sibling position (child index in parent)
258
312
  * @returns Position index or -1 if path is empty
@@ -386,15 +440,23 @@ declare class Matcher {
386
440
  * @param tagName - Name of the tag
387
441
  * @param attrValues - Attribute key-value pairs for current node (optional)
388
442
  * @param namespace - Namespace for the tag (optional)
443
+ * @param options - Push options, e.g. `{ keep: ['version'] }` to retain
444
+ * specific attributes for ancestor lookup after this node stops being current
389
445
  *
390
446
  * @example
391
447
  * ```javascript
392
448
  * matcher.push("user", { id: "123", type: "admin" });
393
449
  * matcher.push("user", { id: "456" }, "ns");
394
450
  * matcher.push("container", null);
451
+ * matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] });
395
452
  * ```
396
453
  */
397
- push(tagName: string, attrValues?: Record<string, any> | null, namespace?: string | null): void;
454
+ push(
455
+ tagName: string,
456
+ attrValues?: Record<string, any> | null,
457
+ namespace?: string | null,
458
+ options?: PushOptions | null
459
+ ): void;
398
460
 
399
461
  /**
400
462
  * Pop the last tag from the path
@@ -434,6 +496,23 @@ declare class Matcher {
434
496
  */
435
497
  hasAttr(attrName: string): boolean;
436
498
 
499
+ /**
500
+ * Get the value of a "kept" attribute from the nearest ancestor (or current
501
+ * node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
502
+ * Cost is proportional to the number of currently-kept attributes, not
503
+ * path depth.
504
+ * @param attrName - Attribute name
505
+ * @returns The kept value, or undefined if no ancestor kept this attribute
506
+ */
507
+ getAnyParentAttr(attrName: string): any;
508
+
509
+ /**
510
+ * Check whether any ancestor (or the current node) kept the given
511
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
512
+ * @param attrName - Attribute name
513
+ */
514
+ hasAnyParentAttr(attrName: string): boolean;
515
+
437
516
  /**
438
517
  * Get current node's sibling position (child index in parent)
439
518
  * @returns Position index or -1 if path is empty
@@ -628,7 +707,9 @@ declare namespace pathExpressionMatcher {
628
707
  Segment,
629
708
  PathNode,
630
709
  MatcherSnapshot,
710
+ KeptAttrEntry,
711
+ PushOptions,
631
712
  };
632
713
  }
633
714
 
634
- export = pathExpressionMatcher;
715
+ export = pathExpressionMatcher;
@@ -1,2 +1,2 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.pem=e():t.pem=e()}(this,()=>(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{Expression:()=>s,ExpressionSet:()=>r,Matcher:()=>n,default:()=>h});class s{constructor(t,e={},s){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=s,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let s=0,i="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(i.trim()&&(e.push(this._parseSegment(i.trim())),i=""),e.push({type:"deep-wildcard"}),s+=2):(i.trim()&&e.push(this._parseSegment(i.trim())),i="",s++):(i+=t[s],s++);return i.trim()&&e.push(this._parseSegment(i.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,i=t;const n=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(n&&(i=n[1]+n[3],n[2])){const t=n[2].slice(1,-1);t&&(s=t)}let r,h,a=i;if(i.includes("::")){const e=i.indexOf("::");if(r=i.substring(0,e).trim(),a=i.substring(e+2).trim(),!r)throw new Error(`Invalid namespace in pattern: ${t}`)}let p=null;if(a.includes(":")){const t=a.lastIndexOf(":"),e=a.substring(0,t).trim(),s=a.substring(t+1).trim();["first","last","odd","even"].includes(s)||/^nth\(\d+\)$/.test(s)?(h=e,p=s):h=a}else h=a;if(!h)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=h,r&&(e.namespace=r),s)if(s.includes("=")){const t=s.indexOf("=");e.attrName=s.substring(0,t).trim(),e.attrValue=s.substring(t+1).trim()}else e.attrName=s.trim();if(p){const t=p.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=p}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class i{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const s=e[e.length-1];return void 0!==s.values&&t in s.values}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class n{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new i(this)}push(t,e=null,s=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const i=this.path.length;this.siblingStacks[i]||(this.siblingStacks[i]=new Map);const n=this.siblingStacks[i],r=s?`${s}:${t}`:t,h=n.get(r)||0;let a=0;for(const t of n.values())a+=t;n.set(r,h+1);const p={tag:t,position:a,counter:h};null!=s&&(p.namespace=s),null!=e&&(p.values=e),this.path.push(p)}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();return this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1),t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const s=t||this.separator;if(s===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,s=t.length-1;for(;s>=0&&e>=0;){const i=t[s];if("deep-wildcard"===i.type){if(s--,s<0)return!0;const i=t[s];let n=!1;for(let t=e;t>=0;t--)if(this._matchSegment(i,this.path[t],t===this.path.length-1)){e=t-1,s--,n=!0;break}if(!n)return!1}else{if(!this._matchSegment(i,this.path[e],e===this.path.length-1))return!1;e--,s--}}return s<0}_matchSegment(t,e,s){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!s)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!s)return!1;const i=e.counter??0;if("first"===t.position&&0!==i)return!1;if("odd"===t.position&&i%2!=1)return!1;if("even"===t.position&&i%2!=0)return!1;if("nth"===t.position&&i!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t))}readOnly(){return this._view}}class r{constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard())return this._deepWildcards.push(t),this;const e=t.length,s=t.segments[t.segments.length-1],i=s?.tag;if(i&&"*"!==i){const s=`${e}:${i}`;this._byDepthAndTag.has(s)||this._byDepthAndTag.set(s,[]),this._byDepthAndTag.get(s).push(t)}else this._wildcardByDepth.has(e)||this._wildcardByDepth.set(e,[]),this._wildcardByDepth.get(e).push(t);return this}addAll(t){for(const e of t)this.add(e);return this}has(t){return this._patterns.has(t.pattern)}get size(){return this._patterns.size}seal(){return this._sealed=!0,this}get isSealed(){return this._sealed}matchesAny(t){return null!==this.findMatch(t)}findMatch(t){const e=t.getDepth(),s=`${e}:${t.getCurrentTag()}`,i=this._byDepthAndTag.get(s);if(i)for(let e=0;e<i.length;e++)if(t.matches(i[e]))return i[e];const n=this._wildcardByDepth.get(e);if(n)for(let e=0;e<n.length;e++)if(t.matches(n[e]))return n[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}const h={Expression:s,Matcher:n,ExpressionSet:r};return e})());
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.pem=e():t.pem=e()}(this,()=>(()=>{"use strict";var t={d:(e,s)=>{for(var n in s)t.o(s,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:s[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{Expression:()=>s,ExpressionSet:()=>i,Matcher:()=>r,default:()=>h});class s{constructor(t,e={},s){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=s,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let s=0,n="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(n.trim()&&(e.push(this._parseSegment(n.trim())),n=""),e.push({type:"deep-wildcard"}),s+=2):(n.trim()&&e.push(this._parseSegment(n.trim())),n="",s++):(n+=t[s],s++);return n.trim()&&e.push(this._parseSegment(n.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,n=t;const r=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(r&&(n=r[1]+r[3],r[2])){const t=r[2].slice(1,-1);t&&(s=t)}let i,h,a=n;if(n.includes("::")){const e=n.indexOf("::");if(i=n.substring(0,e).trim(),a=n.substring(e+2).trim(),!i)throw new Error(`Invalid namespace in pattern: ${t}`)}let p=null;if(a.includes(":")){const t=a.lastIndexOf(":"),e=a.substring(0,t).trim(),s=a.substring(t+1).trim();["first","last","odd","even"].includes(s)||/^nth\(\d+\)$/.test(s)?(h=e,p=s):h=a}else h=a;if(!h)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=h,i&&(e.namespace=i),s)if(s.includes("=")){const t=s.indexOf("=");e.attrName=s.substring(0,t).trim(),e.attrValue=s.substring(t+1).trim()}else e.attrName=s.trim();if(p){const t=p.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=p}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class n{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const s=e[e.length-1];return void 0!==s.values&&t in s.values}getAnyParentAttr(t){return this._matcher.getAnyParentAttr(t)}hasAnyParentAttr(t){return this._matcher.hasAnyParentAttr(t)}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class r{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new n(this),this._keptAttrs=[]}push(t,e=null,s=null,n=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const r=this.path.length;this.siblingStacks[r]||(this.siblingStacks[r]=new Map);const i=this.siblingStacks[r],h=s?`${s}:${t}`:t,a=i.get(h)||0;let p=0;for(const t of i.values())p+=t;i.set(h,a+1);const l={tag:t,position:p,counter:a};null!=s&&(l.namespace=s),null!=e&&(l.values=e),this.path.push(l);const o=this.path.length,g=null!==n?n.keep:null;if(null!=g&&g.length>0&&e)for(let t=0;t<g.length;t++){const s=g[t];void 0!==e[s]&&this._keptAttrs.push({depth:o,name:s,value:e[s]})}}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1);const e=this.path.length+1;for(;this._keptAttrs.length>0&&this._keptAttrs[this._keptAttrs.length-1].depth>=e;)this._keptAttrs.pop();return t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getAnyParentAttr(t){const e=this._keptAttrs;for(let s=e.length-1;s>=0;s--)if(e[s].name===t)return e[s].value}hasAnyParentAttr(t){const e=this._keptAttrs;for(let s=e.length-1;s>=0;s--)if(e[s].name===t)return!0;return!1}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const s=t||this.separator;if(s===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[],this._keptAttrs=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,s=t.length-1;for(;s>=0&&e>=0;){const n=t[s];if("deep-wildcard"===n.type){if(s--,s<0)return!0;const n=t[s];let r=!1;for(let t=e;t>=0;t--)if(this._matchSegment(n,this.path[t],t===this.path.length-1)){e=t-1,s--,r=!0;break}if(!r)return!1}else{if(!this._matchSegment(n,this.path[e],e===this.path.length-1))return!1;e--,s--}}return s<0}_matchSegment(t,e,s){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!s)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!s)return!1;const n=e.counter??0;if("first"===t.position&&0!==n)return!1;if("odd"===t.position&&n%2!=1)return!1;if("even"===t.position&&n%2!=0)return!1;if("nth"===t.position&&n!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t)),keptAttrs:this._keptAttrs.map(t=>({...t}))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t)),this._keptAttrs=(t.keptAttrs||[]).map(t=>({...t}))}readOnly(){return this._view}}class i{constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._deepByTerminalTag=new Map,this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard()){const e=t.segments[t.segments.length-1];if(e&&"deep-wildcard"!==e.type&&"*"!==e.tag){const s=e.tag;this._deepByTerminalTag.has(s)||this._deepByTerminalTag.set(s,[]),this._deepByTerminalTag.get(s).push(t)}else this._deepWildcards.push(t);return this}const e=t.length,s=t.segments[t.segments.length-1],n=s?.tag;if(n&&"*"!==n){const s=`${e}:${n}`;this._byDepthAndTag.has(s)||this._byDepthAndTag.set(s,[]),this._byDepthAndTag.get(s).push(t)}else this._wildcardByDepth.has(e)||this._wildcardByDepth.set(e,[]),this._wildcardByDepth.get(e).push(t);return this}addAll(t){for(const e of t)this.add(e);return this}has(t){return this._patterns.has(t.pattern)}get size(){return this._patterns.size}seal(){return this._sealed=!0,this}get isSealed(){return this._sealed}matchesAny(t){return null!==this.findMatch(t)}findMatch(t){const e=t.getDepth(),s=t.getCurrentTag(),n=`${e}:${s}`,r=this._byDepthAndTag.get(n);if(r)for(let e=0;e<r.length;e++)if(t.matches(r[e]))return r[e];const i=this._wildcardByDepth.get(e);if(i)for(let e=0;e<i.length;e++)if(t.matches(i[e]))return i[e];const h=this._deepByTerminalTag.get(s);if(h)for(let e=0;e<h.length;e++)if(t.matches(h[e]))return h[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}const h={Expression:s,Matcher:r,ExpressionSet:i};return e})());
2
2
  //# sourceMappingURL=pem.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"./lib/pem.min.js","mappings":"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","sources":["webpack://pem/webpack/universalModuleDefinition","webpack://pem/webpack/bootstrap","webpack://pem/webpack/runtime/define property getters","webpack://pem/webpack/runtime/hasOwnProperty shorthand","webpack://pem/webpack/runtime/make namespace object","webpack://pem/./src/Expression.js","webpack://pem/./src/Matcher.js","webpack://pem/./src/ExpressionSet.js","webpack://pem/./src/index.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"pem\"] = factory();\n\telse\n\t\troot[\"pem\"] = factory();\n})(this, () => {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Expression - Parses and stores a tag pattern expression\n * \n * Patterns are parsed once and stored in an optimized structure for fast matching.\n * \n * @example\n * const expr = new Expression(\"root.users.user\");\n * const expr2 = new Expression(\"..user[id]:first\");\n * const expr3 = new Expression(\"root/users/user\", { separator: '/' });\n */\nexport default class Expression {\n /**\n * Create a new Expression\n * @param {string} pattern - Pattern string (e.g., \"root.users.user\", \"..user[id]\")\n * @param {Object} options - Configuration options\n * @param {string} options.separator - Path separator (default: '.')\n */\n constructor(pattern, options = {}, data) {\n this.pattern = pattern;\n this.separator = options.separator || '.';\n this.segments = this._parse(pattern);\n this.data = data;\n // Cache expensive checks for performance (O(1) instead of O(n))\n this._hasDeepWildcard = this.segments.some(seg => seg.type === 'deep-wildcard');\n this._hasAttributeCondition = this.segments.some(seg => seg.attrName !== undefined);\n this._hasPositionSelector = this.segments.some(seg => seg.position !== undefined);\n }\n\n /**\n * Parse pattern string into segments\n * @private\n * @param {string} pattern - Pattern to parse\n * @returns {Array} Array of segment objects\n */\n _parse(pattern) {\n const segments = [];\n\n // Split by separator but handle \"..\" specially\n let i = 0;\n let currentPart = '';\n\n while (i < pattern.length) {\n if (pattern[i] === this.separator) {\n // Check if next char is also separator (deep wildcard)\n if (i + 1 < pattern.length && pattern[i + 1] === this.separator) {\n // Flush current part if any\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n currentPart = '';\n }\n // Add deep wildcard\n segments.push({ type: 'deep-wildcard' });\n i += 2; // Skip both separators\n } else {\n // Regular separator\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n }\n currentPart = '';\n i++;\n }\n } else {\n currentPart += pattern[i];\n i++;\n }\n }\n\n // Flush remaining part\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n }\n\n return segments;\n }\n\n /**\n * Parse a single segment\n * @private\n * @param {string} part - Segment string (e.g., \"user\", \"ns::user\", \"user[id]\", \"ns::user:first\")\n * @returns {Object} Segment object\n */\n _parseSegment(part) {\n const segment = { type: 'tag' };\n\n // NEW NAMESPACE SYNTAX (v2.0):\n // ============================\n // Namespace uses DOUBLE colon (::)\n // Position uses SINGLE colon (:)\n // \n // Examples:\n // \"user\" → tag\n // \"user:first\" → tag + position\n // \"user[id]\" → tag + attribute\n // \"user[id]:first\" → tag + attribute + position\n // \"ns::user\" → namespace + tag\n // \"ns::user:first\" → namespace + tag + position\n // \"ns::user[id]\" → namespace + tag + attribute\n // \"ns::user[id]:first\" → namespace + tag + attribute + position\n // \"ns::first\" → namespace + tag named \"first\" (NO ambiguity!)\n //\n // This eliminates all ambiguity:\n // :: = namespace separator\n // : = position selector\n // [] = attributes\n\n // Step 1: Extract brackets [attr] or [attr=value]\n let bracketContent = null;\n let withoutBrackets = part;\n\n const bracketMatch = part.match(/^([^\\[]+)(\\[[^\\]]*\\])(.*)$/);\n if (bracketMatch) {\n withoutBrackets = bracketMatch[1] + bracketMatch[3];\n if (bracketMatch[2]) {\n const content = bracketMatch[2].slice(1, -1);\n if (content) {\n bracketContent = content;\n }\n }\n }\n\n // Step 2: Check for namespace (double colon ::)\n let namespace = undefined;\n let tagAndPosition = withoutBrackets;\n\n if (withoutBrackets.includes('::')) {\n const nsIndex = withoutBrackets.indexOf('::');\n namespace = withoutBrackets.substring(0, nsIndex).trim();\n tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim(); // Skip ::\n\n if (!namespace) {\n throw new Error(`Invalid namespace in pattern: ${part}`);\n }\n }\n\n // Step 3: Parse tag and position (single colon :)\n let tag = undefined;\n let positionMatch = null;\n\n if (tagAndPosition.includes(':')) {\n const colonIndex = tagAndPosition.lastIndexOf(':'); // Use last colon for position\n const tagPart = tagAndPosition.substring(0, colonIndex).trim();\n const posPart = tagAndPosition.substring(colonIndex + 1).trim();\n\n // Verify position is a valid keyword\n const isPositionKeyword = ['first', 'last', 'odd', 'even'].includes(posPart) ||\n /^nth\\(\\d+\\)$/.test(posPart);\n\n if (isPositionKeyword) {\n tag = tagPart;\n positionMatch = posPart;\n } else {\n // Not a valid position keyword, treat whole thing as tag\n tag = tagAndPosition;\n }\n } else {\n tag = tagAndPosition;\n }\n\n if (!tag) {\n throw new Error(`Invalid segment pattern: ${part}`);\n }\n\n segment.tag = tag;\n if (namespace) {\n segment.namespace = namespace;\n }\n\n // Step 4: Parse attributes\n if (bracketContent) {\n if (bracketContent.includes('=')) {\n const eqIndex = bracketContent.indexOf('=');\n segment.attrName = bracketContent.substring(0, eqIndex).trim();\n segment.attrValue = bracketContent.substring(eqIndex + 1).trim();\n } else {\n segment.attrName = bracketContent.trim();\n }\n }\n\n // Step 5: Parse position selector\n if (positionMatch) {\n const nthMatch = positionMatch.match(/^nth\\((\\d+)\\)$/);\n if (nthMatch) {\n segment.position = 'nth';\n segment.positionValue = parseInt(nthMatch[1], 10);\n } else {\n segment.position = positionMatch;\n }\n }\n\n return segment;\n }\n\n /**\n * Get the number of segments\n * @returns {number}\n */\n get length() {\n return this.segments.length;\n }\n\n /**\n * Check if expression contains deep wildcard\n * @returns {boolean}\n */\n hasDeepWildcard() {\n return this._hasDeepWildcard;\n }\n\n /**\n * Check if expression has attribute conditions\n * @returns {boolean}\n */\n hasAttributeCondition() {\n return this._hasAttributeCondition;\n }\n\n /**\n * Check if expression has position selectors\n * @returns {boolean}\n */\n hasPositionSelector() {\n return this._hasPositionSelector;\n }\n\n /**\n * Get string representation\n * @returns {string}\n */\n toString() {\n return this.pattern;\n }\n}","import ExpressionSet from \"./ExpressionSet.js\";\n\n/**\n * MatcherView - A lightweight read-only view over a Matcher's internal state.\n *\n * Created once by Matcher and reused across all callbacks. Holds a direct\n * reference to the parent Matcher so it always reflects current parser state\n * with zero copying or freezing overhead.\n *\n * Users receive this via {@link Matcher#readOnly} or directly from parser\n * callbacks. It exposes all query and matching methods but has no mutation\n * methods — misuse is caught at the TypeScript level rather than at runtime.\n *\n * @example\n * const matcher = new Matcher();\n * const view = matcher.readOnly();\n *\n * matcher.push(\"root\", {});\n * view.getCurrentTag(); // \"root\"\n * view.getDepth(); // 1\n */\nexport class MatcherView {\n /**\n * @param {Matcher} matcher - The parent Matcher instance to read from.\n */\n constructor(matcher) {\n this._matcher = matcher;\n }\n\n /**\n * Get the path separator used by the parent matcher.\n * @returns {string}\n */\n get separator() {\n return this._matcher.separator;\n }\n\n /**\n * Get current tag name.\n * @returns {string|undefined}\n */\n getCurrentTag() {\n const path = this._matcher.path;\n return path.length > 0 ? path[path.length - 1].tag : undefined;\n }\n\n /**\n * Get current namespace.\n * @returns {string|undefined}\n */\n getCurrentNamespace() {\n const path = this._matcher.path;\n return path.length > 0 ? path[path.length - 1].namespace : undefined;\n }\n\n /**\n * Get current node's attribute value.\n * @param {string} attrName\n * @returns {*}\n */\n getAttrValue(attrName) {\n const path = this._matcher.path;\n if (path.length === 0) return undefined;\n return path[path.length - 1].values?.[attrName];\n }\n\n /**\n * Check if current node has an attribute.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAttr(attrName) {\n const path = this._matcher.path;\n if (path.length === 0) return false;\n const current = path[path.length - 1];\n return current.values !== undefined && attrName in current.values;\n }\n\n /**\n * Get current node's sibling position (child index in parent).\n * @returns {number}\n */\n getPosition() {\n const path = this._matcher.path;\n if (path.length === 0) return -1;\n return path[path.length - 1].position ?? 0;\n }\n\n /**\n * Get current node's repeat counter (occurrence count of this tag name).\n * @returns {number}\n */\n getCounter() {\n const path = this._matcher.path;\n if (path.length === 0) return -1;\n return path[path.length - 1].counter ?? 0;\n }\n\n /**\n * Get current node's sibling index (alias for getPosition).\n * @returns {number}\n * @deprecated Use getPosition() or getCounter() instead\n */\n getIndex() {\n return this.getPosition();\n }\n\n /**\n * Get current path depth.\n * @returns {number}\n */\n getDepth() {\n return this._matcher.path.length;\n }\n\n /**\n * Get path as string.\n * @param {string} [separator] - Optional separator (uses default if not provided)\n * @param {boolean} [includeNamespace=true]\n * @returns {string}\n */\n toString(separator, includeNamespace = true) {\n return this._matcher.toString(separator, includeNamespace);\n }\n\n /**\n * Get path as array of tag names.\n * @returns {string[]}\n */\n toArray() {\n return this._matcher.path.map(n => n.tag);\n }\n\n /**\n * Match current path against an Expression.\n * @param {Expression} expression\n * @returns {boolean}\n */\n matches(expression) {\n return this._matcher.matches(expression);\n }\n\n /**\n * Match any expression in the given set against the current path.\n * @param {ExpressionSet} exprSet\n * @returns {boolean}\n */\n matchesAny(exprSet) {\n return exprSet.matchesAny(this._matcher);\n }\n}\n\n/**\n * Matcher - Tracks current path in XML/JSON tree and matches against Expressions.\n *\n * The matcher maintains a stack of nodes representing the current path from root to\n * current tag. It only stores attribute values for the current (top) node to minimize\n * memory usage. Sibling tracking is used to auto-calculate position and counter.\n *\n * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to\n * user callbacks — it always reflects current state with no Proxy overhead.\n *\n * @example\n * const matcher = new Matcher();\n * matcher.push(\"root\", {});\n * matcher.push(\"users\", {});\n * matcher.push(\"user\", { id: \"123\", type: \"admin\" });\n *\n * const expr = new Expression(\"root.users.user\");\n * matcher.matches(expr); // true\n */\nexport default class Matcher {\n /**\n * Create a new Matcher.\n * @param {Object} [options={}]\n * @param {string} [options.separator='.'] - Default path separator\n */\n constructor(options = {}) {\n this.separator = options.separator || '.';\n this.path = [];\n this.siblingStacks = [];\n // Each path node: { tag, values, position, counter, namespace? }\n // values only present for current (last) node\n // Each siblingStacks entry: Map<tagName, count> tracking occurrences at each level\n this._pathStringCache = null;\n this._view = new MatcherView(this);\n }\n\n /**\n * Push a new tag onto the path.\n * @param {string} tagName\n * @param {Object|null} [attrValues=null]\n * @param {string|null} [namespace=null]\n */\n push(tagName, attrValues = null, namespace = null) {\n this._pathStringCache = null;\n\n // Remove values from previous current node (now becoming ancestor)\n if (this.path.length > 0) {\n this.path[this.path.length - 1].values = undefined;\n }\n\n // Get or create sibling tracking for current level\n const currentLevel = this.path.length;\n if (!this.siblingStacks[currentLevel]) {\n this.siblingStacks[currentLevel] = new Map();\n }\n\n const siblings = this.siblingStacks[currentLevel];\n\n // Create a unique key for sibling tracking that includes namespace\n const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;\n\n // Calculate counter (how many times this tag appeared at this level)\n const counter = siblings.get(siblingKey) || 0;\n\n // Calculate position (total children at this level so far)\n let position = 0;\n for (const count of siblings.values()) {\n position += count;\n }\n\n // Update sibling count for this tag\n siblings.set(siblingKey, counter + 1);\n\n // Create new node\n const node = {\n tag: tagName,\n position: position,\n counter: counter\n };\n\n if (namespace !== null && namespace !== undefined) {\n node.namespace = namespace;\n }\n\n if (attrValues !== null && attrValues !== undefined) {\n node.values = attrValues;\n }\n\n this.path.push(node);\n }\n\n /**\n * Pop the last tag from the path.\n * @returns {Object|undefined} The popped node\n */\n pop() {\n if (this.path.length === 0) return undefined;\n this._pathStringCache = null;\n\n const node = this.path.pop();\n\n if (this.siblingStacks.length > this.path.length + 1) {\n this.siblingStacks.length = this.path.length + 1;\n }\n\n return node;\n }\n\n /**\n * Update current node's attribute values.\n * Useful when attributes are parsed after push.\n * @param {Object} attrValues\n */\n updateCurrent(attrValues) {\n if (this.path.length > 0) {\n const current = this.path[this.path.length - 1];\n if (attrValues !== null && attrValues !== undefined) {\n current.values = attrValues;\n }\n }\n }\n\n /**\n * Get current tag name.\n * @returns {string|undefined}\n */\n getCurrentTag() {\n return this.path.length > 0 ? this.path[this.path.length - 1].tag : undefined;\n }\n\n /**\n * Get current namespace.\n * @returns {string|undefined}\n */\n getCurrentNamespace() {\n return this.path.length > 0 ? this.path[this.path.length - 1].namespace : undefined;\n }\n\n /**\n * Get current node's attribute value.\n * @param {string} attrName\n * @returns {*}\n */\n getAttrValue(attrName) {\n if (this.path.length === 0) return undefined;\n return this.path[this.path.length - 1].values?.[attrName];\n }\n\n /**\n * Check if current node has an attribute.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAttr(attrName) {\n if (this.path.length === 0) return false;\n const current = this.path[this.path.length - 1];\n return current.values !== undefined && attrName in current.values;\n }\n\n /**\n * Get current node's sibling position (child index in parent).\n * @returns {number}\n */\n getPosition() {\n if (this.path.length === 0) return -1;\n return this.path[this.path.length - 1].position ?? 0;\n }\n\n /**\n * Get current node's repeat counter (occurrence count of this tag name).\n * @returns {number}\n */\n getCounter() {\n if (this.path.length === 0) return -1;\n return this.path[this.path.length - 1].counter ?? 0;\n }\n\n /**\n * Get current node's sibling index (alias for getPosition).\n * @returns {number}\n * @deprecated Use getPosition() or getCounter() instead\n */\n getIndex() {\n return this.getPosition();\n }\n\n /**\n * Get current path depth.\n * @returns {number}\n */\n getDepth() {\n return this.path.length;\n }\n\n /**\n * Get path as string.\n * @param {string} [separator] - Optional separator (uses default if not provided)\n * @param {boolean} [includeNamespace=true]\n * @returns {string}\n */\n toString(separator, includeNamespace = true) {\n const sep = separator || this.separator;\n const isDefault = (sep === this.separator && includeNamespace === true);\n\n if (isDefault) {\n if (this._pathStringCache !== null) {\n return this._pathStringCache;\n }\n const result = this.path.map(n =>\n (n.namespace) ? `${n.namespace}:${n.tag}` : n.tag\n ).join(sep);\n this._pathStringCache = result;\n return result;\n }\n\n return this.path.map(n =>\n (includeNamespace && n.namespace) ? `${n.namespace}:${n.tag}` : n.tag\n ).join(sep);\n }\n\n /**\n * Get path as array of tag names.\n * @returns {string[]}\n */\n toArray() {\n return this.path.map(n => n.tag);\n }\n\n /**\n * Reset the path to empty.\n */\n reset() {\n this._pathStringCache = null;\n this.path = [];\n this.siblingStacks = [];\n }\n\n /**\n * Match current path against an Expression.\n * @param {Expression} expression\n * @returns {boolean}\n */\n matches(expression) {\n const segments = expression.segments;\n\n if (segments.length === 0) {\n return false;\n }\n\n if (expression.hasDeepWildcard()) {\n return this._matchWithDeepWildcard(segments);\n }\n\n return this._matchSimple(segments);\n }\n\n /**\n * @private\n */\n _matchSimple(segments) {\n if (this.path.length !== segments.length) {\n return false;\n }\n\n for (let i = 0; i < segments.length; i++) {\n if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * @private\n */\n _matchWithDeepWildcard(segments) {\n let pathIdx = this.path.length - 1;\n let segIdx = segments.length - 1;\n\n while (segIdx >= 0 && pathIdx >= 0) {\n const segment = segments[segIdx];\n\n if (segment.type === 'deep-wildcard') {\n segIdx--;\n\n if (segIdx < 0) {\n return true;\n }\n\n const nextSeg = segments[segIdx];\n let found = false;\n\n for (let i = pathIdx; i >= 0; i--) {\n if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) {\n pathIdx = i - 1;\n segIdx--;\n found = true;\n break;\n }\n }\n\n if (!found) {\n return false;\n }\n } else {\n if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) {\n return false;\n }\n pathIdx--;\n segIdx--;\n }\n }\n\n return segIdx < 0;\n }\n\n /**\n * @private\n */\n _matchSegment(segment, node, isCurrentNode) {\n if (segment.tag !== '*' && segment.tag !== node.tag) {\n return false;\n }\n\n if (segment.namespace !== undefined) {\n if (segment.namespace !== '*' && segment.namespace !== node.namespace) {\n return false;\n }\n }\n\n if (segment.attrName !== undefined) {\n if (!isCurrentNode) {\n return false;\n }\n\n if (!node.values || !(segment.attrName in node.values)) {\n return false;\n }\n\n if (segment.attrValue !== undefined) {\n if (String(node.values[segment.attrName]) !== String(segment.attrValue)) {\n return false;\n }\n }\n }\n\n if (segment.position !== undefined) {\n if (!isCurrentNode) {\n return false;\n }\n\n const counter = node.counter ?? 0;\n\n if (segment.position === 'first' && counter !== 0) {\n return false;\n } else if (segment.position === 'odd' && counter % 2 !== 1) {\n return false;\n } else if (segment.position === 'even' && counter % 2 !== 0) {\n return false;\n } else if (segment.position === 'nth' && counter !== segment.positionValue) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Match any expression in the given set against the current path.\n * @param {ExpressionSet} exprSet\n * @returns {boolean}\n */\n matchesAny(exprSet) {\n return exprSet.matchesAny(this);\n }\n\n /**\n * Create a snapshot of current state.\n * @returns {Object}\n */\n snapshot() {\n return {\n path: this.path.map(node => ({ ...node })),\n siblingStacks: this.siblingStacks.map(map => new Map(map))\n };\n }\n\n /**\n * Restore state from snapshot.\n * @param {Object} snapshot\n */\n restore(snapshot) {\n this._pathStringCache = null;\n this.path = snapshot.path.map(node => ({ ...node }));\n this.siblingStacks = snapshot.siblingStacks.map(map => new Map(map));\n }\n\n /**\n * Return the read-only {@link MatcherView} for this matcher.\n *\n * The same instance is returned on every call — no allocation occurs.\n * It always reflects the current parser state and is safe to pass to\n * user callbacks without risk of accidental mutation.\n *\n * @returns {MatcherView}\n *\n * @example\n * const view = matcher.readOnly();\n * // pass view to callbacks — it stays in sync automatically\n * view.matches(expr); // ✓\n * view.getCurrentTag(); // ✓\n * // view.push(...) // ✗ method does not exist — caught by TypeScript\n */\n readOnly() {\n return this._view;\n }\n}","/**\n * ExpressionSet - An indexed collection of Expressions for efficient bulk matching\n *\n * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes\n * them at insertion time by depth and terminal tag name. At match time, only\n * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1)\n * lookup plus O(small bucket) matches.\n *\n * Three buckets are maintained:\n * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first)\n * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only)\n * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed)\n *\n * @example\n * import { Expression, ExpressionSet } from 'fast-xml-tagger';\n *\n * // Build once at config time\n * const stopNodes = new ExpressionSet();\n * stopNodes.add(new Expression('root.users.user'));\n * stopNodes.add(new Expression('root.config.setting'));\n * stopNodes.add(new Expression('..script'));\n *\n * // Query on every tag — hot path\n * if (stopNodes.matchesAny(matcher)) { ... }\n */\nexport default class ExpressionSet {\n constructor() {\n /** @type {Map<string, import('./Expression.js').default[]>} depth:tag → expressions */\n this._byDepthAndTag = new Map();\n\n /** @type {Map<number, import('./Expression.js').default[]>} depth → wildcard-tag expressions */\n this._wildcardByDepth = new Map();\n\n /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */\n this._deepWildcards = [];\n\n /** @type {Set<string>} pattern strings already added — used for deduplication */\n this._patterns = new Set();\n\n /** @type {boolean} whether the set is sealed against further additions */\n this._sealed = false;\n }\n\n /**\n * Add an Expression to the set.\n * Duplicate patterns (same pattern string) are silently ignored.\n *\n * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance\n * @returns {this} for chaining\n * @throws {TypeError} if called after seal()\n *\n * @example\n * set.add(new Expression('root.users.user'));\n * set.add(new Expression('..script'));\n */\n add(expression) {\n if (this._sealed) {\n throw new TypeError(\n 'ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.'\n );\n }\n\n // Deduplicate by pattern string\n if (this._patterns.has(expression.pattern)) return this;\n this._patterns.add(expression.pattern);\n\n if (expression.hasDeepWildcard()) {\n this._deepWildcards.push(expression);\n return this;\n }\n\n const depth = expression.length;\n const lastSeg = expression.segments[expression.segments.length - 1];\n const tag = lastSeg?.tag;\n\n if (!tag || tag === '*') {\n // Can index by depth but not by tag\n if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []);\n this._wildcardByDepth.get(depth).push(expression);\n } else {\n // Tightest bucket: depth + tag\n const key = `${depth}:${tag}`;\n if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []);\n this._byDepthAndTag.get(key).push(expression);\n }\n\n return this;\n }\n\n /**\n * Add multiple expressions at once.\n *\n * @param {import('./Expression.js').default[]} expressions - Array of Expression instances\n * @returns {this} for chaining\n *\n * @example\n * set.addAll([\n * new Expression('root.users.user'),\n * new Expression('root.config.setting'),\n * ]);\n */\n addAll(expressions) {\n for (const expr of expressions) this.add(expr);\n return this;\n }\n\n /**\n * Check whether a pattern string is already present in the set.\n *\n * @param {import('./Expression.js').default} expression\n * @returns {boolean}\n */\n has(expression) {\n return this._patterns.has(expression.pattern);\n }\n\n /**\n * Number of expressions in the set.\n * @type {number}\n */\n get size() {\n return this._patterns.size;\n }\n\n /**\n * Seal the set against further modifications.\n * Useful to prevent accidental mutations after config is built.\n * Calling add() or addAll() on a sealed set throws a TypeError.\n *\n * @returns {this}\n */\n seal() {\n this._sealed = true;\n return this;\n }\n\n /**\n * Whether the set has been sealed.\n * @type {boolean}\n */\n get isSealed() {\n return this._sealed;\n }\n\n /**\n * Test whether the matcher's current path matches any expression in the set.\n *\n * Evaluation order (cheapest → most expensive):\n * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions\n * 2. Depth-only wildcard bucket — O(1) lookup, rare\n * 3. Deep-wildcard list — always checked, but usually small\n *\n * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)\n * @returns {boolean} true if any expression matches the current path\n *\n * @example\n * if (stopNodes.matchesAny(matcher)) {\n * // handle stop node\n * }\n */\n matchesAny(matcher) {\n return this.findMatch(matcher) !== null;\n }\n /**\n * Find and return the first Expression that matches the matcher's current path.\n *\n * Uses the same evaluation order as matchesAny (cheapest → most expensive):\n * 1. Exact depth + tag bucket\n * 2. Depth-only wildcard bucket\n * 3. Deep-wildcard list\n *\n * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)\n * @returns {import('./Expression.js').default | null} the first matching Expression, or null\n *\n * @example\n * const expr = stopNodes.findMatch(matcher);\n * if (expr) {\n * // access expr.config, expr.pattern, etc.\n * }\n */\n findMatch(matcher) {\n const depth = matcher.getDepth();\n const tag = matcher.getCurrentTag();\n\n // 1. Tightest bucket — most expressions live here\n const exactKey = `${depth}:${tag}`;\n const exactBucket = this._byDepthAndTag.get(exactKey);\n if (exactBucket) {\n for (let i = 0; i < exactBucket.length; i++) {\n if (matcher.matches(exactBucket[i])) return exactBucket[i];\n }\n }\n\n // 2. Depth-matched wildcard-tag expressions\n const wildcardBucket = this._wildcardByDepth.get(depth);\n if (wildcardBucket) {\n for (let i = 0; i < wildcardBucket.length; i++) {\n if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i];\n }\n }\n\n // 3. Deep wildcards — cannot be pre-filtered by depth or tag\n for (let i = 0; i < this._deepWildcards.length; i++) {\n if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];\n }\n\n return null;\n }\n}\n","/**\n * fast-xml-tagger - XML/JSON path matching library\n * \n * Provides efficient path tracking and pattern matching for XML/JSON parsers.\n * \n * @example\n * import { Expression, Matcher } from 'fast-xml-tagger';\n * \n * // Create expression (parse once)\n * const expr = new Expression(\"root.users.user[id]\");\n * \n * // Create matcher (track path)\n * const matcher = new Matcher();\n * matcher.push(\"root\", [], {}, 0);\n * matcher.push(\"users\", [], {}, 0);\n * matcher.push(\"user\", [\"id\", \"type\"], { id: \"123\", type: \"admin\" }, 0);\n * \n * // Match\n * if (matcher.matches(expr)) {\n * console.log(\"Match found!\");\n * }\n */\n\nimport Expression from './Expression.js';\nimport Matcher from './Matcher.js';\nimport ExpressionSet from './ExpressionSet.js';\n\nexport { Expression, Matcher, ExpressionSet };\nexport default { Expression, Matcher, ExpressionSet };\n"],"names":["root","factory","exports","module","define","amd","this","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","Expression","constructor","pattern","options","data","separator","segments","_parse","_hasDeepWildcard","some","seg","type","_hasAttributeCondition","undefined","attrName","_hasPositionSelector","position","i","currentPart","length","trim","push","_parseSegment","part","segment","bracketContent","withoutBrackets","bracketMatch","match","content","slice","namespace","tag","tagAndPosition","includes","nsIndex","indexOf","substring","Error","positionMatch","colonIndex","lastIndexOf","tagPart","posPart","test","eqIndex","attrValue","nthMatch","positionValue","parseInt","hasDeepWildcard","hasAttributeCondition","hasPositionSelector","toString","MatcherView","matcher","_matcher","getCurrentTag","path","getCurrentNamespace","getAttrValue","values","hasAttr","current","getPosition","getCounter","counter","getIndex","getDepth","includeNamespace","toArray","map","n","matches","expression","matchesAny","exprSet","Matcher","siblingStacks","_pathStringCache","_view","tagName","attrValues","currentLevel","Map","siblings","siblingKey","count","set","node","pop","updateCurrent","sep","result","join","reset","_matchWithDeepWildcard","_matchSimple","_matchSegment","pathIdx","segIdx","nextSeg","found","isCurrentNode","String","snapshot","restore","readOnly","ExpressionSet","_byDepthAndTag","_wildcardByDepth","_deepWildcards","_patterns","Set","_sealed","add","TypeError","has","depth","lastSeg","addAll","expressions","expr","size","seal","isSealed","findMatch","exactKey","exactBucket","wildcardBucket"],"sourceRoot":""}
1
+ {"version":3,"file":"./lib/pem.min.js","mappings":"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","sources":["webpack://pem/webpack/universalModuleDefinition","webpack://pem/webpack/bootstrap","webpack://pem/webpack/runtime/define property getters","webpack://pem/webpack/runtime/hasOwnProperty shorthand","webpack://pem/webpack/runtime/make namespace object","webpack://pem/./src/Expression.js","webpack://pem/./src/Matcher.js","webpack://pem/./src/ExpressionSet.js","webpack://pem/./src/index.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"pem\"] = factory();\n\telse\n\t\troot[\"pem\"] = factory();\n})(this, () => {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Expression - Parses and stores a tag pattern expression\n * \n * Patterns are parsed once and stored in an optimized structure for fast matching.\n * \n * @example\n * const expr = new Expression(\"root.users.user\");\n * const expr2 = new Expression(\"..user[id]:first\");\n * const expr3 = new Expression(\"root/users/user\", { separator: '/' });\n */\nexport default class Expression {\n /**\n * Create a new Expression\n * @param {string} pattern - Pattern string (e.g., \"root.users.user\", \"..user[id]\")\n * @param {Object} options - Configuration options\n * @param {string} options.separator - Path separator (default: '.')\n */\n constructor(pattern, options = {}, data) {\n this.pattern = pattern;\n this.separator = options.separator || '.';\n this.segments = this._parse(pattern);\n this.data = data;\n // Cache expensive checks for performance (O(1) instead of O(n))\n this._hasDeepWildcard = this.segments.some(seg => seg.type === 'deep-wildcard');\n this._hasAttributeCondition = this.segments.some(seg => seg.attrName !== undefined);\n this._hasPositionSelector = this.segments.some(seg => seg.position !== undefined);\n }\n\n /**\n * Parse pattern string into segments\n * @private\n * @param {string} pattern - Pattern to parse\n * @returns {Array} Array of segment objects\n */\n _parse(pattern) {\n const segments = [];\n\n // Split by separator but handle \"..\" specially\n let i = 0;\n let currentPart = '';\n\n while (i < pattern.length) {\n if (pattern[i] === this.separator) {\n // Check if next char is also separator (deep wildcard)\n if (i + 1 < pattern.length && pattern[i + 1] === this.separator) {\n // Flush current part if any\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n currentPart = '';\n }\n // Add deep wildcard\n segments.push({ type: 'deep-wildcard' });\n i += 2; // Skip both separators\n } else {\n // Regular separator\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n }\n currentPart = '';\n i++;\n }\n } else {\n currentPart += pattern[i];\n i++;\n }\n }\n\n // Flush remaining part\n if (currentPart.trim()) {\n segments.push(this._parseSegment(currentPart.trim()));\n }\n\n return segments;\n }\n\n /**\n * Parse a single segment\n * @private\n * @param {string} part - Segment string (e.g., \"user\", \"ns::user\", \"user[id]\", \"ns::user:first\")\n * @returns {Object} Segment object\n */\n _parseSegment(part) {\n const segment = { type: 'tag' };\n\n // NEW NAMESPACE SYNTAX (v2.0):\n // ============================\n // Namespace uses DOUBLE colon (::)\n // Position uses SINGLE colon (:)\n // \n // Examples:\n // \"user\" → tag\n // \"user:first\" → tag + position\n // \"user[id]\" → tag + attribute\n // \"user[id]:first\" → tag + attribute + position\n // \"ns::user\" → namespace + tag\n // \"ns::user:first\" → namespace + tag + position\n // \"ns::user[id]\" → namespace + tag + attribute\n // \"ns::user[id]:first\" → namespace + tag + attribute + position\n // \"ns::first\" → namespace + tag named \"first\" (NO ambiguity!)\n //\n // This eliminates all ambiguity:\n // :: = namespace separator\n // : = position selector\n // [] = attributes\n\n // Step 1: Extract brackets [attr] or [attr=value]\n let bracketContent = null;\n let withoutBrackets = part;\n\n const bracketMatch = part.match(/^([^\\[]+)(\\[[^\\]]*\\])(.*)$/);\n if (bracketMatch) {\n withoutBrackets = bracketMatch[1] + bracketMatch[3];\n if (bracketMatch[2]) {\n const content = bracketMatch[2].slice(1, -1);\n if (content) {\n bracketContent = content;\n }\n }\n }\n\n // Step 2: Check for namespace (double colon ::)\n let namespace = undefined;\n let tagAndPosition = withoutBrackets;\n\n if (withoutBrackets.includes('::')) {\n const nsIndex = withoutBrackets.indexOf('::');\n namespace = withoutBrackets.substring(0, nsIndex).trim();\n tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim(); // Skip ::\n\n if (!namespace) {\n throw new Error(`Invalid namespace in pattern: ${part}`);\n }\n }\n\n // Step 3: Parse tag and position (single colon :)\n let tag = undefined;\n let positionMatch = null;\n\n if (tagAndPosition.includes(':')) {\n const colonIndex = tagAndPosition.lastIndexOf(':'); // Use last colon for position\n const tagPart = tagAndPosition.substring(0, colonIndex).trim();\n const posPart = tagAndPosition.substring(colonIndex + 1).trim();\n\n // Verify position is a valid keyword\n const isPositionKeyword = ['first', 'last', 'odd', 'even'].includes(posPart) ||\n /^nth\\(\\d+\\)$/.test(posPart);\n\n if (isPositionKeyword) {\n tag = tagPart;\n positionMatch = posPart;\n } else {\n // Not a valid position keyword, treat whole thing as tag\n tag = tagAndPosition;\n }\n } else {\n tag = tagAndPosition;\n }\n\n if (!tag) {\n throw new Error(`Invalid segment pattern: ${part}`);\n }\n\n segment.tag = tag;\n if (namespace) {\n segment.namespace = namespace;\n }\n\n // Step 4: Parse attributes\n if (bracketContent) {\n if (bracketContent.includes('=')) {\n const eqIndex = bracketContent.indexOf('=');\n segment.attrName = bracketContent.substring(0, eqIndex).trim();\n segment.attrValue = bracketContent.substring(eqIndex + 1).trim();\n } else {\n segment.attrName = bracketContent.trim();\n }\n }\n\n // Step 5: Parse position selector\n if (positionMatch) {\n const nthMatch = positionMatch.match(/^nth\\((\\d+)\\)$/);\n if (nthMatch) {\n segment.position = 'nth';\n segment.positionValue = parseInt(nthMatch[1], 10);\n } else {\n segment.position = positionMatch;\n }\n }\n\n return segment;\n }\n\n /**\n * Get the number of segments\n * @returns {number}\n */\n get length() {\n return this.segments.length;\n }\n\n /**\n * Check if expression contains deep wildcard\n * @returns {boolean}\n */\n hasDeepWildcard() {\n return this._hasDeepWildcard;\n }\n\n /**\n * Check if expression has attribute conditions\n * @returns {boolean}\n */\n hasAttributeCondition() {\n return this._hasAttributeCondition;\n }\n\n /**\n * Check if expression has position selectors\n * @returns {boolean}\n */\n hasPositionSelector() {\n return this._hasPositionSelector;\n }\n\n /**\n * Get string representation\n * @returns {string}\n */\n toString() {\n return this.pattern;\n }\n}","import ExpressionSet from \"./ExpressionSet.js\";\n\n/**\n * MatcherView - A lightweight read-only view over a Matcher's internal state.\n *\n * Created once by Matcher and reused across all callbacks. Holds a direct\n * reference to the parent Matcher so it always reflects current parser state\n * with zero copying or freezing overhead.\n *\n * Users receive this via {@link Matcher#readOnly} or directly from parser\n * callbacks. It exposes all query and matching methods but has no mutation\n * methods — misuse is caught at the TypeScript level rather than at runtime.\n *\n * @example\n * const matcher = new Matcher();\n * const view = matcher.readOnly();\n *\n * matcher.push(\"root\", {});\n * view.getCurrentTag(); // \"root\"\n * view.getDepth(); // 1\n */\nexport class MatcherView {\n /**\n * @param {Matcher} matcher - The parent Matcher instance to read from.\n */\n constructor(matcher) {\n this._matcher = matcher;\n }\n\n /**\n * Get the path separator used by the parent matcher.\n * @returns {string}\n */\n get separator() {\n return this._matcher.separator;\n }\n\n /**\n * Get current tag name.\n * @returns {string|undefined}\n */\n getCurrentTag() {\n const path = this._matcher.path;\n return path.length > 0 ? path[path.length - 1].tag : undefined;\n }\n\n /**\n * Get current namespace.\n * @returns {string|undefined}\n */\n getCurrentNamespace() {\n const path = this._matcher.path;\n return path.length > 0 ? path[path.length - 1].namespace : undefined;\n }\n\n /**\n * Get current node's attribute value.\n * @param {string} attrName\n * @returns {*}\n */\n getAttrValue(attrName) {\n const path = this._matcher.path;\n if (path.length === 0) return undefined;\n return path[path.length - 1].values?.[attrName];\n }\n\n /**\n * Check if current node has an attribute.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAttr(attrName) {\n const path = this._matcher.path;\n if (path.length === 0) return false;\n const current = path[path.length - 1];\n return current.values !== undefined && attrName in current.values;\n }\n\n /**\n * Get the value of a \"kept\" attribute from the nearest ancestor (or\n * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.\n * @param {string} attrName\n * @returns {*}\n */\n getAnyParentAttr(attrName) {\n return this._matcher.getAnyParentAttr(attrName);\n }\n\n /**\n * Check whether any ancestor (or the current node) kept the given\n * attribute via `push(tag, attrs, ns, { keep: [...] })`.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAnyParentAttr(attrName) {\n return this._matcher.hasAnyParentAttr(attrName);\n }\n\n /**\n * Get current node's sibling position (child index in parent).\n * @returns {number}\n */\n getPosition() {\n const path = this._matcher.path;\n if (path.length === 0) return -1;\n return path[path.length - 1].position ?? 0;\n }\n\n /**\n * Get current node's repeat counter (occurrence count of this tag name).\n * @returns {number}\n */\n getCounter() {\n const path = this._matcher.path;\n if (path.length === 0) return -1;\n return path[path.length - 1].counter ?? 0;\n }\n\n /**\n * Get current node's sibling index (alias for getPosition).\n * @returns {number}\n * @deprecated Use getPosition() or getCounter() instead\n */\n getIndex() {\n return this.getPosition();\n }\n\n /**\n * Get current path depth.\n * @returns {number}\n */\n getDepth() {\n return this._matcher.path.length;\n }\n\n /**\n * Get path as string.\n * @param {string} [separator] - Optional separator (uses default if not provided)\n * @param {boolean} [includeNamespace=true]\n * @returns {string}\n */\n toString(separator, includeNamespace = true) {\n return this._matcher.toString(separator, includeNamespace);\n }\n\n /**\n * Get path as array of tag names.\n * @returns {string[]}\n */\n toArray() {\n return this._matcher.path.map(n => n.tag);\n }\n\n /**\n * Match current path against an Expression.\n * @param {Expression} expression\n * @returns {boolean}\n */\n matches(expression) {\n return this._matcher.matches(expression);\n }\n\n /**\n * Match any expression in the given set against the current path.\n * @param {ExpressionSet} exprSet\n * @returns {boolean}\n */\n matchesAny(exprSet) {\n return exprSet.matchesAny(this._matcher);\n }\n}\n\n/**\n * Matcher - Tracks current path in XML/JSON tree and matches against Expressions.\n *\n * The matcher maintains a stack of nodes representing the current path from root to\n * current tag. It only stores attribute values for the current (top) node to minimize\n * memory usage. Sibling tracking is used to auto-calculate position and counter.\n *\n * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to\n * user callbacks — it always reflects current state with no Proxy overhead.\n *\n * @example\n * const matcher = new Matcher();\n * matcher.push(\"root\", {});\n * matcher.push(\"users\", {});\n * matcher.push(\"user\", { id: \"123\", type: \"admin\" });\n *\n * const expr = new Expression(\"root.users.user\");\n * matcher.matches(expr); // true\n */\nexport default class Matcher {\n /**\n * Create a new Matcher.\n * @param {Object} [options={}]\n * @param {string} [options.separator='.'] - Default path separator\n */\n constructor(options = {}) {\n this.separator = options.separator || '.';\n this.path = [];\n this.siblingStacks = [];\n // Each path node: { tag, values, position, counter, namespace? }\n // values only present for current (last) node\n // Each siblingStacks entry: Map<tagName, count> tracking occurrences at each level\n this._pathStringCache = null;\n this._view = new MatcherView(this);\n\n // Kept-attribute stack: only populated when push() is called with options.keep.\n this._keptAttrs = [];\n }\n\n /**\n * Push a new tag onto the path.\n * @param {string} tagName\n * @param {Object|null} [attrValues=null]\n * @param {string|null} [namespace=null]\n * @param {Object|null} [options=null]\n * @param {string[]} [options.keep] - Names of attributes (from attrValues)\n */\n push(tagName, attrValues = null, namespace = null, options = null) {\n this._pathStringCache = null;\n\n // Remove values from previous current node (now becoming ancestor)\n if (this.path.length > 0) {\n this.path[this.path.length - 1].values = undefined;\n }\n\n // Get or create sibling tracking for current level\n const currentLevel = this.path.length;\n if (!this.siblingStacks[currentLevel]) {\n this.siblingStacks[currentLevel] = new Map();\n }\n\n const siblings = this.siblingStacks[currentLevel];\n\n // Create a unique key for sibling tracking that includes namespace\n const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;\n\n // Calculate counter (how many times this tag appeared at this level)\n const counter = siblings.get(siblingKey) || 0;\n\n // Calculate position (total children at this level so far)\n let position = 0;\n for (const count of siblings.values()) {\n position += count;\n }\n\n // Update sibling count for this tag\n siblings.set(siblingKey, counter + 1);\n\n // Create new node\n const node = {\n tag: tagName,\n position: position,\n counter: counter\n };\n\n if (namespace !== null && namespace !== undefined) {\n node.namespace = namespace;\n }\n\n if (attrValues !== null && attrValues !== undefined) {\n node.values = attrValues;\n }\n\n this.path.push(node);\n\n // Depth of the node we just pushed (1-based, matches this.path.length)\n const depth = this.path.length;\n\n // Copy only the requested attributes into the kept-attrs stack. This is\n // the one part of push() whose cost scales with input (O(keep.length))\n // rather than being O(1) — by design, since the caller is explicitly\n // opting in for specific attribute names. No options/keep => zero added\n // cost beyond the two property reads below.\n const keep = options !== null ? options.keep : null;\n if (keep !== null && keep !== undefined && keep.length > 0 && attrValues) {\n for (let i = 0; i < keep.length; i++) {\n const name = keep[i];\n if (attrValues[name] !== undefined) {\n this._keptAttrs.push({ depth, name, value: attrValues[name] });\n }\n }\n }\n }\n\n /**\n * Pop the last tag from the path.\n * @returns {Object|undefined} The popped node\n */\n pop() {\n if (this.path.length === 0) return undefined;\n this._pathStringCache = null;\n\n const node = this.path.pop();\n\n if (this.siblingStacks.length > this.path.length + 1) {\n this.siblingStacks.length = this.path.length + 1;\n }\n\n // Drop any kept attributes that belonged to the popped node (or deeper).\n // _keptAttrs is depth-ordered (push only ever appends increasing depths),\n // so this is a backward scan that stops at the first surviving entry —\n // typically O(1) since kept attrs are rare by design.\n const poppedDepth = this.path.length + 1;\n while (\n this._keptAttrs.length > 0 &&\n this._keptAttrs[this._keptAttrs.length - 1].depth >= poppedDepth\n ) {\n this._keptAttrs.pop();\n }\n\n return node;\n }\n\n /**\n * Update current node's attribute values.\n * Useful when attributes are parsed after push.\n * @param {Object} attrValues\n */\n updateCurrent(attrValues) {\n if (this.path.length > 0) {\n const current = this.path[this.path.length - 1];\n if (attrValues !== null && attrValues !== undefined) {\n current.values = attrValues;\n }\n }\n }\n\n /**\n * Get current tag name.\n * @returns {string|undefined}\n */\n getCurrentTag() {\n return this.path.length > 0 ? this.path[this.path.length - 1].tag : undefined;\n }\n\n /**\n * Get current namespace.\n * @returns {string|undefined}\n */\n getCurrentNamespace() {\n return this.path.length > 0 ? this.path[this.path.length - 1].namespace : undefined;\n }\n\n /**\n * Get current node's attribute value.\n * @param {string} attrName\n * @returns {*}\n */\n getAttrValue(attrName) {\n if (this.path.length === 0) return undefined;\n return this.path[this.path.length - 1].values?.[attrName];\n }\n\n /**\n * Check if current node has an attribute.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAttr(attrName) {\n if (this.path.length === 0) return false;\n const current = this.path[this.path.length - 1];\n return current.values !== undefined && attrName in current.values;\n }\n\n /**\n * Get the value of a \"kept\" attribute from the nearest ancestor (or\n * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.\n * Unlike getAttrValue(), this works regardless of how deep the path has\n * gone since the attribute was pushed — but only for attribute names that\n * were explicitly marked with `keep` at push time. Cost is proportional to\n * the number of currently-kept attributes (typically 0-3), not path depth.\n * @param {string} attrName\n * @returns {*} the value, or undefined if no ancestor kept this attribute\n */\n getAnyParentAttr(attrName) {\n const kept = this._keptAttrs;\n for (let i = kept.length - 1; i >= 0; i--) {\n if (kept[i].name === attrName) return kept[i].value;\n }\n return undefined;\n }\n\n /**\n * Check whether any ancestor (or the current node) kept the given\n * attribute via `push(tag, attrs, ns, { keep: [...] })`.\n * @param {string} attrName\n * @returns {boolean}\n */\n hasAnyParentAttr(attrName) {\n const kept = this._keptAttrs;\n for (let i = kept.length - 1; i >= 0; i--) {\n if (kept[i].name === attrName) return true;\n }\n return false;\n }\n\n /**\n * Get current node's sibling position (child index in parent).\n * @returns {number}\n */\n getPosition() {\n if (this.path.length === 0) return -1;\n return this.path[this.path.length - 1].position ?? 0;\n }\n\n /**\n * Get current node's repeat counter (occurrence count of this tag name).\n * @returns {number}\n */\n getCounter() {\n if (this.path.length === 0) return -1;\n return this.path[this.path.length - 1].counter ?? 0;\n }\n\n /**\n * Get current node's sibling index (alias for getPosition).\n * @returns {number}\n * @deprecated Use getPosition() or getCounter() instead\n */\n getIndex() {\n return this.getPosition();\n }\n\n /**\n * Get current path depth.\n * @returns {number}\n */\n getDepth() {\n return this.path.length;\n }\n\n /**\n * Get path as string.\n * @param {string} [separator] - Optional separator (uses default if not provided)\n * @param {boolean} [includeNamespace=true]\n * @returns {string}\n */\n toString(separator, includeNamespace = true) {\n const sep = separator || this.separator;\n const isDefault = (sep === this.separator && includeNamespace === true);\n\n if (isDefault) {\n if (this._pathStringCache !== null) {\n return this._pathStringCache;\n }\n const result = this.path.map(n =>\n (n.namespace) ? `${n.namespace}:${n.tag}` : n.tag\n ).join(sep);\n this._pathStringCache = result;\n return result;\n }\n\n return this.path.map(n =>\n (includeNamespace && n.namespace) ? `${n.namespace}:${n.tag}` : n.tag\n ).join(sep);\n }\n\n /**\n * Get path as array of tag names.\n * @returns {string[]}\n */\n toArray() {\n return this.path.map(n => n.tag);\n }\n\n /**\n * Reset the path to empty.\n */\n reset() {\n this._pathStringCache = null;\n this.path = [];\n this.siblingStacks = [];\n this._keptAttrs = [];\n }\n\n /**\n * Match current path against an Expression.\n * @param {Expression} expression\n * @returns {boolean}\n */\n matches(expression) {\n const segments = expression.segments;\n\n if (segments.length === 0) {\n return false;\n }\n\n if (expression.hasDeepWildcard()) {\n return this._matchWithDeepWildcard(segments);\n }\n\n return this._matchSimple(segments);\n }\n\n /**\n * @private\n */\n _matchSimple(segments) {\n if (this.path.length !== segments.length) {\n return false;\n }\n\n for (let i = 0; i < segments.length; i++) {\n if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * @private\n */\n _matchWithDeepWildcard(segments) {\n let pathIdx = this.path.length - 1;\n let segIdx = segments.length - 1;\n\n while (segIdx >= 0 && pathIdx >= 0) {\n const segment = segments[segIdx];\n\n if (segment.type === 'deep-wildcard') {\n segIdx--;\n\n if (segIdx < 0) {\n return true;\n }\n\n const nextSeg = segments[segIdx];\n let found = false;\n\n for (let i = pathIdx; i >= 0; i--) {\n if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) {\n pathIdx = i - 1;\n segIdx--;\n found = true;\n break;\n }\n }\n\n if (!found) {\n return false;\n }\n } else {\n if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) {\n return false;\n }\n pathIdx--;\n segIdx--;\n }\n }\n\n return segIdx < 0;\n }\n\n /**\n * @private\n */\n _matchSegment(segment, node, isCurrentNode) {\n if (segment.tag !== '*' && segment.tag !== node.tag) {\n return false;\n }\n\n if (segment.namespace !== undefined) {\n if (segment.namespace !== '*' && segment.namespace !== node.namespace) {\n return false;\n }\n }\n\n if (segment.attrName !== undefined) {\n if (!isCurrentNode) {\n return false;\n }\n\n if (!node.values || !(segment.attrName in node.values)) {\n return false;\n }\n\n if (segment.attrValue !== undefined) {\n if (String(node.values[segment.attrName]) !== String(segment.attrValue)) {\n return false;\n }\n }\n }\n\n if (segment.position !== undefined) {\n if (!isCurrentNode) {\n return false;\n }\n\n const counter = node.counter ?? 0;\n\n if (segment.position === 'first' && counter !== 0) {\n return false;\n } else if (segment.position === 'odd' && counter % 2 !== 1) {\n return false;\n } else if (segment.position === 'even' && counter % 2 !== 0) {\n return false;\n } else if (segment.position === 'nth' && counter !== segment.positionValue) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Match any expression in the given set against the current path.\n * @param {ExpressionSet} exprSet\n * @returns {boolean}\n */\n matchesAny(exprSet) {\n return exprSet.matchesAny(this);\n }\n\n /**\n * Create a snapshot of current state.\n * @returns {Object}\n */\n snapshot() {\n return {\n path: this.path.map(node => ({ ...node })),\n siblingStacks: this.siblingStacks.map(map => new Map(map)),\n keptAttrs: this._keptAttrs.map(entry => ({ ...entry }))\n };\n }\n\n /**\n * Restore state from snapshot.\n * @param {Object} snapshot\n */\n restore(snapshot) {\n this._pathStringCache = null;\n this.path = snapshot.path.map(node => ({ ...node }));\n this.siblingStacks = snapshot.siblingStacks.map(map => new Map(map));\n this._keptAttrs = (snapshot.keptAttrs || []).map(entry => ({ ...entry }));\n }\n\n /**\n * Return the read-only {@link MatcherView} for this matcher.\n *\n * The same instance is returned on every call — no allocation occurs.\n * It always reflects the current parser state and is safe to pass to\n * user callbacks without risk of accidental mutation.\n *\n * @returns {MatcherView}\n *\n * @example\n * const view = matcher.readOnly();\n * // pass view to callbacks — it stays in sync automatically\n * view.matches(expr); // ✓\n * view.getCurrentTag(); // ✓\n * // view.push(...) // ✗ method does not exist — caught by TypeScript\n */\n readOnly() {\n return this._view;\n }\n}\n","/**\n * ExpressionSet - An indexed collection of Expressions for efficient bulk matching\n *\n * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes\n * them at insertion time by depth and terminal tag name. At match time, only\n * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1)\n * lookup plus O(small bucket) matches.\n *\n * Three buckets are maintained:\n * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first)\n * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only)\n * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed)\n *\n * @example\n * import { Expression, ExpressionSet } from 'fast-xml-tagger';\n *\n * // Build once at config time\n * const stopNodes = new ExpressionSet();\n * stopNodes.add(new Expression('root.users.user'));\n * stopNodes.add(new Expression('root.config.setting'));\n * stopNodes.add(new Expression('..script'));\n *\n * // Query on every tag — hot path\n * if (stopNodes.matchesAny(matcher)) { ... }\n */\nexport default class ExpressionSet {\n constructor() {\n /** @type {Map<string, import('./Expression.js').default[]>} depth:tag → expressions */\n this._byDepthAndTag = new Map();\n\n /** @type {Map<number, import('./Expression.js').default[]>} depth → wildcard-tag expressions */\n this._wildcardByDepth = new Map();\n\n /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */\n this._deepWildcards = [];\n\n /** @type {Map<string, import('./Expression.js').default[]>} terminalTag → deep wildcard expressions */\n this._deepByTerminalTag = new Map();\n\n /** @type {Set<string>} pattern strings already added — used for deduplication */\n this._patterns = new Set();\n\n /** @type {boolean} whether the set is sealed against further additions */\n this._sealed = false;\n }\n\n /**\n * Add an Expression to the set.\n * Duplicate patterns (same pattern string) are silently ignored.\n *\n * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance\n * @returns {this} for chaining\n * @throws {TypeError} if called after seal()\n *\n * @example\n * set.add(new Expression('root.users.user'));\n * set.add(new Expression('..script'));\n */\n add(expression) {\n if (this._sealed) {\n throw new TypeError(\n 'ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.'\n );\n }\n\n // Deduplicate by pattern string\n if (this._patterns.has(expression.pattern)) return this;\n this._patterns.add(expression.pattern);\n\n if (expression.hasDeepWildcard()) {\n const lastSeg = expression.segments[expression.segments.length - 1];\n if (lastSeg && lastSeg.type !== 'deep-wildcard' && lastSeg.tag !== '*') {\n const tag = lastSeg.tag;\n if (!this._deepByTerminalTag.has(tag)) this._deepByTerminalTag.set(tag, []);\n this._deepByTerminalTag.get(tag).push(expression);\n } else {\n this._deepWildcards.push(expression);\n }\n return this;\n }\n\n const depth = expression.length;\n const lastSeg = expression.segments[expression.segments.length - 1];\n const tag = lastSeg?.tag;\n\n if (!tag || tag === '*') {\n // Can index by depth but not by tag\n if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []);\n this._wildcardByDepth.get(depth).push(expression);\n } else {\n // Tightest bucket: depth + tag\n const key = `${depth}:${tag}`;\n if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []);\n this._byDepthAndTag.get(key).push(expression);\n }\n\n return this;\n }\n\n /**\n * Add multiple expressions at once.\n *\n * @param {import('./Expression.js').default[]} expressions - Array of Expression instances\n * @returns {this} for chaining\n *\n * @example\n * set.addAll([\n * new Expression('root.users.user'),\n * new Expression('root.config.setting'),\n * ]);\n */\n addAll(expressions) {\n for (const expr of expressions) this.add(expr);\n return this;\n }\n\n /**\n * Check whether a pattern string is already present in the set.\n *\n * @param {import('./Expression.js').default} expression\n * @returns {boolean}\n */\n has(expression) {\n return this._patterns.has(expression.pattern);\n }\n\n /**\n * Number of expressions in the set.\n * @type {number}\n */\n get size() {\n return this._patterns.size;\n }\n\n /**\n * Seal the set against further modifications.\n * Useful to prevent accidental mutations after config is built.\n * Calling add() or addAll() on a sealed set throws a TypeError.\n *\n * @returns {this}\n */\n seal() {\n this._sealed = true;\n return this;\n }\n\n /**\n * Whether the set has been sealed.\n * @type {boolean}\n */\n get isSealed() {\n return this._sealed;\n }\n\n /**\n * Test whether the matcher's current path matches any expression in the set.\n *\n * Evaluation order (cheapest → most expensive):\n * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions\n * 2. Depth-only wildcard bucket — O(1) lookup, rare\n * 3. Deep-wildcard list — always checked, but usually small\n *\n * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)\n * @returns {boolean} true if any expression matches the current path\n *\n * @example\n * if (stopNodes.matchesAny(matcher)) {\n * // handle stop node\n * }\n */\n matchesAny(matcher) {\n return this.findMatch(matcher) !== null;\n }\n /**\n * Find and return the first Expression that matches the matcher's current path.\n *\n * Uses the same evaluation order as matchesAny (cheapest → most expensive):\n * 1. Exact depth + tag bucket\n * 2. Depth-only wildcard bucket\n * 3. Deep-wildcard list\n *\n * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)\n * @returns {import('./Expression.js').default | null} the first matching Expression, or null\n *\n * @example\n * const expr = stopNodes.findMatch(matcher);\n * if (expr) {\n * // access expr.config, expr.pattern, etc.\n * }\n */\n findMatch(matcher) {\n const depth = matcher.getDepth();\n const tag = matcher.getCurrentTag();\n\n // 1. Tightest bucket — most expressions live here\n const exactKey = `${depth}:${tag}`;\n const exactBucket = this._byDepthAndTag.get(exactKey);\n if (exactBucket) {\n for (let i = 0; i < exactBucket.length; i++) {\n if (matcher.matches(exactBucket[i])) return exactBucket[i];\n }\n }\n\n // 2. Depth-matched wildcard-tag expressions\n const wildcardBucket = this._wildcardByDepth.get(depth);\n if (wildcardBucket) {\n for (let i = 0; i < wildcardBucket.length; i++) {\n if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i];\n }\n }\n\n // 3. Deep wildcards — indexed by terminal tag, then unindexed fallback\n const deepBucket = this._deepByTerminalTag.get(tag);\n if (deepBucket) {\n for (let i = 0; i < deepBucket.length; i++) {\n if (matcher.matches(deepBucket[i])) return deepBucket[i];\n }\n }\n for (let i = 0; i < this._deepWildcards.length; i++) {\n if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];\n }\n\n return null;\n }\n}\n","/**\n * fast-xml-tagger - XML/JSON path matching library\n * \n * Provides efficient path tracking and pattern matching for XML/JSON parsers.\n * \n * @example\n * import { Expression, Matcher } from 'fast-xml-tagger';\n * \n * // Create expression (parse once)\n * const expr = new Expression(\"root.users.user[id]\");\n * \n * // Create matcher (track path)\n * const matcher = new Matcher();\n * matcher.push(\"root\", [], {}, 0);\n * matcher.push(\"users\", [], {}, 0);\n * matcher.push(\"user\", [\"id\", \"type\"], { id: \"123\", type: \"admin\" }, 0);\n * \n * // Match\n * if (matcher.matches(expr)) {\n * console.log(\"Match found!\");\n * }\n */\n\nimport Expression from './Expression.js';\nimport Matcher from './Matcher.js';\nimport ExpressionSet from './ExpressionSet.js';\n\nexport { Expression, Matcher, ExpressionSet };\nexport default { Expression, Matcher, ExpressionSet };\n"],"names":["root","factory","exports","module","define","amd","this","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","Expression","constructor","pattern","options","data","separator","segments","_parse","_hasDeepWildcard","some","seg","type","_hasAttributeCondition","undefined","attrName","_hasPositionSelector","position","i","currentPart","length","trim","push","_parseSegment","part","segment","bracketContent","withoutBrackets","bracketMatch","match","content","slice","namespace","tag","tagAndPosition","includes","nsIndex","indexOf","substring","Error","positionMatch","colonIndex","lastIndexOf","tagPart","posPart","test","eqIndex","attrValue","nthMatch","positionValue","parseInt","hasDeepWildcard","hasAttributeCondition","hasPositionSelector","toString","MatcherView","matcher","_matcher","getCurrentTag","path","getCurrentNamespace","getAttrValue","values","hasAttr","current","getAnyParentAttr","hasAnyParentAttr","getPosition","getCounter","counter","getIndex","getDepth","includeNamespace","toArray","map","n","matches","expression","matchesAny","exprSet","Matcher","siblingStacks","_pathStringCache","_view","_keptAttrs","tagName","attrValues","currentLevel","Map","siblings","siblingKey","count","set","node","depth","keep","name","pop","poppedDepth","updateCurrent","kept","sep","result","join","reset","_matchWithDeepWildcard","_matchSimple","_matchSegment","pathIdx","segIdx","nextSeg","found","isCurrentNode","String","snapshot","keptAttrs","entry","restore","readOnly","ExpressionSet","_byDepthAndTag","_wildcardByDepth","_deepWildcards","_deepByTerminalTag","_patterns","Set","_sealed","add","TypeError","has","lastSeg","addAll","expressions","expr","size","seal","isSealed","findMatch","exactKey","exactBucket","wildcardBucket","deepBucket"],"sourceRoot":""}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "path-expression-matcher",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Efficient path tracking and pattern matching for XML/JSON parsers",
5
5
  "main": "./lib/pem.cjs",
6
6
  "type": "module",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "keywords": [
27
27
  "xml",
28
+ "html",
28
29
  "json",
29
30
  "yaml",
30
31
  "path",
@@ -75,4 +76,4 @@
75
76
  "url": "https://github.com/sponsors/NaturalIntelligence"
76
77
  }
77
78
  ]
78
- }
79
+ }
@@ -34,6 +34,9 @@ export default class ExpressionSet {
34
34
  /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */
35
35
  this._deepWildcards = [];
36
36
 
37
+ /** @type {Map<string, import('./Expression.js').default[]>} terminalTag → deep wildcard expressions */
38
+ this._deepByTerminalTag = new Map();
39
+
37
40
  /** @type {Set<string>} pattern strings already added — used for deduplication */
38
41
  this._patterns = new Set();
39
42
 
@@ -65,7 +68,14 @@ export default class ExpressionSet {
65
68
  this._patterns.add(expression.pattern);
66
69
 
67
70
  if (expression.hasDeepWildcard()) {
68
- this._deepWildcards.push(expression);
71
+ const lastSeg = expression.segments[expression.segments.length - 1];
72
+ if (lastSeg && lastSeg.type !== 'deep-wildcard' && lastSeg.tag !== '*') {
73
+ const tag = lastSeg.tag;
74
+ if (!this._deepByTerminalTag.has(tag)) this._deepByTerminalTag.set(tag, []);
75
+ this._deepByTerminalTag.get(tag).push(expression);
76
+ } else {
77
+ this._deepWildcards.push(expression);
78
+ }
69
79
  return this;
70
80
  }
71
81
 
@@ -199,7 +209,13 @@ export default class ExpressionSet {
199
209
  }
200
210
  }
201
211
 
202
- // 3. Deep wildcards — cannot be pre-filtered by depth or tag
212
+ // 3. Deep wildcards — indexed by terminal tag, then unindexed fallback
213
+ const deepBucket = this._deepByTerminalTag.get(tag);
214
+ if (deepBucket) {
215
+ for (let i = 0; i < deepBucket.length; i++) {
216
+ if (matcher.matches(deepBucket[i])) return deepBucket[i];
217
+ }
218
+ }
203
219
  for (let i = 0; i < this._deepWildcards.length; i++) {
204
220
  if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];
205
221
  }
@@ -76,6 +76,26 @@ export class MatcherView {
76
76
  return current.values !== undefined && attrName in current.values;
77
77
  }
78
78
 
79
+ /**
80
+ * Get the value of a "kept" attribute from the nearest ancestor (or
81
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
82
+ * @param {string} attrName
83
+ * @returns {*}
84
+ */
85
+ getAnyParentAttr(attrName) {
86
+ return this._matcher.getAnyParentAttr(attrName);
87
+ }
88
+
89
+ /**
90
+ * Check whether any ancestor (or the current node) kept the given
91
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
92
+ * @param {string} attrName
93
+ * @returns {boolean}
94
+ */
95
+ hasAnyParentAttr(attrName) {
96
+ return this._matcher.hasAnyParentAttr(attrName);
97
+ }
98
+
79
99
  /**
80
100
  * Get current node's sibling position (child index in parent).
81
101
  * @returns {number}
@@ -184,6 +204,9 @@ export default class Matcher {
184
204
  // Each siblingStacks entry: Map<tagName, count> tracking occurrences at each level
185
205
  this._pathStringCache = null;
186
206
  this._view = new MatcherView(this);
207
+
208
+ // Kept-attribute stack: only populated when push() is called with options.keep.
209
+ this._keptAttrs = [];
187
210
  }
188
211
 
189
212
  /**
@@ -191,8 +214,10 @@ export default class Matcher {
191
214
  * @param {string} tagName
192
215
  * @param {Object|null} [attrValues=null]
193
216
  * @param {string|null} [namespace=null]
217
+ * @param {Object|null} [options=null]
218
+ * @param {string[]} [options.keep] - Names of attributes (from attrValues)
194
219
  */
195
- push(tagName, attrValues = null, namespace = null) {
220
+ push(tagName, attrValues = null, namespace = null, options = null) {
196
221
  this._pathStringCache = null;
197
222
 
198
223
  // Remove values from previous current node (now becoming ancestor)
@@ -239,6 +264,24 @@ export default class Matcher {
239
264
  }
240
265
 
241
266
  this.path.push(node);
267
+
268
+ // Depth of the node we just pushed (1-based, matches this.path.length)
269
+ const depth = this.path.length;
270
+
271
+ // Copy only the requested attributes into the kept-attrs stack. This is
272
+ // the one part of push() whose cost scales with input (O(keep.length))
273
+ // rather than being O(1) — by design, since the caller is explicitly
274
+ // opting in for specific attribute names. No options/keep => zero added
275
+ // cost beyond the two property reads below.
276
+ const keep = options !== null ? options.keep : null;
277
+ if (keep !== null && keep !== undefined && keep.length > 0 && attrValues) {
278
+ for (let i = 0; i < keep.length; i++) {
279
+ const name = keep[i];
280
+ if (attrValues[name] !== undefined) {
281
+ this._keptAttrs.push({ depth, name, value: attrValues[name] });
282
+ }
283
+ }
284
+ }
242
285
  }
243
286
 
244
287
  /**
@@ -255,6 +298,18 @@ export default class Matcher {
255
298
  this.siblingStacks.length = this.path.length + 1;
256
299
  }
257
300
 
301
+ // Drop any kept attributes that belonged to the popped node (or deeper).
302
+ // _keptAttrs is depth-ordered (push only ever appends increasing depths),
303
+ // so this is a backward scan that stops at the first surviving entry —
304
+ // typically O(1) since kept attrs are rare by design.
305
+ const poppedDepth = this.path.length + 1;
306
+ while (
307
+ this._keptAttrs.length > 0 &&
308
+ this._keptAttrs[this._keptAttrs.length - 1].depth >= poppedDepth
309
+ ) {
310
+ this._keptAttrs.pop();
311
+ }
312
+
258
313
  return node;
259
314
  }
260
315
 
@@ -309,6 +364,38 @@ export default class Matcher {
309
364
  return current.values !== undefined && attrName in current.values;
310
365
  }
311
366
 
367
+ /**
368
+ * Get the value of a "kept" attribute from the nearest ancestor (or
369
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
370
+ * Unlike getAttrValue(), this works regardless of how deep the path has
371
+ * gone since the attribute was pushed — but only for attribute names that
372
+ * were explicitly marked with `keep` at push time. Cost is proportional to
373
+ * the number of currently-kept attributes (typically 0-3), not path depth.
374
+ * @param {string} attrName
375
+ * @returns {*} the value, or undefined if no ancestor kept this attribute
376
+ */
377
+ getAnyParentAttr(attrName) {
378
+ const kept = this._keptAttrs;
379
+ for (let i = kept.length - 1; i >= 0; i--) {
380
+ if (kept[i].name === attrName) return kept[i].value;
381
+ }
382
+ return undefined;
383
+ }
384
+
385
+ /**
386
+ * Check whether any ancestor (or the current node) kept the given
387
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
388
+ * @param {string} attrName
389
+ * @returns {boolean}
390
+ */
391
+ hasAnyParentAttr(attrName) {
392
+ const kept = this._keptAttrs;
393
+ for (let i = kept.length - 1; i >= 0; i--) {
394
+ if (kept[i].name === attrName) return true;
395
+ }
396
+ return false;
397
+ }
398
+
312
399
  /**
313
400
  * Get current node's sibling position (child index in parent).
314
401
  * @returns {number}
@@ -385,6 +472,7 @@ export default class Matcher {
385
472
  this._pathStringCache = null;
386
473
  this.path = [];
387
474
  this.siblingStacks = [];
475
+ this._keptAttrs = [];
388
476
  }
389
477
 
390
478
  /**
@@ -534,7 +622,8 @@ export default class Matcher {
534
622
  snapshot() {
535
623
  return {
536
624
  path: this.path.map(node => ({ ...node })),
537
- siblingStacks: this.siblingStacks.map(map => new Map(map))
625
+ siblingStacks: this.siblingStacks.map(map => new Map(map)),
626
+ keptAttrs: this._keptAttrs.map(entry => ({ ...entry }))
538
627
  };
539
628
  }
540
629
 
@@ -546,6 +635,7 @@ export default class Matcher {
546
635
  this._pathStringCache = null;
547
636
  this.path = snapshot.path.map(node => ({ ...node }));
548
637
  this.siblingStacks = snapshot.siblingStacks.map(map => new Map(map));
638
+ this._keptAttrs = (snapshot.keptAttrs || []).map(entry => ({ ...entry }));
549
639
  }
550
640
 
551
641
  /**
@@ -567,4 +657,4 @@ export default class Matcher {
567
657
  readOnly() {
568
658
  return this._view;
569
659
  }
570
- }
660
+ }
@@ -186,6 +186,42 @@ export interface MatcherSnapshot {
186
186
  * Copy of sibling tracking maps
187
187
  */
188
188
  siblingStacks: Map<string, number>[];
189
+
190
+ /**
191
+ * Copy of the kept-attrs stack (see {@link PushOptions.keep})
192
+ */
193
+ keptAttrs: KeptAttrEntry[];
194
+ }
195
+
196
+ /**
197
+ * A single entry in the matcher's kept-attrs stack — an attribute value
198
+ * explicitly retained at push time via `{ keep: [...] }` so it remains
199
+ * reachable from descendants after the owning node is no longer current.
200
+ */
201
+ export interface KeptAttrEntry {
202
+ /** Path depth (1-based) of the node that declared this kept attribute */
203
+ depth: number;
204
+ /** Attribute name */
205
+ name: string;
206
+ /** Attribute value at push time */
207
+ value: any;
208
+ }
209
+
210
+ /**
211
+ * Options for {@link Matcher#push}
212
+ */
213
+ export interface PushOptions {
214
+ /**
215
+ * Names of attributes (from `attrValues`) to retain for ancestor lookup
216
+ * (`getAnyParentAttr` / `hasAnyParentAttr`) even after this node is no
217
+ * longer the current node.
218
+ *
219
+ * Use sparingly — this is for attributes you know you'll need much deeper
220
+ * in the tree (e.g. `xml:space`, a SOAP envelope's `version`), not a
221
+ * general substitute for `getAttrValue()`. Cost is proportional to
222
+ * `keep.length`, independent of path depth.
223
+ */
224
+ keep?: string[];
189
225
  }
190
226
 
191
227
  /**
@@ -227,6 +263,16 @@ export class MatcherView {
227
263
  getCurrentNamespace(): string | undefined;
228
264
  getAttrValue(attrName: string): any;
229
265
  hasAttr(attrName: string): boolean;
266
+ /**
267
+ * Get the value of a "kept" attribute from the nearest ancestor (or current
268
+ * node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
269
+ */
270
+ getAnyParentAttr(attrName: string): any;
271
+ /**
272
+ * Check whether any ancestor (or the current node) kept the given
273
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
274
+ */
275
+ hasAnyParentAttr(attrName: string): boolean;
230
276
  getPosition(): number;
231
277
  getCounter(): number;
232
278
  /** @deprecated Use getPosition() or getCounter() instead */
@@ -285,15 +331,23 @@ export class Matcher {
285
331
  * @param tagName - Name of the tag
286
332
  * @param attrValues - Attribute key-value pairs for current node (optional)
287
333
  * @param namespace - Namespace for the tag (optional)
334
+ * @param options - Push options, e.g. `{ keep: ['version'] }` to retain
335
+ * specific attributes for ancestor lookup after this node stops being current
288
336
  *
289
337
  * @example
290
338
  * ```typescript
291
339
  * matcher.push("user", { id: "123", type: "admin" });
292
340
  * matcher.push("user", { id: "456" }, "ns");
293
341
  * matcher.push("container", null);
342
+ * matcher.push("Body", { version: "1.1" }, "soap", { keep: ["version"] });
294
343
  * ```
295
344
  */
296
- push(tagName: string, attrValues?: Record<string, any> | null, namespace?: string | null): void;
345
+ push(
346
+ tagName: string,
347
+ attrValues?: Record<string, any> | null,
348
+ namespace?: string | null,
349
+ options?: PushOptions | null
350
+ ): void;
297
351
 
298
352
  /**
299
353
  * Pop the last tag from the path.
@@ -329,6 +383,18 @@ export class Matcher {
329
383
  getCurrentNamespace(): string | undefined;
330
384
  getAttrValue(attrName: string): any;
331
385
  hasAttr(attrName: string): boolean;
386
+ /**
387
+ * Get the value of a "kept" attribute from the nearest ancestor (or current
388
+ * node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
389
+ * Cost is proportional to the number of currently-kept attributes, not
390
+ * path depth.
391
+ */
392
+ getAnyParentAttr(attrName: string): any;
393
+ /**
394
+ * Check whether any ancestor (or the current node) kept the given
395
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
396
+ */
397
+ hasAnyParentAttr(attrName: string): boolean;
332
398
  getPosition(): number;
333
399
  getCounter(): number;
334
400
  /** @deprecated Use getPosition() or getCounter() instead */
package/package.json CHANGED
@@ -42,7 +42,7 @@
42
42
  "organization": false
43
43
  },
44
44
  "devDependencies": {
45
- "@cdk8s/projen-common": "0.0.716",
45
+ "@cdk8s/projen-common": "0.0.717",
46
46
  "@stylistic/eslint-plugin": "^2",
47
47
  "@types/fs-extra": "^11.0.4",
48
48
  "@types/jest": "^27",
@@ -52,7 +52,7 @@
52
52
  "aws-cdk": "^2.1128.0",
53
53
  "aws-cdk-lib": "2.195.0",
54
54
  "cdk8s": "2.68.91",
55
- "cdk8s-cli": "^2.207.24",
55
+ "cdk8s-cli": "^2.207.25",
56
56
  "commit-and-tag-version": "^12",
57
57
  "constructs": "10.3.0",
58
58
  "eslint": "^9",
@@ -94,7 +94,7 @@
94
94
  "publishConfig": {
95
95
  "access": "public"
96
96
  },
97
- "version": "0.0.607",
97
+ "version": "0.0.608",
98
98
  "jest": {
99
99
  "coverageProvider": "v8",
100
100
  "testMatch": [