@nodable/flexible-xml-parser 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/lib/fxp.cjs +1 -0
- package/package.json +6 -4
- package/src/AttributeProcessor.js +85 -32
- package/src/DocTypeReader.js +6 -6
- package/src/OptionsBuilder.js +1 -0
- package/src/XMLParser.js +42 -12
- package/src/Xml2JsParser.js +23 -5
- package/src/XmlPartReader.js +10 -7
- package/src/XmlSpecialTagsReader.js +15 -5
- package/src/util.js +9 -10
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
**1.2.1 (2026-05-28)**
|
|
3
|
+
- update dependencies to fix duplicate entites
|
|
4
|
+
- include fxp.cjs in npm package
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
**1.2.0 (2026-05-13)**
|
|
8
|
+
- fix: Tag name can be separated with rest of the tag expression by any type of spaces.
|
|
9
|
+
- fix: parser should not fail when tag expresison is very long
|
|
10
|
+
- fix: stop node with namespace should work
|
|
11
|
+
- support `feedable.bufferSize` option to improve/speed up feed method.
|
|
12
|
+
- integrate `xml-naming` library that would also consider xml version
|
|
13
|
+
|
package/lib/fxp.cjs
ADDED
|
@@ -0,0 +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:()=>V,ParseError:()=>R,XMLParser:()=>Lt,default:()=>Lt,quoteEnclosures:()=>_t,xmlEnclosures:()=>gt});const s={nameFor:{text:"#text",comment:"",cdata:""},skip:{declaration:!1,pi:!1,attributes:!0,cdata:!1,comment:!1,nsPrefix:!1,tags:!1},tags:{valueParsers:[],stopNodes:[]},attributes:{prefix:"@_",suffix:"",groupBy:"",valueParsers:[]}},r=["trim","number","boolean","entity"],n=["trim","number","boolean","entity"];function i(t){const e=o(s);return t&&void 0!==t.tags?.valueParsers||(e.tags.valueParsers=[...r]),t&&void 0!==t.attributes?.valueParsers||(e.attributes.valueParsers=[...n]),t&&a(e,t),e}function o(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(o);const e={};for(const s of Object.keys(t))e[s]=o(t[s]);return e}function a(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]={}),a(t[s],e[s])):t[s]=e[s])}const h=/^[-+]?0x[a-fA-F0-9]+$/,c=/^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/,l={hex:!0,leadingZeros:!0,decimalPoint:".",eNotation:!0,infinity:"original"};const u=/^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/,d={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'},f=new Set("!?\\\\/[]$%{}^&*()<>|+");function p(t){if("#"===t[0])throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${t}"`);for(const e of t)if(f.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 _="external",E="base",m="all",x=Object.freeze({allow:0,leave:1,remove:2,throw:3}),T=new Set([9,10,13]);class N{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??_)&&e!==_?e===m?new Set([m]):e===E?new Set([E]):Array.isArray(e)?new Set(e):new Set([_]):new Set([_]),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}setExternalEntities(t){if(t)for(const e of Object.keys(t))p(e);this._externalMap=g(t)}addExternalEntity(t,e){p(t),"string"==typeof e&&-1===e.indexOf("&")&&(this._externalMap[t]=e)}addInputEntities(t){this._totalExpansions=0,this._expandedLength=0,this._inputMap=g(t)}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;const e=t,s=[],r=t.length;let n=0,i=0;const o=this._maxTotalExpansions>0,a=this._maxExpandedLength>0,h=o||a;for(;i<r;){if(38!==t.charCodeAt(i)){i++;continue}let e=i+1;for(;e<r&&59!==t.charCodeAt(e)&&e-i<=32;)e++;if(e>=r||59!==t.charCodeAt(e)){i++;continue}const c=t.slice(i+1,e);if(0===c.length){i++;continue}let l,u;if(this._removeSet.has(c))l="",void 0===u&&(u=_);else{if(this._leaveSet.has(c)){i++;continue}if(35===c.charCodeAt(0)){const t=this._resolveNCR(c);if(void 0===t){i++;continue}l=t,u=E}else{const t=this._resolveName(c);l=t?.value,u=t?.tier}}if(void 0!==l){if(i>n&&s.push(t.slice(n,i)),s.push(l),n=e+1,i=n,h&&this._tierCounts(u)){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=l.length-(c.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 i++}n<r&&s.push(t.slice(n));const c=0===s.length?t:s.join("");return this._postCheck(c,e)}_tierCounts(t){return!!this._limitTiers.has(m)||this._limitTiers.has(t)}_resolveName(t){return t in this._inputMap?{value:this._inputMap[t],tier:_}:t in this._externalMap?{value:this._externalMap[t],tier:_}:t in this._baseMap?{value:this._baseMap[t],tier:E}: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 n=-1===r?this._ncrOnLevel:Math.max(this._ncrOnLevel,r);return this._applyNCRAction(n,t,s)}}class I extends N{constructor(t){super(t)}parse(t){return"string"==typeof t&&(t=this.decode(t)),t}}class w{parse(t){return"string"==typeof t?t.trim():t}}class A{constructor(t,e){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!0;if(-1!==this.falseList.indexOf(e))return!1}return t}}class C{constructor(t){this.options=t||{}}parse(t){return"string"==typeof t&&(t=function(t,e={}){if(e=Object.assign({},l,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.hex&&h.test(s))return function(t){if(parseInt)return parseInt(t,16);if(Number.parseInt)return Number.parseInt(t,16);if(window&&window.parseInt)return window.parseInt(t,16);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}(s);if(isFinite(s)){if(s.includes("e")||s.includes("E"))return function(t,e,s){if(!s.eNotation)return t;const r=e.match(u);if(r){let n=r[1]||"";const i=-1===r[3].indexOf("e")?"E":"e",o=r[2],a=n?t[o.length+1]===i:t[o.length]===i;return o.length>1&&a?t:(1!==o.length||!r[3].startsWith(`.${i}`)&&r[3][0]!==i)&&o.length>0?s.leadingZeros&&!a?(e=(r[1]||"")+r[3],Number(e)):t:Number(e)}return t}(t,s,e);{const n=c.exec(s);if(n){const i=n[1]||"",o=n[2];let a=(r=n[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 h=i?"."===t[o.length+1]:"."===t[o.length];if(!e.leadingZeros&&(o.length>1||1===o.length&&!h))return t;{const r=Number(s),n=String(r);if(0===r)return r;if(-1!==n.search(/[eE]/))return e.eNotation?r:t;if(-1!==s.indexOf("."))return"0"===n||n===a||n===`${i}${a}`?r:t;let h=o?a:s;return o?h===n||i+h===n?r:t:h===n||h===i+n?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)}(t,this.options)),t}}const S={maxLength:200},y={$:"en-US","€":"de-DE","£":"en-GB","¥":"ja-JP","₹":"en-IN"},D=/^\s*(?:-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d{1,2})?\s*(?:\$|€|¥|₹)?\s*$/u;class b{constructor(t){this.options=t||S}parse(t){if("string"==typeof t&&t.length<=this.options.maxLength&&-1!==t.indexOf(",,")&&t.indexOf(!0)){const e=t.match(D);if(e){const s=this.options.locale||y[e[2]||e[5]||"₹"],r=new Intl.NumberFormat(s);t=t.replace(/[^0-9,.]/g,"").trim(),t=Number(t.replace(r.format(1e3)[1],""))}}return t}}b.defaultOptions=S;const P=Object.freeze({ELEMENT:"ELEMENT",ATTRIBUTE:"ATTRIBUTE"});class U{constructor(t){this.matcher=t||null,this._rootName="^"}addAttribute(t,e,s){"version"===t&&this.tagName===this._rootName&&k(this.registeredValParsers,"setXmlVersion",+e);const r=this.options.attributes.prefix+t+this.options.attributes.suffix,n={elementName:t,elementValue:e,elementType:P.ATTRIBUTE,matcher:s,isLeafNode:!0};this.attributes[r]=this.parseValue(e,this.options.attributes.valueParsers,n)}parseValue(t,e,s){for(let r=0;r<e.length;r++){let n=e[r];"string"==typeof n&&(n=this.registeredValParsers[n]),n&&(t=n.parse(t,s))}return t}_addChild(t,e){}addComment(t){this.options.skip.comment||this.options.nameFor.comment&&this._addChild(this.options.nameFor.comment,t)}addLiteral(t){this.options.skip.cdata||(this.options.nameFor.cdata?this._addChild(this.options.nameFor.cdata,t):this.addRawValue(t||""))}addRawValue(t){this.addValue(t)}addInputEntities(t){k(this.registeredValParsers,"addInputEntities",t)}addDeclaration(t){this.addInstruction(t)}addInstruction(t){}onExit(t){}}function k(t,e,s){for(const r of Object.values(t))"function"==typeof r[e]&&r[e](s)}class v{constructor(){this.commonValParsers={entity:new I,trim:new w,boolean:new A,number:new C({hex:!0,leadingZeros:!0,eNotation:!0}),currency:new b}}registerValueParser(t,e){this.commonValParsers[t]=e}getInstance(t,e){return this.resetValueParsers(),new U(t,e,this.commonValParsers)}resetValueParsers(){for(const t of Object.values(this.commonValParsers))t&&t.reset&&t.reset()}}class O{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 n=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(n&&(r=n[1]+n[3],n[2])){const t=n[2].slice(1,-1);t&&(s=t)}let i,o,a=r;if(r.includes("::")){const e=r.indexOf("::");if(i=r.substring(0,e).trim(),a=r.substring(e+2).trim(),!i)throw new Error(`Invalid namespace in pattern: ${t}`)}let h=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,h=s):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,i&&(e.namespace=i),s)if(s.includes("=")){const t=s.indexOf("=");e.attrName=s.substring(0,t).trim(),e.attrValue=s.substring(t+1).trim()}else e.attrName=s.trim();if(h){const t=h.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=h}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 M extends v{constructor(t){super(),this.options=i(t),this.options.alwaysArray&&(this.options.alwaysArray=this.options.alwaysArray.map(t=>"string"==typeof t?new O(t):t))}getInstance(t,e){this.resetValueParsers();const s={...this.commonValParsers};return new L(t,this.options,s,e)}}class L extends U{constructor(t,e,s,r){super(r),this.tagsStack=[],this.options={...e,...t,skip:{...e.skip,...t.skip},nameFor:{...e.nameFor,...t.nameFor},tags:{...e.tags,...t.tags},attributes:{...e.attributes,...t.attributes},textJoint:e.textJoint||"",forceArray:e?.forceArray||null,alwaysArray:e?.alwaysArray||[],forceTextNode:e?.forceTextNode??!1},this.registeredValParsers=s,this.root={},this.parent=this.root,this.tagName=this._rootName,this.value={},this.textValue="",this.attributes={},this.hasAttributes=!1}_buildAttributeValue(){return B(this.attributes)?(this.hasAttributes=!1,""):(this.hasAttributes=!0,this.options.attributes.groupBy?{[this.options.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={}}onStopNode(t,e){"function"==typeof this.options.onStopNode&&this.options.onStopNode(t,e,this.matcher)}_resolveForceArray(t){let e,s;if(this.options.alwaysArray.some(t=>this.matcher.matches(t))&&(e=!0),"function"==typeof this.options.forceArray){const e=this.options.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,n="object"!=typeof e||Array.isArray(e)||B(e)||r,i={elementName:t,elementValue:s,elementType:P.ELEMENT,matcher:this.matcher,isLeafNode:n};if(n){const t=this.parseValue(s,this.options.tags.valueParsers,i);r?(""!==t&&null!=t||this.options.forceTextNode)&&(e[this.options.nameFor.text]=t):e=this.options.forceTextNode?{[this.options.nameFor.text]:t}:t}else if(s.length>0){const t=this.parseValue(s,this.options.tags.valueParsers,i);e[this.options.nameFor.text]=t}else if(s.length>0||this.options.forceTextNode){const t=this.parseValue(s,this.options.tags.valueParsers,i);e[this.options.nameFor.text]=t}let o={tagName:t,value:e};if(void 0!==this.options.onTagClose&&(o=this.options.onTagClose(t,e,s,this.matcher),!o))return;const a=this.tagsStack.pop();let h=a[2];const c=this._resolveForceArray(n);h=this._addChildTo(o.tagName,o.value,h,c),this.tagName=a[0],this.textValue=a[1],this.value=h,this.hasAttributes=a[3]}_addChild(t,e){"string"==typeof this.value&&(this.value={[this.options.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.options.textJoint+t:this.textValue=t}onExit(t){}addInstruction(t){const e=this._buildAttributeValue();this._addChild(t,e),this.attributes={}}getOutput(){return this.value}}function B(t){return 0===Object.keys(t).length}class ${constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard())return this._deepWildcards.push(t),this;const e=t.length,s=t.segments[t.segments.length-1],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=`${e}:${t.getCurrentTag()}`,r=this._byDepthAndTag.get(s);if(r)for(let e=0;e<r.length;e++)if(t.matches(r[e]))return r[e];const n=this._wildcardByDepth.get(e);if(n)for(let e=0;e<n.length;e++)if(t.matches(n[e]))return n[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}class R 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 V=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 X(t){return" "===t||"\t"===t||"\n"===t||"\r"===t||"\f"===t}function Y(t){return 32===t||9===t||10===t||13===t||12===t}const F=["hasOwnProperty","toString","valueOf","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__","toLocaleString","isPrototypeOf","propertyIsEnumerable"],G=["__proto__","constructor","prototype"],j=t=>F.includes(t)?"__"+t:t,z={skip:{declaration:!1,pi:!1,attributes:!0,cdata:!1,comment:!1,nsPrefix:!1,tags:[]},nameFor:{text:"#text",cdata:"",comment:""},attributes:{booleanType:!1,groupBy:"",prefix:"@_",suffix:""},tags:{unpaired:[],stopNodes:[]},strictReservedNames:!1,onDangerousProperty:j,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},H=new Set([...G,...F]);function W(t,e){if("string"==typeof t&&""!==t&&H.has(t))throw new R(`SECURITY: '${t}' is a reserved JavaScript keyword and cannot be used as ${e}`,V.SECURITY_RESERVED_OPTION)}const Z=function(t){if(t&&(t.nameFor?.text&&W(t.nameFor.text,"nameFor.text"),t.nameFor?.cdata&&W(t.nameFor.cdata,"nameFor.cdata"),t.nameFor?.comment&&W(t.nameFor.comment,"nameFor.comment"),t.attributes?.prefix&&W(t.attributes.prefix,"attributes.prefix"),t.attributes?.groupBy&&W(t.attributes.groupBy,"attributes.groupBy"),void 0!==t.limits&&null!==t.limits)){if("object"!=typeof t.limits)throw new R("'limits' must be an object, got "+typeof t.limits,V.INVALID_INPUT);const{maxNestedTags:e,maxAttributesPerTag:s}=t.limits;if(null!=e&&("number"!=typeof e||!Number.isInteger(e)||e<1))throw new R(`'limits.maxNestedTags' must be a positive integer, got ${e}`,V.INVALID_INPUT);if(null!=s&&("number"!=typeof s||!Number.isInteger(s)||s<0))throw new R(`'limits.maxAttributesPerTag' must be a non-negative integer, got ${s}`,V.INVALID_INPUT)}const e=Q(z);if(t&&K(e,t),e.OutputBuilder||(e.OutputBuilder=new M),Array.isArray(e.tags?.stopNodes)){const t=new $;e.tags.stopNodes=e.tags.stopNodes.map(e=>J(e,"stopNodes",t)),t.seal(),e.tags.stopNodesSet=t}if(Array.isArray(e.skip?.tags)){const t=new $;e.skip.tags=e.skip.tags.map(e=>J(e,"skip.tags",t)),t.seal(),e.skip.tagsSet=t}if(null===e.onDangerousProperty&&(e.onDangerousProperty=j),null!==e.exitIf&&void 0!==e.exitIf&&"function"!=typeof e.exitIf)throw new R("'exitIf' must be a function, got "+typeof e.exitIf,V.INVALID_INPUT);return e.autoClose=function(t,e){if(!t)return null;if("html"===t){const t=e.tags.unpaired||[],s=[...new Set([...t,...q])];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},q=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"];function J(t,e,s){let r,n,i;if("string"==typeof t){if(0===t.length)throw new R(`${e} expression cannot be empty`,V.INVALID_INPUT);r=t,n=!1,i=[]}else if(t instanceof O)r=t.toString(),n=t.data?.nested??!1,i=t.data?.skipEnclosures??[];else{if(!t||"object"!=typeof t||void 0===t.expression)throw new R(`Invalid ${e} entry: expected a string, Expression, or { expression, nested?, skipEnclosures? } object.`,V.INVALID_INPUT);{const s=t.expression;if("string"==typeof s){if(0===s.length)throw new R(`${e} expression cannot be empty`,V.INVALID_INPUT);r=s}else{if(!(s instanceof O))throw new R(`${e} expression must be a string or Expression instance`,V.INVALID_INPUT);r=s.toString()}n=!0===t.nested,i=Array.isArray(t.skipEnclosures)?t.skipEnclosures:[]}}const o=new O(r,{},{nested:n,skipEnclosures:i});return s.add(o),o}function Q(t){if(null===t||"object"!=typeof t)return t;if(Array.isArray(t))return t.map(Q);if(t instanceof RegExp)return t;if(t instanceof O)return t;const e={};for(const s of Object.keys(t))e[s]="function"==typeof t[s]?t[s]:Q(t[s]);return e}function K(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]={}),K(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 n=0;n<s;n++)if(this.buffer[r+n]!==t[n]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=r+s,t}}throw new R(`Unexpected end of source reading '${t}'`,V.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new R(`Unexpected end of source reading '${t}'`,V.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,n=0;for(let i=this.startIndex;i<e;i++){if(1===n){const t=this.buffer[i];if(" "===t||"\t"===t)continue;">"===t?n=2:(n=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[i+r]!==t[r]){e=!1;break}e&&(n=1,r=i,i+=s-1)}if(2===n){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=i+1,t}}throw new R(`Unexpected end of source reading '${t}'`,V.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 et{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 n=0;n<s;n++)if(this.buffer[t+n]!==r[n]){e=!1;break}if(e){const e=this.buffer.slice(this.startIndex,t).toString();return this.startIndex=t+s,e}}throw new R(`Unexpected end of source reading '${t}'`,V.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 R(`Unexpected end of source reading '${t}'`,V.UNEXPECTED_END)}readUptoCloseTag(t){const e=this.buffer.length,s=t.length,r=Buffer.from(t);let n=-1,i=0;for(let t=this.startIndex;t<e;t++){if(1===i){const e=this.buffer[t];if(32===e||9===e)continue;62===e?i=2:(i=0,n=-1)}else{let e=!0;for(let n=0;n<s;n++)if(this.buffer[t+n]!==r[n]){e=!1;break}e&&(i=1,n=t,t+=s-1)}if(2===i){const e=this.buffer.slice(this.startIndex,n).toString();return this.startIndex=t+1,e}}throw new R(`Unexpected end of source reading '${t}'`,V.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 st(t){const e=[],s=t.length;let r=0;for(;r<s;){for(;r<s&&Y(t.charCodeAt(r));)r++;if(r>=s)break;const n=r;for(;r<s&&61!==t.charCodeAt(r)&&!Y(t.charCodeAt(r));)r++;const i=t.substring(n,r);for(;r<s&&Y(t.charCodeAt(r));)r++;if(r>=s||61!==t.charCodeAt(r)){const t=[i,i,void 0,void 0,void 0];t.startIndex=n,e.push(t);continue}for(r++;r<s&&Y(t.charCodeAt(r));)r++;const o=t.charCodeAt(r);if(34===o||39===o){r++;let a="",h=r;for(;r<s&&t.charCodeAt(r)!==o;){const e=t.charCodeAt(r);10!==e&&13!==e||(a+=t.substring(h,r)+" ",h=r+1),r++}a+=t.substring(h,r),r++;const c=String.fromCharCode(o),l=[i+"="+c+a+c,i,"="+c+a+c,c,a];l.startIndex=n,e.push(l)}}return e}function rt(t,e){if(!t||0===t.length)return;const s=st(t),r=s.length,n=e.options.limits?.maxAttributesPerTag;if(null!=n&&r>n){const t=e.currentTagDetail?.name??"(unknown)";throw new R(`Tag '${t}' has ${r} attributes, exceeding limit of ${n}`,V.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 n=s[t][4],i=void 0===n||n;e.outputBuilder.addAttribute(r,i,e.readonlyMatcher)}}const nt=":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈--⁰-Ⰰ-、-豈-﷏ﷰ-�",it=":A-Za-z_À-˿Ͱ-ͽͿ-҆҈--⁰-Ⰰ-、-豈-﷏ﷰ-�𐀀-",ot=it+"\\-\\.\\d·̀-ͯ҇‿-⁀",at=(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)}},ht=at(nt,nt+"\\-\\.\\d·̀-ͯ‿-⁀"),ct=at(it,ot,"u"),lt=(t="1.0")=>"1.1"===t?ct:ht,ut=(t,{xmlVersion:e="1.0"}={})=>lt(e).name.test(t),dt=(t,{xmlVersion:e="1.0"}={})=>lt(e).qName.test(t);function ft(t){t.source.markTokenStart(1);let e,s=!1,r=!1,n=!1;for(e=0;t.source.canRead(e);e++){const i=t.source.readChAt(e);if("'"!==i||r)if('"'!==i||s){if(">"===i&&!s&&!r){n=!0;break}}else r=!r;else s=!s}if(!n)throw new R("Unexpected closing of source waiting for '>'",V.UNEXPECTED_END);if(s||r)throw new R("Invalid attribute expression. Quote is not properly closed",V.UNCLOSED_QUOTE);const i=t.source.readStr(e);return t.source.updateBufferBoundary(e+1),pt(i,t)}function pt(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="",n=0;for(;n<t.length;n++)if(X(t[n])){s.tagName=t.substring(0,n),r=t.substring(n+1);break}if(0===s.tagName.length&&n===t.length&&(s.tagName=t),s.tagName=s.tagName.trimEnd(),s._attrsExp=r,!dt(s.tagName,e.xmlVersion))throw new R("Invalid tag name",V.INVALID_TAG_NAME);return!e.options.skip.attributes&&r.length>0&&function(t,e,s){if(!t||0===t.length)return;const r=st(t),n=r.length;let i=0;for(let t=0;t<n;t++){if(!1===e.processAttrName(r[t][1]))continue;i++;const n=r[t][4];s.rawAttributes[r[t][1]]=void 0===n||n}s.rawAttributesLen=i}(r,e,s),s}const gt=[{open:"\x3c!--",close:"--\x3e"},{open:"<![CDATA[",close:"]]>"},{open:"<?",close:"?>"}],_t=[{open:"'",close:"'"},{open:'"',close:'"'},{open:"`",close:"`"}];class Et{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 R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.UNEXPECTED_END)}_collectDepthOnly(t){for(;this._depth>0;){if(!t.canRead())throw new R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.UNEXPECTED_END);if("<"!==t.readChAt(0)){this._content+=t.readCh();continue}if(t.readCh(),!t.canRead())throw new R(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,V.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 R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.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 R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.UNEXPECTED_END)}_collectFull(t){for(;this._depth>0;){if(!t.canRead())throw new R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.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 R(`Unclosed stop node <${this._tagName}> — unexpected end after '<'`,V.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:n}=this._readTagTail(t);this._content+=n,r||s!==this._tagName||this._depth++}throw new R(`Unclosed stop node <${this._tagName}> — unexpected end of input`,V.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,n=t.startIndex;let i=0;for(;t.canRead();){if(t.readChAt(0)===s&&this._peekMatch(t,e)){const e=t.readStr(i,n);return this._skipChars(t,r),e}t.readCh(),i++}throw new R(`Unclosed stop node <${this._tagName}> — unexpected end looking for '${e}'`,V.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,n=!1;for(;t.canRead();){const i=t.readCh();if(s++,"'"!==i||n)if('"'!==i||r){if(!r&&!n){if(">"===i)return{selfClosing:!1,attrText:t.readStr(s,e)};if("/"===i&&t.canRead()&&">"===t.readChAt(0))return t.readCh(),s++,{selfClosing:!0,attrText:t.readStr(s,e)}}}else n=!n;else r=!r}throw new R(`Unclosed stop node <${this._tagName}> — unexpected end inside tag`,V.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 R(`Malformed closing tag for </${this._tagName}>`,V.UNEXPECTED_END)}throw new R(`Unclosed stop node <${this._tagName}> — unexpected end looking for '>'`,V.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}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 xt{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new mt(this)}push(t,e=null,s=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const r=this.path.length;this.siblingStacks[r]||(this.siblingStacks[r]=new Map);const n=this.siblingStacks[r],i=s?`${s}:${t}`:t,o=n.get(i)||0;let a=0;for(const t of n.values())a+=t;n.set(i,o+1);const h={tag:t,position:a,counter:o};null!=s&&(h.namespace=s),null!=e&&(h.values=e),this.path.push(h)}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();return this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1),t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const s=t||this.separator;if(s===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(s)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,s=t.length-1;for(;s>=0&&e>=0;){const r=t[s];if("deep-wildcard"===r.type){if(s--,s<0)return!0;const r=t[s];let n=!1;for(let t=e;t>=0;t--)if(this._matchSegment(r,this.path[t],t===this.path.length-1)){e=t-1,s--,n=!0;break}if(!n)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))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t))}readOnly(){return this._view}}function Tt(t){const e=t.source;if(Ct(e),!e.canRead())throw new R("Unexpected end of source reading entity name",V.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 n=e.readStr(r,s);if(!e.canRead())throw new R(`Unexpected end of source reading entity name "${n}"`,V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(St(n,t.xmlVersion),Ct(e),!e.canRead())throw new R(`Unexpected end of source after entity name "${n}"`,V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(e.canRead(5)&&"SYSTEM"===e.readStr(6).toUpperCase())throw new R("External entities are not supported",V.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if("%"===e.readStr(1))throw new R("Parameter entities are not supported",V.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(!e.canRead())throw new R(`Unexpected end of source reading entity value for "${n}"`,V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});const[i]=At(e,"entity"),o=t.options?.doctypeOptions;if(o?.maxEntitySize&&i.length>o.maxEntitySize)throw new R(`Entity "${n}" size (${i.length}) exceeds maximum allowed size (${o.maxEntitySize})`,V.ENTITY_MAX_SIZE,{line:e.line,col:e.cols,index:e.startIndex});return e.readUptoChar(">"),[n,i]}function Nt(t){const e=t.source;if(Ct(e),!e.canRead())throw new R("Unexpected end of source reading ELEMENT name",V.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 n=e.readStr(r,s);if(!e.canRead())throw new R(`Unexpected end of source after ELEMENT name "${n}"`,V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(!ut(n,t.xmlVersion))throw new R(`Invalid element name: "${n}"`,V.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});if(Ct(e),!e.canRead())throw new R("Unexpected end of source reading ELEMENT content model",V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let i=e.readStr(1);if("E"===i){if(!e.canRead(4))throw new R("Unexpected end of source reading ELEMENT content model keyword",V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("EMPTY"!==e.readStr(5))return e.readUptoChar(">"),{elementName:n,contentModel:""};e.updateBufferBoundary(5)}else if("A"===i){if(!e.canRead(2))throw new R("Unexpected end of source reading ELEMENT content model keyword",V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if("ANY"!==e.readStr(3))return e.readUptoChar(">"),{elementName:n,contentModel:""};e.updateBufferBoundary(3)}else"("===i&&(e.updateBufferBoundary(1),e.readUptoChar(")"));return e.readUptoChar(">"),{elementName:n}}function It(t){t.source.readUptoChar(">")}function wt(t){const e=t.source;if(Ct(e),!e.canRead())throw new R("Unexpected end of source reading NOTATION name",V.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 n=e.readStr(r,s);if(!e.canRead())throw new R(`Unexpected end of source after NOTATION name "${n}"`,V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});if(St(n,t.xmlVersion),Ct(e),!e.canRead(5))throw new R("Unexpected end of source reading NOTATION identifier type",V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let i=e.readStr(6).toUpperCase();if("SYSTEM"===i)e.updateBufferBoundary(6),Ct(e),At(e,"systemIdentifier");else{if("PUBLIC"!==i)throw new R(`Expected SYSTEM or PUBLIC in NOTATION, found "${i}"`,V.INVALID_TAG,{line:e.line,col:e.cols,index:e.startIndex});{if(e.updateBufferBoundary(6),Ct(e),At(e,"publicIdentifier"),Ct(e),!e.canRead())throw new R("Unexpected end of source after NOTATION PUBLIC identifier",V.UNEXPECTED_END,{line:e.line,col:e.cols,index:e.startIndex});let t=e.readStr(1);'"'!==t&&"'"!==t||At(e,"systemIdentifier")}}e.readUptoChar(">")}function At(t,e){if(!t.canRead())throw new R(`Unexpected end of source reading ${e} opening quote`,V.UNEXPECTED_END,{line:t.line,col:t.cols,index:t.startIndex});let s=t.readStr(1);if('"'!==s&&"'"!==s)throw new R(`Expected quoted string for ${e}, found "${s}"`,V.INVALID_TAG,{line:t.line,col:t.cols,index:t.startIndex});return t.updateBufferBoundary(1),[t.readUptoChar(s)]}function Ct(t){for(;t.canRead();){const e=t.readChAt(0);if(" "!==e&&"\t"!==e&&"\n"!==e&&"\r"!==e)break;t.updateBufferBoundary(1)}}function St(t,e){if(ut(t,e))return t;throw new R(`Invalid entity name "${t}"`,V.ENTITY_INVALID_KEY,{})}const yt=Object.freeze({UNCLOSED_EOF:"unclosed-eof",MISMATCHED_CLOSE:"mismatched-close",PHANTOM_CLOSE:"phantom-close",PARTIAL_TAG:"partial-tag"});class Dt{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 R("Unexpected data in the end of document",V.UNEXPECTED_TRAILING_DATA);const{addTextNode:e,popTag:s}=t;let r=t.currentTagDetail;for(;r&&!r.root;)this._recordError(yt.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:n,addTextNode:i}=e;if("throw"===this.onMismatch)throw new R(`Unexpected closing tag '${t}' expecting '${r.name}'`,V.MISMATCHED_CLOSE_TAG,{line:n?n.line:void 0,col:n?n.cols:void 0,index:n?n.startIndex:void 0});if("discard"===this.onMismatch)return this._recordError(yt.MISMATCHED_CLOSE,{tag:t,expected:r.name,line:n?n.line:null,col:n?n.cols:null,index:n?n.startIndex:null}),{action:"discard"};const o=[...s,r];let a=-1;const h=o.length;for(let e=h-1;e>=0;e--)if(o[e].name===t){a=e;break}if(-1===a)return this._recordError(yt.PHANTOM_CLOSE,{tag:t,expected:r.name,line:n?n.line:null,col:n?n.cols:null,index:n?n.startIndex:null}),{action:"discard"};const c=h-1-a;for(let s=0;s<c;s++){const r=o[h-1-s];this._recordError(yt.MISMATCHED_CLOSE,{tag:r.name,expected:t,line:r.line,col:r.col,index:r.index}),i(),e.popTag()}return e.currentTagDetail=o[a],{action:"close-matched"}}handlePartialTag(t,e){this._recordError(yt.PARTIAL_TAG,{tag:bt(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 bt(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 Pt{constructor(t,e=0,s=0,r=0){this.name=t,this.line=e,this.col=s,this.index=r}}class Ut{constructor(t){this.options=t,this.currentTagDetail=null,this.tagTextData="",this.tagsStack=[],this.matcher=new xt,this.readonlyMatcher=this.matcher.readOnly(),this.autoCloseHandler=t.autoClose?new Dt(t.autoClose):null,this._unpairedSet=new Set(this.options.tags.unpaired),this.stopNodeExpressionsSet=this.options.tags.stopNodesSet??new $,this.skipTagExpressionsSet=this.options.skip.tagsSet??new $,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 xt,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 et(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 R("Unexpected end of source after '<'",V.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 R("Unexpected data in the end of document",V.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 R?t.code===V.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 R(`Unexpected end of source reading closing tag '</${r}'`,V.UNEXPECTED_END)}(this.source));if(this.isUnpaired(t)||this.isStopNode())throw new R(`Unexpected closing tag '${t}'`,V.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 R(`Unexpected closing tag '${t}' expecting '${this.currentTagDetail.name}'`,V.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(),ft(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=ft(this);const s=this.processTagName(e.tagName),r=new Pt(s,this.source.line,this.source.cols,this.source.startIndex),n=e.tagName.indexOf(":"),i=-1!==n?e.tagName.slice(0,n):void 0,o=void 0!==i?e.tagName.slice(n+1):s,a=t.limits?.maxNestedTags;if(null!=a){const t=this.tagsStack.length+1;if(t>a)throw new R(`Nesting depth ${t} exceeds limit of ${a} (tag: '${s}')`,V.LIMIT_MAX_NESTED_TAGS,{line:r.line,col:r.col,index:r.index})}let h={},c=0;e.rawAttributes&&(h=e.rawAttributes,c=e.rawAttributesLen),this.matcher.push(o,{},i),c>0&&this.matcher.updateCurrent(h);const l=this.isStopNode(),u=l?null:this.isSkipTag();if(t.skip.attributes||u||rt(e._attrsExp,this),this.isUnpaired(s))this.outputBuilder.addElement(r,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher),this.matcher.pop();else if(e.selfClosing)u||(this.outputBuilder.addElement(r,this.readonlyMatcher),this.outputBuilder.closeElement(this.readonlyMatcher)),this.matcher.pop();else if(l){this._stopNodeProcessor=new Et(e.tagName,{nested:l.nested,skipEnclosures:l.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(u)this._stopNodeProcessor=new Et(e.tagName,{nested:u.nested,skipEnclosures:u.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 R("Unexpected end of source after '<!'",V.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 R("Unexpected end of source reading comment",V.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if("-"!==t.source.readCh())throw new R(`Invalid comment expression at ${t.source.line}:${t.source.cols}`,V.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 R("Unexpected end of source reading CDATA preamble",V.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 R(`Invalid CDATA expression at ${t.source.line}:${t.source.cols}`,V.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 R("Unexpected end of source reading DOCTYPE preamble",V.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 R(`Invalid DOCTYPE expression at ${t.source.line}:${t.source.cols}`,V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const s=Object.create(null);let r=0,n=!1,i=!1;for(;t.source.canRead();){const e=t.source.startIndex;let o=t.source.readCh();if("<"===o&&n&&!i)try{if(!t.source.canRead())throw new R("Unexpected end of source reading DOCTYPE sub-tag",V.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 R(`Invalid DOCTYPE body tag starting with "<${e}"`,V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});if(!t.source.canRead())throw new R("Unexpected end of source reading DOCTYPE sub-tag type",V.UNEXPECTED_END,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});let n=t.source.readStr(1);if(t.source.updateBufferBoundary(1),"-"===n){if(!t.source.canRead())throw new R("Unexpected end of source reading DOCTYPE comment",V.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 R("Invalid comment in DOCTYPE",V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});t.source.readUpto("--\x3e")}else if("E"===n){if(!t.source.canRead())throw new R("Unexpected end of source reading DOCTYPE E-type sub-tag",V.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 R("Unexpected end of source reading DOCTYPE ENTITY keyword",V.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 R("Invalid DOCTYPE ENTITY expression",V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const[n,i]=Tt(t);if(-1===i.indexOf("&")){const e=t.options?.doctypeOptions;if(e?.maxEntityCount&&r>=e.maxEntityCount)throw new R(`Entity count (${r+1}) exceeds maximum allowed (${e.maxEntityCount})`,V.ENTITY_MAX_COUNT,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});const o=n.replace(/[.\-+*:]/g,"\\$&");s[n]={regx:RegExp(`&${o};`,"g"),val:i},r++}}else{if("L"!==e)throw new R(`Invalid DOCTYPE sub-tag "<!E${e}"`,V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(4))throw new R("Unexpected end of source reading DOCTYPE ELEMENT keyword",V.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 R("Invalid DOCTYPE ELEMENT expression",V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});Nt(t)}}}else if("A"===n){if(!t.source.canRead(5))throw new R("Unexpected end of source reading DOCTYPE ATTLIST keyword",V.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 R("Invalid DOCTYPE ATTLIST expression",V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});It(t)}else{if("N"!==n)throw new R(`Invalid DOCTYPE sub-tag "<!${n}"`,V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});{if(!t.source.canRead(6))throw new R("Unexpected end of source reading DOCTYPE NOTATION keyword",V.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 R("Invalid DOCTYPE NOTATION expression",V.INVALID_TAG,{line:t.source.line,col:t.source.cols,index:t.source.startIndex});wt(t)}}}catch(s){throw s.code===V.UNEXPECTED_END&&(t.source.startIndex=e),s}else if("["===o)n=!0;else if("]"===o)i=!0;else if(">"===o&&(!n||i))return s}throw new R("Unclosed DOCTYPE",V.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 R(`Invalid tag '<${t}'`,V.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,n=!1;for(e=0;t.source.canRead(e);e++){const i=t.source.readChAt(e),o=t.source.readChAt(e+1);if("'"!==i||r?'"'!==i||s||(r=!r):s=!s,!s&&!r&&"?"===i&&">"===o){n=!0;break}}if(!n)throw new R("Unexpected closing of source waiting for '?>'",V.UNEXPECTED_END);if(s||r)throw new R("Invalid attribute expression. Quote is not properly closed in PI tag expression",V.UNCLOSED_QUOTE);t.options.skip.attributes;const i=t.source.readStr(e);return t.source.updateBufferBoundary(e+2),pt(i,t)}(t);if(!s)throw new R("Invalid Pi Tag expression.",V.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||rt(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.tagTextData.trim().length>0&&this.outputBuilder.addValue(this.tagTextData,this.readonlyMatcher),this.tagTextData="")}processAttrName(t){const e=this.options;if(t=kt(t,e.skip.nsPrefix),!dt(t,this.xmlVersion))throw new R(`Invalid attribute name: ${t}`,V.INVALID_ATTRIBUTE_NAME);if(t=vt(t,e.onDangerousProperty),e.strictReservedNames&&t===e.attributes.groupBy)throw new R(`Restricted attribute name: ${t}`,V.SECURITY_RESTRICTED_NAME);return t}processTagName(t){const e=this.options,s=e.nameFor;if(t=vt(t=kt(t,e.skip.nsPrefix),e.onDangerousProperty),e.strictReservedNames&&(t===s.comment||t===s.cdata||t===s.text))throw new R(`Restricted tag name: ${t}`,V.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 kt(t,e){if(e){const e=t.split(":");if(2===e.length)return"xmlns"!==e[0]&&e[1];if(e.length>2)throw new R(`Multiple namespaces in name: ${t}`,V.MULTIPLE_NAMESPACES)}return t}function vt(t,e){if(G.includes(t))throw new R(`[SECURITY] Invalid name: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`,V.SECURITY_PROTOTYPE_POLLUTION);return F.includes(t)?e(t):t}class Ot{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 R(`Buffer size limit exceeded (${s+e.length} > ${this.maxBufferSize}). Increase feedable.maxBufferSize or reduce chunk size.`,V.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 n=0;n<s;n++)if(this.buffer[r+n]!==t[n]){e=!1;break}if(e){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=r+s,t}}throw new R(`Unexpected end of source reading '${t}'`,V.UNEXPECTED_END)}readUptoChar(t){const e=this.buffer.indexOf(t,this.startIndex);if(-1===e)throw new R(`Unexpected end of source reading '${t}'`,V.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,n=0;for(let i=this.startIndex;i<e;i++){if(1===n){const t=this.buffer[i];if(" "===t||"\t"===t)continue;">"===t?n=2:(n=0,r=-1)}else{let e=!0;for(let r=0;r<s;r++)if(this.buffer[i+r]!==t[r]){e=!1;break}e&&(n=1,r=i,i+=s-1)}if(2===n){const t=this.buffer.substring(this.startIndex,r);return this.startIndex=i+1,t}}throw new R(`Unexpected end of source reading '${t}'`,V.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 Mt extends Ot{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 Lt{constructor(t){this.options=Z(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 R("XML data must be a string or Buffer.",V.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 R("XML data must be a Uint8Array or ArrayBufferView.",V.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 R("parseStream() requires a Node.js Readable stream.",V.INVALID_STREAM);var e;const s=new Mt(this.options.feedable),r=this._createParser();return r.source=s,r.initializeParser(),new Promise((e,n)=>{let i=!1;const o=e=>{i||(i=!0,t.destroy(),n(e))};s.attachStream(t,t=>{if(t)o(t);else try{r.parseXml()}catch(t){t.code===V.UNEXPECTED_END?s.rewindToMark():o(t)}},()=>{if(!i)try{r.finalizeXml(),this._lastParseErrors=r.autoCloseHandler?.getErrors()??[],i=!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!==V.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 R("feed() data must be a string or Buffer.",V.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 R("No data fed. Call feed() before end().",V.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!==V.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 Ut(this.options)}_initFeedSession(){this._feedSource=new Ot(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.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Fastest XML parser in pure JS with fully customizable ouput",
|
|
5
5
|
"main": "./lib/fxp.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -44,16 +44,17 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@nodable/base-output-builder": "^1.0.
|
|
48
|
-
"@nodable/compact-builder": "^1.0.
|
|
47
|
+
"@nodable/base-output-builder": "^1.0.6",
|
|
48
|
+
"@nodable/compact-builder": "^1.0.9",
|
|
49
49
|
"path-expression-matcher": "^1.5.0",
|
|
50
|
-
"
|
|
50
|
+
"xml-naming": "^0.1.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@babel/core": "^7.29.0",
|
|
54
54
|
"@babel/plugin-transform-runtime": "^7.29.0",
|
|
55
55
|
"@babel/preset-env": "^7.29.2",
|
|
56
56
|
"@babel/register": "^7.28.6",
|
|
57
|
+
"@byspec/xml": "^0.1.0",
|
|
57
58
|
"@nodable/entities": "^2.1.0",
|
|
58
59
|
"@types/node": "^20.19.37",
|
|
59
60
|
"babel-loader": "^10.1.1",
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
"webpack-cli": "^7.0.2"
|
|
65
66
|
},
|
|
66
67
|
"files": [
|
|
68
|
+
"lib/fxp.cjs",
|
|
67
69
|
"lib/fxp.d.cts",
|
|
68
70
|
"src",
|
|
69
71
|
"CHANGELOG.md"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { ParseError, ErrorCode } from './ParseError.js';
|
|
3
|
+
import { isSpaceCode } from "./util.js"
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* AttributeProcessor — owns all attribute parsing logic.
|
|
@@ -21,9 +22,87 @@ import { ParseError, ErrorCode } from './ParseError.js';
|
|
|
21
22
|
* complete attribute context when value parsers execute.
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
|
-
// Module-level regex
|
|
25
|
-
//
|
|
26
|
-
|
|
25
|
+
// Module-level regex kept for reference only — no longer called from this
|
|
26
|
+
// module. parseAttributes() below replaces it with an O(n) linear scanner
|
|
27
|
+
// that is immune to catastrophic backtracking and stack overflow.
|
|
28
|
+
// const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse an attribute expression string into an array of match tuples.
|
|
32
|
+
*
|
|
33
|
+
* Each element has the same shape the old getAllMatches() returned so that
|
|
34
|
+
* callers are unchanged:
|
|
35
|
+
* [fullMatch, name, '=value' | undefined, quote | undefined, value | undefined]
|
|
36
|
+
*
|
|
37
|
+
* The implementation is a single O(n) pass over char codes with no regex and
|
|
38
|
+
* no recursion, making it safe for arbitrarily long attribute strings.
|
|
39
|
+
*
|
|
40
|
+
* State machine:
|
|
41
|
+
* SEEK_NAME — skipping whitespace looking for the start of an attr name
|
|
42
|
+
* IN_NAME — accumulating a name token until whitespace or '='
|
|
43
|
+
* SEEK_VALUE — saw name + optional whitespace, now expecting '=' or next name
|
|
44
|
+
* IN_VALUE — inside a quoted value, accumulating until the closing quote
|
|
45
|
+
*
|
|
46
|
+
* @param {string} attrStr
|
|
47
|
+
* @returns {Array} array of match tuples (see shape above)
|
|
48
|
+
*/
|
|
49
|
+
function parseAttributes(attrStr) {
|
|
50
|
+
const results = [];
|
|
51
|
+
const len = attrStr.length;
|
|
52
|
+
let i = 0;
|
|
53
|
+
|
|
54
|
+
while (i < len) {
|
|
55
|
+
// Skip whitespace between attributes
|
|
56
|
+
while (i < len && isSpaceCode(attrStr.charCodeAt(i))) i++;
|
|
57
|
+
if (i >= len) break;
|
|
58
|
+
|
|
59
|
+
// Read name
|
|
60
|
+
const nameStart = i;
|
|
61
|
+
while (i < len && attrStr.charCodeAt(i) !== 61 && !isSpaceCode(attrStr.charCodeAt(i))) i++;
|
|
62
|
+
const name = attrStr.substring(nameStart, i);
|
|
63
|
+
|
|
64
|
+
// Skip whitespace before '='
|
|
65
|
+
while (i < len && isSpaceCode(attrStr.charCodeAt(i))) i++;
|
|
66
|
+
|
|
67
|
+
if (i >= len || attrStr.charCodeAt(i) !== 61) {
|
|
68
|
+
// Boolean attribute — no '='
|
|
69
|
+
const m = [name, name, undefined, undefined, undefined];
|
|
70
|
+
m.startIndex = nameStart;
|
|
71
|
+
results.push(m);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
i++; // skip '='
|
|
76
|
+
|
|
77
|
+
// Skip whitespace after '='
|
|
78
|
+
while (i < len && isSpaceCode(attrStr.charCodeAt(i))) i++;
|
|
79
|
+
|
|
80
|
+
// Read quoted value
|
|
81
|
+
const quote = attrStr.charCodeAt(i);
|
|
82
|
+
if (quote === 34 || quote === 39) { // " or '
|
|
83
|
+
i++; // skip opening quote
|
|
84
|
+
const valueStart = i;
|
|
85
|
+
let value = '';
|
|
86
|
+
let segStart = i;
|
|
87
|
+
while (i < len && attrStr.charCodeAt(i) !== quote) {
|
|
88
|
+
const c = attrStr.charCodeAt(i);
|
|
89
|
+
if (c === 10 || c === 13) { // \n or \r → space per XML §3.3.3
|
|
90
|
+
value += attrStr.substring(segStart, i) + ' ';
|
|
91
|
+
segStart = i + 1;
|
|
92
|
+
}
|
|
93
|
+
i++;
|
|
94
|
+
}
|
|
95
|
+
value += attrStr.substring(segStart, i);
|
|
96
|
+
i++; // skip closing quote
|
|
97
|
+
const quoteChar = String.fromCharCode(quote);
|
|
98
|
+
const m = [name + '=' + quoteChar + value + quoteChar, name, '=' + quoteChar + value + quoteChar, quoteChar, value];
|
|
99
|
+
m.startIndex = nameStart;
|
|
100
|
+
results.push(m);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return results;
|
|
105
|
+
}
|
|
27
106
|
|
|
28
107
|
/**
|
|
29
108
|
* Pass 1: extract raw (unparsed) attribute values into rawAttributes.
|
|
@@ -33,9 +112,9 @@ const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm
|
|
|
33
112
|
* @param {object} tagExp - tagExp object to populate rawAttributes (Object.create(null))
|
|
34
113
|
*/
|
|
35
114
|
export function collectRawAttributes(attrStr, parser, tagExp) {
|
|
36
|
-
|
|
37
115
|
if (!attrStr || attrStr.length === 0) return;
|
|
38
|
-
|
|
116
|
+
|
|
117
|
+
const matches = parseAttributes(attrStr);
|
|
39
118
|
const len = matches.length;
|
|
40
119
|
let count = 0;
|
|
41
120
|
for (let i = 0; i < len; i++) {
|
|
@@ -56,7 +135,7 @@ export function collectRawAttributes(attrStr, parser, tagExp) {
|
|
|
56
135
|
*/
|
|
57
136
|
export function flushAttributes(attrStr, parser) {
|
|
58
137
|
if (!attrStr || attrStr.length === 0) return;
|
|
59
|
-
const matches =
|
|
138
|
+
const matches = parseAttributes(attrStr);
|
|
60
139
|
const len = matches.length;
|
|
61
140
|
|
|
62
141
|
const maxAttrs = parser.options.limits?.maxAttributesPerTag;
|
|
@@ -78,30 +157,4 @@ export function flushAttributes(attrStr, parser) {
|
|
|
78
157
|
|
|
79
158
|
parser.outputBuilder.addAttribute(attrName, attrVal, parser.readonlyMatcher);
|
|
80
159
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Run the regex against the string and return all capture groups.
|
|
85
|
-
* lastIndex is always reset to 0 before iterating so the module-level
|
|
86
|
-
* stateful regex is safe to share across calls.
|
|
87
|
-
*
|
|
88
|
-
* @param {string} string
|
|
89
|
-
* @param {RegExp} regex
|
|
90
|
-
* @returns {Array}
|
|
91
|
-
*/
|
|
92
|
-
function getAllMatches(string, regex) {
|
|
93
|
-
regex.lastIndex = 0;
|
|
94
|
-
const matches = [];
|
|
95
|
-
let match = regex.exec(string);
|
|
96
|
-
while (match) {
|
|
97
|
-
const allmatches = [];
|
|
98
|
-
allmatches.startIndex = regex.lastIndex - match[0].length;
|
|
99
|
-
const len = match.length;
|
|
100
|
-
for (let index = 0; index < len; index++) {
|
|
101
|
-
allmatches.push(match[index]);
|
|
102
|
-
}
|
|
103
|
-
matches.push(allmatches);
|
|
104
|
-
match = regex.exec(string);
|
|
105
|
-
}
|
|
106
|
-
return matches;
|
|
107
160
|
}
|
package/src/DocTypeReader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isName } from './util.js';
|
|
2
1
|
import { ParseError, ErrorCode } from './ParseError.js';
|
|
2
|
+
import { name as isName, qName as isQName } from 'xml-naming';
|
|
3
3
|
|
|
4
4
|
export function readDocType(parser) {
|
|
5
5
|
parser.source.markTokenStart(1);
|
|
@@ -267,7 +267,7 @@ function readEntityExp(parser) {
|
|
|
267
267
|
{ line: source.line, col: source.cols, index: source.startIndex });
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
validateEntityName(entityName);
|
|
270
|
+
validateEntityName(entityName, parser.xmlVersion);
|
|
271
271
|
skipSourceWhitespace(source);
|
|
272
272
|
|
|
273
273
|
if (!source.canRead()) {
|
|
@@ -346,7 +346,7 @@ function readElementExp(parser) {
|
|
|
346
346
|
{ line: source.line, col: source.cols, index: source.startIndex });
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
if (!isName(elementName)) {
|
|
349
|
+
if (!isName(elementName, parser.xmlVersion)) {
|
|
350
350
|
throw new ParseError(`Invalid element name: "${elementName}"`,
|
|
351
351
|
ErrorCode.INVALID_TAG,
|
|
352
352
|
{ line: source.line, col: source.cols, index: source.startIndex });
|
|
@@ -434,7 +434,7 @@ function readNotationExp(parser) {
|
|
|
434
434
|
{ line: source.line, col: source.cols, index: source.startIndex });
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
-
validateEntityName(notationName);
|
|
437
|
+
validateEntityName(notationName, parser.xmlVersion);
|
|
438
438
|
skipSourceWhitespace(source);
|
|
439
439
|
|
|
440
440
|
// Need all 6 chars of "SYSTEM" / "PUBLIC" before we can classify
|
|
@@ -512,8 +512,8 @@ function skipSourceWhitespace(source) {
|
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
function validateEntityName(name) {
|
|
516
|
-
if (isName(name)) return name;
|
|
515
|
+
function validateEntityName(name, xmlVersion) {
|
|
516
|
+
if (isName(name, xmlVersion)) return name;
|
|
517
517
|
throw new ParseError(
|
|
518
518
|
`Invalid entity name "${name}"`,
|
|
519
519
|
ErrorCode.ENTITY_INVALID_KEY,
|
package/src/OptionsBuilder.js
CHANGED
package/src/XMLParser.js
CHANGED
|
@@ -13,6 +13,10 @@ export default class XMLParser {
|
|
|
13
13
|
this._feedParser = null;
|
|
14
14
|
this._feedSource = null;
|
|
15
15
|
this._isFeeding = false;
|
|
16
|
+
|
|
17
|
+
// ── Batching state ──────────────────────────────────
|
|
18
|
+
this._pendingBytes = 0;
|
|
19
|
+
this._batchThreshold = this.options.feedable?.bufferSize;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
// ─── One-shot parse methods ───────────────────────────────────────────────
|
|
@@ -126,6 +130,37 @@ export default class XMLParser {
|
|
|
126
130
|
|
|
127
131
|
// ─── Incremental feed()/end() API ────────────────────────────────────────
|
|
128
132
|
|
|
133
|
+
_runParse() {
|
|
134
|
+
if (!this._feedParser) return;
|
|
135
|
+
|
|
136
|
+
const beforePos = this._feedSource.startIndex; // bytes consumed so far
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
this._feedParser.parseXml();
|
|
140
|
+
} catch (err) {
|
|
141
|
+
if (err.code === ErrorCode.UNEXPECTED_END) {
|
|
142
|
+
this._feedSource.rewindToMark();
|
|
143
|
+
} else {
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const afterPos = this._feedSource.startIndex;
|
|
149
|
+
const didAdvance = afterPos > beforePos;
|
|
150
|
+
|
|
151
|
+
if (didAdvance) {
|
|
152
|
+
// Real progress made — reset threshold normally
|
|
153
|
+
this._pendingBytes = 0;
|
|
154
|
+
} else {
|
|
155
|
+
// Parser is stuck mid-token — grow the threshold to avoid
|
|
156
|
+
// hammering parseXml() until significantly more data arrives
|
|
157
|
+
this._batchThreshold = Math.min(
|
|
158
|
+
this._batchThreshold * 2,
|
|
159
|
+
this.options.feedable.maxBufferSize
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
129
164
|
/**
|
|
130
165
|
* Feed an XML data chunk for incremental parsing.
|
|
131
166
|
*
|
|
@@ -160,20 +195,12 @@ export default class XMLParser {
|
|
|
160
195
|
}
|
|
161
196
|
|
|
162
197
|
this._feedSource.feed(str);
|
|
198
|
+
this._pendingBytes += str.length;
|
|
163
199
|
|
|
164
|
-
|
|
165
|
-
this.
|
|
166
|
-
} catch (err) {
|
|
167
|
-
if (err.code === ErrorCode.UNEXPECTED_END) {
|
|
168
|
-
// Chunk boundary fell mid-token. Rewind to the token start so the
|
|
169
|
-
// incomplete bytes are re-parsed when the next chunk arrives.
|
|
170
|
-
this._feedSource.rewindToMark();
|
|
171
|
-
} else {
|
|
172
|
-
// Real parse error — clean up and propagate.
|
|
173
|
-
this._cleanupFeedSession();
|
|
174
|
-
throw err;
|
|
175
|
-
}
|
|
200
|
+
if (this._pendingBytes >= this._batchThreshold) {
|
|
201
|
+
this._runParse();
|
|
176
202
|
}
|
|
203
|
+
// Otherwise, delay parsing until next feed() or end()
|
|
177
204
|
|
|
178
205
|
return this;
|
|
179
206
|
}
|
|
@@ -201,6 +228,9 @@ export default class XMLParser {
|
|
|
201
228
|
throw new ParseError('No data fed. Call feed() before end().', ErrorCode.NOT_STREAMING);
|
|
202
229
|
}
|
|
203
230
|
|
|
231
|
+
// Force a final parse (any pending bytes are now processed)
|
|
232
|
+
this._runParse();
|
|
233
|
+
|
|
204
234
|
try {
|
|
205
235
|
// Mark the source as complete so readers know there is no more data.
|
|
206
236
|
this._feedSource.end();
|
package/src/Xml2JsParser.js
CHANGED
|
@@ -5,9 +5,10 @@ import { StopNodeProcessor } from './StopNodeProcessor.js';
|
|
|
5
5
|
import { readComment, readCdata, readPiTag } from './XmlSpecialTagsReader.js';
|
|
6
6
|
import { Expression, ExpressionSet, Matcher } from 'path-expression-matcher';
|
|
7
7
|
import { readDocType } from './DocTypeReader.js';
|
|
8
|
-
import {
|
|
8
|
+
import { DANGEROUS_PROPERTY_NAMES, criticalProperties } from './util.js';
|
|
9
9
|
import AutoCloseHandler from './AutoCloseHandler.js';
|
|
10
10
|
import { ParseError, ErrorCode } from './ParseError.js';
|
|
11
|
+
import { name as isName, qName as isQName } from 'xml-naming';
|
|
11
12
|
|
|
12
13
|
class TagDetail {
|
|
13
14
|
/**
|
|
@@ -60,6 +61,7 @@ export default class Xml2JsParser {
|
|
|
60
61
|
this.tagsStack = [];
|
|
61
62
|
this._stopNodeProcessor = null;
|
|
62
63
|
this._exitIfTriggered = false;
|
|
64
|
+
this.xmlVersion = '1.0';
|
|
63
65
|
|
|
64
66
|
if (!this.matcher) {
|
|
65
67
|
this.matcher = new Matcher();
|
|
@@ -283,6 +285,18 @@ export default class Xml2JsParser {
|
|
|
283
285
|
this.source.startIndex,
|
|
284
286
|
);
|
|
285
287
|
|
|
288
|
+
// Extract namespace prefix and local name from raw tag name (e.g. "ns:tag" → "ns", "tag").
|
|
289
|
+
// Always done from the raw name (tagExp.tagName), before processTagName strips the prefix,
|
|
290
|
+
// so these values are stable regardless of skip.nsPrefix.
|
|
291
|
+
const colonIdx = tagExp.tagName.indexOf(':');
|
|
292
|
+
const tagNamespace = colonIdx !== -1 ? tagExp.tagName.slice(0, colonIdx) : undefined;
|
|
293
|
+
// Local name for the matcher: prefix-free always (e.g. "code" from "ns:code").
|
|
294
|
+
// The matcher library tracks namespace separately via the 3rd push() argument —
|
|
295
|
+
// passing the full "ns:code" as the tag name would break ns::code expression matching.
|
|
296
|
+
const matcherTagName = tagNamespace !== undefined
|
|
297
|
+
? tagExp.tagName.slice(colonIdx + 1)
|
|
298
|
+
: processedTagName;
|
|
299
|
+
|
|
286
300
|
// ── Limit: maxNestedTags ─────────────────────────────────────────────────
|
|
287
301
|
const maxNested = options.limits?.maxNestedTags;
|
|
288
302
|
if (maxNested !== undefined && maxNested !== null) {
|
|
@@ -304,7 +318,7 @@ export default class Xml2JsParser {
|
|
|
304
318
|
raeAttrLen = tagExp.rawAttributesLen;
|
|
305
319
|
}
|
|
306
320
|
|
|
307
|
-
this.matcher.push(
|
|
321
|
+
this.matcher.push(matcherTagName, {}, tagNamespace);
|
|
308
322
|
if (raeAttrLen > 0) {
|
|
309
323
|
this.matcher.updateCurrent(rawAttributes);
|
|
310
324
|
}
|
|
@@ -334,7 +348,10 @@ export default class Xml2JsParser {
|
|
|
334
348
|
this.matcher.pop();
|
|
335
349
|
} else if (stopNodeConfig) {
|
|
336
350
|
// Create a fresh processor with the matching nested + skipEnclosures config.
|
|
337
|
-
|
|
351
|
+
// Raw tag name (tagExp.tagName) is used — the processor scans the source
|
|
352
|
+
// character-by-character and must match the prefix-as-written (e.g. "ns:code"),
|
|
353
|
+
// independent of what skip.nsPrefix does to the processed output name.
|
|
354
|
+
this._stopNodeProcessor = new StopNodeProcessor(tagExp.tagName, {
|
|
338
355
|
nested: stopNodeConfig.nested,
|
|
339
356
|
skipEnclosures: stopNodeConfig.skipEnclosures,
|
|
340
357
|
});
|
|
@@ -351,7 +368,8 @@ export default class Xml2JsParser {
|
|
|
351
368
|
} else if (skipTagConfig) {
|
|
352
369
|
// Skip tag: collect raw content (to advance the source past the closing tag)
|
|
353
370
|
// but call no output builder methods — the tag is silently dropped.
|
|
354
|
-
|
|
371
|
+
// Raw tag name used for the same reason as the stop-node branch above.
|
|
372
|
+
this._stopNodeProcessor = new StopNodeProcessor(tagExp.tagName, {
|
|
355
373
|
nested: skipTagConfig.nested,
|
|
356
374
|
skipEnclosures: skipTagConfig.skipEnclosures,
|
|
357
375
|
});
|
|
@@ -460,7 +478,7 @@ export default class Xml2JsParser {
|
|
|
460
478
|
processAttrName(attrName) {
|
|
461
479
|
const options = this.options;
|
|
462
480
|
attrName = resolveNsPrefix(attrName, options.skip.nsPrefix);
|
|
463
|
-
if (!
|
|
481
|
+
if (!isQName(attrName, this.xmlVersion)) { //TODO: make it optional
|
|
464
482
|
throw new ParseError(`Invalid attribute name: ${attrName}`, ErrorCode.INVALID_ATTRIBUTE_NAME);
|
|
465
483
|
}
|
|
466
484
|
attrName = sanitizeName(attrName, options.onDangerousProperty);
|
package/src/XmlPartReader.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { ParseError, ErrorCode } from './ParseError.js';
|
|
3
3
|
import { collectRawAttributes } from './AttributeProcessor.js';
|
|
4
|
-
import {
|
|
4
|
+
import { isSpace } from "./util.js"
|
|
5
|
+
import { name as isName, qName as isQName } from 'xml-naming';
|
|
5
6
|
// Re-export flushAttributes so Xml2JsParser and XmlSpecialTagsReader can
|
|
6
7
|
// continue to import it from here without changing their import lines.
|
|
7
8
|
export { flushAttributes } from './AttributeProcessor.js';
|
|
@@ -157,19 +158,20 @@ function buildTagExpObj(exp, parser) {
|
|
|
157
158
|
let attrsExp = "";
|
|
158
159
|
let i = 0;
|
|
159
160
|
|
|
160
|
-
for (; i <
|
|
161
|
-
|
|
161
|
+
for (; i < exp.length; i++) {
|
|
162
|
+
const c = exp[i];
|
|
163
|
+
if (isSpace(c)) {
|
|
162
164
|
tagExp.tagName = exp.substring(0, i);
|
|
163
165
|
attrsExp = exp.substring(i + 1);
|
|
164
166
|
break;
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
//only tag
|
|
168
|
-
if (tagExp.tagName.length === 0 && i ===
|
|
170
|
+
if (tagExp.tagName.length === 0 && i === exp.length) tagExp.tagName = exp;
|
|
169
171
|
tagExp.tagName = tagExp.tagName.trimEnd();
|
|
170
172
|
tagExp._attrsExp = attrsExp;
|
|
171
173
|
|
|
172
|
-
if (!
|
|
174
|
+
if (!isQName(tagExp.tagName, parser.xmlVersion)) {
|
|
173
175
|
throw new ParseError("Invalid tag name", ErrorCode.INVALID_TAG_NAME);
|
|
174
176
|
}
|
|
175
177
|
|
|
@@ -178,6 +180,7 @@ function buildTagExpObj(exp, parser) {
|
|
|
178
180
|
if (!parser.options.skip.attributes && attrsExp.length > 0) {
|
|
179
181
|
collectRawAttributes(attrsExp, parser, tagExp);
|
|
180
182
|
}
|
|
181
|
-
|
|
183
|
+
// console.log(tagExp)
|
|
182
184
|
return tagExp;
|
|
183
|
-
}
|
|
185
|
+
}
|
|
186
|
+
|
|
@@ -36,11 +36,21 @@ export function readPiTag(parser) {
|
|
|
36
36
|
parser.source.markTokenStart(1);
|
|
37
37
|
//<? already consumed
|
|
38
38
|
let tagExp = readPiExp(parser, "?>");
|
|
39
|
-
if (!tagExp)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
if (!tagExp) {
|
|
40
|
+
throw new ParseError(
|
|
41
|
+
"Invalid Pi Tag expression.",
|
|
42
|
+
ErrorCode.INVALID_TAG,
|
|
43
|
+
{ line: parser.source.line, col: parser.source.cols, index: parser.source.startIndex }
|
|
44
|
+
)
|
|
45
|
+
} else if (tagExp.tagName === "xml") {
|
|
46
|
+
// Read version from the declaration and store it on the parser for validators.
|
|
47
|
+
const version = tagExp.rawAttributes?.version;
|
|
48
|
+
if (version === '1.1') {
|
|
49
|
+
parser.xmlVersion = 1.1;
|
|
50
|
+
} else {
|
|
51
|
+
parser.xmlVersion = 1.0; // default
|
|
52
|
+
}
|
|
53
|
+
}
|
|
44
54
|
|
|
45
55
|
// Flush attributes into the output builder's this.attributes accumulator
|
|
46
56
|
// so addDeclaration() / addInstruction() pick them up, mirroring what readOpeningTag
|
package/src/util.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
|
|
4
|
-
const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
|
|
5
|
-
export const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*';
|
|
6
|
-
const regexName = new RegExp('^' + nameRegexp + '$');
|
|
7
|
-
|
|
8
1
|
export function getAllMatches(string, regex) {
|
|
9
2
|
const matches = [];
|
|
10
3
|
let match = regex.exec(string);
|
|
@@ -21,9 +14,15 @@ export function getAllMatches(string, regex) {
|
|
|
21
14
|
return matches;
|
|
22
15
|
}
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export function isSpace(char) {
|
|
20
|
+
return char === " " || char === "\t" || char === "\n" || char === "\r" || char === "\f";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
export function isSpaceCode(code) {
|
|
25
|
+
return code === 32 || code === 9 || code === 10 || code === 13 || code === 12; // space \t \n \r \f
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export function isExist(v) {
|