@nodable/flexible-xml-parser 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,11 @@
1
1
 
2
+ **1.5.0 (2026-06-30)**
3
+ - TagDetail.index/line/col now points at '<' (not past '>')
4
+ - TagDetail.openEnd — offset right after the opening tag's '>'
5
+ - closeElement(matcher, closeMeta) — new 2nd arg
6
+ - addAttribute(name, value, matcher, attrMeta) — new 4th arg
7
+ - onStopNode(tagDetail, raw, matcher, stopEnd) — new 4th arg
8
+
2
9
  **1.4.0 (2026-06-16)**
3
10
  - keep `xml:space` to support spaces in parsed values.
4
11
  impact: 'trim' is replaced with 'ws' in pipeline. It means, whitespaces in tags values would be normalized.
package/lib/fxp.cjs CHANGED
@@ -1 +1 @@
1
- (()=>{"use strict";var t={d:(e,s)=>{for(var r in s)t.o(s,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:s[r]})},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,{ErrorCode:()=>ot,ParseError:()=>nt,XMLParser:()=>se,default:()=>se,quoteEnclosures:()=>Lt,xmlEnclosures:()=>$t});class s{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],r=s?.tag;if(r&&"*"!==r){const s=`${e}:${r}`;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(),r=`${e}:${s}`,i=this._byDepthAndTag.get(r);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];const o=this._deepByTerminalTag.get(s);if(o)for(let e=0;e<o.length;e++)if(t.matches(o[e]))return o[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}class r{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,r="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(r.trim()&&(e.push(this._parseSegment(r.trim())),r=""),e.push({type:"deep-wildcard"}),s+=2):(r.trim()&&e.push(this._parseSegment(r.trim())),r="",s++):(r+=t[s],s++);return r.trim()&&e.push(this._parseSegment(r.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,r=t;const i=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(i&&(r=i[1]+i[3],i[2])){const t=i[2].slice(1,-1);t&&(s=t)}let n,o,a=r;if(r.includes("::")){const e=r.indexOf("::");if(n=r.substring(0,e).trim(),a=r.substring(e+2).trim(),!n)throw new Error(`Invalid namespace in pattern: ${t}`)}let c=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)?(o=e,c=s):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,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(c){const t=c.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=c}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}const i={nameFor:{},skip:{},tags:{valueParsers:[]},attributes:{valueParsers:[]},textJoint:"",alwaysArray:[],forceArray:null,forceTextNode:!1},n=["ws","entity","boolean","number"],o=["entity","number","boolean"];function a(t){const e=c(i);t&&void 0!==t.tags?.valueParsers||(e.tags.valueParsers=[...n]),t&&void 0!==t.attributes?.valueParsers||(e.attributes.valueParsers=[...o]);const r=Array.isArray(t?.alwaysArray)?t.alwaysArray:e.alwaysArray,a=new s;for(const t of r)h(t,"alwaysArray",a);return a.seal(),e._alwaysArraySet=a,t&&l(e,t),e}function c(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(c);const e={};for(const s of Object.keys(t))e[s]=c(t[s]);return e}function l(t,e){for(const s of Object.keys(e))"__proto__"!==s&&"constructor"!==s&&"prototype"!==s&&("function"==typeof e[s]||Array.isArray(e[s])?t[s]=e[s]:"object"==typeof e[s]&&null!==e[s]?("object"==typeof t[s]&&null!==t[s]||(t[s]={}),l(t[s],e[s])):t[s]=e[s])}function h(t,e,s){let i;if("string"==typeof t){if(0===t.length)throw new Error(`${e} expression cannot be empty`);i=t}else{if(!("string"==typeof t?.pattern&&t.pattern.length>0&&Array.isArray(t?.segments)))throw new Error(`Invalid ${e} entry: expected a string, or Expression.`);i=t.toString()}const n=new r(i);return s.add(n),n}const d={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'},u=Object.freeze({ALLOW:"allow",BLOCK:"block",THROW:"throw"}),p=new Set("!?\\\\/[]$%{}^&*()<>|+");function f(t){if("#"===t[0])throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${t}"`);for(const e of t)if(p.has(e))throw new Error(`[EntityReplacer] Invalid character '${e}' in entity name: "${t}"`);return t}function g(...t){const e=Object.create(null);for(const s of t)if(s)for(const t of Object.keys(s)){const r=s[t];if("string"==typeof r)e[t]=r;else if(r&&"object"==typeof r&&void 0!==r.val){const s=r.val;"string"==typeof s&&(e[t]=s)}}return e}const m="external",_="base",E="all",x=Object.freeze({allow:0,leave:1,remove:2,throw:3}),T=new Set([9,10,13]);class w{constructor(t={}){var e;this._limit=t.limit||{},this._maxTotalExpansions=this._limit.maxTotalExpansions||0,this._maxExpandedLength=this._limit.maxExpandedLength||0,this._postCheck="function"==typeof t.postCheck?t.postCheck:t=>t,this._limitTiers=(e=this._limit.applyLimitsTo??m)&&e!==m?e===E?new Set([E]):e===_?new Set([_]):Array.isArray(e)?new Set(e):new Set([m]):new Set([m]),this._numericAllowed=t.numericAllowed??!0,this._baseMap=g(d,t.namedEntities||null),this._externalMap=Object.create(null),this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this._removeSet=new Set(t.remove&&Array.isArray(t.remove)?t.remove:[]),this._leaveSet=new Set(t.leave&&Array.isArray(t.leave)?t.leave:[]);const s=function(t){if(!t)return{xmlVersion:1,onLevel:x.allow,nullLevel:x.remove};const e=1.1===t.xmlVersion?1.1:1,s=x[t.onNCR]??x.allow,r=x[t.nullNCR]??x.remove;return{xmlVersion:e,onLevel:s,nullLevel:Math.max(r,x.remove)}}(t.ncr);this._ncrXmlVersion=s.xmlVersion,this._ncrOnLevel=s.onLevel,this._ncrNullLevel=s.nullLevel,this._onExternalEntity="function"==typeof t.onExternalEntity?t.onExternalEntity:null,this._onInputEntity="function"==typeof t.onInputEntity?t.onInputEntity:null}_applyRegistrationHook(t,e,s,r){if(!t)return!0;const i=t(e,s);if(i===u.BLOCK)return!1;if(i===u.THROW)throw new Error(`[EntityDecoder] Registration of ${r} entity "&${e};" was rejected by hook`);return!0}setExternalEntities(t){if(t)for(const e of Object.keys(t))f(e);if(!this._onExternalEntity)return void(this._externalMap=g(t));const e=g(t),s=Object.create(null);for(const[t,r]of Object.entries(e))this._applyRegistrationHook(this._onExternalEntity,t,r,"external")&&(s[t]=r);this._externalMap=s}addExternalEntity(t,e){f(t),"string"==typeof e&&-1===e.indexOf("&")&&this._applyRegistrationHook(this._onExternalEntity,t,e,"external")&&(this._externalMap[t]=e)}addInputEntities(t){if(this._totalExpansions=0,this._expandedLength=0,!this._onInputEntity)return void(this._inputMap=g(t));const e=g(t),s=Object.create(null);for(const[t,r]of Object.entries(e))this._applyRegistrationHook(this._onInputEntity,t,r,"input")&&(s[t]=r);this._inputMap=s}reset(){return this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this}setXmlVersion(t){this._ncrXmlVersion=1.1===t?1.1:1}decode(t){if("string"!=typeof t||0===t.length)return t;if(-1===t.indexOf("&"))return t;const e=t,s=[],r=t.length;let i=0,n=0;const o=this._maxTotalExpansions>0,a=this._maxExpandedLength>0,c=o||a;for(;n<r;){if(38!==t.charCodeAt(n)){n++;continue}let e=n+1;for(;e<r&&59!==t.charCodeAt(e)&&e-n<=32;)e++;if(e>=r||59!==t.charCodeAt(e)){n++;continue}const l=t.slice(n+1,e);if(0===l.length){n++;continue}let h,d;if(this._removeSet.has(l))h="",void 0===d&&(d=m);else{if(this._leaveSet.has(l)){n++;continue}if(35===l.charCodeAt(0)){const t=this._resolveNCR(l);if(void 0===t){n++;continue}h=t,d=_}else{const t=this._resolveName(l);h=t?.value,d=t?.tier}}if(void 0!==h){if(n>i&&s.push(t.slice(i,n)),s.push(h),i=e+1,n=i,c&&this._tierCounts(d)){if(o&&(this._totalExpansions++,this._totalExpansions>this._maxTotalExpansions))throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`);if(a){const t=h.length-(l.length+2);if(t>0&&(this._expandedLength+=t,this._expandedLength>this._maxExpandedLength))throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`)}}}else n++}i<r&&s.push(t.slice(i));const l=0===s.length?t:s.join("");return this._postCheck(l,e)}_tierCounts(t){return!!this._limitTiers.has(E)||this._limitTiers.has(t)}_resolveName(t){return t in this._inputMap?{value:this._inputMap[t],tier:m}:t in this._externalMap?{value:this._externalMap[t],tier:m}:t in this._baseMap?{value:this._baseMap[t],tier:_}:void 0}_classifyNCR(t){return 0===t?this._ncrNullLevel:t>=55296&&t<=57343||1===this._ncrXmlVersion&&t>=1&&t<=31&&!T.has(t)?x.remove:-1}_applyNCRAction(t,e,s){switch(t){case x.allow:return String.fromCodePoint(s);case x.remove:return"";case x.leave:return;case x.throw:throw new Error(`[EntityDecoder] Prohibited numeric character reference &${e}; (U+${s.toString(16).toUpperCase().padStart(4,"0")})`);default:return String.fromCodePoint(s)}}_resolveNCR(t){const e=t.charCodeAt(1);let s;if(s=120===e||88===e?parseInt(t.slice(2),16):parseInt(t.slice(1),10),Number.isNaN(s)||s<0||s>1114111)return;const r=this._classifyNCR(s);if(!this._numericAllowed&&r<x.remove)return;const i=-1===r?this._ncrOnLevel:Math.max(this._ncrOnLevel,r);return this._applyNCRAction(i,t,s)}}const b=[{id:"sql-block-comment-open",description:"SQL block comment open: /* ... */ — unusual in legitimate user text",pattern:/\/\*/},{id:"sql-union-select",description:"UNION SELECT — most common SQL injection aggregation attack",pattern:/\bUNION\s{1,20}(?:ALL\s{1,20})?SELECT\b/i},{id:"sql-drop-table",description:"DROP TABLE — destructive DDL injection",pattern:/\bDROP\s{1,20}TABLE\b/i},{id:"sql-drop-database",description:"DROP DATABASE — destructive DDL injection",pattern:/\bDROP\s{1,20}DATABASE\b/i},{id:"sql-insert-into",description:"INSERT INTO — data injection",pattern:/\bINSERT\s{1,20}INTO\b/i},{id:"sql-delete-from",description:"DELETE FROM — data deletion injection",pattern:/\bDELETE\s{1,20}FROM\b/i},{id:"sql-update-set",description:"UPDATE ... SET — data modification injection",pattern:/\bUPDATE\b[\s\S]{1,60}\bSET\b/i},{id:"sql-exec-xp",description:"EXEC xp_ — MSSQL extended stored procedure execution",pattern:/\bEXEC(?:UTE)?\s{1,20}xp_/i},{id:"sql-tautology-string",description:'Classic string tautology: \' OR \'1\'=\'1 or " OR "1"="1"',pattern:/'\s{0,10}OR\s{0,10}'[^']{0,20}'\s*=\s*'[^']{0,20}/i},{id:"sql-tautology-numeric",description:"Numeric tautology: OR 1=1",pattern:/\bOR\s{1,10}1\s*=\s*1\b/i},{id:"sql-always-true-zero",description:"Numeric tautology: OR 0=0",pattern:/\bOR\s{1,10}0\s*=\s*0\b/i},{id:"sql-sleep-benchmark",description:"Time-based blind injection: SLEEP() or BENCHMARK()",pattern:/\b(?:SLEEP|BENCHMARK)\s*\(/i},{id:"sql-waitfor-delay",description:"MSSQL time-based blind injection: WAITFOR DELAY",pattern:/\bWAITFOR\s{1,20}DELAY\b/i},{id:"sql-char-function",description:"CHAR() function — used to obfuscate injected strings",pattern:/\bCHAR\s*\(\s*\d{1,3}/i},{id:"sql-information-schema",description:"INFORMATION_SCHEMA — reconnaissance query for table/column enumeration",pattern:/\bINFORMATION_SCHEMA\b/i}],y="[\"'\\s]*:",N={HTML:[{id:"html-script-open",description:"<script opening tag",pattern:/<script[\s>/]/i},{id:"html-script-close",description:"<\/script closing tag",pattern:/<\/script[\s>]/i},{id:"html-javascript-protocol",description:"javascript: URI scheme (with optional whitespace/encoding)",pattern:/j[\t\n\r ]*a[\t\n\r ]*v[\t\n\r ]*a[\t\n\r ]*s[\t\n\r ]*c[\t\n\r ]*r[\t\n\r ]*i[\t\n\r ]*p[\t\n\r ]*t[\t\n\r ]*:/i},{id:"html-vbscript-protocol",description:"vbscript: URI scheme",pattern:/vbscript[\t\n\r ]*:/i},{id:"html-data-html",description:"data:text/html URI — can execute scripts in browsers",pattern:/data[\t\n\r ]*:[\t\n\r ]*text\/html/i},{id:"html-data-xhtml",description:"data:application/xhtml+xml URI",pattern:/data[\t\n\r ]*:[\t\n\r ]*application\/xhtml/i},{id:"html-data-svg",description:"data:image/svg+xml URI — can execute scripts",pattern:/data[\t\n\r ]*:[\t\n\r ]*image\/svg\+xml/i},{id:"html-inline-event-handler",description:"Inline event handler attributes: onclick=, onerror=, onload=, etc.",pattern:/\bon\w{1,30}\s*=/i},{id:"html-entity-obfuscated-script",description:"HTML-entity-encoded <script (e.g. &#x3C;script or &lt;script)",pattern:/(?:&#x0*3[Cc];?|&#0*60;?|&lt;)\s*script/i},{id:"html-entity-obfuscated-javascript",description:'HTML-entity-encoded javascript: (partial — catches common &#106; or &#x6a; for "j")',pattern:/(?:&#x0*6[Aa];?|&#0*106;?)\s*(?:&#x0*61;?|a)[\s\S]{0,80}script\s*:/i},{id:"html-style-expression",description:"CSS expression() — IE-era code execution in style attributes",pattern:/style[\s\S]{0,20}expression\s*\(/i},{id:"html-object-embed",description:"<object or <embed tags that can load active content",pattern:/<(?:object|embed)[\s>/]/i},{id:"html-base-tag",description:"<base href= — can hijack all relative URLs on a page",pattern:/<base[\s>]/i},{id:"html-meta-refresh",description:'<meta http-equiv="refresh" — can redirect users',pattern:/<meta[\s\S]{0,40}http-equiv[\s\S]{0,20}refresh/i},{id:"html-srcdoc",description:"srcdoc= attribute on iframes — embeds HTML that can run scripts",pattern:/srcdoc\s*=/i},{id:"html-iframe",description:"<iframe tag",pattern:/<iframe[\s>/]/i},{id:"html-form",description:"<form tag — can be used for phishing / credential harvesting injection",pattern:/<form[\s>/]/i}],XML:[{id:"xml-cdata-injection",description:"CDATA section injection: <![CDATA[ breaks out of text node context",pattern:/<!\[CDATA\[/i},{id:"xml-cdata-close",description:"CDATA close sequence: ]]> can terminate an enclosing CDATA section",pattern:/\]\]>/},{id:"xml-processing-instruction",description:"XML processing instruction: <?xml-stylesheet or <?php etc.",pattern:/<\?(?:xml[\- ]|php|asp)/i},{id:"xml-doctype-injection",description:"DOCTYPE declaration embedded in content — can define entities",pattern:/<!DOCTYPE(?:[\s[]|$)/i},{id:"xml-entity-system",description:"SYSTEM keyword — used in external entity declarations (XXE)",pattern:/\bSYSTEM\s+["']/i},{id:"xml-entity-public",description:"PUBLIC keyword — used in external entity declarations (XXE)",pattern:/\bPUBLIC\s+["']/i},{id:"xml-entity-declaration",description:"<!ENTITY declaration — defines entities, potential XXE or entity expansion",pattern:/<!ENTITY[\s%]/i},{id:"xml-billion-laughs",description:"Entity reference chaining / billion laughs: repeated &eX; style references",pattern:/(?:&\w{1,20};){3,}/},{id:"xml-namespace-confusion",description:"xmlns: attribute injection — can redefine namespaces to confuse parsers",pattern:/\bxmlns\s*(?::\w{1,40})?\s*=/i},{id:"xml-comment-injection",description:"\x3c!-- comment injection — can hide content from some parsers",pattern:/<!--/},{id:"xml-comment-close",description:"--\x3e closes an enclosing XML comment",pattern:/-->/},{id:"xml-pi-close",description:"?> closes an enclosing processing instruction",pattern:/\?>/}],SVG:[{id:"svg-script-element",description:"<script element inside SVG executes JavaScript",pattern:/<script[\s>/]/i},{id:"svg-xlink-href-javascript",description:"xlink:href with javascript: — classic SVG XSS via <a> or <use>",pattern:/xlink\s*:\s*href\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-href-javascript",description:"href= with javascript: in SVG context (<a>, <animate>, etc.)",pattern:/href\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-foreignobject",description:"<foreignObject embeds HTML inside SVG — can execute scripts",pattern:/<foreignObject[\s>/]/i},{id:"svg-use-external",description:"<use xlink:href or href pointing to external resource (non-fragment URL)",pattern:/<use[\s\S]{0,60}(?:xlink\s*:\s*)?href\s*=\s*(?:["'][^#]|[^"'#\s>])/i},{id:"svg-animate-href",description:'<animate attributeName="href" — can dynamically change href to javascript:',pattern:/<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*href["']/i},{id:"svg-animate-xlinkhref",description:'<animate attributeName="xlink:href"',pattern:/<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*xlink\s*:\s*href["']/i},{id:"svg-set-javascript",description:'<set to="javascript:..." — sets an attribute to a javascript: URI',pattern:/<set[\s\S]{0,80}to\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-event-handler",description:"SVG-specific event handler attributes: onload=, onerror=, onactivate=, etc.",pattern:/\bon(?:load|error|activate|begin|end|repeat|focus|blur|click|mouse\w{1,20}|key\w{1,20})\s*=/i},{id:"svg-handler-generic",description:"Generic on* handler catch-all for SVG attributes",pattern:/\bon\w{1,30}\s*=/i},{id:"svg-filter-feimage",description:"<feImage href= — filter primitive that can load external resources",pattern:/<feImage[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=/i},{id:"svg-image-external",description:"<image xlink:href with http/https or javascript protocol",pattern:/<image[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=\s*["']?\s*(?:https?|javascript)\s*:/i},{id:"svg-style-javascript",description:"style= attribute containing javascript: (e.g. background:url(javascript:...))",pattern:/style\s*=[\s\S]{0,60}javascript\s*:/i}],SQL:b,"SQL-STRICT":[...b,{id:"sql-line-comment",description:"SQL line comment: -- followed by whitespace or end of string",pattern:/--(?:\s|$)/},{id:"sql-stacked-query",description:"Stacked queries: semicolon immediately followed by a SQL keyword",pattern:/;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i},{id:"sql-hex-encoding",description:"Hex-encoded string injection: 0x41414141 style (MySQL)",pattern:/\b0x[0-9a-f]{4,}/i}],SHELL:[{id:"shell-path-traversal-unix",description:"Unix path traversal: ../ — climbing the directory tree",pattern:/\.\.\//},{id:"shell-path-traversal-windows",description:"Windows path traversal: ..\\ — climbing the directory tree",pattern:/\.\.\\/},{id:"shell-path-traversal-encoded",description:"URL-encoded path traversal: %2e%2e or %2f variants",pattern:/%2e%2e|%2f\.\.|\.\.%2f/i},{id:"shell-null-byte",description:"Null byte injection: \\x00 or %00 — truncates strings in C-backed functions",pattern:/\x00|%00/},{id:"shell-semicolon",description:"Semicolon command separator: cmd1; cmd2",pattern:/;/},{id:"shell-pipe",description:"Pipe operator: cmd1 | cmd2",pattern:/\|/},{id:"shell-and-operator",description:"AND operator: cmd1 && cmd2",pattern:/&&/},{id:"shell-or-operator",description:"OR operator: cmd1 || cmd2",pattern:/\|\|/},{id:"shell-backtick",description:"Backtick command substitution: `cmd`",pattern:/`/},{id:"shell-dollar-paren",description:"Dollar-paren command substitution: $(cmd)",pattern:/\$\(/},{id:"shell-dollar-brace",description:"Dollar-brace variable expansion: ${var} — can be abused for injection",pattern:/\$\{/},{id:"shell-redirect-out",description:"Output redirection: cmd > file or cmd >> file",pattern:/>{1,2}/},{id:"shell-redirect-in",description:"Input redirection: cmd < file",pattern:/</},{id:"shell-newline-injection",description:"Newline injection: \\n or \\r — can inject new shell commands",pattern:/[\n\r]/},{id:"shell-glob-star",description:"Glob expansion: * or ? — can expand to unintended files",pattern:/[/\\][*?]/},{id:"shell-absolute-root",description:"Absolute root path injection: string starting with / or \\ (Windows UNC)",pattern:/^(?:\/|\\\\)/},{id:"shell-windows-drive",description:"Windows drive letter path injection: C:\\ or D:/",pattern:/^[a-zA-Z]:[/\\]/},{id:"shell-curl-wget",description:"curl/wget with URL or flags — can exfiltrate data or download payloads",pattern:/\b(?:curl|wget)\s+(?:https?:\/\/|ftp:\/\/|-)/i}],REDOS:[{id:"redos-nested-quantifier-plus",description:"Nested + quantifier inside a group with outer quantifier: (a+)+, (.+b)*, etc.",pattern:/\([^)]*\+[^)]*\)[+*]/},{id:"redos-nested-quantifier-star",description:"Nested * quantifier: (a*)* or (a*)+ — catastrophic backtracking",pattern:/\([^)]*\*[^)]*\)[*+]/},{id:"redos-nested-groups",description:"Doubly nested quantified groups: ((a+)+) — guaranteed catastrophic",pattern:/\(\([^)]{0,40}\)[+*]\)[+*]/},{id:"redos-alternation-overlap",description:"Overlapping alternation under quantifier: (a|a)+ — ambiguous NFA paths",pattern:/\(([^|()]{1,20})\|(?:\1)(?:\|[^|()]{1,20}){0,5}\)[+*?]{1,2}/},{id:"redos-star-plus-concat",description:"(x*x)+ pattern — triggers super-linear backtracking",pattern:/\([^)]{0,10}\*[^)]{0,10}\)[+*]/},{id:"redos-dot-star-greedy",description:"(.*){n,} or (.+){n,} — repeated greedy dot quantifiers",pattern:/\(\.[*+]\)\{?\d/},{id:"redos-large-repetition",description:"Very large fixed or range repetition count {1000,} or {1000,n} — denial of service via backtracking",pattern:/\{\d{4,}(?:,\d*)?\}/},{id:"redos-catastrophic-alternation",description:"Long alternation with many similar branches — polynomial backtracking risk",pattern:/\([^)]{0,200}(?:\|[^|)]{0,50}){9,}\)/}],NOSQL:[{id:"nosql-where-operator",description:"$where — executes arbitrary JavaScript server-side in MongoDB",pattern:new RegExp(`\\$where${y}`,"i")},{id:"nosql-ne-operator",description:'$ne — "not equal" operator used to bypass equality checks',pattern:new RegExp(`\\$ne${y}`,"i")},{id:"nosql-gt-operator",description:'$gt — "greater than" used to bypass password/value checks',pattern:new RegExp(`\\$gte?${y}`,"i")},{id:"nosql-lt-operator",description:'$lt / $lte — "less than" bypass variants',pattern:new RegExp(`\\$lte?${y}`,"i")},{id:"nosql-regex-operator",description:"$regex — can be used to extract data character by character (blind injection)",pattern:new RegExp(`\\$regex${y}`,"i")},{id:"nosql-or-operator",description:"$or — logical OR; used to create always-true conditions",pattern:new RegExp(`\\$or${y}\\s*\\[`,"i")},{id:"nosql-and-operator",description:"$and — logical AND operator injection",pattern:new RegExp(`\\$and${y}\\s*\\[`,"i")},{id:"nosql-nor-operator",description:"$nor — logical NOR operator injection",pattern:new RegExp(`\\$nor${y}\\s*\\[`,"i")},{id:"nosql-exists-operator",description:"$exists — can enumerate fields to determine schema",pattern:new RegExp(`\\$exists${y}`,"i")},{id:"nosql-in-operator",description:"$in — matches any value in a list; can enumerate values",pattern:new RegExp(`\\$in${y}\\s*\\[`,"i")},{id:"nosql-expr-operator",description:"$expr — allows aggregation expressions in queries (MongoDB 3.6+)",pattern:new RegExp(`\\$expr${y}`,"i")},{id:"nosql-function-operator",description:"$function — executes arbitrary JavaScript in MongoDB 4.4+",pattern:new RegExp(`\\$function${y}`,"i")},{id:"nosql-accumulator-operator",description:"$accumulator — custom aggregation with arbitrary JS execution",pattern:new RegExp(`\\$accumulator${y}`,"i")},{id:"nosql-proto-pollution",description:"__proto__ — prototype pollution via object key injection",pattern:/__proto__/},{id:"nosql-constructor-prototype",description:"constructor.prototype — alternative prototype pollution vector (dot notation or JSON key)",pattern:/constructor[\s"':.,{\[]*prototype/i},{id:"nosql-proto-bracket",description:'["__proto__"] — bracket-notation prototype pollution',pattern:/\[["']__proto__["']\]/}],LOG:[{id:"log-crlf-injection",description:"CRLF injection: literal \\r or \\n embeds fake log lines",pattern:/[\r\n]/},{id:"log-url-encoded-crlf",description:"URL-encoded CRLF: %0d, %0a, %0D, %0A — decoded by some log parsers",pattern:/%0[dDaA]/},{id:"log-unicode-newline",description:"Unicode newline variants: U+2028 (line separator), U+2029 (paragraph separator)",pattern:/[\u2028\u2029]/},{id:"log-log4shell-jndi",description:"Log4Shell: ${jndi:...} triggers remote code execution in Apache Log4j",pattern:/\$\{jndi\s*:/i},{id:"log-log4shell-obfuscated",description:"Obfuscated Log4Shell: ${::-j}... lookup-bypass prefix used to evade WAF detection",pattern:/\$\{::-/},{id:"log-log4j-lookup",description:"Log4j lookup syntax: ${env:...}, ${sys:...}, ${ctx:...} — data exfiltration",pattern:/\$\{(?:env|sys|ctx|main|map|sd|web|docker|k8s|spring)\s*:/i},{id:"log-ssti-double-brace",description:"SSTI double-brace: {{expression}} — Jinja2, Twig, Handlebars, etc.",pattern:/\{\{[\s\S]{0,80}\}\}/},{id:"log-ssti-hash-brace",description:"SSTI hash-brace: #{expression} — Thymeleaf, Velocity, Ruby ERB",pattern:/#\{[\s\S]{0,80}\}/},{id:"log-ssti-dollar-brace",description:"SSTI/EL injection: ${expression with operators or method calls} — JSP EL, Freemarker, SpEL",pattern:/\$\{[^}]*(?:\.|\(|\*|\+|\bclass\b|\bruntime\b|\bprocess\b|\bexec\b)[^}]{0,80}\}/i},{id:"log-ssti-percent-tag",description:"SSTI ERB/ASP tag: <%= expression %> — Ruby ERB, ASP",pattern:/<%=[\s\S]{0,80}%>/},{id:"log-null-byte",description:"Null byte: \\x00 or %00 — can truncate log entries in C-backed loggers",pattern:/\x00|%00/},{id:"log-ansi-escape",description:"ANSI escape sequence: ESC[ — can manipulate terminal output when logs are tailed",pattern:/\x1b\[/}]},I=N,A=Object.freeze(Object.fromEntries(Object.keys(N).map(t=>[t,t])));function S(t,e){const s=I[e];for(const r of s)if(r.pattern.test(t))return{context:e,id:r.id,description:r.description,pattern:r.pattern};return null}function C(t,e){if(function(t){if("string"!=typeof t)throw new TypeError("is-unsafe: first argument must be a string, got "+typeof t)}(t),function(t){if(!(t instanceof RegExp))if("string"!=typeof t){if(!Array.isArray(t))throw new TypeError("is-unsafe: second argument must be a context string, array of context strings, or RegExp. Got: "+typeof t);if(0===t.length)throw new TypeError("is-unsafe: context array must not be empty");for(const e of t)if("string"!=typeof e||!I[e])throw new TypeError(`is-unsafe: unknown context "${e}" in array. Valid contexts: ${Object.keys(A).join(", ")}`)}else if(!I[t])throw new TypeError(`is-unsafe: unknown context "${t}". Valid contexts: ${Object.keys(A).join(", ")}`)}(e),e instanceof RegExp)return e.test(t);if("string"==typeof e)return null!==S(t,e);for(const s of e)if(null!==S(t,s))return!0;return!1}class D{constructor(t=!1){this.IS_FINAL=t}init(t){this.ctx=t}reset(){}parse(t,e){throw new Error("You must implement parse() in a value parser.")}}const v={namedEntities:{...d},numericAllowed:!0,onInputEntity:(t,e)=>C(e,[A.XML])?u.BLOCK:u.ALLOW},k=[48,1632,1776,2406,2534,2662,2790,2918,3046,3174,3302,3430,3558,3664,3792,3872,4160,4240,6112,6160,6470,6608,6784,6800,6992,7088,7232,7248,65296,120782,120792,120802,120812,120822,66720,68912,69734,69872,69942,70096,70384,70736,70864,71248,71360,71472,71904,72016,72688,72784,73040,73120,73552,92768,92864,93008,123200,123632,124144,125264,130032],P=new Map,O=1632,U=new Uint8Array(63904).fill(255);for(const t of k)for(let e=0;e<10;e++){const s=t+e;s<=65535?U[s-O]=e:P.set(s,e)}const $=new Set([8722,65293,65123]),L=/^[-+]?0x[a-fA-F0-9]+$/,R=/^0b[01]+$/,M=/^0o[0-7]+$/,B=/^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/,j={hex:!0,binary:!1,octal:!1,leadingZeros:!0,decimalPoint:".",eNotation:!0,infinity:"original",unicode:!1};function X(t,e={}){if(e=Object.assign({},j,e),!t||"string"!=typeof t)return t;let s=t.trim();if(0===s.length)return t;if(void 0!==e.skipLike&&e.skipLike.test(s))return t;if("0"===s)return 0;if(e.unicode&&(s=function(t){if("string"!=typeof t)return t;const e=t.length;if(0===e)return t;let s=-1;for(let r=0;r<e;r++){const i=t.charCodeAt(r);if(!(i>=48&&i<=57||45===i))if(i<O){if($.has(i)){s=r;break}}else if(i>=55296&&i<=56319){if(r+1<e){const e=t.charCodeAt(r+1);if(e>=56320&&e<=57343){const t=65536+(i-55296<<10)+(e-56320);if(P.has(t)){s=r;break}}}}else if(255!==U[i-O]||$.has(i)){s=r;break}}if(-1===s)return t;const r=[];s>0&&r.push(t.slice(0,s));for(let i=s;i<e;i++){const s=t.charCodeAt(i);if(s>=48&&s<=57||45===s){r.push(t[i]);continue}if(s<O){r.push($.has(s)?"-":t[i]);continue}if(s>=55296&&s<=56319){if(i+1<e){const e=t.charCodeAt(i+1);if(e>=56320&&e<=57343){const t=65536+(s-55296<<10)+(e-56320),n=P.get(t);if(void 0!==n){r.push(String.fromCharCode(n+48)),i++;continue}}}r.push(t[i]);continue}if($.has(s)){r.push("-");continue}const n=U[s-O];r.push(255!==n?String.fromCharCode(n+48):t[i])}return r.join("")}(s),"0"===s))return 0;if(e.hex&&L.test(s))return Y(s,16);if(e.binary&&R.test(s))return Y(s,2);if(e.octal&&M.test(s))return Y(s,8);if(isFinite(s)){if(s.includes("e")||s.includes("E"))return function(t,e,s){if(!s.eNotation)return t;const r=e.match(V);if(r){let i=r[1]||"";const n=-1===r[3].indexOf("e")?"E":"e",o=r[2],a=i?t[o.length+1]===n:t[o.length]===n;return o.length>1&&a?t:(1!==o.length||!r[3].startsWith(`.${n}`)&&r[3][0]!==n)&&o.length>0?s.leadingZeros&&!a?(e=(r[1]||"")+r[3],Number(e)):t:Number(e)}return t}(t,s,e);{const i=B.exec(s);if(i){const n=i[1]||"",o=i[2];let a=(r=i[3])&&-1!==r.indexOf(".")?("."===(r=r.replace(/0+$/,""))?r="0":"."===r[0]?r="0"+r:"."===r[r.length-1]&&(r=r.substring(0,r.length-1)),r):r;const c=n?"."===t[o.length+1]:"."===t[o.length];if(!e.leadingZeros&&(o.length>1||1===o.length&&!c))return t;{const r=Number(s),i=String(r);if(0===r)return r;if(-1!==i.search(/[eE]/))return e.eNotation?r:t;if(-1!==s.indexOf("."))return"0"===i||i===a||i===`${n}${a}`?r:t;let c=o?a:s;return o?c===i||n+c===i?r:t:c===i||c===n+i?r:t}}return t}}var r;return function(t,e,s){const r=e===1/0;switch(s.infinity.toLowerCase()){case"null":return null;case"infinity":return e;case"string":return r?"Infinity":"-Infinity";default:return t}}(t,Number(s),e)}const V=/^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;function Y(t,e){const s=t.trim();if(2!==e&&8!==e||(t=s.substring(2)),parseInt)return parseInt(t,e);if(Number.parseInt)return Number.parseInt(t,e);if(window&&window.parseInt)return window.parseInt(t,e);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}const F={entity:new class extends D{#t=!1;#e=null;#s=null;constructor(t,e=!1){super(e),this.#s={...v,...t||{},namedEntities:{...v.namedEntities,...t?.namedEntities||{}}}}#r(){if(this.#e||(this.#e=new w(this.#s)),!this.#t){const t=this.ctx?.get("xmlVersion"),e=this.ctx?.get("inputEntities");t&&this.#e.setXmlVersion(t),e&&this.#e.addInputEntities(e),this.#t=!0}}reset(){this.#t=!1,this.#e&&this.#e.reset()}parse(t){return"string"!=typeof t?t:(this.#r(),this.#e.decode(t))}},trim:new class extends D{parse(t){return"string"==typeof t?t.trim():t}},ws:new class extends D{constructor(t,e=!1){super(e);const i=t?.exclude??[],n=new s;for(const t of i)n.add("string"==typeof t?new r(t):t);n.seal(),this._excludeSet=n}parse(t,e){if("string"!=typeof t)return t;if(e){if(e.isAttribute)return t;if(e.matcher){if("preserve"===e.matcher.getAnyParentAttr("xml:space"))return t;if(this._excludeSet.size>0&&this._excludeSet.matchesAny(e.matcher))return t}}return t.replace(/[ \t\r\n]+/g," ").trim()}},boolean:new class extends D{constructor(t,e,s=!1){super(s),this.trueList=t||["true"],this.falseList=e||["false"]}parse(t){if("string"==typeof t){const e=t.toLowerCase();if(-1!==this.trueList.indexOf(e))return!this.IS_FINAL||new z(!0);if(-1!==this.falseList.indexOf(e))return!!this.IS_FINAL&&new z(!1)}return t}},number:new class extends D{constructor(t,e=!1){super(e),this.options=t||{}}parse(t){if("string"==typeof t){const e=X(t,this.options);if(typeof e!==t)return this.IS_FINAL?new z(e):e}return t}}({hex:!0,leadingZeros:!0,eNotation:!0})};class q{constructor(){this.registered={...F}}register(t,e){if(!t||"string"!=typeof t)throw new Error("name must be a string");if(!e)throw new Error("parser is required");if(!e.reset||"function"!=typeof e.reset)throw new Error("parser must implement reset()");if(!e.parse||"function"!=typeof e.parse)throw new Error("parser must implement parse()");this.registered[t]=e}reset(t){this.registered[t]?.reset()}resetAll(){for(const t in this.registered)this.registered[t]?.reset()}get(t){const e=this.registered[t];if(!e)throw new Error("parser not found: "+t);return e}}class G{constructor(t,e,s,r=!1){this.elementName=t,this.matcher=e,this.isLeafNode=s,this.isAttribute=r}}class z{constructor(t){this.value=t}}class H{#i={};set(t,e){this.#i[t]=e}get(t){return this.#i[t]}clear(){this.#i={}}}class W{constructor(t=[],e,s=null){this.valParsers=t,this.registry=e,this.sharedContext=s||new H,this._initAll(t)}run(t,e){for(let s=0;s<this.valParsers.length;s++){let r=this.valParsers[s];if("string"==typeof r&&(r=this.registry.get(r)),r){const s=r.parse(t,e);if(s instanceof z)return s.value;t=s}}return t}resetAll(){for(let t=0;t<this.valParsers.length;t++){let e=this.valParsers[t];"string"==typeof e&&(e=this.registry.get(e)),e&&e.reset&&"function"==typeof e.reset&&e.reset()}}register(t,e){this.registry.register(t,e),e.init&&e.init(this.sharedContext)}_initAll(t){if(!this.sharedContext)return;const e=new Set;for(const s of t){let t=s;"string"==typeof s&&(t=this.registry.get(s)),t&&"function"==typeof t.init&&!e.has(t)&&(e.add(t),t.init(this.sharedContext))}}}const Q=["ws","entity","boolean","number"],J=["entity","boolean","number"];class Z{constructor(t,e,s,r,i=!0){this.matcher=s,this._rootName="^",this.parserOptions=t,this.builderOptions=e,this.registry=r;const n=e?.tags?.valueParsers??Q,o=e?.attributes?.valueParsers??J;this.sharedContext=new H,this.tagsPipeline=new W(n,this.registry,this.sharedContext),this.attrsPipeline=new W(o,this.registry,this.sharedContext),i&&(this.tagsPipeline.resetAll(),this.attrsPipeline.resetAll()),this._pendingStopNode=!1}addAttribute(t,e,s){"version"===t&&this.tagName===this._rootName&&this.sharedContext?.set("xmlVersion",+e);const r=`${this.parserOptions.attributes.prefix}${t}${this.parserOptions.attributes.suffix}`,i=new G(t,s,!0,!0);this.attributes[r]=this.attrsPipeline.run(e,i)}_addChild(t,e){}addComment(t){this.parserOptions.skip.comment||this.parserOptions.nameFor.comment&&this._addChild(this.parserOptions.nameFor.comment,t)}addLiteral(t){this.parserOptions.skip.cdata||(this.parserOptions.nameFor.cdata?this._addChild(this.parserOptions.nameFor.cdata,t):this.addRawValue(t||""))}addRawValue(t){this.addValue(t)}addInputEntities(t){this.sharedContext?.set("inputEntities",t)}addDeclaration(t){this.addInstruction(t)}addInstruction(t){}onStopNode(t,e){this._pendingStopNode=!0,"function"==typeof this.parserOptions.onStopNode&&this.parserOptions.onStopNode(t,e,this.matcher)}onExit(t){}}class K{constructor(t={}){this.builderOptions=t,this.registry=new q}registerValueParser(t,e){this.registry.register(t,e)}getInstance(t,e){throw new Error("getInstance is not implemented")}}class tt extends K{constructor(t={}){super(),this.builderOptions=a(t)}getInstance(t,e){return new et(t,this.builderOptions,e,this.registry)}}class et extends Z{constructor(t,e,s,r){super(t,e,s,r),this.parserOptions=t,this.builderOptions=e,this.tagsStack=[],this.root={},this.parent=this.root,this.tagName=this._rootName,this.value={},this.textValue="",this.attributes={},this.hasAttributes=!1}_buildAttributeValue(){return st(this.attributes)?(this.hasAttributes=!1,""):(this.hasAttributes=!0,this.parserOptions.attributes.groupBy?{[this.parserOptions.attributes.groupBy]:this.attributes}:this.attributes)}addElement(t){const e=this._buildAttributeValue();this.tagsStack.push([this.tagName,this.textValue,this.value,this.hasAttributes]),this.tagName=t.name,this.value=e,this.textValue="",this.attributes={}}_resolveForceArray(t){let e,s;if(this.builderOptions._alwaysArraySet.matchesAny(this.matcher)&&(e=!0),"function"==typeof this.builderOptions.forceArray){const e=this.builderOptions.forceArray(this.matcher,t);!0===e?s=!0:!1===e&&(s=!1)}return!1!==e&&!1!==s&&(!0===e||!0===s)}closeElement(){const t=this.tagName;let e=this.value;const s=this.textValue,r=this.hasAttributes,i="object"!=typeof e||Array.isArray(e)||st(e)||r,n=new G(t,this.matcher,i,!1);if(i){const t=this._pendingStopNode?s:this.tagsPipeline.run(s,n);r?(""!==t&&null!=t||this.builderOptions.forceTextNode)&&(e[this.parserOptions.nameFor.text]=t):e=this.builderOptions.forceTextNode?{[this.parserOptions.nameFor.text]:t}:t}else if(s.length>0||this.builderOptions.forceTextNode){const t=this._pendingStopNode?s:this.tagsPipeline.run(s,n);e[this.parserOptions.nameFor.text]=t}let o={tagName:t,value:e};const a=this.tagsStack.pop();let c=a[2];const l=this._resolveForceArray(i);c=this._addChildTo(o.tagName,o.value,c,l),this.tagName=a[0],this.textValue=a[1],this.value=c,this.hasAttributes=a[3],this._pendingStopNode=!1}_addChild(t,e){"string"==typeof this.value&&(this.value={[this.parserOptions.nameFor.text]:this.value}),this._addChildTo(t,e,this.value,!1),this.attributes={}}_addChildTo(t,e,s,r){return"string"==typeof s&&(s={}),Object.prototype.hasOwnProperty.call(s,t)?(Array.isArray(s[t])||(s[t]=[s[t]]),s[t].push(e)):s[t]=r?[e]:e,s}addValue(t){this.textValue.length>0?this.textValue+=`${this.builderOptions.textJoint}${t}`:this.textValue=t}addInstruction(t){const e=this._buildAttributeValue();this._addChild(t,e),this.attributes={}}onExit(t){}getOutput(){return this.value}}function st(t){return 0===Object.keys(t).length}class rt{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],r=s?.tag;if(r&&"*"!==r){const s=`${e}:${r}`;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(),r=`${e}:${s}`,i=this._byDepthAndTag.get(r);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];const o=this._deepByTerminalTag.get(s);if(o)for(let e=0;e<o.length;e++)if(t.matches(o[e]))return o[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}class it{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,r="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(r.trim()&&(e.push(this._parseSegment(r.trim())),r=""),e.push({type:"deep-wildcard"}),s+=2):(r.trim()&&e.push(this._parseSegment(r.trim())),r="",s++):(r+=t[s],s++);return r.trim()&&e.push(this._parseSegment(r.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,r=t;const i=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(i&&(r=i[1]+i[3],i[2])){const t=i[2].slice(1,-1);t&&(s=t)}let n,o,a=r;if(r.includes("::")){const e=r.indexOf("::");if(n=r.substring(0,e).trim(),a=r.substring(e+2).trim(),!n)throw new Error(`Invalid namespace in pattern: ${t}`)}let c=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)?(o=e,c=s):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,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(c){const t=c.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=c}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 nt extends Error{constructor(t,e,s={}){super(t),this.name="ParseError",this.code=e,this.line=s.line??void 0,this.col=s.col??void 0,this.index=s.index??void 0}toString(){const t=this._posStr();return t?`${this.name} [${this.code}] at ${t}: ${this.message}`:`${this.name} [${this.code}]: ${this.message}`}_posStr(){return void 0!==this.line&&void 0!==this.col?`line ${this.line}, col ${this.col}`:void 0!==this.index?`index ${this.index}`:null}}const ot=Object.freeze({INVALID_INPUT:"INVALID_INPUT",INVALID_STREAM:"INVALID_STREAM",ALREADY_STREAMING:"ALREADY_STREAMING",NOT_STREAMING:"NOT_STREAMING",DATA_MUST_BE_STRING:"DATA_MUST_BE_STRING",UNEXPECTED_END:"UNEXPECTED_END",UNEXPECTED_CLOSE_TAG:"UNEXPECTED_CLOSE_TAG",MISMATCHED_CLOSE_TAG:"MISMATCHED_CLOSE_TAG",UNEXPECTED_TRAILING_DATA:"UNEXPECTED_TRAILING_DATA",INVALID_TAG:"INVALID_TAG",UNCLOSED_QUOTE:"UNCLOSED_QUOTE",MULTIPLE_NAMESPACES:"MULTIPLE_NAMESPACES",SECURITY_PROTOTYPE_POLLUTION:"SECURITY_PROTOTYPE_POLLUTION",SECURITY_RESERVED_OPTION:"SECURITY_RESERVED_OPTION",SECURITY_RESTRICTED_NAME:"SECURITY_RESTRICTED_NAME",LIMIT_MAX_NESTED_TAGS:"LIMIT_MAX_NESTED_TAGS",LIMIT_MAX_ATTRIBUTES:"LIMIT_MAX_ATTRIBUTES",ENTITY_MAX_COUNT:"ENTITY_MAX_COUNT",ENTITY_MAX_SIZE:"ENTITY_MAX_SIZE",ENTITY_MAX_EXPANSIONS:"ENTITY_MAX_EXPANSIONS",ENTITY_MAX_EXPANDED_LENGTH:"ENTITY_MAX_EXPANDED_LENGTH",ENTITY_INVALID_KEY:"ENTITY_INVALID_KEY",ENTITY_INVALID_VALUE:"ENTITY_INVALID_VALUE"});function at(t){return" "===t||"\t"===t||"\n"===t||"\r"===t||"\f"===t}function ct(t){return 32===t||9===t||10===t||13===t||12===t}const lt=["hasOwnProperty","toString","valueOf","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__","toLocaleString","isPrototypeOf","propertyIsEnumerable"],ht=["__proto__","constructor","prototype"],dt=t=>lt.includes(t)?"__"+t:t,ut={skip:{declaration:!1,pi:!1,attributes:!0,cdata:!1,comment:!1,nsPrefix:!1,tags:[],whitespaceText:!0},nameFor:{text:"#text",cdata:"",comment:""},attributes:{booleanType:!1,groupBy:"",prefix:"@_",suffix:""},tags:{unpaired:[],stopNodes:[]},strictReservedNames:!1,onDangerousProperty:dt,only:[],doctypeOptions:{enabled:!1,maxEntityCount:100,maxEntitySize:1e4},autoClose:null,limits:{maxNestedTags:null,maxAttributesPerTag:null},feedable:{maxBufferSize:10485760,autoFlush:!0,flushThreshold:1024,bufferSize:256},exitIf:null,OutputBuilder:null},pt=new Set([...ht,...lt]);function ft(t,e){if("string"==typeof t&&""!==t&&pt.has(t))throw new nt(`SECURITY: '${t}' is a reserved JavaScript keyword and cannot be used as ${e}`,ot.SECURITY_RESERVED_OPTION)}const gt=function(t){if(t&&(t.nameFor?.text&&ft(t.nameFor.text,"nameFor.text"),t.nameFor?.cdata&&ft(t.nameFor.cdata,"nameFor.cdata"),t.nameFor?.comment&&ft(t.nameFor.comment,"nameFor.comment"),t.attributes?.prefix&&ft(t.attributes.prefix,"attributes.prefix"),t.attributes?.groupBy&&ft(t.attributes.groupBy,"attributes.groupBy"),void 0!==t.limits&&null!==t.limits)){if("object"!=typeof t.limits)throw new nt("'limits' must be an object, got "+typeof t.limits,ot.INVALID_INPUT);const{maxNestedTags:e,maxAttributesPerTag:s}=t.limits;if(null!=e&&("number"!=typeof e||!Number.isInteger(e)||e<1))throw new nt(`'limits.maxNestedTags' must be a positive integer, got ${e}`,ot.INVALID_INPUT);if(null!=s&&("number"!=typeof s||!Number.isInteger(s)||s<0))throw new nt(`'limits.maxAttributesPerTag' must be a non-negative integer, got ${s}`,ot.INVALID_INPUT)}const e=Et(ut);if(t&&xt(e,t),e.OutputBuilder||(e.OutputBuilder=new tt),Array.isArray(e.tags?.stopNodes)){const t=new rt;e.tags.stopNodes=e.tags.stopNodes.map(e=>_t(e,"stopNodes",t)),t.seal(),e.tags.stopNodesSet=t}if(Array.isArray(e.skip?.tags)){const t=new rt;e.skip.tags=e.skip.tags.map(e=>_t(e,"skip.tags",t)),t.seal(),e.skip.tagsSet=t}if(null===e.onDangerousProperty&&(e.onDangerousProperty=dt),null!==e.exitIf&&void 0!==e.exitIf&&"function"!=typeof e.exitIf)throw new nt("'exitIf' must be a function, got "+typeof e.exitIf,ot.INVALID_INPUT);return e.autoClose=function(t,e){if(!t)return null;if("html"===t){const t=e.tags.unpaired||[],s=[...new Set([...t,...mt])];return e.tags={...e.tags,unpaired:s},{onEof:"closeAll",onMismatch:"discard",collectErrors:!0}}return"string"==typeof t?{onEof:t,onMismatch:"throw",collectErrors:!1}:"object"==typeof t?{onEof:t.onEof||"throw",onMismatch:t.onMismatch||"throw",collectErrors:t.collectErrors||!1}:null}(e.autoClose,e),e},mt=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"];function _t(t,e,s){let r,i,n;if("string"==typeof t){if(0===t.length)throw new nt(`${e} expression cannot be empty`,ot.INVALID_INPUT);r=t,i=!1,n=[]}else if(t instanceof it)r=t.toString(),i=t.data?.nested??!1,n=t.data?.skipEnclosures??[];else{if(!t||"object"!=typeof t||void 0===t.expression)throw new nt(`Invalid ${e} entry: expected a string, Expression, or { expression, nested?, skipEnclosures? } object.`,ot.INVALID_INPUT);{const s=t.expression;if("string"==typeof s){if(0===s.length)throw new nt(`${e} expression cannot be empty`,ot.INVALID_INPUT);r=s}else{if(!(s instanceof it))throw new nt(`${e} expression must be a string or Expression instance`,ot.INVALID_INPUT);r=s.toString()}i=!0===t.nested,n=Array.isArray(t.skipEnclosures)?t.skipEnclosures:[]}}const o=new it(r,{},{nested:i,skipEnclosures:n});return s.add(o),o}function Et(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(Et);if(t instanceof RegExp)return t;if(t instanceof it)return t;const e={};for(const s of Object.keys(t))e[s]="function"==typeof t[s]?t[s]:Et(t[s]);return e}function xt(t,e){for(const s of Object.keys(e))"__proto__"!==s&&"constructor"!==s&&"prototype"!==s&&("OutputBuilder"===s||"function"==typeof e[s]||e[s]instanceof RegExp||Array.isArray(e[s])?t[s]=e[s]:"object"==typeof e[s]&&null!==e[s]?("object"==typeof t[s]&&null!==t[s]||(t[s]={}),xt(t[s],e[s])):t[s]=e[s])}class Tt{constructor(t,e={}){this.line=1,this.cols=0,this.buffer=t,this.startIndex=0,this.autoFlush=!1!==e.autoFlush,this.flushThreshold=e.flushThreshold??1024,this._marks=[-1,-1]}markTokenStart(t=0){this._marks[t]=this.startIndex}rewindToMark(){}clearMark(){this._marks[0]=-1,this._marks[1]=-1}flush(){let t=this.startIndex;for(const e of this._marks)e>=0&&e<t&&(t=e);if(t>0){this.buffer=this.buffer.substring(t);const e=this._marks.length;for(let s=0;s<e;s++)this._marks[s]>=0&&(this._marks[s]-=t);this.startIndex-=t}}readCh(){return this.buffer[this.startIndex++]}readChAt(t){return this.buffer[this.startIndex+t]}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.substring(e,e+t)}readUpto(t){const e=this.buffer.length,s=t.length;for(let r=this.startIndex;r<e;r++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[r+i]!==t[i]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=r+s,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END);const s=this.buffer.substring(this.startIndex,e);return this.startIndex=e+1,s}readUptoCloseTag(t){const e=this.buffer.length,s=t.length;let r=-1,i=0;for(let n=this.startIndex;n<e;n++){if(1===i){const t=this.buffer[n];if(" "===t||"\t"===t)continue;">"===t?i=2:(i=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[n+r]!==t[r]){e=!1;break}e&&(i=1,r=n,n+=s-1)}if(2===i){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=n+1,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readFromBuffer(t,e){const s=1===t?this.buffer[this.startIndex]:this.buffer.substring(this.startIndex,this.startIndex+t);return e&&this.updateBufferBoundary(t),s}updateBufferBoundary(t=1){this.startIndex+=t;const e=this._marks[0]>=0||this._marks[1]>=0;this.autoFlush&&this.startIndex>=this.flushThreshold&&!e&&this.flush()}canRead(t){return t=void 0!==t?t:this.startIndex,this.buffer.length-t>0}}class wt{constructor(t,e={}){this.line=1,this.cols=0,this.buffer=t,this.startIndex=0,this.autoFlush=!1!==e.autoFlush,this.flushThreshold=e.flushThreshold??1024,this._tokenStart=-1}markTokenStart(){this._tokenStart=this.startIndex}rewindToMark(){}flush(){const t=this._tokenStart>=0?this._tokenStart:this.startIndex;t>0&&(this.buffer=Buffer.from(this.buffer.subarray(t)),this._tokenStart>=0?(this.startIndex-=t,this._tokenStart=0):this.startIndex=0)}readCh(){return String.fromCharCode(this.buffer[this.startIndex++])}readChAt(t){return String.fromCharCode(this.buffer[this.startIndex+t])}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.slice(e,e+t).toString()}readUpto(t){const e=this.buffer.length,s=t.length,r=Buffer.from(t);for(let t=this.startIndex;t<e;t++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[t+i]!==r[i]){e=!1;break}if(e){const e=this.buffer.slice(this.startIndex,t).toString();return this.startIndex=t+s,e}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=t.charCodeAt(0),s=this.buffer,r=s.length;for(let t=this.startIndex;t<r;t++)if(s[t]===e){const e=s.slice(this.startIndex,t).toString();return this.startIndex=t+1,e}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoCloseTag(t){const e=this.buffer.length,s=t.length,r=Buffer.from(t);let i=-1,n=0;for(let t=this.startIndex;t<e;t++){if(1===n){const e=this.buffer[t];if(32===e||9===e)continue;62===e?n=2:(n=0,i=-1)}else{let e=!0;for(let i=0;i<s;i++)if(this.buffer[t+i]!==r[i]){e=!1;break}e&&(n=1,i=t,t+=s-1)}if(2===n){const e=this.buffer.slice(this.startIndex,i).toString();return this.startIndex=t+1,e}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readFromBuffer(t,e){let s;return 1===t?(s=this.buffer[this.startIndex],10===s?(this.line++,this.cols=1):this.cols++,s=String.fromCharCode(s)):(this.cols+=t,s=this.buffer.slice(this.startIndex,this.startIndex+t).toString()),e&&this.updateBufferBoundary(t),s}updateBufferBoundary(t=1){this.startIndex+=t,this.autoFlush&&this.startIndex>=this.flushThreshold&&this._tokenStart<0&&this.flush()}canRead(t){return t=void 0!==t?t:this.startIndex,this.buffer.length-t>0}}function bt(t){const e=[],s=t.length;let r=0;for(;r<s;){for(;r<s&&ct(t.charCodeAt(r));)r++;if(r>=s)break;const i=r;for(;r<s&&61!==t.charCodeAt(r)&&!ct(t.charCodeAt(r));)r++;const n=t.substring(i,r);for(;r<s&&ct(t.charCodeAt(r));)r++;if(r>=s||61!==t.charCodeAt(r)){const t=[n,n,void 0,void 0,void 0];t.startIndex=i,e.push(t);continue}for(r++;r<s&&ct(t.charCodeAt(r));)r++;const o=t.charCodeAt(r);if(34===o||39===o){r++;let a="",c=r;for(;r<s&&t.charCodeAt(r)!==o;){const e=t.charCodeAt(r);10!==e&&13!==e||(a+=t.substring(c,r)+" ",c=r+1),r++}a+=t.substring(c,r),r++;const l=String.fromCharCode(o),h=[n+"="+l+a+l,n,"="+l+a+l,l,a];h.startIndex=i,e.push(h)}}return e}function yt(t,e){if(!t||0===t.length)return;const s=bt(t),r=s.length,i=e.options.limits?.maxAttributesPerTag;if(null!=i&&r>i){const t=e.currentTagDetail?.name??"(unknown)";throw new nt(`Tag '${t}' has ${r} attributes, exceeding limit of ${i}`,ot.LIMIT_MAX_ATTRIBUTES,{line:e.source.line,col:e.source.cols,index:e.source.startIndex})}for(let t=0;t<r;t++){const r=e.processAttrName(s[t][1]);if(!1===r)continue;const i=s[t][4],n=void 0===i||i;e.outputBuilder.addAttribute(r,n,e.readonlyMatcher)}}const Nt=":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�",It=":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿",At=It+"\\-\\.\\d·̀-ͯ҇‿-⁀",St=(t,e,s="")=>{const r=`[${t.replace(":","")}][${e.replace(":","")}]*`;return{name:new RegExp(`^[${t}][${e}]*$`,s),ncName:new RegExp(`^${r}$`,s),qName:new RegExp(`^${r}(?::${r})?$`,s),nmToken:new RegExp(`^[${e}]+$`,s),nmTokens:new RegExp(`^[${e}]+(?:\\s+[${e}]+)*$`,s)}},Ct=St(Nt,Nt+"\\-\\.\\d·̀-ͯ‿-⁀"),Dt=St(It,At,"u"),vt=(t="1.0")=>"1.1"===t?Dt:Ct,kt=(t,{xmlVersion:e="1.0"}={})=>vt(e).name.test(t),Pt=(t,{xmlVersion:e="1.0"}={})=>vt(e).qName.test(t);function Ot(t){t.source.markTokenStart(1);let e,s=!1,r=!1,i=!1;for(e=0;t.source.canRead(e);e++){const n=t.source.readChAt(e);if("'"!==n||r)if('"'!==n||s){if(">"===n&&!s&&!r){i=!0;break}}else r=!r;else s=!s}if(!i)throw new nt("Unexpected closing of source waiting for '>'",ot.UNEXPECTED_END);if(s||r)throw new nt("Invalid attribute expression. Quote is not properly closed",ot.UNCLOSED_QUOTE);const n=t.source.readStr(e);return t.source.updateBufferBoundary(e+1),Ut(n,t)}function Ut(t,e){const s={tagName:"",selfClosing:!1,rawAttributes:Object.create(null),_attrsExp:""};"/"===t[t.length-1]&&(s.selfClosing=!0,t=t.slice(0,-1));let r="",i=0;for(;i<t.length;i++)if(at(t[i])){s.tagName=t.substring(0,i),r=t.substring(i+1);break}if(0===s.tagName.length&&i===t.length&&(s.tagName=t),s.tagName=s.tagName.trimEnd(),s._attrsExp=r,!Pt(s.tagName,e.xmlVersion))throw new nt("Invalid tag name",ot.INVALID_TAG_NAME);return!e.options.skip.attributes&&r.length>0&&function(t,e,s){if(!t||0===t.length)return;const r=bt(t),i=r.length;let n=0;for(let t=0;t<i;t++){if(!1===e.processAttrName(r[t][1]))continue;n++;const i=r[t][4];s.rawAttributes[r[t][1]]=void 0===i||i}s.rawAttributesLen=n}(r,e,s),s}const $t=[{open:"\x3c!--",close:"--\x3e"},{open:"<![CDATA[",close:"]]>"},{open:"<?",close:"?>"}],Lt=[{open:"'",close:"'"},{open:'"',close:'"'},{open:"`",close:"`"}];class Rt{constructor(t,{nested:e=!1,skipEnclosures:s=[]}={}){this._tagName=t,this._nested=e,this._enclosures=s,this._content="",this._depth=1,this._active=!1}isActive(){return this._active}activate(){this._active=!0,this._content="",this._depth=1}resumeAfterOpenTag(){this._content="",this._depth=1}collect(t){t.markTokenStart(1);const e=this._enclosures.length;return this._nested||0!==e?this._nested&&0===e?this._collectDepthOnly(t):!this._nested&&e>0?this._collectEnclosureOnly(t):this._collectFull(t):this._collectPlain(t)}_collectPlain(t){const e="</"+this._tagName;for(;t.canRead();)if("<"===t.readChAt(0)){if(this._peekMatch(t,e)){let s=e.length,r=!1;for(;;){const e=t.readChAt(s);if(">"===e){r=!0;break}if(" "!==e&&"\t"!==e&&"\n"!==e&&"\r"!==e)break;s++}if(r){for(this._skipChars(t,e.length);t.canRead()&&">"!==t.readCh(););return this._finish()}}this._content+=t.readCh()}else this._content+=t.readCh();throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectDepthOnly(t){for(;this._depth>0;){if(!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END);if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}if(t.readCh(),!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,ot.UNEXPECTED_END);if("/"===t.readChAt(0)){t.readCh();const e=this._readTagName(t),s=this._readToAngleClose(t);if(e===this._tagName&&(this._depth--,0===this._depth))return this._finish();this._content+="</"+e+s;continue}const e=this._readTagName(t);this._content+="<"+e;const{selfClosing:s,attrText:r}=this._readTagTail(t);this._content+=r,s||e!==this._tagName||this._depth++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectEnclosureOnly(t){for(;t.canRead();){const e=this._matchEnclosureOpen(t);if(-1!==e){const s=this._enclosures[e];this._skipChars(t,s.open.length),this._content+=s.open;const r=this._readUpto(t,s.close);this._content+=r+s.close;continue}if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}const s="</"+this._tagName;if(this._peekMatch(t,s)){let e=s.length,r=!1;for(;;){const s=t.readChAt(e);if(">"===s){r=!0;break}if(" "!==s&&"\t"!==s&&"\n"!==s&&"\r"!==s)break;e++}if(r){for(this._skipChars(t,s.length);t.canRead()&&">"!==t.readCh(););return this._finish()}}this._content+=t.readCh()}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectFull(t){for(;this._depth>0;){if(!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END);const e=this._matchEnclosureOpen(t);if(-1!==e){const s=this._enclosures[e];this._skipChars(t,s.open.length),this._content+=s.open;const r=this._readUpto(t,s.close);this._content+=r+s.close;continue}if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}if(t.readCh(),!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,ot.UNEXPECTED_END);if("/"===t.readChAt(0)){t.readCh();const e=this._readTagName(t),s=this._readToAngleClose(t);if(e===this._tagName&&(this._depth--,0===this._depth))return this._finish();this._content+="</"+e+s;continue}const s=this._readTagName(t);this._content+="<"+s;const{selfClosing:r,attrText:i}=this._readTagTail(t);this._content+=i,r||s!==this._tagName||this._depth++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_finish(){const t=this._content;return this._active=!1,this._content="",this._depth=1,t}_matchEnclosureOpen(t){const e=this._enclosures.length;for(let s=0;s<e;s++)if(this._peekMatch(t,this._enclosures[s].open))return s;return-1}_readUpto(t,e){const s=e[0],r=e.length,i=t.startIndex;let n=0;for(;t.canRead();){if(t.readChAt(0)===s&&this._peekMatch(t,e)){const e=t.readStr(n,i);return this._skipChars(t,r),e}t.readCh(),n++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end looking for '${e}'`,ot.UNEXPECTED_END)}_peekMatch(t,e){const s=e.length;for(let r=0;r<s;r++)if(t.readChAt(r)!==e[r])return!1;return!0}_skipChars(t,e){for(let s=0;s<e;s++)t.readCh()}_readTagName(t){let e="";for(;t.canRead();){const s=t.readChAt(0);if(">"===s||"/"===s||" "===s||"\t"===s||"\n"===s||"\r"===s)break;e+=t.readCh()}return e}_readTagTail(t){const e=t.startIndex;let s=0,r=!1,i=!1;for(;t.canRead();){const n=t.readCh();if(s++,"'"!==n||i)if('"'!==n||r){if(!r&&!i){if(">"===n)return{selfClosing:!1,attrText:t.readStr(s,e)};if("/"===n&&t.canRead()&&">"===t.readChAt(0))return t.readCh(),s++,{selfClosing:!0,attrText:t.readStr(s,e)}}}else i=!i;else r=!r}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end inside tag`,ot.UNEXPECTED_END)}_readToAngleClose(t){const e=t.startIndex;let s=0;for(;t.canRead();){const r=t.readCh();if(s++,">"===r)return t.readStr(s,e);if(" "!==r&&"\t"!==r&&"\n"!==r&&"\r"!==r)throw new nt(`Malformed closing tag for </${this._tagName}>`,ot.UNEXPECTED_END)}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end looking for '>'`,ot.UNEXPECTED_END)}}class Mt{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 Bt{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new Mt(this),this._keptAttrs=[]}push(t,e=null,s=null,r=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],o=s?`${s}:${t}`:t,a=n.get(o)||0;let c=0;for(const t of n.values())c+=t;n.set(o,a+1);const l={tag:t,position:c,counter:a};null!=s&&(l.namespace=s),null!=e&&(l.values=e),this.path.push(l);const h=this.path.length,d=null!==r?r.keep:null;if(null!=d&&d.length>0&&e)for(let t=0;t<d.length;t++){const s=d[t];void 0!==e[s]&&this._keptAttrs.push({depth:h,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 r=t[s];if("deep-wildcard"===r.type){if(s--,s<0)return!0;const r=t[s];let i=!1;for(let t=e;t>=0;t--)if(this._matchSegment(r,this.path[t],t===this.path.length-1)){e=t-1,s--,i=!0;break}if(!i)return!1}else{if(!this._matchSegment(r,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 r=e.counter??0;if("first"===t.position&&0!==r)return!1;if("odd"===t.position&&r%2!=1)return!1;if("even"===t.position&&r%2!=0)return!1;if("nth"===t.position&&r!==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}}function jt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading entity name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t||'"'===t||"'"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source reading entity name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(Gt(i,t.xmlVersion),qt(e),!e.canRead())throw new nt(`Unexpected end of source after entity name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(e.canRead(5)&&"SYSTEM"===e.readStr(6).toUpperCase())throw new nt("External entities are not supported",ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if("%"===e.readStr(1))throw new nt("Parameter entities are not supported",ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(!e.canRead())throw new nt(`Unexpected end of source reading entity value for "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const[n]=Ft(e,"entity"),o=t.options?.doctypeOptions;if(o?.maxEntitySize&&n.length>o.maxEntitySize)throw new nt(`Entity "${i}" size (${n.length}) exceeds maximum allowed size (${o.maxEntitySize})`,ot.ENTITY_MAX_SIZE,{line:e.line,col:e.cols,index:e.startIndex});return e.readUptoChar(">"),[i,n]}function Xt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading ELEMENT name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source after ELEMENT name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(!kt(i,t.xmlVersion))throw new nt(`Invalid element name: "${i}"`,ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading ELEMENT content model",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let n=e.readStr(1);if("E"===n){if(!e.canRead(4))throw new nt("Unexpected end of source reading ELEMENT content model keyword",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("EMPTY"!==e.readStr(5))return e.readUptoChar(">"),{elementName:i,contentModel:""};e.updateBufferBoundary(5)}else if("A"===n){if(!e.canRead(2))throw new nt("Unexpected end of source reading ELEMENT content model keyword",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("ANY"!==e.readStr(3))return e.readUptoChar(">"),{elementName:i,contentModel:""};e.updateBufferBoundary(3)}else"("===n&&(e.updateBufferBoundary(1),e.readUptoChar(")"));return e.readUptoChar(">"),{elementName:i}}function Vt(t){t.source.readUptoChar(">")}function Yt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading NOTATION name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source after NOTATION name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(Gt(i,t.xmlVersion),qt(e),!e.canRead(5))throw new nt("Unexpected end of source reading NOTATION identifier type",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let n=e.readStr(6).toUpperCase();if("SYSTEM"===n)e.updateBufferBoundary(6),qt(e),Ft(e,"systemIdentifier");else{if("PUBLIC"!==n)throw new nt(`Expected SYSTEM or PUBLIC in NOTATION, found "${n}"`,ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});{if(e.updateBufferBoundary(6),qt(e),Ft(e,"publicIdentifier"),qt(e),!e.canRead())throw new nt("Unexpected end of source after NOTATION PUBLIC identifier",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let t=e.readStr(1);'"'!==t&&"'"!==t||Ft(e,"systemIdentifier")}}e.readUptoChar(">")}function Ft(t,e){if(!t.canRead())throw new nt(`Unexpected end of source reading ${e} opening quote`,ot.UNEXPECTED_END,{line:t.line,col:t.cols,index:t.startIndex});let s=t.readStr(1);if('"'!==s&&"'"!==s)throw new nt(`Expected quoted string for ${e}, found "${s}"`,ot.INVALID_TAG,{line:t.line,col:t.cols,index:t.startIndex});return t.updateBufferBoundary(1),[t.readUptoChar(s)]}function qt(t){for(;t.canRead();){const e=t.readChAt(0);if(" "!==e&&"\t"!==e&&"\n"!==e&&"\r"!==e)break;t.updateBufferBoundary(1)}}function Gt(t,e){if(kt(t,e))return t;throw new nt(`Invalid entity name "${t}"`,ot.ENTITY_INVALID_KEY,{})}const zt=Object.freeze({UNCLOSED_EOF:"unclosed-eof",MISMATCHED_CLOSE:"mismatched-close",PHANTOM_CLOSE:"phantom-close",PARTIAL_TAG:"partial-tag"});class Ht{constructor(t){this.onEof=t.onEof||"throw",this.onMismatch=t.onMismatch||"throw",this.collectErrors=t.collectErrors||!1,this.errors=[]}handleEof(t){if("throw"===this.onEof)throw new nt("Unexpected data in the end of document",ot.UNEXPECTED_TRAILING_DATA);const{addTextNode:e,popTag:s}=t;let r=t.currentTagDetail;for(;r&&!r.root;)this._recordError(zt.UNCLOSED_EOF,{tag:r.name,expected:null,line:r.line,col:r.col,index:r.index}),e(),s(),r=t.currentTagDetail}handleMismatch(t,e){const{tagsStack:s,currentTagDetail:r,source:i,addTextNode:n}=e;if("throw"===this.onMismatch)throw new nt(`Unexpected closing tag '${t}' expecting '${r.name}'`,ot.MISMATCHED_CLOSE_TAG,{line:i?i.line:void 0,col:i?i.cols:void 0,index:i?i.startIndex:void 0});if("discard"===this.onMismatch)return this._recordError(zt.MISMATCHED_CLOSE,{tag:t,expected:r.name,line:i?i.line:null,col:i?i.cols:null,index:i?i.startIndex:null}),{action:"discard"};const o=[...s,r];let a=-1;const c=o.length;for(let e=c-1;e>=0;e--)if(o[e].name===t){a=e;break}if(-1===a)return this._recordError(zt.PHANTOM_CLOSE,{tag:t,expected:r.name,line:i?i.line:null,col:i?i.cols:null,index:i?i.startIndex:null}),{action:"discard"};const l=c-1-a;for(let s=0;s<l;s++){const r=o[c-1-s];this._recordError(zt.MISMATCHED_CLOSE,{tag:r.name,expected:t,line:r.line,col:r.col,index:r.index}),n(),e.popTag()}return e.currentTagDetail=o[a],{action:"close-matched"}}handlePartialTag(t,e){this._recordError(zt.PARTIAL_TAG,{tag:Wt(t),expected:null,line:e.source?e.source.line:null,col:e.source?e.source.cols:null,index:e.source?e.source.startIndex:null}),e.tagTextData="",this.handleEof(e)}getErrors(){return this.errors.slice()}reset(){this.errors=[]}_recordError(t,e){this.collectErrors&&this.errors.push({type:t,...e})}}function Wt(t){if(!t)return null;const e=("string"==typeof t.message?t.message:String(t)).match(/[Rr]eading closing tag '<\/([^']*)/);return e&&e[1]||null}class Qt{constructor(t,e=0,s=0,r=0){this.name=t,this.line=e,this.col=s,this.index=r}}class Jt{constructor(t){this.options=t,this.currentTagDetail=null,this.tagTextData="",this.tagsStack=[],this.matcher=new Bt,this.readonlyMatcher=this.matcher.readOnly(),this.autoCloseHandler=t.autoClose?new Ht(t.autoClose):null,this._unpairedSet=new Set(this.options.tags.unpaired),this.stopNodeExpressionsSet=this.options.tags.stopNodesSet??new rt,this.skipTagExpressionsSet=this.options.skip.tagsSet??new rt,this._exitIf="function"==typeof t.exitIf?t.exitIf:null}initializeParser(){this.tagTextData="",this.tagsStack=[],this._stopNodeProcessor=null,this._exitIfTriggered=!1,this.xmlVersion="1.0",this.matcher||(this.matcher=new Bt,this.readonlyMatcher=this.matcher.readOnly()),this.outputBuilder=this._createOutputBuilder(),this.root={root:!0,name:""},this.currentTagDetail=this.root}_createOutputBuilder(){return this.options.OutputBuilder.getInstance(this.options,this.readonlyMatcher)}wasExited(){return!0===this._exitIfTriggered}parse(t){return this.source=new Tt(t),this.initializeParser(),this._parseAndFinalize(),this.outputBuilder.getOutput()}parseBytesArr(t){return this.source=new wt(t),this.initializeParser(),this._parseAndFinalize(),this.outputBuilder.getOutput()}parseXml(){for(;this.source.canRead()&&!this._exitIfTriggered;){this.source.markTokenStart(0);const t=this.source.readCh();if(void 0===t||""===t)break;if("<"===t){const t=this.source.readChAt(0);if(""===t)throw new nt("Unexpected end of source after '<'",ot.UNEXPECTED_END,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});"!"===t||"?"===t?(this.source.updateBufferBoundary(),this.addTextNode(),this.readSpecialTag(t)):"/"===t?(this.source.updateBufferBoundary(),this.readClosingTag()):this.readOpeningTag()}else{let e=0;for(;;){const t=this.source.readChAt(e);if("<"===t||void 0===t||""===t)break;e++}e>0?(this.tagTextData+=t+this.source.readStr(e,this.source.startIndex),this.source.updateBufferBoundary(e)):this.tagTextData+=t}}}finalizeXml(){if(this._exitIfTriggered)return;const t=this.tagsStack.length>0||this.currentTagDetail&&!this.currentTagDetail.root,e=!t&&void 0!==this.tagTextData&&this.tagTextData.trimEnd().length>0;if(t||e){if(!this.autoCloseHandler||!t||e)throw new nt("Unexpected data in the end of document",ot.UNEXPECTED_TRAILING_DATA);this.autoCloseHandler.handleEof(this._parserState())}}_parseAndFinalize(){let t=null;this.autoCloseHandler&&this.autoCloseHandler.reset();try{this.parseXml()}catch(e){if(!this.autoCloseHandler||!function(t){return t instanceof nt?t.code===ot.UNEXPECTED_END:t.message.startsWith("Unexpected end of source")||t.message.startsWith("Unexpected closing of source")}(e))throw e;t=e}t?this.autoCloseHandler.handlePartialTag(t,this._parserState()):this.finalizeXml()}readClosingTag(){const t=this.processTagName(function(t){t.markTokenStart(1);let e=0;const s=t.startIndex;for(;t.canRead();){if(">"===t.readCh()){const r=t.readStr(e,s);return r?r.trimEnd():""}e++}const r=t.readStr(e,s);throw t.updateBufferBoundary(e),new nt(`Unexpected end of source reading closing tag '</${r}'`,ot.UNEXPECTED_END)}(this.source));if(this.isUnpaired(t)||this.isStopNode())throw new nt(`Unexpected closing tag '${t}'`,ot.UNEXPECTED_CLOSE_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if(t!==this.currentTagDetail.name){if(!this.autoCloseHandler)throw new nt(`Unexpected closing tag '${t}' expecting '${this.currentTagDetail.name}'`,ot.MISMATCHED_CLOSE_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if("discard"===this.autoCloseHandler.handleMismatch(t,this._parserState()).action)return}this.currentTagDetail.root||this.addTextNode(),this.popTag()}readOpeningTag(){const t=this.options;if(this.addTextNode(),this._stopNodeProcessor&&this._stopNodeProcessor.isActive()){const{tagDetail:t,isSkip:e}=this._stopNodeProcessorMeta;this._stopNodeProcessor.resumeAfterOpenTag(),Ot(this);const s=this._stopNodeProcessor.collect(this.source);return e||(this.outputBuilder.addElement(t,this.readonlyMatcher),this.outputBuilder.onStopNode?.(t,s,this.readonlyMatcher),this.outputBuilder.addValue(s,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher)),this.matcher.pop(),this._stopNodeProcessor=null,void(this._stopNodeProcessorMeta=null)}let e=Ot(this);const s=this.processTagName(e.tagName),r=new Qt(s,this.source.line,this.source.cols,this.source.startIndex),i=e.tagName.indexOf(":"),n=-1!==i?e.tagName.slice(0,i):void 0,o=void 0!==n?e.tagName.slice(i+1):s,a=t.limits?.maxNestedTags;if(null!=a){const t=this.tagsStack.length+1;if(t>a)throw new nt(`Nesting depth ${t} exceeds limit of ${a} (tag: '${s}')`,ot.LIMIT_MAX_NESTED_TAGS,{line:r.line,col:r.col,index:r.index})}let c={},l=0;e.rawAttributes&&(c=e.rawAttributes,l=e.rawAttributesLen),l>0?this.matcher.push(o,c,n,{keep:["xml:space"]}):this.matcher.push(o,{},n);const h=this.isStopNode(),d=h?null:this.isSkipTag();if(t.skip.attributes||d||yt(e._attrsExp,this),this.isUnpaired(s))this.outputBuilder.addElement(r,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher),this.matcher.pop();else if(e.selfClosing)d||(this.outputBuilder.addElement(r,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher)),this.matcher.pop();else if(h){this._stopNodeProcessor=new Rt(e.tagName,{nested:h.nested,skipEnclosures:h.skipEnclosures}),this._stopNodeProcessorMeta={tagDetail:r,isSkip:!1},this._stopNodeProcessor.activate();const t=this._stopNodeProcessor.collect(this.source);this.outputBuilder.addElement(r,this.readonlyMatcher),this.outputBuilder.onStopNode?.(r,t,this.readonlyMatcher),this.outputBuilder.addValue(t,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher),this.matcher.pop(),this._stopNodeProcessor=null,this._stopNodeProcessorMeta=null}else if(d)this._stopNodeProcessor=new Rt(e.tagName,{nested:d.nested,skipEnclosures:d.skipEnclosures}),this._stopNodeProcessorMeta={tagDetail:r,isSkip:!0},this._stopNodeProcessor.activate(),this._stopNodeProcessor.collect(this.source),this.matcher.pop(),this._stopNodeProcessor=null,this._stopNodeProcessorMeta=null;else if(this._exitIf&&this._exitIf(this.readonlyMatcher)){const t=this.tagsStack.length;for(this.matcher.pop();this.currentTagDetail&&!this.currentTagDetail.root;)this.addTextNode(),this.popTag();"function"==typeof this.outputBuilder.onExit&&this.outputBuilder.onExit({tagDetail:r,matcher:this.readonlyMatcher,depth:t}),this._exitIfTriggered=!0}else this.pushTag(r)}pushTag(t){this.tagsStack.push(this.currentTagDetail),this.outputBuilder.addElement(t,this.readonlyMatcher),this.currentTagDetail=t}popTag(){this.outputBuilder.closeElement(this.readonlyMatcher),this.matcher.pop(),this.currentTagDetail=this.tagsStack.pop()}readSpecialTag(t){if("!"===t){let t=this.source.readCh();if(null==t)throw new nt("Unexpected end of source after '<!'",ot.UNEXPECTED_END,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if("-"===t)!function(t){if(t.source.markTokenStart(1),!t.source.canRead())throw new nt("Unexpected end of source reading comment",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if("-"!==t.source.readCh())throw new nt(`Invalid comment expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readUpto("--\x3e");t.outputBuilder.addComment(e)}(this);else if("["===t)!function(t){if(t.source.markTokenStart(1),!t.source.canRead(5))throw new nt("Unexpected end of source reading CDATA preamble",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"CDATA["!==e)throw new nt(`Invalid CDATA expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let s=t.source.readUpto("]]>");t.outputBuilder.addLiteral(s)}(this);else if("D"===t){const t=function(t){if(t.source.markTokenStart(1),!t.source.canRead(5))throw new nt("Unexpected end of source reading DOCTYPE preamble",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"OCTYPE"!==e)throw new nt(`Invalid DOCTYPE expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const s=Object.create(null);let r=0,i=!1,n=!1;for(;t.source.canRead();){const e=t.source.startIndex;let o=t.source.readCh();if("<"===o&&i&&!n)try{if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE sub-tag",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"!"!==e)throw new nt(`Invalid DOCTYPE body tag starting with "<${e}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE sub-tag type",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let i=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"-"===i){if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE comment",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"-"!==e)throw new nt("Invalid comment in DOCTYPE",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});t.source.readUpto("--\x3e")}else if("E"===i){if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE E-type sub-tag",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"N"===e){if(!t.source.canRead(3))throw new nt("Unexpected end of source reading DOCTYPE ENTITY keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(4);if(t.source.updateBufferBoundary(4),"TITY"!==e)throw new nt("Invalid DOCTYPE ENTITY expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const[i,n]=jt(t);if(-1===n.indexOf("&")){const e=t.options?.doctypeOptions;if(e?.maxEntityCount&&r>=e.maxEntityCount)throw new nt(`Entity count (${r+1}) exceeds maximum allowed (${e.maxEntityCount})`,ot.ENTITY_MAX_COUNT,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const o=i.replace(/[.\-+*:]/g,"\\$&");s[i]={regx:RegExp(`&${o};`,"g"),val:n},r++}}else{if("L"!==e)throw new nt(`Invalid DOCTYPE sub-tag "<!E${e}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(4))throw new nt("Unexpected end of source reading DOCTYPE ELEMENT keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(5);if(t.source.updateBufferBoundary(5),"EMENT"!==e)throw new nt("Invalid DOCTYPE ELEMENT expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Xt(t)}}}else if("A"===i){if(!t.source.canRead(5))throw new nt("Unexpected end of source reading DOCTYPE ATTLIST keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"TTLIST"!==e)throw new nt("Invalid DOCTYPE ATTLIST expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Vt(t)}else{if("N"!==i)throw new nt(`Invalid DOCTYPE sub-tag "<!${i}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(6))throw new nt("Unexpected end of source reading DOCTYPE NOTATION keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(7);if(t.source.updateBufferBoundary(7),"OTATION"!==e)throw new nt("Invalid DOCTYPE NOTATION expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Yt(t)}}}catch(s){throw s.code===ot.UNEXPECTED_END&&(t.source.startIndex=e),s}else if("["===o)i=!0;else if("]"===o)n=!0;else if(">"===o&&(!i||n))return s}throw new nt("Unclosed DOCTYPE",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex})}(this);this.options.doctypeOptions.enabled&&t&&Object.keys(t).length>0&&this.outputBuilder.addInputEntities(t)}}else{if("?"!==t)throw new nt(`Invalid tag '<${t}'`,ot.INVALID_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});!function(t){const e=t.options.skip;t.source.markTokenStart(1);let s=function(t){t.source.markTokenStart(1);let e,s=!1,r=!1,i=!1;for(e=0;t.source.canRead(e);e++){const n=t.source.readChAt(e),o=t.source.readChAt(e+1);if("'"!==n||r?'"'!==n||s||(r=!r):s=!s,!s&&!r&&"?"===n&&">"===o){i=!0;break}}if(!i)throw new nt("Unexpected closing of source waiting for '?>'",ot.UNEXPECTED_END);if(s||r)throw new nt("Invalid attribute expression. Quote is not properly closed in PI tag expression",ot.UNCLOSED_QUOTE);t.options.skip.attributes;const n=t.source.readStr(e);return t.source.updateBufferBoundary(e+2),Ut(n,t)}(t);if(!s)throw new nt("Invalid Pi Tag expression.",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if("xml"===s.tagName){const e=s.rawAttributes?.version;t.xmlVersion="1.1"===e?1.1:1}e.attributes||yt(s._attrsExp,t),"xml"===s.tagName?e.declaration||t.outputBuilder.addDeclaration("?xml"):e.pi||t.outputBuilder.addInstruction("?"+s.tagName)}(this)}}addTextNode(){void 0!==this.tagTextData&&""!==this.tagTextData&&((!this.options.skip.whitespaceText||this.tagTextData.trim().length>0)&&this.outputBuilder.addValue(this.tagTextData,this.readonlyMatcher),this.tagTextData="")}processAttrName(t){const e=this.options;if(t=Zt(t,e.skip.nsPrefix),!Pt(t,this.xmlVersion))throw new nt(`Invalid attribute name: ${t}`,ot.INVALID_ATTRIBUTE_NAME);if(t=Kt(t,e.onDangerousProperty),e.strictReservedNames&&t===e.attributes.groupBy)throw new nt(`Restricted attribute name: ${t}`,ot.SECURITY_RESTRICTED_NAME);return t}processTagName(t){const e=this.options,s=e.nameFor;if(t=Kt(t=Zt(t,e.skip.nsPrefix),e.onDangerousProperty),e.strictReservedNames&&(t===s.comment||t===s.cdata||t===s.text))throw new nt(`Restricted tag name: ${t}`,ot.SECURITY_RESTRICTED_NAME);return t}isUnpaired(t){return this._unpairedSet.has(t)}isStopNode(){if(0===this.stopNodeExpressionsSet.size)return null;const t=this.stopNodeExpressionsSet.findMatch(this.matcher);return t?t.data:null}isSkipTag(){if(0===this.skipTagExpressionsSet.size)return null;const t=this.skipTagExpressionsSet.findMatch(this.matcher);return t?t.data:null}_parserState(){const t=this;return{get tagsStack(){return t.tagsStack},get currentTagDetail(){return t.currentTagDetail},set currentTagDetail(e){t.currentTagDetail=e},get outputBuilder(){return t.outputBuilder},get readonlyMatcher(){return t.readonlyMatcher},get matcher(){return t.matcher},get source(){return t.source},get tagTextData(){return t.tagTextData},set tagTextData(e){t.tagTextData=e},addTextNode:t.addTextNode.bind(t),popTag:t.popTag.bind(t)}}}function Zt(t,e){if(e){const e=t.split(":");if(2===e.length)return"xmlns"!==e[0]&&e[1];if(e.length>2)throw new nt(`Multiple namespaces in name: ${t}`,ot.MULTIPLE_NAMESPACES)}return t}function Kt(t,e){if(ht.includes(t))throw new nt(`[SECURITY] Invalid name: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`,ot.SECURITY_PROTOTYPE_POLLUTION);return lt.includes(t)?e(t):t}class te{constructor(t={}){this.line=1,this.cols=0,this.buffer="",this.startIndex=0,this.isComplete=!1,this.maxBufferSize=t.maxBufferSize||10485760,this.autoFlush=!1!==t.autoFlush,this.flushThreshold=t.flushThreshold||1024,this._marks=[-1,-1]}feed(t){const e="string"==typeof t?t:t.toString(),s=this.buffer.length-this.startIndex;if(s+e.length>this.maxBufferSize)throw new nt(`Buffer size limit exceeded (${s+e.length} > ${this.maxBufferSize}). Increase feedable.maxBufferSize or reduce chunk size.`,ot.INVALID_INPUT);this.buffer+=e}end(){this.isComplete=!0}canRead(t=0){return this.startIndex+t<this.buffer.length}markTokenStart(t=0){this._marks[t]=this.startIndex}rewindToMark(){this._marks[0]>=0&&(this.startIndex=this._marks[0]),this._marks[0]=-1,this._marks[1]=-1}clearMark(){this._marks[0]=-1,this._marks[1]=-1}readCh(){const t=this.buffer[this.startIndex++];return"\n"===t?(this.line++,this.cols=0):this.cols++,t}readChAt(t){return this.buffer[this.startIndex+t]}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.substring(e,e+t)}readUpto(t){const e=this.buffer.length,s=t.length;for(let r=this.startIndex;r<e;r++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[r+i]!==t[i]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=r+s,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END);const s=this.buffer.substring(this.startIndex,e);return this.startIndex=e+1,s}readUptoCloseTag(t){const e=this.buffer.length,s=t.length;let r=-1,i=0;for(let n=this.startIndex;n<e;n++){if(1===i){const t=this.buffer[n];if(" "===t||"\t"===t)continue;">"===t?i=2:(i=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[n+r]!==t[r]){e=!1;break}e&&(i=1,r=n,n+=s-1)}if(2===i){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=n+1,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}updateBufferBoundary(t=1){this.startIndex+=t;const e=this._marks[0]>=0||this._marks[1]>=0;this.autoFlush&&this.startIndex>=this.flushThreshold&&!e&&this.flush()}flush(){let t=this.startIndex;for(const e of this._marks)e>=0&&e<t&&(t=e);if(t>0){this.buffer=this.buffer.substring(t);const e=this._marks.length;for(let s=0;s<e;s++)this._marks[s]>=0&&(this._marks[s]-=t);this.startIndex-=t}}}class ee extends te{attachStream(t,e,s,r){t.on("data",t=>{try{this.feed("string"==typeof t?t:t.toString()),e(null)}catch(t){e(t)}}),t.on("error",r),t.on("end",()=>{try{this.end(),s()}catch(t){r(t)}})}}class se{constructor(t){this.options=gt(t),this._feedParser=null,this._feedSource=null,this._isFeeding=!1,this._pendingBytes=0,this._batchThreshold=this.options.feedable?.bufferSize}parse(t){if(t instanceof Buffer||ArrayBuffer.isView(t))t=t.toString();else if("string"!=typeof t){if(!t||"function"!=typeof t.toString)throw new nt("XML data must be a string or Buffer.",ot.INVALID_INPUT);t=t.toString()}const e=this._createParser(),s=e.parse(t);return this.wasExited=e.wasExited(),this._lastParseErrors=e.autoCloseHandler?.getErrors()??[],s}parseBytesArr(t){if(!(t instanceof Uint8Array||ArrayBuffer.isView(t)))throw new nt("XML data must be a Uint8Array or ArrayBufferView.",ot.INVALID_INPUT);t=Buffer.from(t);const e=this._createParser(),s=e.parseBytesArr(t);return this.wasExited=e.wasExited(),this._lastParseErrors=e.autoCloseHandler?.getErrors()??[],s}parseStream(t){if(null===(e=t)||"object"!=typeof e||"function"!=typeof e.read||"function"!=typeof e.on||"boolean"!=typeof e.readableEnded)throw new nt("parseStream() requires a Node.js Readable stream.",ot.INVALID_STREAM);var e;const s=new ee(this.options.feedable),r=this._createParser();return r.source=s,r.initializeParser(),new Promise((e,i)=>{let n=!1;const o=e=>{n||(n=!0,t.destroy(),i(e))};s.attachStream(t,t=>{if(t)o(t);else try{r.parseXml()}catch(t){t.code===ot.UNEXPECTED_END?s.rewindToMark():o(t)}},()=>{if(!n)try{r.finalizeXml(),this._lastParseErrors=r.autoCloseHandler?.getErrors()??[],n=!0,e(r.outputBuilder.getOutput())}catch(t){o(t)}},o)})}_runParse(){if(!this._feedParser)return;const t=this._feedSource.startIndex;try{this._feedParser.parseXml()}catch(t){if(t.code!==ot.UNEXPECTED_END)throw t;this._feedSource.rewindToMark()}this._feedSource.startIndex>t?this._pendingBytes=0:this._batchThreshold=Math.min(2*this._batchThreshold,this.options.feedable.maxBufferSize)}feed(t){let e;if(this._isFeeding||this._initFeedSession(),"string"==typeof t)e=t;else if(Buffer.isBuffer(t))e=t.toString();else{if(!t?.toString)throw new nt("feed() data must be a string or Buffer.",ot.DATA_MUST_BE_STRING);e=t.toString()}return this._feedSource.feed(e),this._pendingBytes+=e.length,this._pendingBytes>=this._batchThreshold&&this._runParse(),this}end(){if(!this._isFeeding)throw new nt("No data fed. Call feed() before end().",ot.NOT_STREAMING);this._runParse();try{this._feedSource.end();let t=null;const e=this._feedParser.autoCloseHandler;e&&e.reset();try{this._feedParser.parseXml()}catch(s){if(s.code!==ot.UNEXPECTED_END)throw s;if(!e)throw s;t=s}return t?e.handlePartialTag(t,this._feedParser._parserState()):this._feedParser.finalizeXml(),this._lastParseErrors=e?.getErrors()??[],this.wasExited=this._feedParser.wasExited(),this._feedParser.outputBuilder.getOutput()}finally{this._cleanupFeedSession()}}getParseErrors(){return this._lastParseErrors??[]}_createParser(){return new Jt(this.options)}_initFeedSession(){this._feedSource=new te(this.options.feedable),this._feedParser=this._createParser(),this._feedParser.source=this._feedSource,this._feedParser.initializeParser(),this._isFeeding=!0}_cleanupFeedSession(){this._feedParser=null,this._feedSource=null,this._isFeeding=!1}}module.exports=e})();
1
+ (()=>{"use strict";var t={d:(e,s)=>{for(var r in s)t.o(s,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:s[r]})},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,{ErrorCode:()=>ot,ParseError:()=>nt,XMLParser:()=>se,default:()=>se,quoteEnclosures:()=>$t,xmlEnclosures:()=>Lt});class s{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],r=s?.tag;if(r&&"*"!==r){const s=`${e}:${r}`;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(),r=`${e}:${s}`,i=this._byDepthAndTag.get(r);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];const o=this._deepByTerminalTag.get(s);if(o)for(let e=0;e<o.length;e++)if(t.matches(o[e]))return o[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}class r{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,r="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(r.trim()&&(e.push(this._parseSegment(r.trim())),r=""),e.push({type:"deep-wildcard"}),s+=2):(r.trim()&&e.push(this._parseSegment(r.trim())),r="",s++):(r+=t[s],s++);return r.trim()&&e.push(this._parseSegment(r.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,r=t;const i=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(i&&(r=i[1]+i[3],i[2])){const t=i[2].slice(1,-1);t&&(s=t)}let n,o,a=r;if(r.includes("::")){const e=r.indexOf("::");if(n=r.substring(0,e).trim(),a=r.substring(e+2).trim(),!n)throw new Error(`Invalid namespace in pattern: ${t}`)}let c=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)?(o=e,c=s):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,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(c){const t=c.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=c}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}const i={nameFor:{},skip:{},tags:{valueParsers:[]},attributes:{valueParsers:[]},textJoint:"",alwaysArray:[],forceArray:null,forceTextNode:!1},n=["ws","entity","boolean","number"],o=["entity","number","boolean"];function a(t){const e=c(i);t&&void 0!==t.tags?.valueParsers||(e.tags.valueParsers=[...n]),t&&void 0!==t.attributes?.valueParsers||(e.attributes.valueParsers=[...o]);const r=Array.isArray(t?.alwaysArray)?t.alwaysArray:e.alwaysArray,a=new s;for(const t of r)h(t,"alwaysArray",a);return a.seal(),e._alwaysArraySet=a,t&&l(e,t),e}function c(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(c);const e={};for(const s of Object.keys(t))e[s]=c(t[s]);return e}function l(t,e){for(const s of Object.keys(e))"__proto__"!==s&&"constructor"!==s&&"prototype"!==s&&("function"==typeof e[s]||Array.isArray(e[s])?t[s]=e[s]:"object"==typeof e[s]&&null!==e[s]?("object"==typeof t[s]&&null!==t[s]||(t[s]={}),l(t[s],e[s])):t[s]=e[s])}function h(t,e,s){let i;if("string"==typeof t){if(0===t.length)throw new Error(`${e} expression cannot be empty`);i=t}else{if(!("string"==typeof t?.pattern&&t.pattern.length>0&&Array.isArray(t?.segments)))throw new Error(`Invalid ${e} entry: expected a string, or Expression.`);i=t.toString()}const n=new r(i);return s.add(n),n}const d={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'},u=Object.freeze({ALLOW:"allow",BLOCK:"block",THROW:"throw"}),p=new Set("!?\\\\/[]$%{}^&*()<>|+");function f(t){if("#"===t[0])throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${t}"`);for(const e of t)if(p.has(e))throw new Error(`[EntityReplacer] Invalid character '${e}' in entity name: "${t}"`);return t}function g(...t){const e=Object.create(null);for(const s of t)if(s)for(const t of Object.keys(s)){const r=s[t];if("string"==typeof r)e[t]=r;else if(r&&"object"==typeof r&&void 0!==r.val){const s=r.val;"string"==typeof s&&(e[t]=s)}}return e}const m="external",_="base",E="all",x=Object.freeze({allow:0,leave:1,remove:2,throw:3}),T=new Set([9,10,13]);class w{constructor(t={}){var e;this._limit=t.limit||{},this._maxTotalExpansions=this._limit.maxTotalExpansions||0,this._maxExpandedLength=this._limit.maxExpandedLength||0,this._postCheck="function"==typeof t.postCheck?t.postCheck:t=>t,this._limitTiers=(e=this._limit.applyLimitsTo??m)&&e!==m?e===E?new Set([E]):e===_?new Set([_]):Array.isArray(e)?new Set(e):new Set([m]):new Set([m]),this._numericAllowed=t.numericAllowed??!0,this._baseMap=g(d,t.namedEntities||null),this._externalMap=Object.create(null),this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this._removeSet=new Set(t.remove&&Array.isArray(t.remove)?t.remove:[]),this._leaveSet=new Set(t.leave&&Array.isArray(t.leave)?t.leave:[]);const s=function(t){if(!t)return{xmlVersion:1,onLevel:x.allow,nullLevel:x.remove};const e=1.1===t.xmlVersion?1.1:1,s=x[t.onNCR]??x.allow,r=x[t.nullNCR]??x.remove;return{xmlVersion:e,onLevel:s,nullLevel:Math.max(r,x.remove)}}(t.ncr);this._ncrXmlVersion=s.xmlVersion,this._ncrOnLevel=s.onLevel,this._ncrNullLevel=s.nullLevel,this._onExternalEntity="function"==typeof t.onExternalEntity?t.onExternalEntity:null,this._onInputEntity="function"==typeof t.onInputEntity?t.onInputEntity:null}_applyRegistrationHook(t,e,s,r){if(!t)return!0;const i=t(e,s);if(i===u.BLOCK)return!1;if(i===u.THROW)throw new Error(`[EntityDecoder] Registration of ${r} entity "&${e};" was rejected by hook`);return!0}setExternalEntities(t){if(t)for(const e of Object.keys(t))f(e);if(!this._onExternalEntity)return void(this._externalMap=g(t));const e=g(t),s=Object.create(null);for(const[t,r]of Object.entries(e))this._applyRegistrationHook(this._onExternalEntity,t,r,"external")&&(s[t]=r);this._externalMap=s}addExternalEntity(t,e){f(t),"string"==typeof e&&-1===e.indexOf("&")&&this._applyRegistrationHook(this._onExternalEntity,t,e,"external")&&(this._externalMap[t]=e)}addInputEntities(t){if(this._totalExpansions=0,this._expandedLength=0,!this._onInputEntity)return void(this._inputMap=g(t));const e=g(t),s=Object.create(null);for(const[t,r]of Object.entries(e))this._applyRegistrationHook(this._onInputEntity,t,r,"input")&&(s[t]=r);this._inputMap=s}reset(){return this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this}setXmlVersion(t){this._ncrXmlVersion=1.1===t?1.1:1}decode(t){if("string"!=typeof t||0===t.length)return t;if(-1===t.indexOf("&"))return t;const e=t,s=[],r=t.length;let i=0,n=0;const o=this._maxTotalExpansions>0,a=this._maxExpandedLength>0,c=o||a;for(;n<r;){if(38!==t.charCodeAt(n)){n++;continue}let e=n+1;for(;e<r&&59!==t.charCodeAt(e)&&e-n<=32;)e++;if(e>=r||59!==t.charCodeAt(e)){n++;continue}const l=t.slice(n+1,e);if(0===l.length){n++;continue}let h,d;if(this._removeSet.has(l))h="",void 0===d&&(d=m);else{if(this._leaveSet.has(l)){n++;continue}if(35===l.charCodeAt(0)){const t=this._resolveNCR(l);if(void 0===t){n++;continue}h=t,d=_}else{const t=this._resolveName(l);h=t?.value,d=t?.tier}}if(void 0!==h){if(n>i&&s.push(t.slice(i,n)),s.push(h),i=e+1,n=i,c&&this._tierCounts(d)){if(o&&(this._totalExpansions++,this._totalExpansions>this._maxTotalExpansions))throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`);if(a){const t=h.length-(l.length+2);if(t>0&&(this._expandedLength+=t,this._expandedLength>this._maxExpandedLength))throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`)}}}else n++}i<r&&s.push(t.slice(i));const l=0===s.length?t:s.join("");return this._postCheck(l,e)}_tierCounts(t){return!!this._limitTiers.has(E)||this._limitTiers.has(t)}_resolveName(t){return t in this._inputMap?{value:this._inputMap[t],tier:m}:t in this._externalMap?{value:this._externalMap[t],tier:m}:t in this._baseMap?{value:this._baseMap[t],tier:_}:void 0}_classifyNCR(t){return 0===t?this._ncrNullLevel:t>=55296&&t<=57343||1===this._ncrXmlVersion&&t>=1&&t<=31&&!T.has(t)?x.remove:-1}_applyNCRAction(t,e,s){switch(t){case x.allow:return String.fromCodePoint(s);case x.remove:return"";case x.leave:return;case x.throw:throw new Error(`[EntityDecoder] Prohibited numeric character reference &${e}; (U+${s.toString(16).toUpperCase().padStart(4,"0")})`);default:return String.fromCodePoint(s)}}_resolveNCR(t){const e=t.charCodeAt(1);let s;if(s=120===e||88===e?parseInt(t.slice(2),16):parseInt(t.slice(1),10),Number.isNaN(s)||s<0||s>1114111)return;const r=this._classifyNCR(s);if(!this._numericAllowed&&r<x.remove)return;const i=-1===r?this._ncrOnLevel:Math.max(this._ncrOnLevel,r);return this._applyNCRAction(i,t,s)}}const b=[{id:"sql-block-comment-open",description:"SQL block comment open: /* ... */ — unusual in legitimate user text",pattern:/\/\*/},{id:"sql-union-select",description:"UNION SELECT — most common SQL injection aggregation attack",pattern:/\bUNION\s{1,20}(?:ALL\s{1,20})?SELECT\b/i},{id:"sql-drop-table",description:"DROP TABLE — destructive DDL injection",pattern:/\bDROP\s{1,20}TABLE\b/i},{id:"sql-drop-database",description:"DROP DATABASE — destructive DDL injection",pattern:/\bDROP\s{1,20}DATABASE\b/i},{id:"sql-insert-into",description:"INSERT INTO — data injection",pattern:/\bINSERT\s{1,20}INTO\b/i},{id:"sql-delete-from",description:"DELETE FROM — data deletion injection",pattern:/\bDELETE\s{1,20}FROM\b/i},{id:"sql-update-set",description:"UPDATE ... SET — data modification injection",pattern:/\bUPDATE\b[\s\S]{1,60}\bSET\b/i},{id:"sql-exec-xp",description:"EXEC xp_ — MSSQL extended stored procedure execution",pattern:/\bEXEC(?:UTE)?\s{1,20}xp_/i},{id:"sql-tautology-string",description:'Classic string tautology: \' OR \'1\'=\'1 or " OR "1"="1"',pattern:/'\s{0,10}OR\s{0,10}'[^']{0,20}'\s*=\s*'[^']{0,20}/i},{id:"sql-tautology-numeric",description:"Numeric tautology: OR 1=1",pattern:/\bOR\s{1,10}1\s*=\s*1\b/i},{id:"sql-always-true-zero",description:"Numeric tautology: OR 0=0",pattern:/\bOR\s{1,10}0\s*=\s*0\b/i},{id:"sql-sleep-benchmark",description:"Time-based blind injection: SLEEP() or BENCHMARK()",pattern:/\b(?:SLEEP|BENCHMARK)\s*\(/i},{id:"sql-waitfor-delay",description:"MSSQL time-based blind injection: WAITFOR DELAY",pattern:/\bWAITFOR\s{1,20}DELAY\b/i},{id:"sql-char-function",description:"CHAR() function — used to obfuscate injected strings",pattern:/\bCHAR\s*\(\s*\d{1,3}/i},{id:"sql-information-schema",description:"INFORMATION_SCHEMA — reconnaissance query for table/column enumeration",pattern:/\bINFORMATION_SCHEMA\b/i}],y="[\"'\\s]*:",I={HTML:[{id:"html-script-open",description:"<script opening tag",pattern:/<script[\s>/]/i},{id:"html-script-close",description:"<\/script closing tag",pattern:/<\/script[\s>]/i},{id:"html-javascript-protocol",description:"javascript: URI scheme (with optional whitespace/encoding)",pattern:/j[\t\n\r ]*a[\t\n\r ]*v[\t\n\r ]*a[\t\n\r ]*s[\t\n\r ]*c[\t\n\r ]*r[\t\n\r ]*i[\t\n\r ]*p[\t\n\r ]*t[\t\n\r ]*:/i},{id:"html-vbscript-protocol",description:"vbscript: URI scheme",pattern:/vbscript[\t\n\r ]*:/i},{id:"html-data-html",description:"data:text/html URI — can execute scripts in browsers",pattern:/data[\t\n\r ]*:[\t\n\r ]*text\/html/i},{id:"html-data-xhtml",description:"data:application/xhtml+xml URI",pattern:/data[\t\n\r ]*:[\t\n\r ]*application\/xhtml/i},{id:"html-data-svg",description:"data:image/svg+xml URI — can execute scripts",pattern:/data[\t\n\r ]*:[\t\n\r ]*image\/svg\+xml/i},{id:"html-inline-event-handler",description:"Inline event handler attributes: onclick=, onerror=, onload=, etc.",pattern:/\bon\w{1,30}\s*=/i},{id:"html-entity-obfuscated-script",description:"HTML-entity-encoded <script (e.g. &#x3C;script or &lt;script)",pattern:/(?:&#x0*3[Cc];?|&#0*60;?|&lt;)\s*script/i},{id:"html-entity-obfuscated-javascript",description:'HTML-entity-encoded javascript: (partial — catches common &#106; or &#x6a; for "j")',pattern:/(?:&#x0*6[Aa];?|&#0*106;?)\s*(?:&#x0*61;?|a)[\s\S]{0,80}script\s*:/i},{id:"html-style-expression",description:"CSS expression() — IE-era code execution in style attributes",pattern:/style[\s\S]{0,20}expression\s*\(/i},{id:"html-object-embed",description:"<object or <embed tags that can load active content",pattern:/<(?:object|embed)[\s>/]/i},{id:"html-base-tag",description:"<base href= — can hijack all relative URLs on a page",pattern:/<base[\s>]/i},{id:"html-meta-refresh",description:'<meta http-equiv="refresh" — can redirect users',pattern:/<meta[\s\S]{0,40}http-equiv[\s\S]{0,20}refresh/i},{id:"html-srcdoc",description:"srcdoc= attribute on iframes — embeds HTML that can run scripts",pattern:/srcdoc\s*=/i},{id:"html-iframe",description:"<iframe tag",pattern:/<iframe[\s>/]/i},{id:"html-form",description:"<form tag — can be used for phishing / credential harvesting injection",pattern:/<form[\s>/]/i}],XML:[{id:"xml-cdata-injection",description:"CDATA section injection: <![CDATA[ breaks out of text node context",pattern:/<!\[CDATA\[/i},{id:"xml-cdata-close",description:"CDATA close sequence: ]]> can terminate an enclosing CDATA section",pattern:/\]\]>/},{id:"xml-processing-instruction",description:"XML processing instruction: <?xml-stylesheet or <?php etc.",pattern:/<\?(?:xml[\- ]|php|asp)/i},{id:"xml-doctype-injection",description:"DOCTYPE declaration embedded in content — can define entities",pattern:/<!DOCTYPE(?:[\s[]|$)/i},{id:"xml-entity-system",description:"SYSTEM keyword — used in external entity declarations (XXE)",pattern:/\bSYSTEM\s+["']/i},{id:"xml-entity-public",description:"PUBLIC keyword — used in external entity declarations (XXE)",pattern:/\bPUBLIC\s+["']/i},{id:"xml-entity-declaration",description:"<!ENTITY declaration — defines entities, potential XXE or entity expansion",pattern:/<!ENTITY[\s%]/i},{id:"xml-billion-laughs",description:"Entity reference chaining / billion laughs: repeated &eX; style references",pattern:/(?:&\w{1,20};){3,}/},{id:"xml-namespace-confusion",description:"xmlns: attribute injection — can redefine namespaces to confuse parsers",pattern:/\bxmlns\s*(?::\w{1,40})?\s*=/i},{id:"xml-comment-injection",description:"\x3c!-- comment injection — can hide content from some parsers",pattern:/<!--/},{id:"xml-comment-close",description:"--\x3e closes an enclosing XML comment",pattern:/-->/},{id:"xml-pi-close",description:"?> closes an enclosing processing instruction",pattern:/\?>/}],SVG:[{id:"svg-script-element",description:"<script element inside SVG executes JavaScript",pattern:/<script[\s>/]/i},{id:"svg-xlink-href-javascript",description:"xlink:href with javascript: — classic SVG XSS via <a> or <use>",pattern:/xlink\s*:\s*href\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-href-javascript",description:"href= with javascript: in SVG context (<a>, <animate>, etc.)",pattern:/href\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-foreignobject",description:"<foreignObject embeds HTML inside SVG — can execute scripts",pattern:/<foreignObject[\s>/]/i},{id:"svg-use-external",description:"<use xlink:href or href pointing to external resource (non-fragment URL)",pattern:/<use[\s\S]{0,60}(?:xlink\s*:\s*)?href\s*=\s*(?:["'][^#]|[^"'#\s>])/i},{id:"svg-animate-href",description:'<animate attributeName="href" — can dynamically change href to javascript:',pattern:/<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*href["']/i},{id:"svg-animate-xlinkhref",description:'<animate attributeName="xlink:href"',pattern:/<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*xlink\s*:\s*href["']/i},{id:"svg-set-javascript",description:'<set to="javascript:..." — sets an attribute to a javascript: URI',pattern:/<set[\s\S]{0,80}to\s*=\s*["']?\s*javascript\s*:/i},{id:"svg-event-handler",description:"SVG-specific event handler attributes: onload=, onerror=, onactivate=, etc.",pattern:/\bon(?:load|error|activate|begin|end|repeat|focus|blur|click|mouse\w{1,20}|key\w{1,20})\s*=/i},{id:"svg-handler-generic",description:"Generic on* handler catch-all for SVG attributes",pattern:/\bon\w{1,30}\s*=/i},{id:"svg-filter-feimage",description:"<feImage href= — filter primitive that can load external resources",pattern:/<feImage[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=/i},{id:"svg-image-external",description:"<image xlink:href with http/https or javascript protocol",pattern:/<image[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=\s*["']?\s*(?:https?|javascript)\s*:/i},{id:"svg-style-javascript",description:"style= attribute containing javascript: (e.g. background:url(javascript:...))",pattern:/style\s*=[\s\S]{0,60}javascript\s*:/i}],SQL:b,"SQL-STRICT":[...b,{id:"sql-line-comment",description:"SQL line comment: -- followed by whitespace or end of string",pattern:/--(?:\s|$)/},{id:"sql-stacked-query",description:"Stacked queries: semicolon immediately followed by a SQL keyword",pattern:/;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i},{id:"sql-hex-encoding",description:"Hex-encoded string injection: 0x41414141 style (MySQL)",pattern:/\b0x[0-9a-f]{4,}/i}],SHELL:[{id:"shell-path-traversal-unix",description:"Unix path traversal: ../ — climbing the directory tree",pattern:/\.\.\//},{id:"shell-path-traversal-windows",description:"Windows path traversal: ..\\ — climbing the directory tree",pattern:/\.\.\\/},{id:"shell-path-traversal-encoded",description:"URL-encoded path traversal: %2e%2e or %2f variants",pattern:/%2e%2e|%2f\.\.|\.\.%2f/i},{id:"shell-null-byte",description:"Null byte injection: \\x00 or %00 — truncates strings in C-backed functions",pattern:/\x00|%00/},{id:"shell-semicolon",description:"Semicolon command separator: cmd1; cmd2",pattern:/;/},{id:"shell-pipe",description:"Pipe operator: cmd1 | cmd2",pattern:/\|/},{id:"shell-and-operator",description:"AND operator: cmd1 && cmd2",pattern:/&&/},{id:"shell-or-operator",description:"OR operator: cmd1 || cmd2",pattern:/\|\|/},{id:"shell-backtick",description:"Backtick command substitution: `cmd`",pattern:/`/},{id:"shell-dollar-paren",description:"Dollar-paren command substitution: $(cmd)",pattern:/\$\(/},{id:"shell-dollar-brace",description:"Dollar-brace variable expansion: ${var} — can be abused for injection",pattern:/\$\{/},{id:"shell-redirect-out",description:"Output redirection: cmd > file or cmd >> file",pattern:/>{1,2}/},{id:"shell-redirect-in",description:"Input redirection: cmd < file",pattern:/</},{id:"shell-newline-injection",description:"Newline injection: \\n or \\r — can inject new shell commands",pattern:/[\n\r]/},{id:"shell-glob-star",description:"Glob expansion: * or ? — can expand to unintended files",pattern:/[/\\][*?]/},{id:"shell-absolute-root",description:"Absolute root path injection: string starting with / or \\ (Windows UNC)",pattern:/^(?:\/|\\\\)/},{id:"shell-windows-drive",description:"Windows drive letter path injection: C:\\ or D:/",pattern:/^[a-zA-Z]:[/\\]/},{id:"shell-curl-wget",description:"curl/wget with URL or flags — can exfiltrate data or download payloads",pattern:/\b(?:curl|wget)\s+(?:https?:\/\/|ftp:\/\/|-)/i}],REDOS:[{id:"redos-nested-quantifier-plus",description:"Nested + quantifier inside a group with outer quantifier: (a+)+, (.+b)*, etc.",pattern:/\([^)]*\+[^)]*\)[+*]/},{id:"redos-nested-quantifier-star",description:"Nested * quantifier: (a*)* or (a*)+ — catastrophic backtracking",pattern:/\([^)]*\*[^)]*\)[*+]/},{id:"redos-nested-groups",description:"Doubly nested quantified groups: ((a+)+) — guaranteed catastrophic",pattern:/\(\([^)]{0,40}\)[+*]\)[+*]/},{id:"redos-alternation-overlap",description:"Overlapping alternation under quantifier: (a|a)+ — ambiguous NFA paths",pattern:/\(([^|()]{1,20})\|(?:\1)(?:\|[^|()]{1,20}){0,5}\)[+*?]{1,2}/},{id:"redos-star-plus-concat",description:"(x*x)+ pattern — triggers super-linear backtracking",pattern:/\([^)]{0,10}\*[^)]{0,10}\)[+*]/},{id:"redos-dot-star-greedy",description:"(.*){n,} or (.+){n,} — repeated greedy dot quantifiers",pattern:/\(\.[*+]\)\{?\d/},{id:"redos-large-repetition",description:"Very large fixed or range repetition count {1000,} or {1000,n} — denial of service via backtracking",pattern:/\{\d{4,}(?:,\d*)?\}/},{id:"redos-catastrophic-alternation",description:"Long alternation with many similar branches — polynomial backtracking risk",pattern:/\([^)]{0,200}(?:\|[^|)]{0,50}){9,}\)/}],NOSQL:[{id:"nosql-where-operator",description:"$where — executes arbitrary JavaScript server-side in MongoDB",pattern:new RegExp(`\\$where${y}`,"i")},{id:"nosql-ne-operator",description:'$ne — "not equal" operator used to bypass equality checks',pattern:new RegExp(`\\$ne${y}`,"i")},{id:"nosql-gt-operator",description:'$gt — "greater than" used to bypass password/value checks',pattern:new RegExp(`\\$gte?${y}`,"i")},{id:"nosql-lt-operator",description:'$lt / $lte — "less than" bypass variants',pattern:new RegExp(`\\$lte?${y}`,"i")},{id:"nosql-regex-operator",description:"$regex — can be used to extract data character by character (blind injection)",pattern:new RegExp(`\\$regex${y}`,"i")},{id:"nosql-or-operator",description:"$or — logical OR; used to create always-true conditions",pattern:new RegExp(`\\$or${y}\\s*\\[`,"i")},{id:"nosql-and-operator",description:"$and — logical AND operator injection",pattern:new RegExp(`\\$and${y}\\s*\\[`,"i")},{id:"nosql-nor-operator",description:"$nor — logical NOR operator injection",pattern:new RegExp(`\\$nor${y}\\s*\\[`,"i")},{id:"nosql-exists-operator",description:"$exists — can enumerate fields to determine schema",pattern:new RegExp(`\\$exists${y}`,"i")},{id:"nosql-in-operator",description:"$in — matches any value in a list; can enumerate values",pattern:new RegExp(`\\$in${y}\\s*\\[`,"i")},{id:"nosql-expr-operator",description:"$expr — allows aggregation expressions in queries (MongoDB 3.6+)",pattern:new RegExp(`\\$expr${y}`,"i")},{id:"nosql-function-operator",description:"$function — executes arbitrary JavaScript in MongoDB 4.4+",pattern:new RegExp(`\\$function${y}`,"i")},{id:"nosql-accumulator-operator",description:"$accumulator — custom aggregation with arbitrary JS execution",pattern:new RegExp(`\\$accumulator${y}`,"i")},{id:"nosql-proto-pollution",description:"__proto__ — prototype pollution via object key injection",pattern:/__proto__/},{id:"nosql-constructor-prototype",description:"constructor.prototype — alternative prototype pollution vector (dot notation or JSON key)",pattern:/constructor[\s"':.,{\[]*prototype/i},{id:"nosql-proto-bracket",description:'["__proto__"] — bracket-notation prototype pollution',pattern:/\[["']__proto__["']\]/}],LOG:[{id:"log-crlf-injection",description:"CRLF injection: literal \\r or \\n embeds fake log lines",pattern:/[\r\n]/},{id:"log-url-encoded-crlf",description:"URL-encoded CRLF: %0d, %0a, %0D, %0A — decoded by some log parsers",pattern:/%0[dDaA]/},{id:"log-unicode-newline",description:"Unicode newline variants: U+2028 (line separator), U+2029 (paragraph separator)",pattern:/[\u2028\u2029]/},{id:"log-log4shell-jndi",description:"Log4Shell: ${jndi:...} triggers remote code execution in Apache Log4j",pattern:/\$\{jndi\s*:/i},{id:"log-log4shell-obfuscated",description:"Obfuscated Log4Shell: ${::-j}... lookup-bypass prefix used to evade WAF detection",pattern:/\$\{::-/},{id:"log-log4j-lookup",description:"Log4j lookup syntax: ${env:...}, ${sys:...}, ${ctx:...} — data exfiltration",pattern:/\$\{(?:env|sys|ctx|main|map|sd|web|docker|k8s|spring)\s*:/i},{id:"log-ssti-double-brace",description:"SSTI double-brace: {{expression}} — Jinja2, Twig, Handlebars, etc.",pattern:/\{\{[\s\S]{0,80}\}\}/},{id:"log-ssti-hash-brace",description:"SSTI hash-brace: #{expression} — Thymeleaf, Velocity, Ruby ERB",pattern:/#\{[\s\S]{0,80}\}/},{id:"log-ssti-dollar-brace",description:"SSTI/EL injection: ${expression with operators or method calls} — JSP EL, Freemarker, SpEL",pattern:/\$\{[^}]*(?:\.|\(|\*|\+|\bclass\b|\bruntime\b|\bprocess\b|\bexec\b)[^}]{0,80}\}/i},{id:"log-ssti-percent-tag",description:"SSTI ERB/ASP tag: <%= expression %> — Ruby ERB, ASP",pattern:/<%=[\s\S]{0,80}%>/},{id:"log-null-byte",description:"Null byte: \\x00 or %00 — can truncate log entries in C-backed loggers",pattern:/\x00|%00/},{id:"log-ansi-escape",description:"ANSI escape sequence: ESC[ — can manipulate terminal output when logs are tailed",pattern:/\x1b\[/}]},N=I,A=Object.freeze(Object.fromEntries(Object.keys(I).map(t=>[t,t])));function S(t,e){const s=N[e];for(const r of s)if(r.pattern.test(t))return{context:e,id:r.id,description:r.description,pattern:r.pattern};return null}function C(t,e){if(function(t){if("string"!=typeof t)throw new TypeError("is-unsafe: first argument must be a string, got "+typeof t)}(t),function(t){if(!(t instanceof RegExp))if("string"!=typeof t){if(!Array.isArray(t))throw new TypeError("is-unsafe: second argument must be a context string, array of context strings, or RegExp. Got: "+typeof t);if(0===t.length)throw new TypeError("is-unsafe: context array must not be empty");for(const e of t)if("string"!=typeof e||!N[e])throw new TypeError(`is-unsafe: unknown context "${e}" in array. Valid contexts: ${Object.keys(A).join(", ")}`)}else if(!N[t])throw new TypeError(`is-unsafe: unknown context "${t}". Valid contexts: ${Object.keys(A).join(", ")}`)}(e),e instanceof RegExp)return e.test(t);if("string"==typeof e)return null!==S(t,e);for(const s of e)if(null!==S(t,s))return!0;return!1}class D{constructor(t=!1){this.IS_FINAL=t}init(t){this.ctx=t}reset(){}parse(t,e){throw new Error("You must implement parse() in a value parser.")}}const v={namedEntities:{...d},numericAllowed:!0,onInputEntity:(t,e)=>C(e,[A.XML])?u.BLOCK:u.ALLOW},k=[48,1632,1776,2406,2534,2662,2790,2918,3046,3174,3302,3430,3558,3664,3792,3872,4160,4240,6112,6160,6470,6608,6784,6800,6992,7088,7232,7248,65296,120782,120792,120802,120812,120822,66720,68912,69734,69872,69942,70096,70384,70736,70864,71248,71360,71472,71904,72016,72688,72784,73040,73120,73552,92768,92864,93008,123200,123632,124144,125264,130032],P=new Map,O=1632,U=new Uint8Array(63904).fill(255);for(const t of k)for(let e=0;e<10;e++){const s=t+e;s<=65535?U[s-O]=e:P.set(s,e)}const L=new Set([8722,65293,65123]),$=/^[-+]?0x[a-fA-F0-9]+$/,R=/^0b[01]+$/,M=/^0o[0-7]+$/,B=/^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/,j={hex:!0,binary:!1,octal:!1,leadingZeros:!0,decimalPoint:".",eNotation:!0,infinity:"original",unicode:!1};function X(t,e={}){if(e=Object.assign({},j,e),!t||"string"!=typeof t)return t;let s=t.trim();if(0===s.length)return t;if(void 0!==e.skipLike&&e.skipLike.test(s))return t;if("0"===s)return 0;if(e.unicode&&(s=function(t){if("string"!=typeof t)return t;const e=t.length;if(0===e)return t;let s=-1;for(let r=0;r<e;r++){const i=t.charCodeAt(r);if(!(i>=48&&i<=57||45===i))if(i<O){if(L.has(i)){s=r;break}}else if(i>=55296&&i<=56319){if(r+1<e){const e=t.charCodeAt(r+1);if(e>=56320&&e<=57343){const t=65536+(i-55296<<10)+(e-56320);if(P.has(t)){s=r;break}}}}else if(255!==U[i-O]||L.has(i)){s=r;break}}if(-1===s)return t;const r=[];s>0&&r.push(t.slice(0,s));for(let i=s;i<e;i++){const s=t.charCodeAt(i);if(s>=48&&s<=57||45===s){r.push(t[i]);continue}if(s<O){r.push(L.has(s)?"-":t[i]);continue}if(s>=55296&&s<=56319){if(i+1<e){const e=t.charCodeAt(i+1);if(e>=56320&&e<=57343){const t=65536+(s-55296<<10)+(e-56320),n=P.get(t);if(void 0!==n){r.push(String.fromCharCode(n+48)),i++;continue}}}r.push(t[i]);continue}if(L.has(s)){r.push("-");continue}const n=U[s-O];r.push(255!==n?String.fromCharCode(n+48):t[i])}return r.join("")}(s),"0"===s))return 0;if(e.hex&&$.test(s))return Y(s,16);if(e.binary&&R.test(s))return Y(s,2);if(e.octal&&M.test(s))return Y(s,8);if(isFinite(s)){if(s.includes("e")||s.includes("E"))return function(t,e,s){if(!s.eNotation)return t;const r=e.match(V);if(r){let i=r[1]||"";const n=-1===r[3].indexOf("e")?"E":"e",o=r[2],a=i?t[o.length+1]===n:t[o.length]===n;return o.length>1&&a?t:(1!==o.length||!r[3].startsWith(`.${n}`)&&r[3][0]!==n)&&o.length>0?s.leadingZeros&&!a?(e=(r[1]||"")+r[3],Number(e)):t:Number(e)}return t}(t,s,e);{const i=B.exec(s);if(i){const n=i[1]||"",o=i[2];let a=(r=i[3])&&-1!==r.indexOf(".")?("."===(r=r.replace(/0+$/,""))?r="0":"."===r[0]?r="0"+r:"."===r[r.length-1]&&(r=r.substring(0,r.length-1)),r):r;const c=n?"."===t[o.length+1]:"."===t[o.length];if(!e.leadingZeros&&(o.length>1||1===o.length&&!c))return t;{const r=Number(s),i=String(r);if(0===r)return r;if(-1!==i.search(/[eE]/))return e.eNotation?r:t;if(-1!==s.indexOf("."))return"0"===i||i===a||i===`${n}${a}`?r:t;let c=o?a:s;return o?c===i||n+c===i?r:t:c===i||c===n+i?r:t}}return t}}var r;return function(t,e,s){const r=e===1/0;switch(s.infinity.toLowerCase()){case"null":return null;case"infinity":return e;case"string":return r?"Infinity":"-Infinity";default:return t}}(t,Number(s),e)}const V=/^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;function Y(t,e){const s=t.trim();if(2!==e&&8!==e||(t=s.substring(2)),parseInt)return parseInt(t,e);if(Number.parseInt)return Number.parseInt(t,e);if(window&&window.parseInt)return window.parseInt(t,e);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}const F={entity:new class extends D{#t=!1;#e=null;#s=null;constructor(t,e=!1){super(e),this.#s={...v,...t||{},namedEntities:{...v.namedEntities,...t?.namedEntities||{}}}}#r(){if(this.#e||(this.#e=new w(this.#s)),!this.#t){const t=this.ctx?.get("xmlVersion"),e=this.ctx?.get("inputEntities");t&&this.#e.setXmlVersion(t),e&&this.#e.addInputEntities(e),this.#t=!0}}reset(){this.#t=!1,this.#e&&this.#e.reset()}parse(t){return"string"!=typeof t?t:(this.#r(),this.#e.decode(t))}},trim:new class extends D{parse(t){return"string"==typeof t?t.trim():t}},ws:new class extends D{constructor(t,e=!1){super(e);const i=t?.exclude??[],n=new s;for(const t of i)n.add("string"==typeof t?new r(t):t);n.seal(),this._excludeSet=n}parse(t,e){if("string"!=typeof t)return t;if(e){if(e.isAttribute)return t;if(e.matcher){if("preserve"===e.matcher.getAnyParentAttr("xml:space"))return t;if(this._excludeSet.size>0&&this._excludeSet.matchesAny(e.matcher))return t}}return t.replace(/[ \t\r\n]+/g," ").trim()}},boolean:new class extends D{constructor(t,e,s=!1){super(s),this.trueList=t||["true"],this.falseList=e||["false"]}parse(t){if("string"==typeof t){const e=t.toLowerCase();if(-1!==this.trueList.indexOf(e))return!this.IS_FINAL||new z(!0);if(-1!==this.falseList.indexOf(e))return!!this.IS_FINAL&&new z(!1)}return t}},number:new class extends D{constructor(t,e=!1){super(e),this.options=t||{}}parse(t){if("string"==typeof t){const e=X(t,this.options);if(typeof e!==t)return this.IS_FINAL?new z(e):e}return t}}({hex:!0,leadingZeros:!0,eNotation:!0})};class q{constructor(){this.registered={...F}}register(t,e){if(!t||"string"!=typeof t)throw new Error("name must be a string");if(!e)throw new Error("parser is required");if(!e.reset||"function"!=typeof e.reset)throw new Error("parser must implement reset()");if(!e.parse||"function"!=typeof e.parse)throw new Error("parser must implement parse()");this.registered[t]=e}reset(t){this.registered[t]?.reset()}resetAll(){for(const t in this.registered)this.registered[t]?.reset()}get(t){const e=this.registered[t];if(!e)throw new Error("parser not found: "+t);return e}}class G{constructor(t,e,s,r=!1){this.elementName=t,this.matcher=e,this.isLeafNode=s,this.isAttribute=r}}class z{constructor(t){this.value=t}}class H{#i={};set(t,e){this.#i[t]=e}get(t){return this.#i[t]}clear(){this.#i={}}}class W{constructor(t=[],e,s=null){this.valParsers=t,this.registry=e,this.sharedContext=s||new H,this._initAll(t)}run(t,e){for(let s=0;s<this.valParsers.length;s++){let r=this.valParsers[s];if("string"==typeof r&&(r=this.registry.get(r)),r){const s=r.parse(t,e);if(s instanceof z)return s.value;t=s}}return t}resetAll(){for(let t=0;t<this.valParsers.length;t++){let e=this.valParsers[t];"string"==typeof e&&(e=this.registry.get(e)),e&&e.reset&&"function"==typeof e.reset&&e.reset()}}register(t,e){this.registry.register(t,e),e.init&&e.init(this.sharedContext)}_initAll(t){if(!this.sharedContext)return;const e=new Set;for(const s of t){let t=s;"string"==typeof s&&(t=this.registry.get(s)),t&&"function"==typeof t.init&&!e.has(t)&&(e.add(t),t.init(this.sharedContext))}}}const Q=["ws","entity","boolean","number"],J=["entity","boolean","number"];class Z{constructor(t,e,s,r,i=!0){this.matcher=s,this._rootName="^",this.parserOptions=t,this.builderOptions=e,this.registry=r;const n=e?.tags?.valueParsers??Q,o=e?.attributes?.valueParsers??J;this.sharedContext=new H,this.tagsPipeline=new W(n,this.registry,this.sharedContext),this.attrsPipeline=new W(o,this.registry,this.sharedContext),i&&(this.tagsPipeline.resetAll(),this.attrsPipeline.resetAll()),this._pendingStopNode=!1}addAttribute(t,e,s){"version"===t&&this.tagName===this._rootName&&this.sharedContext?.set("xmlVersion",+e);const r=`${this.parserOptions.attributes.prefix}${t}${this.parserOptions.attributes.suffix}`,i=new G(t,s,!0,!0);this.attributes[r]=this.attrsPipeline.run(e,i)}_addChild(t,e){}addComment(t){this.parserOptions.skip.comment||this.parserOptions.nameFor.comment&&this._addChild(this.parserOptions.nameFor.comment,t)}addLiteral(t){this.parserOptions.skip.cdata||(this.parserOptions.nameFor.cdata?this._addChild(this.parserOptions.nameFor.cdata,t):this.addRawValue(t||""))}addRawValue(t){this.addValue(t)}addInputEntities(t){this.sharedContext?.set("inputEntities",t)}addDeclaration(t){this.addInstruction(t)}addInstruction(t){}onStopNode(t,e){this._pendingStopNode=!0,"function"==typeof this.parserOptions.onStopNode&&this.parserOptions.onStopNode(t,e,this.matcher)}onExit(t){}}class K{constructor(t={}){this.builderOptions=t,this.registry=new q}registerValueParser(t,e){this.registry.register(t,e)}getInstance(t,e){throw new Error("getInstance is not implemented")}}class tt extends K{constructor(t={}){super(),this.builderOptions=a(t)}getInstance(t,e){return new et(t,this.builderOptions,e,this.registry)}}class et extends Z{constructor(t,e,s,r){super(t,e,s,r),this.parserOptions=t,this.builderOptions=e,this.tagsStack=[],this.root={},this.parent=this.root,this.tagName=this._rootName,this.value={},this.textValue="",this.attributes={},this.hasAttributes=!1}_buildAttributeValue(){return st(this.attributes)?(this.hasAttributes=!1,""):(this.hasAttributes=!0,this.parserOptions.attributes.groupBy?{[this.parserOptions.attributes.groupBy]:this.attributes}:this.attributes)}addElement(t){const e=this._buildAttributeValue();this.tagsStack.push([this.tagName,this.textValue,this.value,this.hasAttributes]),this.tagName=t.name,this.value=e,this.textValue="",this.attributes={}}_resolveForceArray(t){let e,s;if(this.builderOptions._alwaysArraySet.matchesAny(this.matcher)&&(e=!0),"function"==typeof this.builderOptions.forceArray){const e=this.builderOptions.forceArray(this.matcher,t);!0===e?s=!0:!1===e&&(s=!1)}return!1!==e&&!1!==s&&(!0===e||!0===s)}closeElement(){const t=this.tagName;let e=this.value;const s=this.textValue,r=this.hasAttributes,i="object"!=typeof e||Array.isArray(e)||st(e)||r,n=new G(t,this.matcher,i,!1);if(i){const t=this._pendingStopNode?s:this.tagsPipeline.run(s,n);r?(""!==t&&null!=t||this.builderOptions.forceTextNode)&&(e[this.parserOptions.nameFor.text]=t):e=this.builderOptions.forceTextNode?{[this.parserOptions.nameFor.text]:t}:t}else if(s.length>0||this.builderOptions.forceTextNode){const t=this._pendingStopNode?s:this.tagsPipeline.run(s,n);e[this.parserOptions.nameFor.text]=t}let o={tagName:t,value:e};const a=this.tagsStack.pop();let c=a[2];const l=this._resolveForceArray(i);c=this._addChildTo(o.tagName,o.value,c,l),this.tagName=a[0],this.textValue=a[1],this.value=c,this.hasAttributes=a[3],this._pendingStopNode=!1}_addChild(t,e){"string"==typeof this.value&&(this.value={[this.parserOptions.nameFor.text]:this.value}),this._addChildTo(t,e,this.value,!1),this.attributes={}}_addChildTo(t,e,s,r){return"string"==typeof s&&(s={}),Object.prototype.hasOwnProperty.call(s,t)?(Array.isArray(s[t])||(s[t]=[s[t]]),s[t].push(e)):s[t]=r?[e]:e,s}addValue(t){this.textValue.length>0?this.textValue+=`${this.builderOptions.textJoint}${t}`:this.textValue=t}addInstruction(t){const e=this._buildAttributeValue();this._addChild(t,e),this.attributes={}}onExit(t){}getOutput(){return this.value}}function st(t){return 0===Object.keys(t).length}class rt{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],r=s?.tag;if(r&&"*"!==r){const s=`${e}:${r}`;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(),r=`${e}:${s}`,i=this._byDepthAndTag.get(r);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];const o=this._deepByTerminalTag.get(s);if(o)for(let e=0;e<o.length;e++)if(t.matches(o[e]))return o[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}class it{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,r="";for(;s<t.length;)t[s]===this.separator?s+1<t.length&&t[s+1]===this.separator?(r.trim()&&(e.push(this._parseSegment(r.trim())),r=""),e.push({type:"deep-wildcard"}),s+=2):(r.trim()&&e.push(this._parseSegment(r.trim())),r="",s++):(r+=t[s],s++);return r.trim()&&e.push(this._parseSegment(r.trim())),e}_parseSegment(t){const e={type:"tag"};let s=null,r=t;const i=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(i&&(r=i[1]+i[3],i[2])){const t=i[2].slice(1,-1);t&&(s=t)}let n,o,a=r;if(r.includes("::")){const e=r.indexOf("::");if(n=r.substring(0,e).trim(),a=r.substring(e+2).trim(),!n)throw new Error(`Invalid namespace in pattern: ${t}`)}let c=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)?(o=e,c=s):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,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(c){const t=c.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=c}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 nt extends Error{constructor(t,e,s={}){super(t),this.name="ParseError",this.code=e,this.line=s.line??void 0,this.col=s.col??void 0,this.index=s.index??void 0}toString(){const t=this._posStr();return t?`${this.name} [${this.code}] at ${t}: ${this.message}`:`${this.name} [${this.code}]: ${this.message}`}_posStr(){return void 0!==this.line&&void 0!==this.col?`line ${this.line}, col ${this.col}`:void 0!==this.index?`index ${this.index}`:null}}const ot=Object.freeze({INVALID_INPUT:"INVALID_INPUT",INVALID_STREAM:"INVALID_STREAM",ALREADY_STREAMING:"ALREADY_STREAMING",NOT_STREAMING:"NOT_STREAMING",DATA_MUST_BE_STRING:"DATA_MUST_BE_STRING",UNEXPECTED_END:"UNEXPECTED_END",UNEXPECTED_CLOSE_TAG:"UNEXPECTED_CLOSE_TAG",MISMATCHED_CLOSE_TAG:"MISMATCHED_CLOSE_TAG",UNEXPECTED_TRAILING_DATA:"UNEXPECTED_TRAILING_DATA",INVALID_TAG:"INVALID_TAG",UNCLOSED_QUOTE:"UNCLOSED_QUOTE",MULTIPLE_NAMESPACES:"MULTIPLE_NAMESPACES",SECURITY_PROTOTYPE_POLLUTION:"SECURITY_PROTOTYPE_POLLUTION",SECURITY_RESERVED_OPTION:"SECURITY_RESERVED_OPTION",SECURITY_RESTRICTED_NAME:"SECURITY_RESTRICTED_NAME",LIMIT_MAX_NESTED_TAGS:"LIMIT_MAX_NESTED_TAGS",LIMIT_MAX_ATTRIBUTES:"LIMIT_MAX_ATTRIBUTES",ENTITY_MAX_COUNT:"ENTITY_MAX_COUNT",ENTITY_MAX_SIZE:"ENTITY_MAX_SIZE",ENTITY_MAX_EXPANSIONS:"ENTITY_MAX_EXPANSIONS",ENTITY_MAX_EXPANDED_LENGTH:"ENTITY_MAX_EXPANDED_LENGTH",ENTITY_INVALID_KEY:"ENTITY_INVALID_KEY",ENTITY_INVALID_VALUE:"ENTITY_INVALID_VALUE"});function at(t){return" "===t||"\t"===t||"\n"===t||"\r"===t||"\f"===t}function ct(t){return 32===t||9===t||10===t||13===t||12===t}const lt=["hasOwnProperty","toString","valueOf","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__","toLocaleString","isPrototypeOf","propertyIsEnumerable"],ht=["__proto__","constructor","prototype"],dt=t=>lt.includes(t)?"__"+t:t,ut={skip:{declaration:!1,pi:!1,attributes:!0,cdata:!1,comment:!1,nsPrefix:!1,tags:[],whitespaceText:!0},nameFor:{text:"#text",cdata:"",comment:""},attributes:{booleanType:!1,groupBy:"",prefix:"@_",suffix:""},tags:{unpaired:[],stopNodes:[]},strictReservedNames:!1,onDangerousProperty:dt,only:[],doctypeOptions:{enabled:!1,maxEntityCount:100,maxEntitySize:1e4},autoClose:null,limits:{maxNestedTags:null,maxAttributesPerTag:null},feedable:{maxBufferSize:10485760,autoFlush:!0,flushThreshold:1024,bufferSize:256},exitIf:null,OutputBuilder:null},pt=new Set([...ht,...lt]);function ft(t,e){if("string"==typeof t&&""!==t&&pt.has(t))throw new nt(`SECURITY: '${t}' is a reserved JavaScript keyword and cannot be used as ${e}`,ot.SECURITY_RESERVED_OPTION)}const gt=function(t){if(t&&(t.nameFor?.text&&ft(t.nameFor.text,"nameFor.text"),t.nameFor?.cdata&&ft(t.nameFor.cdata,"nameFor.cdata"),t.nameFor?.comment&&ft(t.nameFor.comment,"nameFor.comment"),t.attributes?.prefix&&ft(t.attributes.prefix,"attributes.prefix"),t.attributes?.groupBy&&ft(t.attributes.groupBy,"attributes.groupBy"),void 0!==t.limits&&null!==t.limits)){if("object"!=typeof t.limits)throw new nt("'limits' must be an object, got "+typeof t.limits,ot.INVALID_INPUT);const{maxNestedTags:e,maxAttributesPerTag:s}=t.limits;if(null!=e&&("number"!=typeof e||!Number.isInteger(e)||e<1))throw new nt(`'limits.maxNestedTags' must be a positive integer, got ${e}`,ot.INVALID_INPUT);if(null!=s&&("number"!=typeof s||!Number.isInteger(s)||s<0))throw new nt(`'limits.maxAttributesPerTag' must be a non-negative integer, got ${s}`,ot.INVALID_INPUT)}const e=Et(ut);if(t&&xt(e,t),e.OutputBuilder||(e.OutputBuilder=new tt),Array.isArray(e.tags?.stopNodes)){const t=new rt;e.tags.stopNodes=e.tags.stopNodes.map(e=>_t(e,"stopNodes",t)),t.seal(),e.tags.stopNodesSet=t}if(Array.isArray(e.skip?.tags)){const t=new rt;e.skip.tags=e.skip.tags.map(e=>_t(e,"skip.tags",t)),t.seal(),e.skip.tagsSet=t}if(null===e.onDangerousProperty&&(e.onDangerousProperty=dt),null!==e.exitIf&&void 0!==e.exitIf&&"function"!=typeof e.exitIf)throw new nt("'exitIf' must be a function, got "+typeof e.exitIf,ot.INVALID_INPUT);return e.autoClose=function(t,e){if(!t)return null;if("html"===t){const t=e.tags.unpaired||[],s=[...new Set([...t,...mt])];return e.tags={...e.tags,unpaired:s},{onEof:"closeAll",onMismatch:"discard",collectErrors:!0}}return"string"==typeof t?{onEof:t,onMismatch:"throw",collectErrors:!1}:"object"==typeof t?{onEof:t.onEof||"throw",onMismatch:t.onMismatch||"throw",collectErrors:t.collectErrors||!1}:null}(e.autoClose,e),e},mt=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"];function _t(t,e,s){let r,i,n;if("string"==typeof t){if(0===t.length)throw new nt(`${e} expression cannot be empty`,ot.INVALID_INPUT);r=t,i=!1,n=[]}else if(t instanceof it)r=t.toString(),i=t.data?.nested??!1,n=t.data?.skipEnclosures??[];else{if(!t||"object"!=typeof t||void 0===t.expression)throw new nt(`Invalid ${e} entry: expected a string, Expression, or { expression, nested?, skipEnclosures? } object.`,ot.INVALID_INPUT);{const s=t.expression;if("string"==typeof s){if(0===s.length)throw new nt(`${e} expression cannot be empty`,ot.INVALID_INPUT);r=s}else{if(!(s instanceof it))throw new nt(`${e} expression must be a string or Expression instance`,ot.INVALID_INPUT);r=s.toString()}i=!0===t.nested,n=Array.isArray(t.skipEnclosures)?t.skipEnclosures:[]}}const o=new it(r,{},{nested:i,skipEnclosures:n});return s.add(o),o}function Et(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(Et);if(t instanceof RegExp)return t;if(t instanceof it)return t;const e={};for(const s of Object.keys(t))e[s]="function"==typeof t[s]?t[s]:Et(t[s]);return e}function xt(t,e){for(const s of Object.keys(e))"__proto__"!==s&&"constructor"!==s&&"prototype"!==s&&("OutputBuilder"===s||"function"==typeof e[s]||e[s]instanceof RegExp||Array.isArray(e[s])?t[s]=e[s]:"object"==typeof e[s]&&null!==e[s]?("object"==typeof t[s]&&null!==t[s]||(t[s]={}),xt(t[s],e[s])):t[s]=e[s])}class Tt{constructor(t,e={}){this.line=1,this.cols=0,this.buffer=t,this.startIndex=0,this.autoFlush=!1!==e.autoFlush,this.flushThreshold=e.flushThreshold??1024,this._marks=[-1,-1]}markTokenStart(t=0){this._marks[t]=this.startIndex}rewindToMark(){}clearMark(){this._marks[0]=-1,this._marks[1]=-1}flush(){let t=this.startIndex;for(const e of this._marks)e>=0&&e<t&&(t=e);if(t>0){this.buffer=this.buffer.substring(t);const e=this._marks.length;for(let s=0;s<e;s++)this._marks[s]>=0&&(this._marks[s]-=t);this.startIndex-=t}}readCh(){const t=this.buffer[this.startIndex++];return"\n"===t?(this.line++,this.cols=0):this.cols++,t}readChAt(t){return this.buffer[this.startIndex+t]}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.substring(e,e+t)}_advanceLineCol(t){let e=-1;for(let s=this.startIndex;s<t;s++)"\n"===this.buffer[s]&&(this.line++,e=s);e>=0?this.cols=t-e-1:this.cols+=t-this.startIndex}readUpto(t){const e=this.buffer.length,s=t.length;for(let r=this.startIndex;r<e;r++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[r+i]!==t[i]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this._advanceLineCol(r+s),this.startIndex=r+s,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END);const s=this.buffer.substring(this.startIndex,e);return this._advanceLineCol(e+1),this.startIndex=e+1,s}readUptoCloseTag(t){const e=this.buffer.length,s=t.length;let r=-1,i=0;for(let n=this.startIndex;n<e;n++){if(1===i){const t=this.buffer[n];if(" "===t||"\t"===t)continue;">"===t?i=2:(i=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[n+r]!==t[r]){e=!1;break}e&&(i=1,r=n,n+=s-1)}if(2===i){const t=this.buffer.substring(this.startIndex,r);return this._advanceLineCol(n+1),this.startIndex=n+1,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readFromBuffer(t,e){const s=1===t?this.buffer[this.startIndex]:this.buffer.substring(this.startIndex,this.startIndex+t);return e&&this.updateBufferBoundary(t),s}updateBufferBoundary(t=1){const e=this.startIndex+t;this._advanceLineCol(e),this.startIndex=e;const s=this._marks[0]>=0||this._marks[1]>=0;this.autoFlush&&this.startIndex>=this.flushThreshold&&!s&&this.flush()}canRead(t){return t=void 0!==t?t:this.startIndex,this.buffer.length-t>0}}class wt{constructor(t,e={}){this.line=1,this.cols=0,this.buffer=t,this.startIndex=0,this.autoFlush=!1!==e.autoFlush,this.flushThreshold=e.flushThreshold??1024,this._tokenStart=-1}markTokenStart(){this._tokenStart=this.startIndex}rewindToMark(){}flush(){const t=this._tokenStart>=0?this._tokenStart:this.startIndex;t>0&&(this.buffer=Buffer.from(this.buffer.subarray(t)),this._tokenStart>=0?(this.startIndex-=t,this._tokenStart=0):this.startIndex=0)}readCh(){const t=this.buffer[this.startIndex++];return 10===t?(this.line++,this.cols=0):this.cols++,String.fromCharCode(t)}readChAt(t){return String.fromCharCode(this.buffer[this.startIndex+t])}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.slice(e,e+t).toString()}_advanceLineCol(t){let e=-1;for(let s=this.startIndex;s<t;s++)10===this.buffer[s]&&(this.line++,e=s);e>=0?this.cols=t-e-1:this.cols+=t-this.startIndex}readUpto(t){const e=this.buffer.length,s=t.length,r=Buffer.from(t);for(let t=this.startIndex;t<e;t++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[t+i]!==r[i]){e=!1;break}if(e){const e=this.buffer.slice(this.startIndex,t).toString();return this._advanceLineCol(t+s),this.startIndex=t+s,e}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=t.charCodeAt(0),s=this.buffer,r=s.length;for(let t=this.startIndex;t<r;t++)if(s[t]===e){const e=s.slice(this.startIndex,t).toString();return this._advanceLineCol(t+1),this.startIndex=t+1,e}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoCloseTag(t){const e=this.buffer.length,s=t.length,r=Buffer.from(t);let i=-1,n=0;for(let t=this.startIndex;t<e;t++){if(1===n){const e=this.buffer[t];if(32===e||9===e)continue;62===e?n=2:(n=0,i=-1)}else{let e=!0;for(let i=0;i<s;i++)if(this.buffer[t+i]!==r[i]){e=!1;break}e&&(n=1,i=t,t+=s-1)}if(2===n){const e=this.buffer.slice(this.startIndex,i).toString();return this._advanceLineCol(t+1),this.startIndex=t+1,e}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readFromBuffer(t,e){let s;return 1===t?(s=this.buffer[this.startIndex],10===s?(this.line++,this.cols=1):this.cols++,s=String.fromCharCode(s)):(this.cols+=t,s=this.buffer.slice(this.startIndex,this.startIndex+t).toString()),e&&this.updateBufferBoundary(t),s}updateBufferBoundary(t=1){const e=this.startIndex+t;this._advanceLineCol(e),this.startIndex=e,this.autoFlush&&this.startIndex>=this.flushThreshold&&this._tokenStart<0&&this.flush()}canRead(t){return t=void 0!==t?t:this.startIndex,this.buffer.length-t>0}}function bt(t){const e=[],s=t.length;let r=0;for(;r<s;){for(;r<s&&ct(t.charCodeAt(r));)r++;if(r>=s)break;const i=r;for(;r<s&&61!==t.charCodeAt(r)&&!ct(t.charCodeAt(r));)r++;const n=t.substring(i,r);for(;r<s&&ct(t.charCodeAt(r));)r++;if(r>=s||61!==t.charCodeAt(r)){const t=[n,n,void 0,void 0,void 0];t.startIndex=i,e.push(t);continue}for(r++;r<s&&ct(t.charCodeAt(r));)r++;const o=t.charCodeAt(r);if(34===o||39===o){r++;let a="",c=r;for(;r<s&&t.charCodeAt(r)!==o;){const e=t.charCodeAt(r);10!==e&&13!==e||(a+=t.substring(c,r)+" ",c=r+1),r++}a+=t.substring(c,r),r++;const l=String.fromCharCode(o),h=[n+"="+l+a+l,n,"="+l+a+l,l,a];h.startIndex=i,e.push(h)}}return e}function yt(t,e,s){if(!t||0===t.length)return;const r=bt(t),i=r.length,n=e.options.limits?.maxAttributesPerTag;if(null!=n&&i>n){const t=e.currentTagDetail?.name??"(unknown)";throw new nt(`Tag '${t}' has ${i} attributes, exceeding limit of ${n}`,ot.LIMIT_MAX_ATTRIBUTES,{line:e.source.line,col:e.source.cols,index:e.source.startIndex})}for(let t=0;t<i;t++){const i=e.processAttrName(r[t][1]);if(!1===i)continue;const n=r[t][4],o=void 0===n||n,a=void 0!==s?{index:s+r[t].startIndex}:void 0;e.outputBuilder.addAttribute(i,o,e.readonlyMatcher,a)}}const It=":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�",Nt=":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿",At=Nt+"\\-\\.\\d·̀-ͯ҇‿-⁀",St=(t,e,s="")=>{const r=`[${t.replace(":","")}][${e.replace(":","")}]*`;return{name:new RegExp(`^[${t}][${e}]*$`,s),ncName:new RegExp(`^${r}$`,s),qName:new RegExp(`^${r}(?::${r})?$`,s),nmToken:new RegExp(`^[${e}]+$`,s),nmTokens:new RegExp(`^[${e}]+(?:\\s+[${e}]+)*$`,s)}},Ct=St(It,It+"\\-\\.\\d·̀-ͯ‿-⁀"),Dt=St(Nt,At,"u"),vt=(t="1.0")=>"1.1"===t?Dt:Ct,kt=(t,{xmlVersion:e="1.0"}={})=>vt(e).name.test(t),Pt=(t,{xmlVersion:e="1.0"}={})=>vt(e).qName.test(t);function Ot(t){t.source.markTokenStart(1);const e=t.source.startIndex;let s,r=!1,i=!1,n=!1;for(s=0;t.source.canRead(s);s++){const e=t.source.readChAt(s);if("'"!==e||i)if('"'!==e||r){if(">"===e&&!r&&!i){n=!0;break}}else i=!i;else r=!r}if(!n)throw new nt("Unexpected closing of source waiting for '>'",ot.UNEXPECTED_END);if(r||i)throw new nt("Invalid attribute expression. Quote is not properly closed",ot.UNCLOSED_QUOTE);const o=t.source.readStr(s);return t.source.updateBufferBoundary(s+1),Ut(o,t,e)}function Ut(t,e,s){const r={tagName:"",selfClosing:!1,rawAttributes:Object.create(null),_attrsExp:"",_attrsExpStart:void 0};"/"===t[t.length-1]&&(r.selfClosing=!0,t=t.slice(0,-1));let i="",n=0;for(;n<t.length;n++)if(at(t[n])){r.tagName=t.substring(0,n),i=t.substring(n+1),void 0!==s&&(r._attrsExpStart=s+n+1);break}if(0===r.tagName.length&&n===t.length&&(r.tagName=t),r.tagName=r.tagName.trimEnd(),r._attrsExp=i,!Pt(r.tagName,e.xmlVersion))throw new nt("Invalid tag name",ot.INVALID_TAG_NAME);return!e.options.skip.attributes&&i.length>0&&function(t,e,s){if(!t||0===t.length)return;const r=bt(t),i=r.length;let n=0;for(let t=0;t<i;t++){if(!1===e.processAttrName(r[t][1]))continue;n++;const i=r[t][4];s.rawAttributes[r[t][1]]=void 0===i||i}s.rawAttributesLen=n}(i,e,r),r}const Lt=[{open:"\x3c!--",close:"--\x3e"},{open:"<![CDATA[",close:"]]>"},{open:"<?",close:"?>"}],$t=[{open:"'",close:"'"},{open:'"',close:'"'},{open:"`",close:"`"}];class Rt{constructor(t,{nested:e=!1,skipEnclosures:s=[]}={}){this._tagName=t,this._nested=e,this._enclosures=s,this._content="",this._depth=1,this._active=!1}isActive(){return this._active}activate(){this._active=!0,this._content="",this._depth=1}resumeAfterOpenTag(){this._content="",this._depth=1}collect(t){t.markTokenStart(1);const e=this._enclosures.length;return this._nested||0!==e?this._nested&&0===e?this._collectDepthOnly(t):!this._nested&&e>0?this._collectEnclosureOnly(t):this._collectFull(t):this._collectPlain(t)}_collectPlain(t){const e="</"+this._tagName;for(;t.canRead();)if("<"===t.readChAt(0)){if(this._peekMatch(t,e)){let s=e.length,r=!1;for(;;){const e=t.readChAt(s);if(">"===e){r=!0;break}if(" "!==e&&"\t"!==e&&"\n"!==e&&"\r"!==e)break;s++}if(r){for(this._skipChars(t,e.length);t.canRead()&&">"!==t.readCh(););return this._finish(t)}}this._content+=t.readCh()}else this._content+=t.readCh();throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectDepthOnly(t){for(;this._depth>0;){if(!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END);if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}if(t.readCh(),!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,ot.UNEXPECTED_END);if("/"===t.readChAt(0)){t.readCh();const e=this._readTagName(t),s=this._readToAngleClose(t);if(e===this._tagName&&(this._depth--,0===this._depth))return this._finish(t);this._content+="</"+e+s;continue}const e=this._readTagName(t);this._content+="<"+e;const{selfClosing:s,attrText:r}=this._readTagTail(t);this._content+=r,s||e!==this._tagName||this._depth++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectEnclosureOnly(t){for(;t.canRead();){const e=this._matchEnclosureOpen(t);if(-1!==e){const s=this._enclosures[e];this._skipChars(t,s.open.length),this._content+=s.open;const r=this._readUpto(t,s.close);this._content+=r+s.close;continue}if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}const s="</"+this._tagName;if(this._peekMatch(t,s)){let e=s.length,r=!1;for(;;){const s=t.readChAt(e);if(">"===s){r=!0;break}if(" "!==s&&"\t"!==s&&"\n"!==s&&"\r"!==s)break;e++}if(r){for(this._skipChars(t,s.length);t.canRead()&&">"!==t.readCh(););return this._finish(t)}}this._content+=t.readCh()}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_collectFull(t){for(;this._depth>0;){if(!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END);const e=this._matchEnclosureOpen(t);if(-1!==e){const s=this._enclosures[e];this._skipChars(t,s.open.length),this._content+=s.open;const r=this._readUpto(t,s.close);this._content+=r+s.close;continue}if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}if(t.readCh(),!t.canRead())throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,ot.UNEXPECTED_END);if("/"===t.readChAt(0)){t.readCh();const e=this._readTagName(t),s=this._readToAngleClose(t);if(e===this._tagName&&(this._depth--,0===this._depth))return this._finish(t);this._content+="</"+e+s;continue}const s=this._readTagName(t);this._content+="<"+s;const{selfClosing:r,attrText:i}=this._readTagTail(t);this._content+=i,r||s!==this._tagName||this._depth++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end of input`,ot.UNEXPECTED_END)}_finish(t){const e=this._content,s={index:t.startIndex,line:t.line,col:t.cols};return this._active=!1,this._content="",this._depth=1,{content:e,end:s}}_matchEnclosureOpen(t){const e=this._enclosures.length;for(let s=0;s<e;s++)if(this._peekMatch(t,this._enclosures[s].open))return s;return-1}_readUpto(t,e){const s=e[0],r=e.length,i=t.startIndex;let n=0;for(;t.canRead();){if(t.readChAt(0)===s&&this._peekMatch(t,e)){const e=t.readStr(n,i);return this._skipChars(t,r),e}t.readCh(),n++}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end looking for '${e}'`,ot.UNEXPECTED_END)}_peekMatch(t,e){const s=e.length;for(let r=0;r<s;r++)if(t.readChAt(r)!==e[r])return!1;return!0}_skipChars(t,e){for(let s=0;s<e;s++)t.readCh()}_readTagName(t){let e="";for(;t.canRead();){const s=t.readChAt(0);if(">"===s||"/"===s||" "===s||"\t"===s||"\n"===s||"\r"===s)break;e+=t.readCh()}return e}_readTagTail(t){const e=t.startIndex;let s=0,r=!1,i=!1;for(;t.canRead();){const n=t.readCh();if(s++,"'"!==n||i)if('"'!==n||r){if(!r&&!i){if(">"===n)return{selfClosing:!1,attrText:t.readStr(s,e)};if("/"===n&&t.canRead()&&">"===t.readChAt(0))return t.readCh(),s++,{selfClosing:!0,attrText:t.readStr(s,e)}}}else i=!i;else r=!r}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end inside tag`,ot.UNEXPECTED_END)}_readToAngleClose(t){const e=t.startIndex;let s=0;for(;t.canRead();){const r=t.readCh();if(s++,">"===r)return t.readStr(s,e);if(" "!==r&&"\t"!==r&&"\n"!==r&&"\r"!==r)throw new nt(`Malformed closing tag for </${this._tagName}>`,ot.UNEXPECTED_END)}throw new nt(`Unclosed stop node <${this._tagName}> — unexpected end looking for '>'`,ot.UNEXPECTED_END)}}class Mt{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 Bt{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new Mt(this),this._keptAttrs=[]}push(t,e=null,s=null,r=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],o=s?`${s}:${t}`:t,a=n.get(o)||0;let c=0;for(const t of n.values())c+=t;n.set(o,a+1);const l={tag:t,position:c,counter:a};null!=s&&(l.namespace=s),null!=e&&(l.values=e),this.path.push(l);const h=this.path.length,d=null!==r?r.keep:null;if(null!=d&&d.length>0&&e)for(let t=0;t<d.length;t++){const s=d[t];void 0!==e[s]&&this._keptAttrs.push({depth:h,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 r=t[s];if("deep-wildcard"===r.type){if(s--,s<0)return!0;const r=t[s];let i=!1;for(let t=e;t>=0;t--)if(this._matchSegment(r,this.path[t],t===this.path.length-1)){e=t-1,s--,i=!0;break}if(!i)return!1}else{if(!this._matchSegment(r,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 r=e.counter??0;if("first"===t.position&&0!==r)return!1;if("odd"===t.position&&r%2!=1)return!1;if("even"===t.position&&r%2!=0)return!1;if("nth"===t.position&&r!==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}}function jt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading entity name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t||'"'===t||"'"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source reading entity name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(Gt(i,t.xmlVersion),qt(e),!e.canRead())throw new nt(`Unexpected end of source after entity name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(e.canRead(5)&&"SYSTEM"===e.readStr(6).toUpperCase())throw new nt("External entities are not supported",ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if("%"===e.readStr(1))throw new nt("Parameter entities are not supported",ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(!e.canRead())throw new nt(`Unexpected end of source reading entity value for "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const[n]=Ft(e,"entity"),o=t.options?.doctypeOptions;if(o?.maxEntitySize&&n.length>o.maxEntitySize)throw new nt(`Entity "${i}" size (${n.length}) exceeds maximum allowed size (${o.maxEntitySize})`,ot.ENTITY_MAX_SIZE,{line:e.line,col:e.cols,index:e.startIndex});return e.readUptoChar(">"),[i,n]}function Xt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading ELEMENT name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source after ELEMENT name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(!kt(i,t.xmlVersion))throw new nt(`Invalid element name: "${i}"`,ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading ELEMENT content model",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let n=e.readStr(1);if("E"===n){if(!e.canRead(4))throw new nt("Unexpected end of source reading ELEMENT content model keyword",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("EMPTY"!==e.readStr(5))return e.readUptoChar(">"),{elementName:i,contentModel:""};e.updateBufferBoundary(5)}else if("A"===n){if(!e.canRead(2))throw new nt("Unexpected end of source reading ELEMENT content model keyword",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("ANY"!==e.readStr(3))return e.readUptoChar(">"),{elementName:i,contentModel:""};e.updateBufferBoundary(3)}else"("===n&&(e.updateBufferBoundary(1),e.readUptoChar(")"));return e.readUptoChar(">"),{elementName:i}}function Vt(t){t.source.readUptoChar(">")}function Yt(t){const e=t.source;if(qt(e),!e.canRead())throw new nt("Unexpected end of source reading NOTATION name",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const s=e.startIndex;let r=0;for(;e.canRead();){const t=e.readCh();if(" "===t||"\t"===t||"\n"===t||"\r"===t)break;r++}const i=e.readStr(r,s);if(!e.canRead())throw new nt(`Unexpected end of source after NOTATION name "${i}"`,ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(Gt(i,t.xmlVersion),qt(e),!e.canRead(5))throw new nt("Unexpected end of source reading NOTATION identifier type",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let n=e.readStr(6).toUpperCase();if("SYSTEM"===n)e.updateBufferBoundary(6),qt(e),Ft(e,"systemIdentifier");else{if("PUBLIC"!==n)throw new nt(`Expected SYSTEM or PUBLIC in NOTATION, found "${n}"`,ot.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});{if(e.updateBufferBoundary(6),qt(e),Ft(e,"publicIdentifier"),qt(e),!e.canRead())throw new nt("Unexpected end of source after NOTATION PUBLIC identifier",ot.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let t=e.readStr(1);'"'!==t&&"'"!==t||Ft(e,"systemIdentifier")}}e.readUptoChar(">")}function Ft(t,e){if(!t.canRead())throw new nt(`Unexpected end of source reading ${e} opening quote`,ot.UNEXPECTED_END,{line:t.line,col:t.cols,index:t.startIndex});let s=t.readStr(1);if('"'!==s&&"'"!==s)throw new nt(`Expected quoted string for ${e}, found "${s}"`,ot.INVALID_TAG,{line:t.line,col:t.cols,index:t.startIndex});return t.updateBufferBoundary(1),[t.readUptoChar(s)]}function qt(t){for(;t.canRead();){const e=t.readChAt(0);if(" "!==e&&"\t"!==e&&"\n"!==e&&"\r"!==e)break;t.updateBufferBoundary(1)}}function Gt(t,e){if(kt(t,e))return t;throw new nt(`Invalid entity name "${t}"`,ot.ENTITY_INVALID_KEY,{})}const zt=Object.freeze({UNCLOSED_EOF:"unclosed-eof",MISMATCHED_CLOSE:"mismatched-close",PHANTOM_CLOSE:"phantom-close",PARTIAL_TAG:"partial-tag"});class Ht{constructor(t){this.onEof=t.onEof||"throw",this.onMismatch=t.onMismatch||"throw",this.collectErrors=t.collectErrors||!1,this.errors=[]}handleEof(t){if("throw"===this.onEof)throw new nt("Unexpected data in the end of document",ot.UNEXPECTED_TRAILING_DATA);const{addTextNode:e,popTag:s}=t;let r=t.currentTagDetail;for(;r&&!r.root;)this._recordError(zt.UNCLOSED_EOF,{tag:r.name,expected:null,line:r.line,col:r.col,index:r.index}),e(),s(),r=t.currentTagDetail}handleMismatch(t,e){const{tagsStack:s,currentTagDetail:r,source:i,addTextNode:n}=e;if("throw"===this.onMismatch)throw new nt(`Unexpected closing tag '${t}' expecting '${r.name}'`,ot.MISMATCHED_CLOSE_TAG,{line:i?i.line:void 0,col:i?i.cols:void 0,index:i?i.startIndex:void 0});if("discard"===this.onMismatch)return this._recordError(zt.MISMATCHED_CLOSE,{tag:t,expected:r.name,line:i?i.line:null,col:i?i.cols:null,index:i?i.startIndex:null}),{action:"discard"};const o=[...s,r];let a=-1;const c=o.length;for(let e=c-1;e>=0;e--)if(o[e].name===t){a=e;break}if(-1===a)return this._recordError(zt.PHANTOM_CLOSE,{tag:t,expected:r.name,line:i?i.line:null,col:i?i.cols:null,index:i?i.startIndex:null}),{action:"discard"};const l=c-1-a;for(let s=0;s<l;s++){const r=o[c-1-s];this._recordError(zt.MISMATCHED_CLOSE,{tag:r.name,expected:t,line:r.line,col:r.col,index:r.index}),n(),e.popTag()}return e.currentTagDetail=o[a],{action:"close-matched"}}handlePartialTag(t,e){this._recordError(zt.PARTIAL_TAG,{tag:Wt(t),expected:null,line:e.source?e.source.line:null,col:e.source?e.source.cols:null,index:e.source?e.source.startIndex:null}),e.tagTextData="",this.handleEof(e)}getErrors(){return this.errors.slice()}reset(){this.errors=[]}_recordError(t,e){this.collectErrors&&this.errors.push({type:t,...e})}}function Wt(t){if(!t)return null;const e=("string"==typeof t.message?t.message:String(t)).match(/[Rr]eading closing tag '<\/([^']*)/);return e&&e[1]||null}class Qt{constructor(t,e=0,s=0,r=0,i=void 0){this.name=t,this.line=e,this.col=s,this.index=r,this.openEnd=i}}class Jt{constructor(t){this.options=t,this.currentTagDetail=null,this.tagTextData="",this.tagsStack=[],this.matcher=new Bt,this.readonlyMatcher=this.matcher.readOnly(),this.autoCloseHandler=t.autoClose?new Ht(t.autoClose):null,this._unpairedSet=new Set(this.options.tags.unpaired),this.stopNodeExpressionsSet=this.options.tags.stopNodesSet??new rt,this.skipTagExpressionsSet=this.options.skip.tagsSet??new rt,this._exitIf="function"==typeof t.exitIf?t.exitIf:null}initializeParser(){this.tagTextData="",this.tagsStack=[],this._stopNodeProcessor=null,this._exitIfTriggered=!1,this.xmlVersion="1.0",this.matcher||(this.matcher=new Bt,this.readonlyMatcher=this.matcher.readOnly()),this.outputBuilder=this._createOutputBuilder(),this.root={root:!0,name:""},this.currentTagDetail=this.root}_createOutputBuilder(){return this.options.OutputBuilder.getInstance(this.options,this.readonlyMatcher)}wasExited(){return!0===this._exitIfTriggered}parse(t){return this.source=new Tt(t),this.initializeParser(),this._parseAndFinalize(),this.outputBuilder.getOutput()}parseBytesArr(t){return this.source=new wt(t),this.initializeParser(),this._parseAndFinalize(),this.outputBuilder.getOutput()}parseXml(){for(;this.source.canRead()&&!this._exitIfTriggered;){this.source.markTokenStart(0);const t={line:this.source.line,col:this.source.cols,index:this.source.startIndex},e=this.source.readCh();if(void 0===e||""===e)break;if("<"===e){const e=t,s=this.source.readChAt(0);if(""===s)throw new nt("Unexpected end of source after '<'",ot.UNEXPECTED_END,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});"!"===s||"?"===s?(this.source.updateBufferBoundary(),this.addTextNode(),this.readSpecialTag(s)):"/"===s?(this.source.updateBufferBoundary(),this.readClosingTag(e)):this.readOpeningTag(e)}else{let t=0;for(;;){const e=this.source.readChAt(t);if("<"===e||void 0===e||""===e)break;t++}t>0?(this.tagTextData+=e+this.source.readStr(t,this.source.startIndex),this.source.updateBufferBoundary(t)):this.tagTextData+=e}}}finalizeXml(){if(this._exitIfTriggered)return;const t=this.tagsStack.length>0||this.currentTagDetail&&!this.currentTagDetail.root,e=!t&&void 0!==this.tagTextData&&this.tagTextData.trimEnd().length>0;if(t||e){if(!this.autoCloseHandler||!t||e)throw new nt("Unexpected data in the end of document",ot.UNEXPECTED_TRAILING_DATA);this.autoCloseHandler.handleEof(this._parserState())}}_parseAndFinalize(){let t=null;this.autoCloseHandler&&this.autoCloseHandler.reset();try{this.parseXml()}catch(e){if(!this.autoCloseHandler||!function(t){return t instanceof nt?t.code===ot.UNEXPECTED_END:t.message.startsWith("Unexpected end of source")||t.message.startsWith("Unexpected closing of source")}(e))throw e;t=e}t?this.autoCloseHandler.handlePartialTag(t,this._parserState()):this.finalizeXml()}readClosingTag(t){const e=this.processTagName(function(t){t.markTokenStart(1);let e=0;const s=t.startIndex;for(;t.canRead();){if(">"===t.readCh()){const r=t.readStr(e,s);return r?r.trimEnd():""}e++}const r=t.readStr(e,s);throw t.updateBufferBoundary(e),new nt(`Unexpected end of source reading closing tag '</${r}'`,ot.UNEXPECTED_END)}(this.source)),s={name:e,line:t.line,col:t.col,index:t.index,closeEnd:this.source.startIndex};if(this.isUnpaired(e)||this.isStopNode())throw new nt(`Unexpected closing tag '${e}'`,ot.UNEXPECTED_CLOSE_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if(e!==this.currentTagDetail.name){if(!this.autoCloseHandler)throw new nt(`Unexpected closing tag '${e}' expecting '${this.currentTagDetail.name}'`,ot.MISMATCHED_CLOSE_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if("discard"===this.autoCloseHandler.handleMismatch(e,this._parserState()).action)return}this.currentTagDetail.root||this.addTextNode(),this.popTag(s)}readOpeningTag(t){const e=this.options;if(this.addTextNode(),this._stopNodeProcessor&&this._stopNodeProcessor.isActive()){const{tagDetail:t,isSkip:e}=this._stopNodeProcessorMeta;this._stopNodeProcessor.resumeAfterOpenTag(),Ot(this),t.openEnd=this.source.startIndex;const{content:s,end:r}=this._stopNodeProcessor.collect(this.source);return e||(this.outputBuilder.addElement(t,this.readonlyMatcher),this.outputBuilder.onStopNode?.(t,s,this.readonlyMatcher,r),this.outputBuilder.addValue(s,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher,{name:t.name,closeEnd:r.index})),this.matcher.pop(),this._stopNodeProcessor=null,void(this._stopNodeProcessorMeta=null)}let s=Ot(this);const r=this.processTagName(s.tagName),i=new Qt(r,t.line,t.col,t.index,this.source.startIndex),n=s.tagName.indexOf(":"),o=-1!==n?s.tagName.slice(0,n):void 0,a=void 0!==o?s.tagName.slice(n+1):r,c=e.limits?.maxNestedTags;if(null!=c){const t=this.tagsStack.length+1;if(t>c)throw new nt(`Nesting depth ${t} exceeds limit of ${c} (tag: '${r}')`,ot.LIMIT_MAX_NESTED_TAGS,{line:i.line,col:i.col,index:i.index})}let l={},h=0;s.rawAttributes&&(l=s.rawAttributes,h=s.rawAttributesLen),h>0?this.matcher.push(a,l,o,{keep:["xml:space"]}):this.matcher.push(a,{},o);const d=this.isStopNode(),u=d?null:this.isSkipTag();if(e.skip.attributes||u||yt(s._attrsExp,this,s._attrsExpStart),this.isUnpaired(r))this.outputBuilder.addElement(i,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher,this._closeMetaFor(i)),this.matcher.pop();else if(s.selfClosing)u||(this.outputBuilder.addElement(i,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher,this._closeMetaFor(i))),this.matcher.pop();else if(d){this._stopNodeProcessor=new Rt(s.tagName,{nested:d.nested,skipEnclosures:d.skipEnclosures}),this._stopNodeProcessorMeta={tagDetail:i,isSkip:!1},this._stopNodeProcessor.activate();const{content:t,end:e}=this._stopNodeProcessor.collect(this.source);this.outputBuilder.addElement(i,this.readonlyMatcher),this.outputBuilder.onStopNode?.(i,t,this.readonlyMatcher,e),this.outputBuilder.addValue(t,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher,{name:i.name,closeEnd:e.index}),this.matcher.pop(),this._stopNodeProcessor=null,this._stopNodeProcessorMeta=null}else if(u)this._stopNodeProcessor=new Rt(s.tagName,{nested:u.nested,skipEnclosures:u.skipEnclosures}),this._stopNodeProcessorMeta={tagDetail:i,isSkip:!0},this._stopNodeProcessor.activate(),this._stopNodeProcessor.collect(this.source),this.matcher.pop(),this._stopNodeProcessor=null,this._stopNodeProcessorMeta=null;else if(this._exitIf&&this._exitIf(this.readonlyMatcher)){const t=this.tagsStack.length;for(this.matcher.pop();this.currentTagDetail&&!this.currentTagDetail.root;)this.addTextNode(),this.popTag();"function"==typeof this.outputBuilder.onExit&&this.outputBuilder.onExit({tagDetail:i,matcher:this.readonlyMatcher,depth:t}),this._exitIfTriggered=!0}else this.pushTag(i)}pushTag(t){this.tagsStack.push(this.currentTagDetail),this.outputBuilder.addElement(t,this.readonlyMatcher),this.currentTagDetail=t}popTag(t){this.outputBuilder.closeElement(this.readonlyMatcher,t??{name:this.currentTagDetail?.name}),this.matcher.pop(),this.currentTagDetail=this.tagsStack.pop()}_closeMetaFor(t){return{name:t.name,line:t.line,col:t.col,index:t.index,closeEnd:t.openEnd}}readSpecialTag(t){if("!"===t){let t=this.source.readCh();if(null==t)throw new nt("Unexpected end of source after '<!'",ot.UNEXPECTED_END,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});if("-"===t)!function(t){if(t.source.markTokenStart(1),!t.source.canRead())throw new nt("Unexpected end of source reading comment",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if("-"!==t.source.readCh())throw new nt(`Invalid comment expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readUpto("--\x3e");t.outputBuilder.addComment(e)}(this);else if("["===t)!function(t){if(t.source.markTokenStart(1),!t.source.canRead(5))throw new nt("Unexpected end of source reading CDATA preamble",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"CDATA["!==e)throw new nt(`Invalid CDATA expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let s=t.source.readUpto("]]>");t.outputBuilder.addLiteral(s)}(this);else if("D"===t){const t=function(t){if(t.source.markTokenStart(1),!t.source.canRead(5))throw new nt("Unexpected end of source reading DOCTYPE preamble",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"OCTYPE"!==e)throw new nt(`Invalid DOCTYPE expression at ${t.source.line}:${t.source.cols}`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const s=Object.create(null);let r=0,i=!1,n=!1;for(;t.source.canRead();){const e=t.source.startIndex;let o=t.source.readCh();if("<"===o&&i&&!n)try{if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE sub-tag",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"!"!==e)throw new nt(`Invalid DOCTYPE body tag starting with "<${e}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE sub-tag type",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let i=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"-"===i){if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE comment",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"-"!==e)throw new nt("Invalid comment in DOCTYPE",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});t.source.readUpto("--\x3e")}else if("E"===i){if(!t.source.canRead())throw new nt("Unexpected end of source reading DOCTYPE E-type sub-tag",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"N"===e){if(!t.source.canRead(3))throw new nt("Unexpected end of source reading DOCTYPE ENTITY keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(4);if(t.source.updateBufferBoundary(4),"TITY"!==e)throw new nt("Invalid DOCTYPE ENTITY expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const[i,n]=jt(t);if(-1===n.indexOf("&")){const e=t.options?.doctypeOptions;if(e?.maxEntityCount&&r>=e.maxEntityCount)throw new nt(`Entity count (${r+1}) exceeds maximum allowed (${e.maxEntityCount})`,ot.ENTITY_MAX_COUNT,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const o=i.replace(/[.\-+*:]/g,"\\$&");s[i]={regx:RegExp(`&${o};`,"g"),val:n},r++}}else{if("L"!==e)throw new nt(`Invalid DOCTYPE sub-tag "<!E${e}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(4))throw new nt("Unexpected end of source reading DOCTYPE ELEMENT keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(5);if(t.source.updateBufferBoundary(5),"EMENT"!==e)throw new nt("Invalid DOCTYPE ELEMENT expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Xt(t)}}}else if("A"===i){if(!t.source.canRead(5))throw new nt("Unexpected end of source reading DOCTYPE ATTLIST keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(6);if(t.source.updateBufferBoundary(6),"TTLIST"!==e)throw new nt("Invalid DOCTYPE ATTLIST expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Vt(t)}else{if("N"!==i)throw new nt(`Invalid DOCTYPE sub-tag "<!${i}"`,ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(6))throw new nt("Unexpected end of source reading DOCTYPE NOTATION keyword",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let e=t.source.readStr(7);if(t.source.updateBufferBoundary(7),"OTATION"!==e)throw new nt("Invalid DOCTYPE NOTATION expression",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Yt(t)}}}catch(s){throw s.code===ot.UNEXPECTED_END&&(t.source.startIndex=e),s}else if("["===o)i=!0;else if("]"===o)n=!0;else if(">"===o&&(!i||n))return s}throw new nt("Unclosed DOCTYPE",ot.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex})}(this);this.options.doctypeOptions.enabled&&t&&Object.keys(t).length>0&&this.outputBuilder.addInputEntities(t)}}else{if("?"!==t)throw new nt(`Invalid tag '<${t}'`,ot.INVALID_TAG,{line:this.source.line,col:this.source.cols,index:this.source.startIndex});!function(t){const e=t.options.skip;t.source.markTokenStart(1);let s=function(t){t.source.markTokenStart(1);const e=t.source.startIndex;let s,r=!1,i=!1,n=!1;for(s=0;t.source.canRead(s);s++){const e=t.source.readChAt(s),o=t.source.readChAt(s+1);if("'"!==e||i?'"'!==e||r||(i=!i):r=!r,!r&&!i&&"?"===e&&">"===o){n=!0;break}}if(!n)throw new nt("Unexpected closing of source waiting for '?>'",ot.UNEXPECTED_END);if(r||i)throw new nt("Invalid attribute expression. Quote is not properly closed in PI tag expression",ot.UNCLOSED_QUOTE);t.options.skip.attributes;const o=t.source.readStr(s);return t.source.updateBufferBoundary(s+2),Ut(o,t,e)}(t);if(!s)throw new nt("Invalid Pi Tag expression.",ot.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if("xml"===s.tagName){const e=s.rawAttributes?.version;t.xmlVersion="1.1"===e?1.1:1}e.attributes||yt(s._attrsExp,t,s._attrsExpStart),"xml"===s.tagName?e.declaration||t.outputBuilder.addDeclaration("?xml"):e.pi||t.outputBuilder.addInstruction("?"+s.tagName)}(this)}}addTextNode(){void 0!==this.tagTextData&&""!==this.tagTextData&&((!this.options.skip.whitespaceText||this.tagTextData.trim().length>0)&&this.outputBuilder.addValue(this.tagTextData,this.readonlyMatcher),this.tagTextData="")}processAttrName(t){const e=this.options;if(t=Zt(t,e.skip.nsPrefix),!Pt(t,this.xmlVersion))throw new nt(`Invalid attribute name: ${t}`,ot.INVALID_ATTRIBUTE_NAME);if(t=Kt(t,e.onDangerousProperty),e.strictReservedNames&&t===e.attributes.groupBy)throw new nt(`Restricted attribute name: ${t}`,ot.SECURITY_RESTRICTED_NAME);return t}processTagName(t){const e=this.options,s=e.nameFor;if(t=Kt(t=Zt(t,e.skip.nsPrefix),e.onDangerousProperty),e.strictReservedNames&&(t===s.comment||t===s.cdata||t===s.text))throw new nt(`Restricted tag name: ${t}`,ot.SECURITY_RESTRICTED_NAME);return t}isUnpaired(t){return this._unpairedSet.has(t)}isStopNode(){if(0===this.stopNodeExpressionsSet.size)return null;const t=this.stopNodeExpressionsSet.findMatch(this.matcher);return t?t.data:null}isSkipTag(){if(0===this.skipTagExpressionsSet.size)return null;const t=this.skipTagExpressionsSet.findMatch(this.matcher);return t?t.data:null}_parserState(){const t=this;return{get tagsStack(){return t.tagsStack},get currentTagDetail(){return t.currentTagDetail},set currentTagDetail(e){t.currentTagDetail=e},get outputBuilder(){return t.outputBuilder},get readonlyMatcher(){return t.readonlyMatcher},get matcher(){return t.matcher},get source(){return t.source},get tagTextData(){return t.tagTextData},set tagTextData(e){t.tagTextData=e},addTextNode:t.addTextNode.bind(t),popTag:t.popTag.bind(t)}}}function Zt(t,e){if(e){const e=t.split(":");if(2===e.length)return"xmlns"!==e[0]&&e[1];if(e.length>2)throw new nt(`Multiple namespaces in name: ${t}`,ot.MULTIPLE_NAMESPACES)}return t}function Kt(t,e){if(ht.includes(t))throw new nt(`[SECURITY] Invalid name: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`,ot.SECURITY_PROTOTYPE_POLLUTION);return lt.includes(t)?e(t):t}class te{constructor(t={}){this.line=1,this.cols=0,this.buffer="",this.startIndex=0,this.isComplete=!1,this.maxBufferSize=t.maxBufferSize||10485760,this.autoFlush=!1!==t.autoFlush,this.flushThreshold=t.flushThreshold||1024,this._marks=[null,null]}feed(t){const e="string"==typeof t?t:t.toString(),s=this.buffer.length-this.startIndex;if(s+e.length>this.maxBufferSize)throw new nt(`Buffer size limit exceeded (${s+e.length} > ${this.maxBufferSize}). Increase feedable.maxBufferSize or reduce chunk size.`,ot.INVALID_INPUT);this.buffer+=e}end(){this.isComplete=!0}canRead(t=0){return this.startIndex+t<this.buffer.length}markTokenStart(t=0){this._marks[t]={startIndex:this.startIndex,line:this.line,cols:this.cols}}rewindToMark(){null!==this._marks[0]&&(this.startIndex=this._marks[0].startIndex,this.line=this._marks[0].line,this.cols=this._marks[0].cols),this._marks[0]=null,this._marks[1]=null}clearMark(){this._marks[0]=null,this._marks[1]=null}readCh(){const t=this.buffer[this.startIndex++];return"\n"===t?(this.line++,this.cols=0):this.cols++,t}readChAt(t){return this.buffer[this.startIndex+t]}readStr(t,e){return void 0===e&&(e=this.startIndex),this.buffer.substring(e,e+t)}_advanceLineCol(t){let e=-1;for(let s=this.startIndex;s<t;s++)"\n"===this.buffer[s]&&(this.line++,e=s);e>=0?this.cols=t-e-1:this.cols+=t-this.startIndex}readUpto(t){const e=this.buffer.length,s=t.length;for(let r=this.startIndex;r<e;r++){let e=!0;for(let i=0;i<s;i++)if(this.buffer[r+i]!==t[i]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this._advanceLineCol(r+s),this.startIndex=r+s,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END);const s=this.buffer.substring(this.startIndex,e);return this._advanceLineCol(e+1),this.startIndex=e+1,s}readUptoCloseTag(t){const e=this.buffer.length,s=t.length;let r=-1,i=0;for(let n=this.startIndex;n<e;n++){if(1===i){const t=this.buffer[n];if(" "===t||"\t"===t)continue;">"===t?i=2:(i=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[n+r]!==t[r]){e=!1;break}e&&(i=1,r=n,n+=s-1)}if(2===i){const t=this.buffer.substring(this.startIndex,r);return this._advanceLineCol(n+1),this.startIndex=n+1,t}}throw new nt(`Unexpected end of source reading '${t}'`,ot.UNEXPECTED_END)}updateBufferBoundary(t=1){const e=this.startIndex+t;this._advanceLineCol(e),this.startIndex=e;const s=null!==this._marks[0]||null!==this._marks[1];this.autoFlush&&this.startIndex>=this.flushThreshold&&!s&&this.flush()}flush(){let t=this.startIndex;for(const e of this._marks)null!==e&&e.startIndex<t&&(t=e.startIndex);if(t>0){this.buffer=this.buffer.substring(t);const e=this._marks.length;for(let s=0;s<e;s++)null!==this._marks[s]&&(this._marks[s].startIndex-=t);this.startIndex-=t}}}class ee extends te{attachStream(t,e,s,r){t.on("data",t=>{try{this.feed("string"==typeof t?t:t.toString()),e(null)}catch(t){e(t)}}),t.on("error",r),t.on("end",()=>{try{this.end(),s()}catch(t){r(t)}})}}class se{constructor(t){this.options=gt(t),this._feedParser=null,this._feedSource=null,this._isFeeding=!1,this._pendingBytes=0,this._batchThreshold=this.options.feedable?.bufferSize}parse(t){if(t instanceof Buffer||ArrayBuffer.isView(t))t=t.toString();else if("string"!=typeof t){if(!t||"function"!=typeof t.toString)throw new nt("XML data must be a string or Buffer.",ot.INVALID_INPUT);t=t.toString()}const e=this._createParser(),s=e.parse(t);return this.wasExited=e.wasExited(),this._lastParseErrors=e.autoCloseHandler?.getErrors()??[],s}parseBytesArr(t){if(!(t instanceof Uint8Array||ArrayBuffer.isView(t)))throw new nt("XML data must be a Uint8Array or ArrayBufferView.",ot.INVALID_INPUT);t=Buffer.from(t);const e=this._createParser(),s=e.parseBytesArr(t);return this.wasExited=e.wasExited(),this._lastParseErrors=e.autoCloseHandler?.getErrors()??[],s}parseStream(t){if(null===(e=t)||"object"!=typeof e||"function"!=typeof e.read||"function"!=typeof e.on||"boolean"!=typeof e.readableEnded)throw new nt("parseStream() requires a Node.js Readable stream.",ot.INVALID_STREAM);var e;const s=new ee(this.options.feedable),r=this._createParser();return r.source=s,r.initializeParser(),new Promise((e,i)=>{let n=!1;const o=e=>{n||(n=!0,t.destroy(),i(e))};s.attachStream(t,t=>{if(t)o(t);else try{r.parseXml()}catch(t){t.code===ot.UNEXPECTED_END?s.rewindToMark():o(t)}},()=>{if(!n)try{r.finalizeXml(),this._lastParseErrors=r.autoCloseHandler?.getErrors()??[],n=!0,e(r.outputBuilder.getOutput())}catch(t){o(t)}},o)})}_runParse(){if(!this._feedParser)return;const t=this._feedSource.startIndex;try{this._feedParser.parseXml()}catch(t){if(t.code!==ot.UNEXPECTED_END)throw t;this._feedSource.rewindToMark()}this._feedSource.startIndex>t?this._pendingBytes=0:this._batchThreshold=Math.min(2*this._batchThreshold,this.options.feedable.maxBufferSize)}feed(t){let e;if(this._isFeeding||this._initFeedSession(),"string"==typeof t)e=t;else if(Buffer.isBuffer(t))e=t.toString();else{if(!t?.toString)throw new nt("feed() data must be a string or Buffer.",ot.DATA_MUST_BE_STRING);e=t.toString()}return this._feedSource.feed(e),this._pendingBytes+=e.length,this._pendingBytes>=this._batchThreshold&&this._runParse(),this}end(){if(!this._isFeeding)throw new nt("No data fed. Call feed() before end().",ot.NOT_STREAMING);this._runParse();try{this._feedSource.end();let t=null;const e=this._feedParser.autoCloseHandler;e&&e.reset();try{this._feedParser.parseXml()}catch(s){if(s.code!==ot.UNEXPECTED_END)throw s;if(!e)throw s;t=s}return t?e.handlePartialTag(t,this._feedParser._parserState()):this._feedParser.finalizeXml(),this._lastParseErrors=e?.getErrors()??[],this.wasExited=this._feedParser.wasExited(),this._feedParser.outputBuilder.getOutput()}finally{this._cleanupFeedSession()}}getParseErrors(){return this._lastParseErrors??[]}_createParser(){return new Jt(this.options)}_initFeedSession(){this._feedSource=new te(this.options.feedable),this._feedParser=this._createParser(),this._feedParser.source=this._feedSource,this._feedParser.initializeParser(),this._isFeeding=!0}_cleanupFeedSession(){this._feedParser=null,this._feedSource=null,this._isFeeding=!1}}module.exports=e})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodable/flexible-xml-parser",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Fastest and fully customizable XML parser in pure JS with fully customizable ouput",
5
5
  "main": "./lib/fxp.cjs",
6
6
  "type": "module",
@@ -82,4 +82,4 @@
82
82
  "type": "git",
83
83
  "url": "git+https://github.com/nodable/flexible-xml-parser.git"
84
84
  }
85
- }
85
+ }
@@ -132,8 +132,15 @@ export function collectRawAttributes(attrStr, parser, tagExp) {
132
132
  *
133
133
  * @param {string} attrStr - raw attribute expression substring
134
134
  * @param {object} parser - Xml2JsParser instance
135
+ * @param {number} [attrsExpStart] - absolute document offset where `attrStr`
136
+ * begins (tagExp._attrsExpStart from buildTagExpObj). When provided, each
137
+ * attribute's absolute document index is computed and passed to
138
+ * addAttribute() as a 4th argument: { index }. Line/col are intentionally
139
+ * NOT computed here — doing so would require re-scanning attrStr for
140
+ * newlines on every call, for a field most builders won't use; callers
141
+ * that need it can derive line/col from `index` plus the document text.
135
142
  */
136
- export function flushAttributes(attrStr, parser) {
143
+ export function flushAttributes(attrStr, parser, attrsExpStart) {
137
144
  if (!attrStr || attrStr.length === 0) return;
138
145
  const matches = parseAttributes(attrStr);
139
146
  const len = matches.length;
@@ -155,6 +162,10 @@ export function flushAttributes(attrStr, parser) {
155
162
  const rawVal = matches[i][4];
156
163
  const attrVal = rawVal !== undefined ? rawVal : true;
157
164
 
158
- parser.outputBuilder.addAttribute(attrName, attrVal, parser.readonlyMatcher);
165
+ const attrMeta = attrsExpStart !== undefined
166
+ ? { index: attrsExpStart + matches[i].startIndex }
167
+ : undefined;
168
+
169
+ parser.outputBuilder.addAttribute(attrName, attrVal, parser.readonlyMatcher, attrMeta);
159
170
  }
160
171
  }
@@ -95,7 +95,14 @@ export default class BufferSource {
95
95
  // ─── Core read interface ──────────────────────────────────────────────────
96
96
 
97
97
  readCh() {
98
- return String.fromCharCode(this.buffer[this.startIndex++]);
98
+ const code = this.buffer[this.startIndex++];
99
+ if (code === 10) { // '\n'
100
+ this.line++;
101
+ this.cols = 0;
102
+ } else {
103
+ this.cols++;
104
+ }
105
+ return String.fromCharCode(code);
99
106
  }
100
107
 
101
108
  readChAt(index) {
@@ -107,6 +114,34 @@ export default class BufferSource {
107
114
  return this.buffer.slice(from, from + n).toString();
108
115
  }
109
116
 
117
+ /**
118
+ * Scan buffer[this.startIndex, end) for byte code 10 ('\n') and advance
119
+ * line/cols to match, mirroring readCh()'s per-byte logic. Does NOT touch
120
+ * startIndex — callers set that themselves afterwards (their "end" is not
121
+ * always startIndex + n; readUptoCloseTag's consumed span includes the
122
+ * matched stop string).
123
+ *
124
+ * Shared by updateBufferBoundary() and the readUpto*() family so every path
125
+ * that advances the cursor in bulk keeps line/col accurate, not just the
126
+ * single-byte readCh() path.
127
+ *
128
+ * @param {number} end — exclusive end of the span being skipped
129
+ */
130
+ _advanceLineCol(end) {
131
+ let lastNewlineIdx = -1;
132
+ for (let i = this.startIndex; i < end; i++) {
133
+ if (this.buffer[i] === 10) {
134
+ this.line++;
135
+ lastNewlineIdx = i;
136
+ }
137
+ }
138
+ if (lastNewlineIdx >= 0) {
139
+ this.cols = end - lastNewlineIdx - 1;
140
+ } else {
141
+ this.cols += end - this.startIndex;
142
+ }
143
+ }
144
+
110
145
  readUpto(stopStr) {
111
146
  const inputLength = this.buffer.length;
112
147
  const stopLength = stopStr.length;
@@ -119,6 +154,7 @@ export default class BufferSource {
119
154
  }
120
155
  if (match) {
121
156
  const result = this.buffer.slice(this.startIndex, i).toString();
157
+ this._advanceLineCol(i + stopLength);
122
158
  this.startIndex = i + stopLength;
123
159
  return result;
124
160
  }
@@ -142,6 +178,7 @@ export default class BufferSource {
142
178
  for (let i = this.startIndex; i < len; i++) {
143
179
  if (buf[i] === stopCode) {
144
180
  const result = buf.slice(this.startIndex, i).toString();
181
+ this._advanceLineCol(i + 1);
145
182
  this.startIndex = i + 1;
146
183
  return result;
147
184
  }
@@ -177,6 +214,7 @@ export default class BufferSource {
177
214
  }
178
215
  if (state === 2) {
179
216
  const result = this.buffer.slice(this.startIndex, tagMatchStart).toString();
217
+ this._advanceLineCol(i + 1);
180
218
  this.startIndex = i + 1;
181
219
  return result;
182
220
  }
@@ -215,7 +253,9 @@ export default class BufferSource {
215
253
  * @param {number} [n=1]
216
254
  */
217
255
  updateBufferBoundary(n = 1) {
218
- this.startIndex += n;
256
+ const end = this.startIndex + n;
257
+ this._advanceLineCol(end);
258
+ this.startIndex = end;
219
259
  if (this.autoFlush && this.startIndex >= this.flushThreshold && this._tokenStart < 0) {
220
260
  this.flush();
221
261
  }
@@ -69,9 +69,15 @@ export default class FeedableSource {
69
69
  * _marks[1] — inner mark: set by individual reader functions.
70
70
  * Used only by flush() as the safe trim boundary.
71
71
  *
72
- * -1 means "not set" for that level.
72
+ * `null` means "not set" for that level.
73
+ *
74
+ * Each entry is { startIndex, line, cols } (or null when unset) — line/cols
75
+ * are captured alongside startIndex so a rewind can undo readCh()'s
76
+ * line/col advancement too, not just the buffer offset. Without this,
77
+ * any token that fails mid-read (UNEXPECTED_END) and gets replayed on
78
+ * the next feed() double-counts every '\n' it consumed before failing.
73
79
  */
74
- this._marks = [-1, -1];
80
+ this._marks = [null, null];
75
81
  }
76
82
 
77
83
  /**
@@ -132,7 +138,7 @@ export default class FeedableSource {
132
138
  * @param {0|1} [level=0]
133
139
  */
134
140
  markTokenStart(level = 0) {
135
- this._marks[level] = this.startIndex;
141
+ this._marks[level] = { startIndex: this.startIndex, line: this.line, cols: this.cols };
136
142
  }
137
143
 
138
144
  /**
@@ -145,11 +151,13 @@ export default class FeedableSource {
145
151
  * Called by XMLParser.feed() when a reader throws UNEXPECTED_END.
146
152
  */
147
153
  rewindToMark() {
148
- if (this._marks[0] >= 0) {
149
- this.startIndex = this._marks[0];
154
+ if (this._marks[0] !== null) {
155
+ this.startIndex = this._marks[0].startIndex;
156
+ this.line = this._marks[0].line;
157
+ this.cols = this._marks[0].cols;
150
158
  }
151
- this._marks[0] = -1;
152
- this._marks[1] = -1;
159
+ this._marks[0] = null;
160
+ this._marks[1] = null;
153
161
  }
154
162
 
155
163
  /**
@@ -165,8 +173,8 @@ export default class FeedableSource {
165
173
  * stale mark only delays flushing — it does not cause correctness issues.
166
174
  */
167
175
  clearMark() {
168
- this._marks[0] = -1;
169
- this._marks[1] = -1;
176
+ this._marks[0] = null;
177
+ this._marks[1] = null;
170
178
  }
171
179
 
172
180
  /**
@@ -212,6 +220,33 @@ export default class FeedableSource {
212
220
  * @returns {string} content before the stop string (stop string is consumed)
213
221
  * @throws {ParseError} UNEXPECTED_END when stop string is not found
214
222
  */
223
+ /**
224
+ * Scan buffer[this.startIndex, end) for '\n' and advance line/cols to match,
225
+ * mirroring readCh()'s per-char logic. Does NOT touch startIndex — callers
226
+ * set that themselves afterwards (their "end" is not always startIndex + n;
227
+ * readUptoCloseTag's consumed span includes the matched stop string).
228
+ *
229
+ * Shared by updateBufferBoundary() and the readUpto*() family so every path
230
+ * that advances the cursor in bulk keeps line/col accurate, not just the
231
+ * single-character readCh() path.
232
+ *
233
+ * @param {number} end — exclusive end of the span being skipped
234
+ */
235
+ _advanceLineCol(end) {
236
+ let lastNewlineIdx = -1;
237
+ for (let i = this.startIndex; i < end; i++) {
238
+ if (this.buffer[i] === '\n') {
239
+ this.line++;
240
+ lastNewlineIdx = i;
241
+ }
242
+ }
243
+ if (lastNewlineIdx >= 0) {
244
+ this.cols = end - lastNewlineIdx - 1;
245
+ } else {
246
+ this.cols += end - this.startIndex;
247
+ }
248
+ }
249
+
215
250
  readUpto(stopStr) {
216
251
  const inputLength = this.buffer.length;
217
252
  const stopLength = stopStr.length;
@@ -223,6 +258,7 @@ export default class FeedableSource {
223
258
  }
224
259
  if (match) {
225
260
  const result = this.buffer.substring(this.startIndex, i);
261
+ this._advanceLineCol(i + stopLength);
226
262
  this.startIndex = i + stopLength;
227
263
  return result;
228
264
  }
@@ -245,6 +281,7 @@ export default class FeedableSource {
245
281
  throw new ParseError(`Unexpected end of source reading '${stopChar}'`, ErrorCode.UNEXPECTED_END);
246
282
  }
247
283
  const result = this.buffer.substring(this.startIndex, i);
284
+ this._advanceLineCol(i + 1);
248
285
  this.startIndex = i + 1;
249
286
  return result;
250
287
  }
@@ -281,6 +318,7 @@ export default class FeedableSource {
281
318
  }
282
319
  if (state === 2) {
283
320
  const result = this.buffer.substring(this.startIndex, tagMatchStart);
321
+ this._advanceLineCol(i + 1);
284
322
  this.startIndex = i + 1;
285
323
  return result;
286
324
  }
@@ -300,8 +338,10 @@ export default class FeedableSource {
300
338
  * @param {number} [n=1]
301
339
  */
302
340
  updateBufferBoundary(n = 1) {
303
- this.startIndex += n;
304
- const anyMarkActive = this._marks[0] >= 0 || this._marks[1] >= 0;
341
+ const end = this.startIndex + n;
342
+ this._advanceLineCol(end);
343
+ this.startIndex = end;
344
+ const anyMarkActive = this._marks[0] !== null || this._marks[1] !== null;
305
345
  if (this.autoFlush && this.startIndex >= this.flushThreshold && !anyMarkActive) {
306
346
  this.flush();
307
347
  }
@@ -322,16 +362,17 @@ export default class FeedableSource {
322
362
  // Determine the earliest position that must be kept.
323
363
  let origin = this.startIndex;
324
364
  for (const m of this._marks) {
325
- if (m >= 0 && m < origin) origin = m;
365
+ if (m !== null && m.startIndex < origin) origin = m.startIndex;
326
366
  }
327
367
 
328
368
  if (origin > 0) {
329
369
  this.buffer = this.buffer.substring(origin);
330
370
 
331
- // Adjust all mark positions by the amount trimmed.
371
+ // Adjust all mark buffer-offsets by the amount trimmed.
372
+ // line/cols are not buffer-relative — they stay untouched.
332
373
  const marksLen = this._marks.length;
333
374
  for (let i = 0; i < marksLen; i++) {
334
- if (this._marks[i] >= 0) this._marks[i] -= origin;
375
+ if (this._marks[i] !== null) this._marks[i].startIndex -= origin;
335
376
  }
336
377
 
337
378
  this.startIndex -= origin;
@@ -108,7 +108,14 @@ export default class StringSource {
108
108
  // ─── Core read interface ──────────────────────────────────────────────────
109
109
 
110
110
  readCh() {
111
- return this.buffer[this.startIndex++];
111
+ const ch = this.buffer[this.startIndex++];
112
+ if (ch === '\n') {
113
+ this.line++;
114
+ this.cols = 0;
115
+ } else {
116
+ this.cols++;
117
+ }
118
+ return ch;
112
119
  }
113
120
 
114
121
  readChAt(index) {
@@ -120,6 +127,33 @@ export default class StringSource {
120
127
  return this.buffer.substring(from, from + n);
121
128
  }
122
129
 
130
+ /**
131
+ * Scan buffer[this.startIndex, end) for '\n' and advance line/cols to match,
132
+ * mirroring readCh()'s per-char logic. Does NOT touch startIndex — callers
133
+ * set that themselves afterwards (their "end" is not always startIndex + n;
134
+ * readUptoCloseTag's consumed span includes the matched stop string).
135
+ *
136
+ * Shared by updateBufferBoundary() and the readUpto*() family so every path
137
+ * that advances the cursor in bulk keeps line/col accurate, not just the
138
+ * single-character readCh() path.
139
+ *
140
+ * @param {number} end — exclusive end of the span being skipped
141
+ */
142
+ _advanceLineCol(end) {
143
+ let lastNewlineIdx = -1;
144
+ for (let i = this.startIndex; i < end; i++) {
145
+ if (this.buffer[i] === '\n') {
146
+ this.line++;
147
+ lastNewlineIdx = i;
148
+ }
149
+ }
150
+ if (lastNewlineIdx >= 0) {
151
+ this.cols = end - lastNewlineIdx - 1;
152
+ } else {
153
+ this.cols += end - this.startIndex;
154
+ }
155
+ }
156
+
123
157
  readUpto(stopStr) {
124
158
  const inputLength = this.buffer.length;
125
159
  const stopLength = stopStr.length;
@@ -131,6 +165,7 @@ export default class StringSource {
131
165
  }
132
166
  if (match) {
133
167
  const result = this.buffer.substring(this.startIndex, i);
168
+ this._advanceLineCol(i + stopLength);
134
169
  this.startIndex = i + stopLength;
135
170
  return result;
136
171
  }
@@ -153,6 +188,7 @@ export default class StringSource {
153
188
  throw new ParseError(`Unexpected end of source reading '${stopChar}'`, ErrorCode.UNEXPECTED_END);
154
189
  }
155
190
  const result = this.buffer.substring(this.startIndex, i);
191
+ this._advanceLineCol(i + 1);
156
192
  this.startIndex = i + 1;
157
193
  return result;
158
194
  }
@@ -184,6 +220,7 @@ export default class StringSource {
184
220
  }
185
221
  if (state === 2) {
186
222
  const result = this.buffer.substring(this.startIndex, tagMatchStart);
223
+ this._advanceLineCol(i + 1);
187
224
  this.startIndex = i + 1;
188
225
  return result;
189
226
  }
@@ -211,7 +248,9 @@ export default class StringSource {
211
248
  * @param {number} [n=1]
212
249
  */
213
250
  updateBufferBoundary(n = 1) {
214
- this.startIndex += n;
251
+ const end = this.startIndex + n;
252
+ this._advanceLineCol(end);
253
+ this.startIndex = end;
215
254
  const anyMarkActive = this._marks[0] >= 0 || this._marks[1] >= 0;
216
255
  if (this.autoFlush && this.startIndex >= this.flushThreshold && !anyMarkActive) {
217
256
  this.flush();
@@ -143,7 +143,12 @@ export class StopNodeProcessor {
143
143
  * chunk-boundary `UNEXPECTED_END` can be retried seamlessly.
144
144
  *
145
145
  * @param {object} source Any source object with the standard read interface.
146
- * @returns {string} Raw content between the opening and closing tags.
146
+ * @returns {{content: string, end: {index: number, line: number, col: number}}}
147
+ * `content` is the raw text between the opening and closing tags.
148
+ * `end` is the position immediately after the matched closing tag's '>' —
149
+ * mirrors `TagDetail.openEnd` / closeMeta.closeEnd for the opening-tag side,
150
+ * letting a caller recover the exact span of `<tag>...</tag>` including
151
+ * both delimiters, not just the inner content.
147
152
  */
148
153
  collect(source) {
149
154
  source.markTokenStart(1);
@@ -198,7 +203,7 @@ export class StopNodeProcessor {
198
203
  const c = source.readCh();
199
204
  if (c === '>') break;
200
205
  }
201
- return this._finish();
206
+ return this._finish(source);
202
207
  }
203
208
  }
204
209
 
@@ -253,7 +258,7 @@ export class StopNodeProcessor {
253
258
 
254
259
  if (closeName === this._tagName) {
255
260
  this._depth--;
256
- if (this._depth === 0) return this._finish();
261
+ if (this._depth === 0) return this._finish(source);
257
262
  }
258
263
  this._content += '</' + closeName + closeSuffix;
259
264
  continue;
@@ -322,7 +327,7 @@ export class StopNodeProcessor {
322
327
  const c = source.readCh();
323
328
  if (c === '>') break;
324
329
  }
325
- return this._finish();
330
+ return this._finish(source);
326
331
  }
327
332
  }
328
333
 
@@ -389,7 +394,7 @@ export class StopNodeProcessor {
389
394
 
390
395
  if (closeName === this._tagName) {
391
396
  this._depth--;
392
- if (this._depth === 0) return this._finish();
397
+ if (this._depth === 0) return this._finish(source);
393
398
  }
394
399
  this._content += '</' + closeName + closeSuffix;
395
400
  continue;
@@ -417,16 +422,20 @@ export class StopNodeProcessor {
417
422
  // ── Shared finish helper ───────────────────────────────────────────────────
418
423
 
419
424
  /**
420
- * Reset runtime state and return the accumulated content.
421
- * Called by every strategy when the closing tag is confirmed.
422
- * @returns {string}
425
+ * Reset runtime state and return the accumulated content plus the end
426
+ * position (immediately after the matched closing tag's '>').
427
+ * Called by every strategy when the closing tag is confirmed — always
428
+ * right after that '>' has just been consumed from `source`.
429
+ * @param {object} source
430
+ * @returns {{content: string, end: {index: number, line: number, col: number}}}
423
431
  */
424
- _finish() {
432
+ _finish(source) {
425
433
  const result = this._content;
434
+ const end = { index: source.startIndex, line: source.line, col: source.cols };
426
435
  this._active = false;
427
436
  this._content = '';
428
437
  this._depth = 1;
429
- return result;
438
+ return { content: result, end };
430
439
  }
431
440
 
432
441
  // ── Private helpers ────────────────────────────────────────────────────────
@@ -13,15 +13,20 @@ import { name as isName, qName as isQName } from 'xml-naming';
13
13
  class TagDetail {
14
14
  /**
15
15
  * @param {string} name - Tag name
16
- * @param {number} line - 1-based line number where the opening tag began
17
- * @param {number} col - 1-based column where the opening tag began
18
- * @param {number} index - Character offset from document start
16
+ * @param {number} line - 1-based line number where the opening tag's '<' began
17
+ * @param {number} col - 1-based column where the opening tag's '<' began
18
+ * @param {number} index - Character offset of '<' from document start
19
+ * @param {number} [openEnd] - Character offset immediately after the opening
20
+ * tag's closing '>' (i.e. end of `<tag attr="x">`). Undefined until the
21
+ * opening tag expression has been fully read; set in readOpeningTag().
22
+ * For self-closing tags this is the offset after '/>'.
19
23
  */
20
- constructor(name, line = 0, col = 0, index = 0) {
24
+ constructor(name, line = 0, col = 0, index = 0, openEnd = undefined) {
21
25
  this.name = name;
22
26
  this.line = line;
23
27
  this.col = col;
24
28
  this.index = index;
29
+ this.openEnd = openEnd;
25
30
  }
26
31
  }
27
32
 
@@ -125,10 +130,20 @@ export default class Xml2JsParser {
125
130
  // which never overwrite this position.
126
131
  this.source.markTokenStart(0);
127
132
 
133
+ // Position of the next character, captured before it's read. When that
134
+ // character turns out to be '<', this is exactly the position of '<'
135
+ // itself — used below as the authoritative tag-start position for both
136
+ // TagDetail (open tags) and closeMeta (close tags), instead of deriving
137
+ // it after the fact from source.startIndex once the tag name/attrs have
138
+ // already been consumed (which points past the tag, not at its start).
139
+ const preReadPos = { line: this.source.line, col: this.source.cols, index: this.source.startIndex };
140
+
128
141
  const ch = this.source.readCh();
129
142
  if (ch === undefined || ch === '') break;
130
143
 
131
144
  if (ch === '<') {
145
+ const tagStart = preReadPos;
146
+
132
147
  const nextChar = this.source.readChAt(0);
133
148
  if (nextChar === '') throw new ParseError(
134
149
  "Unexpected end of source after '<'",
@@ -142,9 +157,9 @@ export default class Xml2JsParser {
142
157
  this.readSpecialTag(nextChar);
143
158
  } else if (nextChar === '/') {
144
159
  this.source.updateBufferBoundary();
145
- this.readClosingTag();
160
+ this.readClosingTag(tagStart);
146
161
  } else {
147
- this.readOpeningTag();
162
+ this.readOpeningTag(tagStart);
148
163
  }
149
164
  } else {
150
165
  // ch is already consumed. Peek ahead for more non-'<' chars and grab
@@ -223,8 +238,18 @@ export default class Xml2JsParser {
223
238
  this.finalizeXml();
224
239
  }
225
240
 
226
- readClosingTag() {
241
+ readClosingTag(tagStart) {
227
242
  const tagName = this.processTagName(readClosingTagName(this.source));
243
+ // closeMeta: position of this closing tag's '</' (tagStart, passed in from
244
+ // parseXml's dispatch) plus the offset right after its '>' (closeEnd) —
245
+ // mirrors tagDetail.index / tagDetail.openEnd for the opening-tag side.
246
+ const closeMeta = {
247
+ name: tagName,
248
+ line: tagStart.line,
249
+ col: tagStart.col,
250
+ index: tagStart.index,
251
+ closeEnd: this.source.startIndex,
252
+ };
228
253
 
229
254
  if (this.isUnpaired(tagName) || this.isStopNode()) {
230
255
  throw new ParseError(`Unexpected closing tag '${tagName}'`, ErrorCode.UNEXPECTED_CLOSE_TAG, { line: this.source.line, col: this.source.cols, index: this.source.startIndex });
@@ -246,10 +271,10 @@ export default class Xml2JsParser {
246
271
  }
247
272
 
248
273
  if (!this.currentTagDetail.root) this.addTextNode();
249
- this.popTag();
274
+ this.popTag(closeMeta);
250
275
  }
251
276
 
252
- readOpeningTag() {
277
+ readOpeningTag(tagStart) {
253
278
  const options = this.options;
254
279
  this.addTextNode();
255
280
 
@@ -263,12 +288,15 @@ export default class Xml2JsParser {
263
288
  const { tagDetail, isSkip } = this._stopNodeProcessorMeta;
264
289
  this._stopNodeProcessor.resumeAfterOpenTag();
265
290
  readTagExp(this); // re-consume the opening tag from the rewound source
266
- const content = this._stopNodeProcessor.collect(this.source);
291
+ // openEnd reflects the offset right after this opening tag's '>' — stable
292
+ // across retries since the opening tag is fully re-read every time.
293
+ tagDetail.openEnd = this.source.startIndex;
294
+ const { content, end: stopEnd } = this._stopNodeProcessor.collect(this.source);
267
295
  if (!isSkip) {
268
296
  this.outputBuilder.addElement(tagDetail, this.readonlyMatcher);
269
- this.outputBuilder.onStopNode?.(tagDetail, content, this.readonlyMatcher);
297
+ this.outputBuilder.onStopNode?.(tagDetail, content, this.readonlyMatcher, stopEnd);
270
298
  this.outputBuilder.addValue(content, this.readonlyMatcher);
271
- this.outputBuilder.closeElement(this.readonlyMatcher);
299
+ this.outputBuilder.closeElement(this.readonlyMatcher, { name: tagDetail.name, closeEnd: stopEnd.index });
272
300
  }
273
301
  this.matcher.pop();
274
302
  this._stopNodeProcessor = null;
@@ -280,9 +308,10 @@ export default class Xml2JsParser {
280
308
  const processedTagName = this.processTagName(tagExp.tagName);
281
309
  const tagDetail = new TagDetail(
282
310
  processedTagName,
283
- this.source.line,
284
- this.source.cols,
285
- this.source.startIndex,
311
+ tagStart.line,
312
+ tagStart.col,
313
+ tagStart.index,
314
+ this.source.startIndex, // openEnd: offset right after this opening tag's '>'
286
315
  );
287
316
 
288
317
  // Extract namespace prefix and local name from raw tag name (e.g. "ns:tag" → "ns", "tag").
@@ -331,7 +360,7 @@ export default class Xml2JsParser {
331
360
  const skipTagConfig = stopNodeConfig ? null : this.isSkipTag();
332
361
 
333
362
  if (!options.skip.attributes && !skipTagConfig) {
334
- flushAttributes(tagExp._attrsExp, this);
363
+ flushAttributes(tagExp._attrsExp, this, tagExp._attrsExpStart);
335
364
  }
336
365
 
337
366
  // Stop-node and skip-tag checks AFTER attributes are set so attribute conditions work.
@@ -341,12 +370,15 @@ export default class Xml2JsParser {
341
370
 
342
371
  if (this.isUnpaired(processedTagName)) {
343
372
  this.outputBuilder.addElement(tagDetail, this.readonlyMatcher);
344
- this.outputBuilder.closeElement(this.readonlyMatcher);
373
+ // Unpaired tags (e.g. <br>, <img>) have no separate closing tag — the
374
+ // close position is the same as the open tag's end.
375
+ this.outputBuilder.closeElement(this.readonlyMatcher, this._closeMetaFor(tagDetail));
345
376
  this.matcher.pop();
346
377
  } else if (tagExp.selfClosing) {
347
378
  if (!skipTagConfig) {
348
379
  this.outputBuilder.addElement(tagDetail, this.readonlyMatcher);
349
- this.outputBuilder.closeElement(this.readonlyMatcher);
380
+ // Self-closing tags (<tag/>) likewise have no distinct closing tag.
381
+ this.outputBuilder.closeElement(this.readonlyMatcher, this._closeMetaFor(tagDetail));
350
382
  }
351
383
  this.matcher.pop();
352
384
  } else if (stopNodeConfig) {
@@ -360,11 +392,16 @@ export default class Xml2JsParser {
360
392
  });
361
393
  this._stopNodeProcessorMeta = { tagDetail, isSkip: false };
362
394
  this._stopNodeProcessor.activate();
363
- const content = this._stopNodeProcessor.collect(this.source);
395
+ const { content, end: stopEnd } = this._stopNodeProcessor.collect(this.source);
364
396
  this.outputBuilder.addElement(tagDetail, this.readonlyMatcher);
365
- this.outputBuilder.onStopNode?.(tagDetail, content, this.readonlyMatcher);
397
+ this.outputBuilder.onStopNode?.(tagDetail, content, this.readonlyMatcher, stopEnd);
366
398
  this.outputBuilder.addValue(content, this.readonlyMatcher);
367
- this.outputBuilder.closeElement(this.readonlyMatcher);
399
+ // closeMeta for a stop node carries only `closeEnd` (offset right after
400
+ // the matched </tagname> was consumed) — StopNodeProcessor scans the
401
+ // closing tag opaquely and doesn't track where '</tagname' itself starts,
402
+ // so unlike the normal close path we don't have a real index/line/col
403
+ // for the close tag's own start, only its end.
404
+ this.outputBuilder.closeElement(this.readonlyMatcher, { name: tagDetail.name, closeEnd: stopEnd.index });
368
405
  this.matcher.pop();
369
406
  this._stopNodeProcessor = null;
370
407
  this._stopNodeProcessorMeta = null;
@@ -435,13 +472,36 @@ export default class Xml2JsParser {
435
472
  * Pop the current tag from the parser stack and notify the output builder.
436
473
  * This is the single point of exit for closing a tag — both stacks are
437
474
  * updated together.
475
+ *
476
+ * @param {object} [closeMeta] - Position info for the closing tag:
477
+ * { name, line, col, index, closeEnd }. Omitted when there is no real
478
+ * closing tag to report a position for — e.g. AutoCloseHandler synthesizing
479
+ * a close at EOF, or exitIf closing already-open ancestors. In that case a
480
+ * minimal `{ name }` is passed to the builder instead of nothing, so
481
+ * closeElement() never has to special-case "no second argument at all".
438
482
  */
439
- popTag() {
440
- this.outputBuilder.closeElement(this.readonlyMatcher);
483
+ popTag(closeMeta) {
484
+ this.outputBuilder.closeElement(this.readonlyMatcher, closeMeta ?? { name: this.currentTagDetail?.name });
441
485
  this.matcher.pop();
442
486
  this.currentTagDetail = this.tagsStack.pop();
443
487
  }
444
488
 
489
+ /**
490
+ * Build a closeMeta object for tags with no distinct closing token
491
+ * (unpaired tags like <br>, and self-closing tags like <tag/>) — the close
492
+ * position is just the opening tag's own end.
493
+ * @param {TagDetail} tagDetail
494
+ */
495
+ _closeMetaFor(tagDetail) {
496
+ return {
497
+ name: tagDetail.name,
498
+ line: tagDetail.line,
499
+ col: tagDetail.col,
500
+ index: tagDetail.index,
501
+ closeEnd: tagDetail.openEnd,
502
+ };
503
+ }
504
+
445
505
  readSpecialTag(startCh) {
446
506
  if (startCh === "!") {
447
507
  let nextChar = this.source.readCh();
@@ -48,6 +48,10 @@ export function readClosingTagName(source) {
48
48
  */
49
49
  export function readTagExp(parser) {
50
50
  parser.source.markTokenStart(1);
51
+ // Absolute document offset where `exp` (tag name onward, right after '<')
52
+ // begins — captured before any reads so buildTagExpObj can compute each
53
+ // attribute's absolute document position from its offset within attrsExp.
54
+ const expStart = parser.source.startIndex;
51
55
  let inSingleQuotes = false;
52
56
  let inDoubleQuotes = false;
53
57
  let i;
@@ -77,7 +81,7 @@ export function readTagExp(parser) {
77
81
 
78
82
  const exp = parser.source.readStr(i);
79
83
  parser.source.updateBufferBoundary(i + 1);
80
- return buildTagExpObj(exp, parser);
84
+ return buildTagExpObj(exp, parser, expStart);
81
85
  }
82
86
 
83
87
  /**
@@ -90,6 +94,7 @@ export function readTagExp(parser) {
90
94
  */
91
95
  export function readPiExp(parser) {
92
96
  parser.source.markTokenStart(1);
97
+ const expStart = parser.source.startIndex;
93
98
  let inSingleQuotes = false;
94
99
  let inDoubleQuotes = false;
95
100
  let i;
@@ -127,7 +132,7 @@ export function readPiExp(parser) {
127
132
 
128
133
  const exp = parser.source.readStr(i);
129
134
  parser.source.updateBufferBoundary(i + 2);
130
- return buildTagExpObj(exp, parser);
135
+ return buildTagExpObj(exp, parser, expStart);
131
136
  }
132
137
 
133
138
  // ─── Internal helpers ─────────────────────────────────────────────────────────
@@ -135,16 +140,22 @@ export function readPiExp(parser) {
135
140
  /**
136
141
  * Parse a raw tag expression string into a structured tag descriptor.
137
142
  *
138
- * @param {string} exp - everything between '<' and '>' (exclusive)
143
+ * @param {string} exp - everything between '<' and '>' (exclusive)
139
144
  * @param {object} parser
140
- * @returns {{ tagName, selfClosing, rawAttributes, _attrsExp }}
145
+ * @param {number} [expStart] - absolute document offset where `exp` begins
146
+ * (i.e. right after '<' or '<?'). Used to compute each attribute's absolute
147
+ * document position (tagExp._attrsExpStart) for addAttribute()'s meta arg.
148
+ * Optional so callers that don't have/need it can omit it — attribute
149
+ * position metadata is simply unavailable in that case, not an error.
150
+ * @returns {{ tagName, selfClosing, rawAttributes, _attrsExp, _attrsExpStart }}
141
151
  */
142
- function buildTagExpObj(exp, parser) {
152
+ function buildTagExpObj(exp, parser, expStart) {
143
153
  const tagExp = {
144
154
  tagName: "",
145
155
  selfClosing: false,
146
156
  rawAttributes: Object.create(null),
147
157
  _attrsExp: "", // stored for two-pass attribute flushing in readOpeningTag
158
+ _attrsExpStart: undefined, // absolute document offset of _attrsExp's first char
148
159
  };
149
160
 
150
161
  const expLen = exp.length;
@@ -163,6 +174,7 @@ function buildTagExpObj(exp, parser) {
163
174
  if (isSpace(c)) {
164
175
  tagExp.tagName = exp.substring(0, i);
165
176
  attrsExp = exp.substring(i + 1);
177
+ if (expStart !== undefined) tagExp._attrsExpStart = expStart + i + 1;
166
178
  break;
167
179
  }
168
180
  }
@@ -57,7 +57,7 @@ export function readPiTag(parser) {
57
57
  // does for regular tags. PI tags are not pushed onto the matcher, so no
58
58
  // updateCurrent() call is needed here.
59
59
  if (!skipOptions.attributes) {
60
- flushAttributes(tagExp._attrsExp, parser);
60
+ flushAttributes(tagExp._attrsExp, parser, tagExp._attrsExpStart);
61
61
  }
62
62
 
63
63
  if (tagExp.tagName === "xml") {