scream-code 0.17.3 → 0.17.6

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.
@@ -4,7 +4,7 @@ import { dirname as __cjsShimDirname } from 'node:path';
4
4
  const __filename = __cjsShimFileURLToPath(import.meta.url);
5
5
  const __dirname = __cjsShimDirname(__filename);
6
6
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
7
- import { t as require_base64_js } from "./base64-js-DzVmk6Nb.mjs";
7
+ import { n as require_base64_js, t as XMLParser } from "./XMLParser-DFAnGqkc.mjs";
8
8
  import * as fs$1 from "node:fs/promises";
9
9
  import * as path$1 from "node:path";
10
10
  import { createRequire } from "module";
@@ -49834,3867 +49834,6 @@ var DocxConverter = class {
49834
49834
  }
49835
49835
  };
49836
49836
  //#endregion
49837
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/util.js
49838
- const regexName = /* @__PURE__ */ new RegExp("^[: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][: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\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$");
49839
- function getAllMatches(string, regex) {
49840
- const matches = [];
49841
- let match = regex.exec(string);
49842
- while (match) {
49843
- const allmatches = [];
49844
- allmatches.startIndex = regex.lastIndex - match[0].length;
49845
- const len = match.length;
49846
- for (let index = 0; index < len; index++) allmatches.push(match[index]);
49847
- matches.push(allmatches);
49848
- match = regex.exec(string);
49849
- }
49850
- return matches;
49851
- }
49852
- const isName = function(string) {
49853
- const match = regexName.exec(string);
49854
- return !(match === null || typeof match === "undefined");
49855
- };
49856
- function isExist(v) {
49857
- return typeof v !== "undefined";
49858
- }
49859
- /**
49860
- * Dangerous property names that could lead to prototype pollution or security issues
49861
- */
49862
- const DANGEROUS_PROPERTY_NAMES = [
49863
- "hasOwnProperty",
49864
- "toString",
49865
- "valueOf",
49866
- "__defineGetter__",
49867
- "__defineSetter__",
49868
- "__lookupGetter__",
49869
- "__lookupSetter__"
49870
- ];
49871
- const criticalProperties = [
49872
- "__proto__",
49873
- "constructor",
49874
- "prototype"
49875
- ];
49876
- //#endregion
49877
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/validator.js
49878
- const defaultOptions$1 = {
49879
- allowBooleanAttributes: false,
49880
- unpairedTags: []
49881
- };
49882
- function validate(xmlData, options) {
49883
- options = Object.assign({}, defaultOptions$1, options);
49884
- const tags = [];
49885
- let tagFound = false;
49886
- let reachedRoot = false;
49887
- if (xmlData[0] === "") xmlData = xmlData.substr(1);
49888
- for (let i = 0; i < xmlData.length; i++) if (xmlData[i] === "<" && xmlData[i + 1] === "?") {
49889
- i += 2;
49890
- i = readPI(xmlData, i);
49891
- if (i.err) return i;
49892
- } else if (xmlData[i] === "<") {
49893
- let tagStartPos = i;
49894
- i++;
49895
- if (xmlData[i] === "!") {
49896
- i = readCommentAndCDATA(xmlData, i);
49897
- continue;
49898
- } else {
49899
- let closingTag = false;
49900
- if (xmlData[i] === "/") {
49901
- closingTag = true;
49902
- i++;
49903
- }
49904
- let tagName = "";
49905
- for (; i < xmlData.length && xmlData[i] !== ">" && xmlData[i] !== " " && xmlData[i] !== " " && xmlData[i] !== "\n" && xmlData[i] !== "\r"; i++) tagName += xmlData[i];
49906
- tagName = tagName.trim();
49907
- if (tagName[tagName.length - 1] === "/") {
49908
- tagName = tagName.substring(0, tagName.length - 1);
49909
- i--;
49910
- }
49911
- if (!validateTagName(tagName)) {
49912
- let msg;
49913
- if (tagName.trim().length === 0) msg = "Invalid space after '<'.";
49914
- else msg = "Tag '" + tagName + "' is an invalid name.";
49915
- return getErrorObject("InvalidTag", msg, getLineNumberForPosition(xmlData, i));
49916
- }
49917
- const result = readAttributeStr(xmlData, i);
49918
- if (result === false) return getErrorObject("InvalidAttr", "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i));
49919
- let attrStr = result.value;
49920
- i = result.index;
49921
- if (attrStr[attrStr.length - 1] === "/") {
49922
- const attrStrStart = i - attrStr.length;
49923
- attrStr = attrStr.substring(0, attrStr.length - 1);
49924
- const isValid = validateAttributeString(attrStr, options);
49925
- if (isValid === true) tagFound = true;
49926
- else return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
49927
- } else if (closingTag) if (!result.tagClosed) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
49928
- else if (attrStr.trim().length > 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
49929
- else if (tags.length === 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
49930
- else {
49931
- const otg = tags.pop();
49932
- if (tagName !== otg.tagName) {
49933
- let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
49934
- return getErrorObject("InvalidTag", "Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.", getLineNumberForPosition(xmlData, tagStartPos));
49935
- }
49936
- if (tags.length == 0) reachedRoot = true;
49937
- }
49938
- else {
49939
- const isValid = validateAttributeString(attrStr, options);
49940
- if (isValid !== true) return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
49941
- if (reachedRoot === true) return getErrorObject("InvalidXml", "Multiple possible root nodes found.", getLineNumberForPosition(xmlData, i));
49942
- else if (options.unpairedTags.indexOf(tagName) !== -1) {} else tags.push({
49943
- tagName,
49944
- tagStartPos
49945
- });
49946
- tagFound = true;
49947
- }
49948
- for (i++; i < xmlData.length; i++) if (xmlData[i] === "<") if (xmlData[i + 1] === "!") {
49949
- i++;
49950
- i = readCommentAndCDATA(xmlData, i);
49951
- continue;
49952
- } else if (xmlData[i + 1] === "?") {
49953
- i = readPI(xmlData, ++i);
49954
- if (i.err) return i;
49955
- } else break;
49956
- else if (xmlData[i] === "&") {
49957
- const afterAmp = validateAmpersand(xmlData, i);
49958
- if (afterAmp == -1) return getErrorObject("InvalidChar", "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
49959
- i = afterAmp;
49960
- } else if (reachedRoot === true && !isWhiteSpace(xmlData[i])) return getErrorObject("InvalidXml", "Extra text at the end", getLineNumberForPosition(xmlData, i));
49961
- if (xmlData[i] === "<") i--;
49962
- }
49963
- } else {
49964
- if (isWhiteSpace(xmlData[i])) continue;
49965
- return getErrorObject("InvalidChar", "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i));
49966
- }
49967
- if (!tagFound) return getErrorObject("InvalidXml", "Start tag expected.", 1);
49968
- else if (tags.length == 1) return getErrorObject("InvalidTag", "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
49969
- else if (tags.length > 0) return getErrorObject("InvalidXml", "Invalid '" + JSON.stringify(tags.map((t) => t.tagName), null, 4).replace(/\r?\n/g, "") + "' found.", {
49970
- line: 1,
49971
- col: 1
49972
- });
49973
- return true;
49974
- }
49975
- function isWhiteSpace(char) {
49976
- return char === " " || char === " " || char === "\n" || char === "\r";
49977
- }
49978
- /**
49979
- * Read Processing insstructions and skip
49980
- * @param {*} xmlData
49981
- * @param {*} i
49982
- */
49983
- function readPI(xmlData, i) {
49984
- const start = i;
49985
- for (; i < xmlData.length; i++) if (xmlData[i] == "?" || xmlData[i] == " ") {
49986
- const tagname = xmlData.substr(start, i - start);
49987
- if (i > 5 && tagname === "xml") return getErrorObject("InvalidXml", "XML declaration allowed only at the start of the document.", getLineNumberForPosition(xmlData, i));
49988
- else if (xmlData[i] == "?" && xmlData[i + 1] == ">") {
49989
- i++;
49990
- break;
49991
- } else continue;
49992
- }
49993
- return i;
49994
- }
49995
- function readCommentAndCDATA(xmlData, i) {
49996
- if (xmlData.length > i + 5 && xmlData[i + 1] === "-" && xmlData[i + 2] === "-") {
49997
- for (i += 3; i < xmlData.length; i++) if (xmlData[i] === "-" && xmlData[i + 1] === "-" && xmlData[i + 2] === ">") {
49998
- i += 2;
49999
- break;
50000
- }
50001
- } else if (xmlData.length > i + 8 && xmlData[i + 1] === "D" && xmlData[i + 2] === "O" && xmlData[i + 3] === "C" && xmlData[i + 4] === "T" && xmlData[i + 5] === "Y" && xmlData[i + 6] === "P" && xmlData[i + 7] === "E") {
50002
- let angleBracketsCount = 1;
50003
- for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "<") angleBracketsCount++;
50004
- else if (xmlData[i] === ">") {
50005
- angleBracketsCount--;
50006
- if (angleBracketsCount === 0) break;
50007
- }
50008
- } else if (xmlData.length > i + 9 && xmlData[i + 1] === "[" && xmlData[i + 2] === "C" && xmlData[i + 3] === "D" && xmlData[i + 4] === "A" && xmlData[i + 5] === "T" && xmlData[i + 6] === "A" && xmlData[i + 7] === "[") {
50009
- for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "]" && xmlData[i + 1] === "]" && xmlData[i + 2] === ">") {
50010
- i += 2;
50011
- break;
50012
- }
50013
- }
50014
- return i;
50015
- }
50016
- const doubleQuote = "\"";
50017
- const singleQuote = "'";
50018
- /**
50019
- * Keep reading xmlData until '<' is found outside the attribute value.
50020
- * @param {string} xmlData
50021
- * @param {number} i
50022
- */
50023
- function readAttributeStr(xmlData, i) {
50024
- let attrStr = "";
50025
- let startChar = "";
50026
- let tagClosed = false;
50027
- for (; i < xmlData.length; i++) {
50028
- if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) if (startChar === "") startChar = xmlData[i];
50029
- else if (startChar !== xmlData[i]) {} else startChar = "";
50030
- else if (xmlData[i] === ">") {
50031
- if (startChar === "") {
50032
- tagClosed = true;
50033
- break;
50034
- }
50035
- }
50036
- attrStr += xmlData[i];
50037
- }
50038
- if (startChar !== "") return false;
50039
- return {
50040
- value: attrStr,
50041
- index: i,
50042
- tagClosed
50043
- };
50044
- }
50045
- /**
50046
- * Select all the attributes whether valid or invalid.
50047
- */
50048
- const validAttrStrRegxp = /* @__PURE__ */ new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?", "g");
50049
- function validateAttributeString(attrStr, options) {
50050
- const matches = getAllMatches(attrStr, validAttrStrRegxp);
50051
- const attrNames = {};
50052
- for (let i = 0; i < matches.length; i++) {
50053
- if (matches[i][1].length === 0) return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i]));
50054
- else if (matches[i][3] !== void 0 && matches[i][4] === void 0) return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' is without value.", getPositionFromMatch(matches[i]));
50055
- else if (matches[i][3] === void 0 && !options.allowBooleanAttributes) return getErrorObject("InvalidAttr", "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i]));
50056
- const attrName = matches[i][2];
50057
- if (!validateAttrName(attrName)) return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i]));
50058
- if (!Object.prototype.hasOwnProperty.call(attrNames, attrName)) attrNames[attrName] = 1;
50059
- else return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i]));
50060
- }
50061
- return true;
50062
- }
50063
- function validateNumberAmpersand(xmlData, i) {
50064
- let re = /\d/;
50065
- if (xmlData[i] === "x") {
50066
- i++;
50067
- re = /[\da-fA-F]/;
50068
- }
50069
- for (; i < xmlData.length; i++) {
50070
- if (xmlData[i] === ";") return i;
50071
- if (!xmlData[i].match(re)) break;
50072
- }
50073
- return -1;
50074
- }
50075
- function validateAmpersand(xmlData, i) {
50076
- i++;
50077
- if (xmlData[i] === ";") return -1;
50078
- if (xmlData[i] === "#") {
50079
- i++;
50080
- return validateNumberAmpersand(xmlData, i);
50081
- }
50082
- let count = 0;
50083
- for (; i < xmlData.length; i++, count++) {
50084
- if (xmlData[i].match(/\w/) && count < 20) continue;
50085
- if (xmlData[i] === ";") break;
50086
- return -1;
50087
- }
50088
- return i;
50089
- }
50090
- function getErrorObject(code, message, lineNumber) {
50091
- return { err: {
50092
- code,
50093
- msg: message,
50094
- line: lineNumber.line || lineNumber,
50095
- col: lineNumber.col
50096
- } };
50097
- }
50098
- function validateAttrName(attrName) {
50099
- return isName(attrName);
50100
- }
50101
- function validateTagName(tagname) {
50102
- return isName(tagname);
50103
- }
50104
- function getLineNumberForPosition(xmlData, index) {
50105
- const lines = xmlData.substring(0, index).split(/\r?\n/);
50106
- return {
50107
- line: lines.length,
50108
- col: lines[lines.length - 1].length + 1
50109
- };
50110
- }
50111
- function getPositionFromMatch(match) {
50112
- return match.startIndex + match[1].length;
50113
- }
50114
- //#endregion
50115
- //#region ../../node_modules/.pnpm/@nodable+entities@3.0.0/node_modules/@nodable/entities/src/entities.js
50116
- /**
50117
- * Currency Symbols
50118
- * @type {Record<string, string>}
50119
- */
50120
- const CURRENCY = {
50121
- cent: "¢",
50122
- pound: "£",
50123
- curren: "¤",
50124
- yen: "¥",
50125
- euro: "€",
50126
- dollar: "$",
50127
- fnof: "ƒ",
50128
- inr: "₹",
50129
- af: "؋",
50130
- birr: "ብር",
50131
- peso: "₱",
50132
- rub: "₽",
50133
- won: "₩",
50134
- yuan: "¥",
50135
- cedil: "¸"
50136
- };
50137
- const XML = {
50138
- amp: "&",
50139
- apos: "'",
50140
- gt: ">",
50141
- lt: "<",
50142
- quot: "\""
50143
- };
50144
- const COMMON_HTML = {
50145
- nbsp: "\xA0",
50146
- copy: "©",
50147
- reg: "®",
50148
- trade: "™",
50149
- mdash: "—",
50150
- ndash: "–",
50151
- hellip: "…",
50152
- laquo: "«",
50153
- raquo: "»",
50154
- lsquo: "‘",
50155
- rsquo: "’",
50156
- ldquo: "“",
50157
- rdquo: "”",
50158
- bull: "•",
50159
- para: "¶",
50160
- sect: "§",
50161
- deg: "°",
50162
- frac12: "½",
50163
- frac14: "¼",
50164
- frac34: "¾"
50165
- };
50166
- //#endregion
50167
- //#region ../../node_modules/.pnpm/@nodable+entities@3.0.0/node_modules/@nodable/entities/src/EntityDecoder.js
50168
- /**
50169
- * Action constants for `onExternalEntity` and `onInputEntity` hooks.
50170
- *
50171
- * Use these instead of raw strings to avoid typos:
50172
- *
50173
- * @example
50174
- * import EntityDecoder, { ENTITY_ACTION } from './EntityDecoder.js';
50175
- * const dec = new EntityDecoder({
50176
- * onInputEntity: (name, value) => ENTITY_ACTION.BLOCK,
50177
- * });
50178
- */
50179
- const ENTITY_ACTION = Object.freeze({
50180
- /** Resolve and expand the entity normally. */
50181
- ALLOW: "allow",
50182
- /** Silently skip this entity — it will not be registered. */
50183
- BLOCK: "block",
50184
- /** Throw an error, aborting entity registration entirely. */
50185
- THROW: "throw"
50186
- });
50187
- const SPECIAL_CHARS = /* @__PURE__ */ new Set("!?\\\\/[]$%{}^&*()<>|+");
50188
- /**
50189
- * Validate that an entity name contains no dangerous characters.
50190
- * @param {string} name
50191
- * @returns {string} the name, unchanged
50192
- * @throws {Error} on invalid characters
50193
- */
50194
- function validateEntityName$1(name) {
50195
- if (name[0] === "#") throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${name}"`);
50196
- for (const ch of name) if (SPECIAL_CHARS.has(ch)) throw new Error(`[EntityReplacer] Invalid character '${ch}' in entity name: "${name}"`);
50197
- return name;
50198
- }
50199
- /**
50200
- * Merge one or more entity maps into a flat name→string map.
50201
- * Accepts either:
50202
- * - plain string values: { amp: '&' }
50203
- * - legacy {regex,val} / {regx,val}: { lt: { regex: /.../, val: '<' } }
50204
- *
50205
- * Values containing '&' are skipped (recursive expansion risk).
50206
- *
50207
- * @param {...object} maps
50208
- * @returns {Record<string, string>}
50209
- */
50210
- function mergeEntityMaps(...maps) {
50211
- const out = Object.create(null);
50212
- for (const map of maps) {
50213
- if (!map) continue;
50214
- for (const key of Object.keys(map)) {
50215
- const raw = map[key];
50216
- if (typeof raw === "string") out[key] = raw;
50217
- else if (raw && typeof raw === "object" && raw.val !== void 0) {
50218
- const val = raw.val;
50219
- if (typeof val === "string") out[key] = val;
50220
- }
50221
- }
50222
- }
50223
- return out;
50224
- }
50225
- const LIMIT_TIER_EXTERNAL = "external";
50226
- const LIMIT_TIER_BASE = "base";
50227
- const LIMIT_TIER_ALL = "all";
50228
- /**
50229
- * Resolve `applyLimitsTo` option into a normalised Set of tier strings.
50230
- * Accepted values: 'external' | 'base' | 'all' | string[]
50231
- * Default: 'external' (only untrusted injected entities are counted).
50232
- * @param {string|string[]|undefined} raw
50233
- * @returns {Set<string>}
50234
- */
50235
- function parseLimitTiers(raw) {
50236
- if (!raw || raw === LIMIT_TIER_EXTERNAL) return new Set([LIMIT_TIER_EXTERNAL]);
50237
- if (raw === LIMIT_TIER_ALL) return new Set([LIMIT_TIER_ALL]);
50238
- if (raw === LIMIT_TIER_BASE) return new Set([LIMIT_TIER_BASE]);
50239
- if (Array.isArray(raw)) return new Set(raw);
50240
- return new Set([LIMIT_TIER_EXTERNAL]);
50241
- }
50242
- const NCR_LEVEL = Object.freeze({
50243
- allow: 0,
50244
- leave: 1,
50245
- remove: 2,
50246
- throw: 3
50247
- });
50248
- const XML10_ALLOWED_C0 = new Set([
50249
- 9,
50250
- 10,
50251
- 13
50252
- ]);
50253
- /**
50254
- * Parse the `ncr` constructor option into flat, hot-path-friendly fields.
50255
- * @param {object|undefined} ncr
50256
- * @returns {{ xmlVersion: number, onLevel: number, nullLevel: number }}
50257
- */
50258
- function parseNCRConfig(ncr) {
50259
- if (!ncr) return {
50260
- xmlVersion: 1,
50261
- onLevel: NCR_LEVEL.allow,
50262
- nullLevel: NCR_LEVEL.remove
50263
- };
50264
- const xmlVersion = ncr.xmlVersion === 1.1 ? 1.1 : 1;
50265
- const onLevel = NCR_LEVEL[ncr.onNCR] ?? NCR_LEVEL.allow;
50266
- const nullLevel = NCR_LEVEL[ncr.nullNCR] ?? NCR_LEVEL.remove;
50267
- return {
50268
- xmlVersion,
50269
- onLevel,
50270
- nullLevel: Math.max(nullLevel, NCR_LEVEL.remove)
50271
- };
50272
- }
50273
- /**
50274
- * Single-pass, zero-regex entity replacer for XML/HTML content.
50275
- *
50276
- * Algorithm: scan the string once for '&', read to ';', resolve via map
50277
- * or direct codepoint conversion, build output chunks, join once at the end.
50278
- *
50279
- * Entity lookup priority (highest → lowest):
50280
- * 1. input / runtime (DOCTYPE entities for current document)
50281
- * 2. persistent external (survive across documents)
50282
- * 3. base named map (DEFAULT_XML_ENTITIES + user-supplied namedEntities)
50283
- *
50284
- * Both input and external resolve as the 'external' tier for limit purposes.
50285
- * Base map entities resolve as the 'base' tier.
50286
- *
50287
- * Numeric / hex references (&#NNN; / &#xHH;) are resolved directly via
50288
- * String.fromCodePoint() — no map needed. They count as 'base' tier.
50289
- *
50290
- * @example
50291
- * const replacer = new EntityReplacer({ namedEntities: COMMON_HTML });
50292
- * replacer.setExternalEntities({ brand: 'Acme' });
50293
- *
50294
- * const instance = replacer.reset();
50295
- * instance.addInputEntities({ version: '1.0' });
50296
- * instance.encode('&brand; v&version; &lt;'); // 'Acme v1.0 <'
50297
- */
50298
- var EntityDecoder = class {
50299
- /**
50300
- * @param {object} [options]
50301
- * @param {object|null} [options.namedEntities] — extra named entities merged into base map
50302
- * @param {object} [options.limit] — security limits
50303
- * @param {number} [options.limit.maxTotalExpansions=0] — 0 = unlimited
50304
- * @param {number} [options.limit.maxExpandedLength=0] — 0 = unlimited
50305
- * @param {'external'|'base'|'all'|string[]} [options.limit.applyLimitsTo='external']
50306
- * Which entity tiers count against the security limits:
50307
- * - 'external' (default) — only input/runtime + persistent external entities
50308
- * - 'base' — only DEFAULT_XML_ENTITIES + namedEntities
50309
- * - 'all' — every entity regardless of tier
50310
- * - string[] — explicit combination, e.g. ['external', 'base']
50311
- * @param {((resolved: string, original: string) => string)|null} [options.postCheck=null]
50312
- * @param {string[]} [options.remove=[]] — entity names (e.g. ['nbsp', '#13']) to delete (replace with empty string)
50313
- * @param {string[]} [options.leave=[]] — entity names to keep as literal (unchanged in output)
50314
- * @param {object} [options.ncr] — Numeric Character Reference controls
50315
- * @param {1.0|1.1} [options.ncr.xmlVersion=1.0]
50316
- * XML version governing which codepoint ranges are restricted:
50317
- * - 1.0 — C0 controls U+0001–U+001F (except U+0009/000A/000D) are prohibited
50318
- * - 1.1 — C0 controls are allowed when written as NCRs; C1 (U+007F–U+009F) decoded as-is
50319
- * @param {'allow'|'leave'|'remove'|'throw'} [options.ncr.onNCR='allow']
50320
- * Base action for numeric references. Severity order: allow < leave < remove < throw.
50321
- * For codepoint ranges that carry a minimum level (surrogates → remove, XML 1.0 C0 → remove),
50322
- * the effective action is max(onNCR, rangeMinimum).
50323
- * @param {'remove'|'throw'} [options.ncr.nullNCR='remove']
50324
- * Action for U+0000 (null). 'allow' and 'leave' are clamped to 'remove' since null is never safe.
50325
- * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onExternalEntity=null]
50326
- * Hook called when an external entity is registered via `setExternalEntities()` or
50327
- * `addExternalEntity()`. Return `ENTITY_ACTION.ALLOW` to accept the entity,
50328
- * `ENTITY_ACTION.BLOCK` to silently skip it, or `ENTITY_ACTION.THROW` to abort with an error.
50329
- * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onInputEntity=null]
50330
- * Hook called when an input entity is registered via `addInputEntities()`. Return
50331
- * `ENTITY_ACTION.ALLOW` to accept, `ENTITY_ACTION.BLOCK` to silently skip, or
50332
- * `ENTITY_ACTION.THROW` to abort with an error.
50333
- */
50334
- constructor(options = {}) {
50335
- this._limit = options.limit || {};
50336
- this._maxTotalExpansions = this._limit.maxTotalExpansions || 0;
50337
- this._maxExpandedLength = this._limit.maxExpandedLength || 0;
50338
- this._postCheck = typeof options.postCheck === "function" ? options.postCheck : (r) => r;
50339
- this._limitTiers = parseLimitTiers(this._limit.applyLimitsTo ?? LIMIT_TIER_EXTERNAL);
50340
- this._numericAllowed = options.numericAllowed ?? true;
50341
- this._baseMap = mergeEntityMaps(XML, options.namedEntities || null);
50342
- /** @type {Record<string, string>} */
50343
- this._externalMap = Object.create(null);
50344
- /** @type {Record<string, string>} */
50345
- this._inputMap = Object.create(null);
50346
- this._totalExpansions = 0;
50347
- this._expandedLength = 0;
50348
- /** @type {Set<string>} */
50349
- this._removeSet = new Set(options.remove && Array.isArray(options.remove) ? options.remove : []);
50350
- /** @type {Set<string>} */
50351
- this._leaveSet = new Set(options.leave && Array.isArray(options.leave) ? options.leave : []);
50352
- const ncrCfg = parseNCRConfig(options.ncr);
50353
- this._ncrXmlVersion = ncrCfg.xmlVersion;
50354
- this._ncrOnLevel = ncrCfg.onLevel;
50355
- this._ncrNullLevel = ncrCfg.nullLevel;
50356
- /** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
50357
- this._onExternalEntity = typeof options.onExternalEntity === "function" ? options.onExternalEntity : null;
50358
- /** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
50359
- this._onInputEntity = typeof options.onInputEntity === "function" ? options.onInputEntity : null;
50360
- }
50361
- /**
50362
- * Invoke a registration hook for a single entity name/value pair.
50363
- * Returns true when the entity should be accepted, false when it should be
50364
- * silently skipped (BLOCK), and throws when the hook returns THROW.
50365
- *
50366
- * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} hook
50367
- * @param {string} name
50368
- * @param {string} value
50369
- * @param {string} context — used in error messages ('external' | 'input')
50370
- * @returns {boolean} true = accept, false = skip
50371
- */
50372
- _applyRegistrationHook(hook, name, value, context) {
50373
- if (!hook) return true;
50374
- const action = hook(name, value);
50375
- if (action === ENTITY_ACTION.BLOCK) return false;
50376
- if (action === ENTITY_ACTION.THROW) throw new Error(`[EntityDecoder] Registration of ${context} entity "&${name};" was rejected by hook`);
50377
- return true;
50378
- }
50379
- /**
50380
- * Replace the full set of persistent external entities.
50381
- * All keys are validated — throws on invalid characters.
50382
- * If `onExternalEntity` is set, it is called once per entry; entries that
50383
- * return `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW`
50384
- * aborts the whole call.
50385
- * @param {Record<string, string | { regex?: RegExp, val: string }>} map
50386
- */
50387
- setExternalEntities(map) {
50388
- if (map) for (const key of Object.keys(map)) validateEntityName$1(key);
50389
- if (!this._onExternalEntity) {
50390
- this._externalMap = mergeEntityMaps(map);
50391
- return;
50392
- }
50393
- const flat = mergeEntityMaps(map);
50394
- const filtered = Object.create(null);
50395
- for (const [name, value] of Object.entries(flat)) if (this._applyRegistrationHook(this._onExternalEntity, name, value, "external")) filtered[name] = value;
50396
- this._externalMap = filtered;
50397
- }
50398
- /**
50399
- * Add a single persistent external entity.
50400
- * If `onExternalEntity` is set it is called before the entity is stored;
50401
- * `ENTITY_ACTION.BLOCK` silently skips storage, `ENTITY_ACTION.THROW` raises.
50402
- * @param {string} key
50403
- * @param {string} value
50404
- */
50405
- addExternalEntity(key, value) {
50406
- validateEntityName$1(key);
50407
- if (typeof value === "string" && value.indexOf("&") === -1) {
50408
- if (this._applyRegistrationHook(this._onExternalEntity, key, value, "external")) this._externalMap[key] = value;
50409
- }
50410
- }
50411
- /**
50412
- * Inject DOCTYPE entities for the current document.
50413
- * Also resets per-document expansion counters.
50414
- * If `onInputEntity` is set it is called once per entry; entries returning
50415
- * `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW` aborts.
50416
- * @param {Record<string, string | { regx?: RegExp, regex?: RegExp, val: string }>} map
50417
- */
50418
- addInputEntities(map) {
50419
- this._totalExpansions = 0;
50420
- this._expandedLength = 0;
50421
- if (!this._onInputEntity) {
50422
- this._inputMap = mergeEntityMaps(map);
50423
- return;
50424
- }
50425
- const flat = mergeEntityMaps(map);
50426
- const filtered = Object.create(null);
50427
- for (const [name, value] of Object.entries(flat)) if (this._applyRegistrationHook(this._onInputEntity, name, value, "input")) filtered[name] = value;
50428
- this._inputMap = filtered;
50429
- }
50430
- /**
50431
- * Wipe input/runtime entities and reset counters.
50432
- * Call this before processing each new document.
50433
- * @returns {this}
50434
- */
50435
- reset() {
50436
- this._inputMap = Object.create(null);
50437
- this._totalExpansions = 0;
50438
- this._expandedLength = 0;
50439
- return this;
50440
- }
50441
- /**
50442
- * Update the XML version used for NCR classification.
50443
- * Call this as soon as the document's `<?xml version="...">` declaration is parsed.
50444
- * @param {1.0|1.1|number} version
50445
- */
50446
- setXmlVersion(version) {
50447
- this._ncrXmlVersion = version === 1.1 ? 1.1 : 1;
50448
- }
50449
- /**
50450
- * Replace all entity references in `str` in a single pass.
50451
- *
50452
- * @param {string} str
50453
- * @returns {string}
50454
- */
50455
- decode(str) {
50456
- if (typeof str !== "string" || str.length === 0) return str;
50457
- if (str.indexOf("&") === -1) return str;
50458
- const original = str;
50459
- const chunks = [];
50460
- const len = str.length;
50461
- let last = 0;
50462
- let i = 0;
50463
- const limitExpansions = this._maxTotalExpansions > 0;
50464
- const limitLength = this._maxExpandedLength > 0;
50465
- const checkLimits = limitExpansions || limitLength;
50466
- while (i < len) {
50467
- if (str.charCodeAt(i) !== 38) {
50468
- i++;
50469
- continue;
50470
- }
50471
- let j = i + 1;
50472
- while (j < len && str.charCodeAt(j) !== 59 && j - i <= 32) j++;
50473
- if (j >= len || str.charCodeAt(j) !== 59) {
50474
- i++;
50475
- continue;
50476
- }
50477
- const token = str.slice(i + 1, j);
50478
- if (token.length === 0) {
50479
- i++;
50480
- continue;
50481
- }
50482
- let replacement;
50483
- let tier;
50484
- if (this._removeSet.has(token)) {
50485
- replacement = "";
50486
- if (tier === void 0) tier = LIMIT_TIER_EXTERNAL;
50487
- } else if (this._leaveSet.has(token)) {
50488
- i++;
50489
- continue;
50490
- } else if (token.charCodeAt(0) === 35) {
50491
- const ncrResult = this._resolveNCR(token);
50492
- if (ncrResult === void 0) {
50493
- i++;
50494
- continue;
50495
- }
50496
- replacement = ncrResult;
50497
- tier = LIMIT_TIER_BASE;
50498
- } else {
50499
- const resolved = this._resolveName(token);
50500
- replacement = resolved?.value;
50501
- tier = resolved?.tier;
50502
- }
50503
- if (replacement === void 0) {
50504
- i++;
50505
- continue;
50506
- }
50507
- if (i > last) chunks.push(str.slice(last, i));
50508
- chunks.push(replacement);
50509
- last = j + 1;
50510
- i = last;
50511
- if (checkLimits && this._tierCounts(tier)) {
50512
- if (limitExpansions) {
50513
- this._totalExpansions++;
50514
- if (this._totalExpansions > this._maxTotalExpansions) throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`);
50515
- }
50516
- if (limitLength) {
50517
- const delta = replacement.length - (token.length + 2);
50518
- if (delta > 0) {
50519
- this._expandedLength += delta;
50520
- if (this._expandedLength > this._maxExpandedLength) throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`);
50521
- }
50522
- }
50523
- }
50524
- }
50525
- if (last < len) chunks.push(str.slice(last));
50526
- const result = chunks.length === 0 ? str : chunks.join("");
50527
- return this._postCheck(result, original);
50528
- }
50529
- /**
50530
- * Returns true if a resolved entity of the given tier should count
50531
- * against the expansion/length limits.
50532
- * @param {string} tier — LIMIT_TIER_EXTERNAL | LIMIT_TIER_BASE
50533
- * @returns {boolean}
50534
- */
50535
- _tierCounts(tier) {
50536
- if (this._limitTiers.has(LIMIT_TIER_ALL)) return true;
50537
- return this._limitTiers.has(tier);
50538
- }
50539
- /**
50540
- * Resolve a named entity token (without & and ;).
50541
- * Priority: inputMap > externalMap > baseMap
50542
- * Returns the resolved value tagged with its limit tier.
50543
- *
50544
- * @param {string} name
50545
- * @returns {{ value: string, tier: string }|undefined}
50546
- */
50547
- _resolveName(name) {
50548
- if (name in this._inputMap) return {
50549
- value: this._inputMap[name],
50550
- tier: LIMIT_TIER_EXTERNAL
50551
- };
50552
- if (name in this._externalMap) return {
50553
- value: this._externalMap[name],
50554
- tier: LIMIT_TIER_EXTERNAL
50555
- };
50556
- if (name in this._baseMap) return {
50557
- value: this._baseMap[name],
50558
- tier: LIMIT_TIER_BASE
50559
- };
50560
- }
50561
- /**
50562
- * Classify a codepoint and return the minimum action level that must be applied.
50563
- * Returns -1 when no minimum is imposed (normal allow path).
50564
- *
50565
- * Ranges checked (in priority order):
50566
- * 1. U+0000 — null, governed by nullNCR (always ≥ remove)
50567
- * 2. U+D800–U+DFFF — surrogates, always prohibited (min: remove)
50568
- * 3. U+0001–U+001F \ {0x09,0x0A,0x0D} — XML 1.0 restricted C0 (min: remove)
50569
- * (skipped in XML 1.1 — C0 controls are allowed when written as NCRs)
50570
- *
50571
- * @param {number} cp — codepoint
50572
- * @returns {number} — minimum NCR_LEVEL value, or -1 for no restriction
50573
- */
50574
- _classifyNCR(cp) {
50575
- if (cp === 0) return this._ncrNullLevel;
50576
- if (cp >= 55296 && cp <= 57343) return NCR_LEVEL.remove;
50577
- if (this._ncrXmlVersion === 1) {
50578
- if (cp >= 1 && cp <= 31 && !XML10_ALLOWED_C0.has(cp)) return NCR_LEVEL.remove;
50579
- }
50580
- return -1;
50581
- }
50582
- /**
50583
- * Execute a resolved NCR action.
50584
- *
50585
- * @param {number} action — NCR_LEVEL value
50586
- * @param {string} token — raw token (e.g. '#38') for error messages
50587
- * @param {number} cp — codepoint, used only for error messages
50588
- * @returns {string|undefined}
50589
- * - decoded character string → 'allow'
50590
- * - '' → 'remove'
50591
- * - undefined → 'leave' (caller must skip past '&' only)
50592
- * - throws Error → 'throw'
50593
- */
50594
- _applyNCRAction(action, token, cp) {
50595
- switch (action) {
50596
- case NCR_LEVEL.allow: return String.fromCodePoint(cp);
50597
- case NCR_LEVEL.remove: return "";
50598
- case NCR_LEVEL.leave: return;
50599
- case NCR_LEVEL.throw: throw new Error(`[EntityDecoder] Prohibited numeric character reference &${token}; (U+${cp.toString(16).toUpperCase().padStart(4, "0")})`);
50600
- default: return String.fromCodePoint(cp);
50601
- }
50602
- }
50603
- /**
50604
- * Full NCR resolution pipeline for a numeric token.
50605
- *
50606
- * Steps:
50607
- * 1. Parse the codepoint (decimal or hex).
50608
- * 2. Validate the raw codepoint range (NaN, <0, >0x10FFFF).
50609
- * 3. If numericAllowed is false and no minimum restriction applies → leave as-is.
50610
- * 4. Classify the codepoint to find the minimum required action level.
50611
- * 5. Resolve effective action = max(onNCR, minimum).
50612
- * 6. Apply and return.
50613
- *
50614
- * @param {string} token — e.g. '#38', '#x26', '#X26'
50615
- * @returns {string|undefined}
50616
- * - string (incl. '') — replacement ('' = remove)
50617
- * - undefined — leave original &token; as-is
50618
- */
50619
- _resolveNCR(token) {
50620
- const second = token.charCodeAt(1);
50621
- let cp;
50622
- if (second === 120 || second === 88) cp = parseInt(token.slice(2), 16);
50623
- else cp = parseInt(token.slice(1), 10);
50624
- if (Number.isNaN(cp) || cp < 0 || cp > 1114111) return void 0;
50625
- const minimum = this._classifyNCR(cp);
50626
- if (!this._numericAllowed && minimum < NCR_LEVEL.remove) return void 0;
50627
- const effective = minimum === -1 ? this._ncrOnLevel : Math.max(this._ncrOnLevel, minimum);
50628
- return this._applyNCRAction(effective, token, cp);
50629
- }
50630
- };
50631
- //#endregion
50632
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
50633
- const defaultOnDangerousProperty = (name) => {
50634
- if (DANGEROUS_PROPERTY_NAMES.includes(name)) return "__" + name;
50635
- return name;
50636
- };
50637
- const defaultOptions = {
50638
- preserveOrder: false,
50639
- attributeNamePrefix: "@_",
50640
- attributesGroupName: false,
50641
- textNodeName: "#text",
50642
- ignoreAttributes: true,
50643
- removeNSPrefix: false,
50644
- allowBooleanAttributes: false,
50645
- parseTagValue: true,
50646
- parseAttributeValue: false,
50647
- trimValues: true,
50648
- cdataPropName: false,
50649
- numberParseOptions: {
50650
- hex: true,
50651
- leadingZeros: true,
50652
- eNotation: true,
50653
- unicode: false
50654
- },
50655
- tagValueProcessor: function(tagName, val) {
50656
- return val;
50657
- },
50658
- attributeValueProcessor: function(attrName, val) {
50659
- return val;
50660
- },
50661
- stopNodes: [],
50662
- alwaysCreateTextNode: false,
50663
- isArray: () => false,
50664
- commentPropName: false,
50665
- unpairedTags: [],
50666
- processEntities: true,
50667
- htmlEntities: false,
50668
- entityDecoder: null,
50669
- ignoreDeclaration: false,
50670
- ignorePiTags: false,
50671
- transformTagName: false,
50672
- transformAttributeName: false,
50673
- updateTag: function(tagName, jPath, attrs) {
50674
- return tagName;
50675
- },
50676
- captureMetaData: false,
50677
- maxNestedTags: 100,
50678
- strictReservedNames: true,
50679
- jPath: true,
50680
- onDangerousProperty: defaultOnDangerousProperty
50681
- };
50682
- /**
50683
- * Validates that a property name is safe to use
50684
- * @param {string} propertyName - The property name to validate
50685
- * @param {string} optionName - The option field name (for error message)
50686
- * @throws {Error} If property name is dangerous
50687
- */
50688
- function validatePropertyName(propertyName, optionName) {
50689
- if (typeof propertyName !== "string") return;
50690
- const normalized = propertyName.toLowerCase();
50691
- if (DANGEROUS_PROPERTY_NAMES.some((dangerous) => normalized === dangerous.toLowerCase())) throw new Error(`[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`);
50692
- if (criticalProperties.some((dangerous) => normalized === dangerous.toLowerCase())) throw new Error(`[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`);
50693
- }
50694
- /**
50695
- * Normalizes processEntities option for backward compatibility
50696
- * @param {boolean|object} value
50697
- * @returns {object} Always returns normalized object
50698
- */
50699
- function normalizeProcessEntities(value, htmlEntities) {
50700
- if (typeof value === "boolean") return {
50701
- enabled: value,
50702
- maxEntitySize: 1e4,
50703
- maxExpansionDepth: 1e4,
50704
- maxTotalExpansions: Infinity,
50705
- maxExpandedLength: 1e5,
50706
- maxEntityCount: 1e3,
50707
- allowedTags: null,
50708
- tagFilter: null,
50709
- appliesTo: "all"
50710
- };
50711
- if (typeof value === "object" && value !== null) return {
50712
- enabled: value.enabled !== false,
50713
- maxEntitySize: Math.max(1, value.maxEntitySize ?? 1e4),
50714
- maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 1e4),
50715
- maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity),
50716
- maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 1e5),
50717
- maxEntityCount: Math.max(1, value.maxEntityCount ?? 1e3),
50718
- allowedTags: value.allowedTags ?? null,
50719
- tagFilter: value.tagFilter ?? null,
50720
- appliesTo: value.appliesTo ?? "all"
50721
- };
50722
- return normalizeProcessEntities(true);
50723
- }
50724
- const buildOptions = function(options) {
50725
- const built = Object.assign({}, defaultOptions, options);
50726
- const propertyNameOptions = [
50727
- {
50728
- value: built.attributeNamePrefix,
50729
- name: "attributeNamePrefix"
50730
- },
50731
- {
50732
- value: built.attributesGroupName,
50733
- name: "attributesGroupName"
50734
- },
50735
- {
50736
- value: built.textNodeName,
50737
- name: "textNodeName"
50738
- },
50739
- {
50740
- value: built.cdataPropName,
50741
- name: "cdataPropName"
50742
- },
50743
- {
50744
- value: built.commentPropName,
50745
- name: "commentPropName"
50746
- }
50747
- ];
50748
- for (const { value, name } of propertyNameOptions) if (value) validatePropertyName(value, name);
50749
- if (built.onDangerousProperty === null) built.onDangerousProperty = defaultOnDangerousProperty;
50750
- built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities);
50751
- built.unpairedTagsSet = new Set(built.unpairedTags);
50752
- if (built.stopNodes && Array.isArray(built.stopNodes)) built.stopNodes = built.stopNodes.map((node) => {
50753
- if (typeof node === "string" && node.startsWith("*.")) return ".." + node.substring(2);
50754
- return node;
50755
- });
50756
- return built;
50757
- };
50758
- //#endregion
50759
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
50760
- let METADATA_SYMBOL$1;
50761
- if (typeof Symbol !== "function") METADATA_SYMBOL$1 = "@@xmlMetadata";
50762
- else METADATA_SYMBOL$1 = Symbol("XML Node Metadata");
50763
- var XmlNode = class {
50764
- constructor(tagname) {
50765
- this.tagname = tagname;
50766
- this.child = [];
50767
- this[":@"] = Object.create(null);
50768
- }
50769
- add(key, val) {
50770
- if (key === "__proto__") key = "#__proto__";
50771
- this.child.push({ [key]: val });
50772
- }
50773
- addChild(node, startIndex) {
50774
- if (node.tagname === "__proto__") node.tagname = "#__proto__";
50775
- if (node[":@"] && Object.keys(node[":@"]).length > 0) this.child.push({
50776
- [node.tagname]: node.child,
50777
- [":@"]: node[":@"]
50778
- });
50779
- else this.child.push({ [node.tagname]: node.child });
50780
- if (startIndex !== void 0) this.child[this.child.length - 1][METADATA_SYMBOL$1] = { startIndex };
50781
- }
50782
- /** symbol used for metadata */
50783
- static getMetaDataSymbol() {
50784
- return METADATA_SYMBOL$1;
50785
- }
50786
- };
50787
- //#endregion
50788
- //#region ../../node_modules/.pnpm/xml-naming@0.3.0/node_modules/xml-naming/src/index.js
50789
- /**
50790
- * xml-naming
50791
- * Validates XML Name productions as defined in the XML 1.0 and 1.1 specifications.
50792
- * Covers: Name, NCName, QName, NMToken, NMTokens
50793
- *
50794
- * XML 1.0 spec: https://www.w3.org/TR/xml/#NT-Name
50795
- * XML 1.1 spec: https://www.w3.org/TR/xml11/#NT-NameStartChar
50796
- * XML NS spec: https://www.w3.org/TR/xml-names/#NT-NCName
50797
- */
50798
- const nameStartChar10 = ":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�";
50799
- const nameChar10 = ":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�\\-\\.\\d·̀-ͯ‿-⁀";
50800
- const nameStartChar11 = ":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿";
50801
- const nameChar11 = ":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿\\-\\.\\d·̀-ͯ҇‿-⁀";
50802
- const buildRegexes = (startChar, char, flags = "") => {
50803
- const ncNamePat = `[${startChar.replace(":", "")}][${char.replace(":", "")}]*`;
50804
- return {
50805
- name: new RegExp(`^[${startChar}][${char}]*$`, flags),
50806
- ncName: new RegExp(`^${ncNamePat}$`, flags),
50807
- qName: new RegExp(`^${ncNamePat}(?::${ncNamePat})?$`, flags),
50808
- nmToken: new RegExp(`^[${char}]+$`, flags),
50809
- nmTokens: new RegExp(`^[${char}]+(?:\\s+[${char}]+)*$`, flags)
50810
- };
50811
- };
50812
- const regexes10 = buildRegexes(nameStartChar10, nameChar10);
50813
- const regexes11 = buildRegexes(nameStartChar11, nameChar11, "u");
50814
- const regexesAscii = buildRegexes(":A-Za-z_", ":A-Za-z_\\-\\.\\d");
50815
- const getRegexes = (xmlVersion = "1.0", asciiOnly = false) => {
50816
- if (asciiOnly) return regexesAscii;
50817
- return xmlVersion === "1.1" ? regexes11 : regexes10;
50818
- };
50819
- /**
50820
- * Returns true if the string is a valid QName (Qualified Name).
50821
- * Allows exactly one colon as a prefix separator: prefix:localName.
50822
- * Used for: element and attribute names in namespace-aware XML/SVG.
50823
- *
50824
- * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
50825
- * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
50826
- */
50827
- const qName = (str, { xmlVersion = "1.0", asciiOnly = false } = {}) => getRegexes(xmlVersion, asciiOnly).qName.test(str);
50828
- //#endregion
50829
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
50830
- var DocTypeReader = class {
50831
- constructor(options, xmlVersion) {
50832
- this.suppressValidationErr = !options;
50833
- this.options = options;
50834
- this.xmlVersion = xmlVersion || 1;
50835
- }
50836
- setXmlVersion(xmlVersion = 1) {
50837
- this.xmlVersion = xmlVersion;
50838
- }
50839
- readDocType(xmlData, i) {
50840
- const entities = Object.create(null);
50841
- let entityCount = 0;
50842
- if (xmlData[i + 3] === "O" && xmlData[i + 4] === "C" && xmlData[i + 5] === "T" && xmlData[i + 6] === "Y" && xmlData[i + 7] === "P" && xmlData[i + 8] === "E") {
50843
- i = i + 9;
50844
- let angleBracketsCount = 1;
50845
- let hasBody = false, comment = false;
50846
- let exp = "";
50847
- for (; i < xmlData.length; i++) if (xmlData[i] === "<" && !comment) {
50848
- if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
50849
- i += 7;
50850
- let entityName, val;
50851
- [entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
50852
- if (val.indexOf("&") === -1) {
50853
- if (this.options.enabled !== false && this.options.maxEntityCount != null && entityCount >= this.options.maxEntityCount) throw new Error(`Entity count (${entityCount + 1}) exceeds maximum allowed (${this.options.maxEntityCount})`);
50854
- entities[entityName] = val;
50855
- entityCount++;
50856
- }
50857
- } else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
50858
- i += 8;
50859
- const { index } = this.readElementExp(xmlData, i + 1);
50860
- i = index;
50861
- } else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) i += 8;
50862
- else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) {
50863
- i += 9;
50864
- const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr);
50865
- i = index;
50866
- } else if (hasSeq(xmlData, "!--", i)) comment = true;
50867
- else throw new Error(`Invalid DOCTYPE`);
50868
- angleBracketsCount++;
50869
- exp = "";
50870
- } else if (xmlData[i] === ">") {
50871
- if (comment) {
50872
- if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") {
50873
- comment = false;
50874
- angleBracketsCount--;
50875
- }
50876
- } else angleBracketsCount--;
50877
- if (angleBracketsCount === 0) break;
50878
- } else if (xmlData[i] === "[") hasBody = true;
50879
- else exp += xmlData[i];
50880
- if (angleBracketsCount !== 0) throw new Error(`Unclosed DOCTYPE`);
50881
- } else throw new Error(`Invalid Tag instead of DOCTYPE`);
50882
- return {
50883
- entities,
50884
- i
50885
- };
50886
- }
50887
- readEntityExp(xmlData, i) {
50888
- i = skipWhitespace(xmlData, i);
50889
- const startIndex = i;
50890
- while (i < xmlData.length && !/\s/.test(xmlData[i]) && xmlData[i] !== "\"" && xmlData[i] !== "'") i++;
50891
- let entityName = xmlData.substring(startIndex, i);
50892
- validateEntityName(entityName, { xmlVersion: this.xmlVersion });
50893
- i = skipWhitespace(xmlData, i);
50894
- if (!this.suppressValidationErr) {
50895
- if (xmlData.substring(i, i + 6).toUpperCase() === "SYSTEM") throw new Error("External entities are not supported");
50896
- else if (xmlData[i] === "%") throw new Error("Parameter entities are not supported");
50897
- }
50898
- let entityValue = "";
50899
- [i, entityValue] = this.readIdentifierVal(xmlData, i, "entity");
50900
- if (this.options.enabled !== false && this.options.maxEntitySize != null && entityValue.length > this.options.maxEntitySize) throw new Error(`Entity "${entityName}" size (${entityValue.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`);
50901
- i--;
50902
- return [
50903
- entityName,
50904
- entityValue,
50905
- i
50906
- ];
50907
- }
50908
- readNotationExp(xmlData, i) {
50909
- i = skipWhitespace(xmlData, i);
50910
- const startIndex = i;
50911
- while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
50912
- let notationName = xmlData.substring(startIndex, i);
50913
- !this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion });
50914
- i = skipWhitespace(xmlData, i);
50915
- const identifierType = xmlData.substring(i, i + 6).toUpperCase();
50916
- if (!this.suppressValidationErr && identifierType !== "SYSTEM" && identifierType !== "PUBLIC") throw new Error(`Expected SYSTEM or PUBLIC, found "${identifierType}"`);
50917
- i += identifierType.length;
50918
- i = skipWhitespace(xmlData, i);
50919
- let publicIdentifier = null;
50920
- let systemIdentifier = null;
50921
- if (identifierType === "PUBLIC") {
50922
- [i, publicIdentifier] = this.readIdentifierVal(xmlData, i, "publicIdentifier");
50923
- i = skipWhitespace(xmlData, i);
50924
- if (xmlData[i] === "\"" || xmlData[i] === "'") [i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
50925
- } else if (identifierType === "SYSTEM") {
50926
- [i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
50927
- if (!this.suppressValidationErr && !systemIdentifier) throw new Error("Missing mandatory system identifier for SYSTEM notation");
50928
- }
50929
- return {
50930
- notationName,
50931
- publicIdentifier,
50932
- systemIdentifier,
50933
- index: --i
50934
- };
50935
- }
50936
- readIdentifierVal(xmlData, i, type) {
50937
- let identifierVal = "";
50938
- const startChar = xmlData[i];
50939
- if (startChar !== "\"" && startChar !== "'") throw new Error(`Expected quoted string, found "${startChar}"`);
50940
- i++;
50941
- const startIndex = i;
50942
- while (i < xmlData.length && xmlData[i] !== startChar) i++;
50943
- identifierVal = xmlData.substring(startIndex, i);
50944
- if (xmlData[i] !== startChar) throw new Error(`Unterminated ${type} value`);
50945
- i++;
50946
- return [i, identifierVal];
50947
- }
50948
- readElementExp(xmlData, i) {
50949
- i = skipWhitespace(xmlData, i);
50950
- const startIndex = i;
50951
- while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
50952
- let elementName = xmlData.substring(startIndex, i);
50953
- if (!this.suppressValidationErr && !qName(elementName, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid element name: "${elementName}"`);
50954
- i = skipWhitespace(xmlData, i);
50955
- let contentModel = "";
50956
- if (xmlData[i] === "E" && hasSeq(xmlData, "MPTY", i)) i += 4;
50957
- else if (xmlData[i] === "A" && hasSeq(xmlData, "NY", i)) i += 2;
50958
- else if (xmlData[i] === "(") {
50959
- i++;
50960
- const startIndex = i;
50961
- while (i < xmlData.length && xmlData[i] !== ")") i++;
50962
- contentModel = xmlData.substring(startIndex, i);
50963
- if (xmlData[i] !== ")") throw new Error("Unterminated content model");
50964
- } else if (!this.suppressValidationErr) throw new Error(`Invalid Element Expression, found "${xmlData[i]}"`);
50965
- return {
50966
- elementName,
50967
- contentModel: contentModel.trim(),
50968
- index: i
50969
- };
50970
- }
50971
- readAttlistExp(xmlData, i) {
50972
- i = skipWhitespace(xmlData, i);
50973
- let startIndex = i;
50974
- while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
50975
- let elementName = xmlData.substring(startIndex, i);
50976
- validateEntityName(elementName, { xmlVersion: this.xmlVersion });
50977
- i = skipWhitespace(xmlData, i);
50978
- startIndex = i;
50979
- while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
50980
- let attributeName = xmlData.substring(startIndex, i);
50981
- if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid attribute name: "${attributeName}"`);
50982
- i = skipWhitespace(xmlData, i);
50983
- let attributeType = "";
50984
- if (xmlData.substring(i, i + 8).toUpperCase() === "NOTATION") {
50985
- attributeType = "NOTATION";
50986
- i += 8;
50987
- i = skipWhitespace(xmlData, i);
50988
- if (xmlData[i] !== "(") throw new Error(`Expected '(', found "${xmlData[i]}"`);
50989
- i++;
50990
- let allowedNotations = [];
50991
- while (i < xmlData.length && xmlData[i] !== ")") {
50992
- const startIndex = i;
50993
- while (i < xmlData.length && xmlData[i] !== "|" && xmlData[i] !== ")") i++;
50994
- let notation = xmlData.substring(startIndex, i);
50995
- notation = notation.trim();
50996
- if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid notation name: "${notation}"`);
50997
- allowedNotations.push(notation);
50998
- if (xmlData[i] === "|") {
50999
- i++;
51000
- i = skipWhitespace(xmlData, i);
51001
- }
51002
- }
51003
- if (xmlData[i] !== ")") throw new Error("Unterminated list of notations");
51004
- i++;
51005
- attributeType += " (" + allowedNotations.join("|") + ")";
51006
- } else {
51007
- const startIndex = i;
51008
- while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
51009
- attributeType += xmlData.substring(startIndex, i);
51010
- if (!this.suppressValidationErr && ![
51011
- "CDATA",
51012
- "ID",
51013
- "IDREF",
51014
- "IDREFS",
51015
- "ENTITY",
51016
- "ENTITIES",
51017
- "NMTOKEN",
51018
- "NMTOKENS"
51019
- ].includes(attributeType.toUpperCase())) throw new Error(`Invalid attribute type: "${attributeType}"`);
51020
- }
51021
- i = skipWhitespace(xmlData, i);
51022
- let defaultValue = "";
51023
- if (xmlData.substring(i, i + 8).toUpperCase() === "#REQUIRED") {
51024
- defaultValue = "#REQUIRED";
51025
- i += 8;
51026
- } else if (xmlData.substring(i, i + 7).toUpperCase() === "#IMPLIED") {
51027
- defaultValue = "#IMPLIED";
51028
- i += 7;
51029
- } else [i, defaultValue] = this.readIdentifierVal(xmlData, i, "ATTLIST");
51030
- return {
51031
- elementName,
51032
- attributeName,
51033
- attributeType,
51034
- defaultValue,
51035
- index: i
51036
- };
51037
- }
51038
- };
51039
- const skipWhitespace = (data, index) => {
51040
- while (index < data.length && /\s/.test(data[index])) index++;
51041
- return index;
51042
- };
51043
- function hasSeq(data, seq, i) {
51044
- for (let j = 0; j < seq.length; j++) if (seq[j] !== data[i + j + 1]) return false;
51045
- return true;
51046
- }
51047
- function validateEntityName(name, xmlVersion) {
51048
- if (qName(name, { xmlVersion })) return name;
51049
- else throw new Error(`Invalid entity name ${name}`);
51050
- }
51051
- //#endregion
51052
- //#region ../../node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/digitTable.js
51053
- /**
51054
- * Flat lookup table: maps Unicode code point → ASCII digit (0-9).
51055
- * Only decimal digit characters (Unicode category Nd) are included.
51056
- *
51057
- * Strategy: Int32Array of size (maxCodePoint - minCodePoint + 1).
51058
- * Value 0xFF means "not a digit". Value 0-9 is the ASCII digit value.
51059
- * This gives O(1) lookup with no branching, no bisect, no loop.
51060
- *
51061
- * Memory: range is 0x0660 to 0x1FBF0 → ~129,936 entries × 1 byte = ~127 KB.
51062
- * Acceptable for a one-time init; lookup is a single array index.
51063
- */
51064
- const SCRIPT_ZEROS = [
51065
- 48,
51066
- 1632,
51067
- 1776,
51068
- 2406,
51069
- 2534,
51070
- 2662,
51071
- 2790,
51072
- 2918,
51073
- 3046,
51074
- 3174,
51075
- 3302,
51076
- 3430,
51077
- 3558,
51078
- 3664,
51079
- 3792,
51080
- 3872,
51081
- 4160,
51082
- 4240,
51083
- 6112,
51084
- 6160,
51085
- 6470,
51086
- 6608,
51087
- 6784,
51088
- 6800,
51089
- 6992,
51090
- 7088,
51091
- 7232,
51092
- 7248,
51093
- 65296,
51094
- 120782,
51095
- 120792,
51096
- 120802,
51097
- 120812,
51098
- 120822,
51099
- 66720,
51100
- 68912,
51101
- 69734,
51102
- 69872,
51103
- 69942,
51104
- 70096,
51105
- 70384,
51106
- 70736,
51107
- 70864,
51108
- 71248,
51109
- 71360,
51110
- 71472,
51111
- 71904,
51112
- 72016,
51113
- 72688,
51114
- 72784,
51115
- 73040,
51116
- 73120,
51117
- 73552,
51118
- 92768,
51119
- 92864,
51120
- 93008,
51121
- 123200,
51122
- 123632,
51123
- 124144,
51124
- 125264,
51125
- 130032
51126
- ];
51127
- const HIGH_MAP = /* @__PURE__ */ new Map();
51128
- const LOW_MAX = 65535;
51129
- const TABLE_OFFSET = 1632;
51130
- const TABLE = new Uint8Array(63904).fill(255);
51131
- for (const zero of SCRIPT_ZEROS) for (let d = 0; d < 10; d++) {
51132
- const cp = zero + d;
51133
- if (cp <= LOW_MAX) TABLE[cp - TABLE_OFFSET] = d;
51134
- else HIGH_MAP.set(cp, d);
51135
- }
51136
- //#endregion
51137
- //#region ../../node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/anynum.js
51138
- const CHAR_0 = 48;
51139
- const CHAR_9 = 57;
51140
- const CHAR_MINUS = 45;
51141
- const MINUS_SET = new Set([
51142
- 8722,
51143
- 65293,
51144
- 65123
51145
- ]);
51146
- /**
51147
- * Normalize all Unicode decimal digit characters in a string to ASCII (0-9),
51148
- * and normalize Unicode minus variants to ASCII '-' (U+002D).
51149
- *
51150
- * Non-digit, non-minus characters are passed through unchanged.
51151
- *
51152
- * Performance design:
51153
- * - Fast path: if the string has no convertible characters, return it unchanged
51154
- * (zero allocation).
51155
- * - BMP digits (0x0660..0xFFFF excl. surrogates): flat Uint8Array lookup (O(1)).
51156
- * - Supplementary plane digits (> 0xFFFF, encoded as surrogate pairs): Map lookup.
51157
- * - Minus variants: checked inline with a small fixed Set.
51158
- *
51159
- * @param {string} str
51160
- * @returns {string}
51161
- */
51162
- function anynum(str) {
51163
- if (typeof str !== "string") return str;
51164
- const len = str.length;
51165
- if (len === 0) return str;
51166
- let firstHit = -1;
51167
- for (let i = 0; i < len; i++) {
51168
- const cc = str.charCodeAt(i);
51169
- if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) continue;
51170
- if (cc < 1632) {
51171
- if (MINUS_SET.has(cc)) {
51172
- firstHit = i;
51173
- break;
51174
- }
51175
- continue;
51176
- }
51177
- if (cc >= 55296 && cc <= 56319) {
51178
- if (i + 1 < len) {
51179
- const low = str.charCodeAt(i + 1);
51180
- if (low >= 56320 && low <= 57343) {
51181
- const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
51182
- if (HIGH_MAP.has(cp)) {
51183
- firstHit = i;
51184
- break;
51185
- }
51186
- }
51187
- }
51188
- continue;
51189
- }
51190
- if (TABLE[cc - 1632] !== 255 || MINUS_SET.has(cc)) {
51191
- firstHit = i;
51192
- break;
51193
- }
51194
- }
51195
- if (firstHit === -1) return str;
51196
- const chars = [];
51197
- if (firstHit > 0) chars.push(str.slice(0, firstHit));
51198
- for (let i = firstHit; i < len; i++) {
51199
- const cc = str.charCodeAt(i);
51200
- if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) {
51201
- chars.push(str[i]);
51202
- continue;
51203
- }
51204
- if (cc < 1632) {
51205
- chars.push(MINUS_SET.has(cc) ? "-" : str[i]);
51206
- continue;
51207
- }
51208
- if (cc >= 55296 && cc <= 56319) {
51209
- if (i + 1 < len) {
51210
- const low = str.charCodeAt(i + 1);
51211
- if (low >= 56320 && low <= 57343) {
51212
- const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
51213
- const d = HIGH_MAP.get(cp);
51214
- if (d !== void 0) {
51215
- chars.push(String.fromCharCode(d + 48));
51216
- i++;
51217
- continue;
51218
- }
51219
- }
51220
- }
51221
- chars.push(str[i]);
51222
- continue;
51223
- }
51224
- if (MINUS_SET.has(cc)) {
51225
- chars.push("-");
51226
- continue;
51227
- }
51228
- const d = TABLE[cc - TABLE_OFFSET];
51229
- chars.push(d !== 255 ? String.fromCharCode(d + 48) : str[i]);
51230
- }
51231
- return chars.join("");
51232
- }
51233
- //#endregion
51234
- //#region ../../node_modules/.pnpm/strnum@2.4.1/node_modules/strnum/strnum.js
51235
- const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
51236
- const binRegex = /^0b[01]+$/;
51237
- const octRegex = /^0o[0-7]+$/;
51238
- const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
51239
- const consider = {
51240
- hex: true,
51241
- binary: false,
51242
- octal: false,
51243
- leadingZeros: true,
51244
- decimalPoint: ".",
51245
- eNotation: true,
51246
- infinity: "original",
51247
- unicode: false
51248
- };
51249
- function toNumber(str, options = {}) {
51250
- options = Object.assign({}, consider, options);
51251
- if (!str || typeof str !== "string") return str;
51252
- let trimmedStr = str.trim();
51253
- if (trimmedStr.length === 0) return str;
51254
- else if (options.skipLike !== void 0 && options.skipLike.test(trimmedStr)) return str;
51255
- else if (trimmedStr === "0") return 0;
51256
- if (options.unicode) {
51257
- trimmedStr = anynum(trimmedStr);
51258
- if (trimmedStr === "0") return 0;
51259
- }
51260
- if (options.hex && hexRegex.test(trimmedStr)) return parse_int(trimmedStr, 16);
51261
- else if (options.binary && binRegex.test(trimmedStr)) return parse_int(trimmedStr, 2);
51262
- else if (options.octal && octRegex.test(trimmedStr)) return parse_int(trimmedStr, 8);
51263
- else if (!isFinite(trimmedStr)) return handleInfinity(str, Number(trimmedStr), options);
51264
- else if (trimmedStr.includes("e") || trimmedStr.includes("E")) return resolveEnotation(str, trimmedStr, options);
51265
- else {
51266
- const match = numRegex.exec(trimmedStr);
51267
- if (match) {
51268
- const sign = match[1] || "";
51269
- const leadingZeros = match[2];
51270
- let numTrimmedByZeros = trimZeros(match[3]);
51271
- const decimalAdjacentToLeadingZeros = sign ? str[leadingZeros.length + 1] === "." : str[leadingZeros.length] === ".";
51272
- if (!options.leadingZeros && (leadingZeros.length > 1 || leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros)) return str;
51273
- else {
51274
- const num = Number(trimmedStr);
51275
- const parsedStr = String(num);
51276
- if (num === 0) return num;
51277
- if (parsedStr.search(/[eE]/) !== -1) if (options.eNotation) return num;
51278
- else return str;
51279
- else if (trimmedStr.indexOf(".") !== -1) if (parsedStr === "0") return num;
51280
- else if (parsedStr === numTrimmedByZeros) return num;
51281
- else if (parsedStr === `${sign}${numTrimmedByZeros}`) return num;
51282
- else return str;
51283
- let n = leadingZeros ? numTrimmedByZeros : trimmedStr;
51284
- if (leadingZeros) return n === parsedStr || sign + n === parsedStr ? num : str;
51285
- else return n === parsedStr || n === sign + parsedStr ? num : str;
51286
- }
51287
- } else return str;
51288
- }
51289
- }
51290
- const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
51291
- function resolveEnotation(str, trimmedStr, options) {
51292
- if (!options.eNotation) return str;
51293
- const notation = trimmedStr.match(eNotationRegx);
51294
- if (notation) {
51295
- let sign = notation[1] || "";
51296
- const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
51297
- const leadingZeros = notation[2];
51298
- const eAdjacentToLeadingZeros = sign ? str[leadingZeros.length + 1] === eChar : str[leadingZeros.length] === eChar;
51299
- if (leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
51300
- else if (leadingZeros.length === 1 && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)) return Number(trimmedStr);
51301
- else if (leadingZeros.length > 0) if (options.leadingZeros && !eAdjacentToLeadingZeros) {
51302
- trimmedStr = (notation[1] || "") + notation[3];
51303
- return Number(trimmedStr);
51304
- } else return str;
51305
- else return Number(trimmedStr);
51306
- } else return str;
51307
- }
51308
- /**
51309
- *
51310
- * @param {string} numStr without leading zeros
51311
- * @returns
51312
- */
51313
- function trimZeros(numStr) {
51314
- if (numStr && numStr.indexOf(".") !== -1) {
51315
- numStr = numStr.replace(/0+$/, "");
51316
- if (numStr === ".") numStr = "0";
51317
- else if (numStr[0] === ".") numStr = "0" + numStr;
51318
- else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
51319
- return numStr;
51320
- }
51321
- return numStr;
51322
- }
51323
- function parse_int(numStr, base) {
51324
- const str = numStr.trim();
51325
- if (base === 2 || base === 8) numStr = str.substring(2);
51326
- if (parseInt) return parseInt(numStr, base);
51327
- else if (Number.parseInt) return Number.parseInt(numStr, base);
51328
- else if (window && window.parseInt) return window.parseInt(numStr, base);
51329
- else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported");
51330
- }
51331
- /**
51332
- * Handle infinite values based on user option
51333
- * @param {string} str - original input string
51334
- * @param {number} num - parsed number (Infinity or -Infinity)
51335
- * @param {object} options - user options
51336
- * @returns {string|number|null} based on infinity option
51337
- */
51338
- function handleInfinity(str, num, options) {
51339
- const isPositive = num === Infinity;
51340
- switch (options.infinity.toLowerCase()) {
51341
- case "null": return null;
51342
- case "infinity": return num;
51343
- case "string": return isPositive ? "Infinity" : "-Infinity";
51344
- default: return str;
51345
- }
51346
- }
51347
- //#endregion
51348
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/ignoreAttributes.js
51349
- function getIgnoreAttributesFn(ignoreAttributes) {
51350
- if (typeof ignoreAttributes === "function") return ignoreAttributes;
51351
- if (Array.isArray(ignoreAttributes)) return (attrName) => {
51352
- for (const pattern of ignoreAttributes) {
51353
- if (typeof pattern === "string" && attrName === pattern) return true;
51354
- if (pattern instanceof RegExp && pattern.test(attrName)) return true;
51355
- }
51356
- };
51357
- return () => false;
51358
- }
51359
- //#endregion
51360
- //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/Expression.js
51361
- /**
51362
- * Expression - Parses and stores a tag pattern expression
51363
- *
51364
- * Patterns are parsed once and stored in an optimized structure for fast matching.
51365
- *
51366
- * @example
51367
- * const expr = new Expression("root.users.user");
51368
- * const expr2 = new Expression("..user[id]:first");
51369
- * const expr3 = new Expression("root/users/user", { separator: '/' });
51370
- */
51371
- var Expression = class {
51372
- /**
51373
- * Create a new Expression
51374
- * @param {string} pattern - Pattern string (e.g., "root.users.user", "..user[id]")
51375
- * @param {Object} options - Configuration options
51376
- * @param {string} options.separator - Path separator (default: '.')
51377
- */
51378
- constructor(pattern, options = {}, data) {
51379
- this.pattern = pattern;
51380
- this.separator = options.separator || ".";
51381
- this.segments = this._parse(pattern);
51382
- this.data = data;
51383
- this._hasDeepWildcard = this.segments.some((seg) => seg.type === "deep-wildcard");
51384
- this._hasAttributeCondition = this.segments.some((seg) => seg.attrName !== void 0);
51385
- this._hasPositionSelector = this.segments.some((seg) => seg.position !== void 0);
51386
- }
51387
- /**
51388
- * Parse pattern string into segments
51389
- * @private
51390
- * @param {string} pattern - Pattern to parse
51391
- * @returns {Array} Array of segment objects
51392
- */
51393
- _parse(pattern) {
51394
- const segments = [];
51395
- let i = 0;
51396
- let currentPart = "";
51397
- while (i < pattern.length) if (pattern[i] === this.separator) if (i + 1 < pattern.length && pattern[i + 1] === this.separator) {
51398
- if (currentPart.trim()) {
51399
- segments.push(this._parseSegment(currentPart.trim()));
51400
- currentPart = "";
51401
- }
51402
- segments.push({ type: "deep-wildcard" });
51403
- i += 2;
51404
- } else {
51405
- if (currentPart.trim()) segments.push(this._parseSegment(currentPart.trim()));
51406
- currentPart = "";
51407
- i++;
51408
- }
51409
- else {
51410
- currentPart += pattern[i];
51411
- i++;
51412
- }
51413
- if (currentPart.trim()) segments.push(this._parseSegment(currentPart.trim()));
51414
- return segments;
51415
- }
51416
- /**
51417
- * Parse a single segment
51418
- * @private
51419
- * @param {string} part - Segment string (e.g., "user", "ns::user", "user[id]", "ns::user:first")
51420
- * @returns {Object} Segment object
51421
- */
51422
- _parseSegment(part) {
51423
- const segment = { type: "tag" };
51424
- let bracketContent = null;
51425
- let withoutBrackets = part;
51426
- const bracketMatch = part.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);
51427
- if (bracketMatch) {
51428
- withoutBrackets = bracketMatch[1] + bracketMatch[3];
51429
- if (bracketMatch[2]) {
51430
- const content = bracketMatch[2].slice(1, -1);
51431
- if (content) bracketContent = content;
51432
- }
51433
- }
51434
- let namespace = void 0;
51435
- let tagAndPosition = withoutBrackets;
51436
- if (withoutBrackets.includes("::")) {
51437
- const nsIndex = withoutBrackets.indexOf("::");
51438
- namespace = withoutBrackets.substring(0, nsIndex).trim();
51439
- tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim();
51440
- if (!namespace) throw new Error(`Invalid namespace in pattern: ${part}`);
51441
- }
51442
- let tag = void 0;
51443
- let positionMatch = null;
51444
- if (tagAndPosition.includes(":")) {
51445
- const colonIndex = tagAndPosition.lastIndexOf(":");
51446
- const tagPart = tagAndPosition.substring(0, colonIndex).trim();
51447
- const posPart = tagAndPosition.substring(colonIndex + 1).trim();
51448
- if ([
51449
- "first",
51450
- "last",
51451
- "odd",
51452
- "even"
51453
- ].includes(posPart) || /^nth\(\d+\)$/.test(posPart)) {
51454
- tag = tagPart;
51455
- positionMatch = posPart;
51456
- } else tag = tagAndPosition;
51457
- } else tag = tagAndPosition;
51458
- if (!tag) throw new Error(`Invalid segment pattern: ${part}`);
51459
- segment.tag = tag;
51460
- if (namespace) segment.namespace = namespace;
51461
- if (bracketContent) if (bracketContent.includes("=")) {
51462
- const eqIndex = bracketContent.indexOf("=");
51463
- segment.attrName = bracketContent.substring(0, eqIndex).trim();
51464
- segment.attrValue = bracketContent.substring(eqIndex + 1).trim();
51465
- } else segment.attrName = bracketContent.trim();
51466
- if (positionMatch) {
51467
- const nthMatch = positionMatch.match(/^nth\((\d+)\)$/);
51468
- if (nthMatch) {
51469
- segment.position = "nth";
51470
- segment.positionValue = parseInt(nthMatch[1], 10);
51471
- } else segment.position = positionMatch;
51472
- }
51473
- return segment;
51474
- }
51475
- /**
51476
- * Get the number of segments
51477
- * @returns {number}
51478
- */
51479
- get length() {
51480
- return this.segments.length;
51481
- }
51482
- /**
51483
- * Check if expression contains deep wildcard
51484
- * @returns {boolean}
51485
- */
51486
- hasDeepWildcard() {
51487
- return this._hasDeepWildcard;
51488
- }
51489
- /**
51490
- * Check if expression has attribute conditions
51491
- * @returns {boolean}
51492
- */
51493
- hasAttributeCondition() {
51494
- return this._hasAttributeCondition;
51495
- }
51496
- /**
51497
- * Check if expression has position selectors
51498
- * @returns {boolean}
51499
- */
51500
- hasPositionSelector() {
51501
- return this._hasPositionSelector;
51502
- }
51503
- /**
51504
- * Get string representation
51505
- * @returns {string}
51506
- */
51507
- toString() {
51508
- return this.pattern;
51509
- }
51510
- };
51511
- //#endregion
51512
- //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/ExpressionSet.js
51513
- /**
51514
- * ExpressionSet - An indexed collection of Expressions for efficient bulk matching
51515
- *
51516
- * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes
51517
- * them at insertion time by depth and terminal tag name. At match time, only
51518
- * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1)
51519
- * lookup plus O(small bucket) matches.
51520
- *
51521
- * Three buckets are maintained:
51522
- * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first)
51523
- * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only)
51524
- * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed)
51525
- *
51526
- * @example
51527
- * import { Expression, ExpressionSet } from 'fast-xml-tagger';
51528
- *
51529
- * // Build once at config time
51530
- * const stopNodes = new ExpressionSet();
51531
- * stopNodes.add(new Expression('root.users.user'));
51532
- * stopNodes.add(new Expression('root.config.setting'));
51533
- * stopNodes.add(new Expression('..script'));
51534
- *
51535
- * // Query on every tag — hot path
51536
- * if (stopNodes.matchesAny(matcher)) { ... }
51537
- */
51538
- var ExpressionSet = class {
51539
- constructor() {
51540
- /** @type {Map<string, import('./Expression.js').default[]>} depth:tag → expressions */
51541
- this._byDepthAndTag = /* @__PURE__ */ new Map();
51542
- /** @type {Map<number, import('./Expression.js').default[]>} depth → wildcard-tag expressions */
51543
- this._wildcardByDepth = /* @__PURE__ */ new Map();
51544
- /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */
51545
- this._deepWildcards = [];
51546
- /** @type {Map<string, import('./Expression.js').default[]>} terminalTag → deep wildcard expressions */
51547
- this._deepByTerminalTag = /* @__PURE__ */ new Map();
51548
- /** @type {Set<string>} pattern strings already added — used for deduplication */
51549
- this._patterns = /* @__PURE__ */ new Set();
51550
- /** @type {boolean} whether the set is sealed against further additions */
51551
- this._sealed = false;
51552
- }
51553
- /**
51554
- * Add an Expression to the set.
51555
- * Duplicate patterns (same pattern string) are silently ignored.
51556
- *
51557
- * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance
51558
- * @returns {this} for chaining
51559
- * @throws {TypeError} if called after seal()
51560
- *
51561
- * @example
51562
- * set.add(new Expression('root.users.user'));
51563
- * set.add(new Expression('..script'));
51564
- */
51565
- add(expression) {
51566
- if (this._sealed) throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");
51567
- if (this._patterns.has(expression.pattern)) return this;
51568
- this._patterns.add(expression.pattern);
51569
- if (expression.hasDeepWildcard()) {
51570
- const lastSeg = expression.segments[expression.segments.length - 1];
51571
- if (lastSeg && lastSeg.type !== "deep-wildcard" && lastSeg.tag !== "*") {
51572
- const tag = lastSeg.tag;
51573
- if (!this._deepByTerminalTag.has(tag)) this._deepByTerminalTag.set(tag, []);
51574
- this._deepByTerminalTag.get(tag).push(expression);
51575
- } else this._deepWildcards.push(expression);
51576
- return this;
51577
- }
51578
- const depth = expression.length;
51579
- const tag = expression.segments[expression.segments.length - 1]?.tag;
51580
- if (!tag || tag === "*") {
51581
- if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []);
51582
- this._wildcardByDepth.get(depth).push(expression);
51583
- } else {
51584
- const key = `${depth}:${tag}`;
51585
- if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []);
51586
- this._byDepthAndTag.get(key).push(expression);
51587
- }
51588
- return this;
51589
- }
51590
- /**
51591
- * Add multiple expressions at once.
51592
- *
51593
- * @param {import('./Expression.js').default[]} expressions - Array of Expression instances
51594
- * @returns {this} for chaining
51595
- *
51596
- * @example
51597
- * set.addAll([
51598
- * new Expression('root.users.user'),
51599
- * new Expression('root.config.setting'),
51600
- * ]);
51601
- */
51602
- addAll(expressions) {
51603
- for (const expr of expressions) this.add(expr);
51604
- return this;
51605
- }
51606
- /**
51607
- * Check whether a pattern string is already present in the set.
51608
- *
51609
- * @param {import('./Expression.js').default} expression
51610
- * @returns {boolean}
51611
- */
51612
- has(expression) {
51613
- return this._patterns.has(expression.pattern);
51614
- }
51615
- /**
51616
- * Number of expressions in the set.
51617
- * @type {number}
51618
- */
51619
- get size() {
51620
- return this._patterns.size;
51621
- }
51622
- /**
51623
- * Seal the set against further modifications.
51624
- * Useful to prevent accidental mutations after config is built.
51625
- * Calling add() or addAll() on a sealed set throws a TypeError.
51626
- *
51627
- * @returns {this}
51628
- */
51629
- seal() {
51630
- this._sealed = true;
51631
- return this;
51632
- }
51633
- /**
51634
- * Whether the set has been sealed.
51635
- * @type {boolean}
51636
- */
51637
- get isSealed() {
51638
- return this._sealed;
51639
- }
51640
- /**
51641
- * Test whether the matcher's current path matches any expression in the set.
51642
- *
51643
- * Evaluation order (cheapest → most expensive):
51644
- * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions
51645
- * 2. Depth-only wildcard bucket — O(1) lookup, rare
51646
- * 3. Deep-wildcard list — always checked, but usually small
51647
- *
51648
- * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
51649
- * @returns {boolean} true if any expression matches the current path
51650
- *
51651
- * @example
51652
- * if (stopNodes.matchesAny(matcher)) {
51653
- * // handle stop node
51654
- * }
51655
- */
51656
- matchesAny(matcher) {
51657
- return this.findMatch(matcher) !== null;
51658
- }
51659
- /**
51660
- * Find and return the first Expression that matches the matcher's current path.
51661
- *
51662
- * Uses the same evaluation order as matchesAny (cheapest → most expensive):
51663
- * 1. Exact depth + tag bucket
51664
- * 2. Depth-only wildcard bucket
51665
- * 3. Deep-wildcard list
51666
- *
51667
- * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
51668
- * @returns {import('./Expression.js').default | null} the first matching Expression, or null
51669
- *
51670
- * @example
51671
- * const expr = stopNodes.findMatch(matcher);
51672
- * if (expr) {
51673
- * // access expr.config, expr.pattern, etc.
51674
- * }
51675
- */
51676
- findMatch(matcher) {
51677
- const depth = matcher.getDepth();
51678
- const tag = matcher.getCurrentTag();
51679
- const exactKey = `${depth}:${tag}`;
51680
- const exactBucket = this._byDepthAndTag.get(exactKey);
51681
- if (exactBucket) {
51682
- for (let i = 0; i < exactBucket.length; i++) if (matcher.matches(exactBucket[i])) return exactBucket[i];
51683
- }
51684
- const wildcardBucket = this._wildcardByDepth.get(depth);
51685
- if (wildcardBucket) {
51686
- for (let i = 0; i < wildcardBucket.length; i++) if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i];
51687
- }
51688
- const deepBucket = this._deepByTerminalTag.get(tag);
51689
- if (deepBucket) {
51690
- for (let i = 0; i < deepBucket.length; i++) if (matcher.matches(deepBucket[i])) return deepBucket[i];
51691
- }
51692
- for (let i = 0; i < this._deepWildcards.length; i++) if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];
51693
- return null;
51694
- }
51695
- };
51696
- //#endregion
51697
- //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/Matcher.js
51698
- /**
51699
- * MatcherView - A lightweight read-only view over a Matcher's internal state.
51700
- *
51701
- * Created once by Matcher and reused across all callbacks. Holds a direct
51702
- * reference to the parent Matcher so it always reflects current parser state
51703
- * with zero copying or freezing overhead.
51704
- *
51705
- * Users receive this via {@link Matcher#readOnly} or directly from parser
51706
- * callbacks. It exposes all query and matching methods but has no mutation
51707
- * methods — misuse is caught at the TypeScript level rather than at runtime.
51708
- *
51709
- * @example
51710
- * const matcher = new Matcher();
51711
- * const view = matcher.readOnly();
51712
- *
51713
- * matcher.push("root", {});
51714
- * view.getCurrentTag(); // "root"
51715
- * view.getDepth(); // 1
51716
- */
51717
- var MatcherView = class {
51718
- /**
51719
- * @param {Matcher} matcher - The parent Matcher instance to read from.
51720
- */
51721
- constructor(matcher) {
51722
- this._matcher = matcher;
51723
- }
51724
- /**
51725
- * Get the path separator used by the parent matcher.
51726
- * @returns {string}
51727
- */
51728
- get separator() {
51729
- return this._matcher.separator;
51730
- }
51731
- /**
51732
- * Get current tag name.
51733
- * @returns {string|undefined}
51734
- */
51735
- getCurrentTag() {
51736
- const path = this._matcher.path;
51737
- return path.length > 0 ? path[path.length - 1].tag : void 0;
51738
- }
51739
- /**
51740
- * Get current namespace.
51741
- * @returns {string|undefined}
51742
- */
51743
- getCurrentNamespace() {
51744
- const path = this._matcher.path;
51745
- return path.length > 0 ? path[path.length - 1].namespace : void 0;
51746
- }
51747
- /**
51748
- * Get current node's attribute value.
51749
- * @param {string} attrName
51750
- * @returns {*}
51751
- */
51752
- getAttrValue(attrName) {
51753
- const path = this._matcher.path;
51754
- if (path.length === 0) return void 0;
51755
- return path[path.length - 1].values?.[attrName];
51756
- }
51757
- /**
51758
- * Check if current node has an attribute.
51759
- * @param {string} attrName
51760
- * @returns {boolean}
51761
- */
51762
- hasAttr(attrName) {
51763
- const path = this._matcher.path;
51764
- if (path.length === 0) return false;
51765
- const current = path[path.length - 1];
51766
- return current.values !== void 0 && attrName in current.values;
51767
- }
51768
- /**
51769
- * Get the value of a "kept" attribute from the nearest ancestor (or
51770
- * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
51771
- * @param {string} attrName
51772
- * @returns {*}
51773
- */
51774
- getAnyParentAttr(attrName) {
51775
- return this._matcher.getAnyParentAttr(attrName);
51776
- }
51777
- /**
51778
- * Check whether any ancestor (or the current node) kept the given
51779
- * attribute via `push(tag, attrs, ns, { keep: [...] })`.
51780
- * @param {string} attrName
51781
- * @returns {boolean}
51782
- */
51783
- hasAnyParentAttr(attrName) {
51784
- return this._matcher.hasAnyParentAttr(attrName);
51785
- }
51786
- /**
51787
- * Get current node's sibling position (child index in parent).
51788
- * @returns {number}
51789
- */
51790
- getPosition() {
51791
- const path = this._matcher.path;
51792
- if (path.length === 0) return -1;
51793
- return path[path.length - 1].position ?? 0;
51794
- }
51795
- /**
51796
- * Get current node's repeat counter (occurrence count of this tag name).
51797
- * @returns {number}
51798
- */
51799
- getCounter() {
51800
- const path = this._matcher.path;
51801
- if (path.length === 0) return -1;
51802
- return path[path.length - 1].counter ?? 0;
51803
- }
51804
- /**
51805
- * Get current node's sibling index (alias for getPosition).
51806
- * @returns {number}
51807
- * @deprecated Use getPosition() or getCounter() instead
51808
- */
51809
- getIndex() {
51810
- return this.getPosition();
51811
- }
51812
- /**
51813
- * Get current path depth.
51814
- * @returns {number}
51815
- */
51816
- getDepth() {
51817
- return this._matcher.path.length;
51818
- }
51819
- /**
51820
- * Get path as string.
51821
- * @param {string} [separator] - Optional separator (uses default if not provided)
51822
- * @param {boolean} [includeNamespace=true]
51823
- * @returns {string}
51824
- */
51825
- toString(separator, includeNamespace = true) {
51826
- return this._matcher.toString(separator, includeNamespace);
51827
- }
51828
- /**
51829
- * Get path as array of tag names.
51830
- * @returns {string[]}
51831
- */
51832
- toArray() {
51833
- return this._matcher.path.map((n) => n.tag);
51834
- }
51835
- /**
51836
- * Match current path against an Expression.
51837
- * @param {Expression} expression
51838
- * @returns {boolean}
51839
- */
51840
- matches(expression) {
51841
- return this._matcher.matches(expression);
51842
- }
51843
- /**
51844
- * Match any expression in the given set against the current path.
51845
- * @param {ExpressionSet} exprSet
51846
- * @returns {boolean}
51847
- */
51848
- matchesAny(exprSet) {
51849
- return exprSet.matchesAny(this._matcher);
51850
- }
51851
- };
51852
- /**
51853
- * Matcher - Tracks current path in XML/JSON tree and matches against Expressions.
51854
- *
51855
- * The matcher maintains a stack of nodes representing the current path from root to
51856
- * current tag. It only stores attribute values for the current (top) node to minimize
51857
- * memory usage. Sibling tracking is used to auto-calculate position and counter.
51858
- *
51859
- * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to
51860
- * user callbacks — it always reflects current state with no Proxy overhead.
51861
- *
51862
- * @example
51863
- * const matcher = new Matcher();
51864
- * matcher.push("root", {});
51865
- * matcher.push("users", {});
51866
- * matcher.push("user", { id: "123", type: "admin" });
51867
- *
51868
- * const expr = new Expression("root.users.user");
51869
- * matcher.matches(expr); // true
51870
- */
51871
- var Matcher = class {
51872
- /**
51873
- * Create a new Matcher.
51874
- * @param {Object} [options={}]
51875
- * @param {string} [options.separator='.'] - Default path separator
51876
- */
51877
- constructor(options = {}) {
51878
- this.separator = options.separator || ".";
51879
- this.path = [];
51880
- this.siblingStacks = [];
51881
- this._pathStringCache = null;
51882
- this._view = new MatcherView(this);
51883
- this._keptAttrs = [];
51884
- }
51885
- /**
51886
- * Push a new tag onto the path.
51887
- * @param {string} tagName
51888
- * @param {Object|null} [attrValues=null]
51889
- * @param {string|null} [namespace=null]
51890
- * @param {Object|null} [options=null]
51891
- * @param {string[]} [options.keep] - Names of attributes (from attrValues)
51892
- */
51893
- push(tagName, attrValues = null, namespace = null, options = null) {
51894
- this._pathStringCache = null;
51895
- if (this.path.length > 0) this.path[this.path.length - 1].values = void 0;
51896
- const currentLevel = this.path.length;
51897
- let level = this.siblingStacks[currentLevel];
51898
- if (!level) {
51899
- level = {
51900
- counts: /* @__PURE__ */ new Map(),
51901
- total: 0
51902
- };
51903
- this.siblingStacks[currentLevel] = level;
51904
- }
51905
- const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
51906
- const counter = level.counts.get(siblingKey) || 0;
51907
- const position = level.total;
51908
- level.counts.set(siblingKey, counter + 1);
51909
- level.total++;
51910
- const node = {
51911
- tag: tagName,
51912
- position,
51913
- counter
51914
- };
51915
- if (namespace !== null && namespace !== void 0) node.namespace = namespace;
51916
- if (attrValues !== null && attrValues !== void 0) node.values = attrValues;
51917
- this.path.push(node);
51918
- const depth = this.path.length;
51919
- const keep = options !== null ? options.keep : null;
51920
- if (keep !== null && keep !== void 0 && keep.length > 0 && attrValues) for (let i = 0; i < keep.length; i++) {
51921
- const name = keep[i];
51922
- if (attrValues[name] !== void 0) this._keptAttrs.push({
51923
- depth,
51924
- name,
51925
- value: attrValues[name]
51926
- });
51927
- }
51928
- }
51929
- /**
51930
- * Pop the last tag from the path.
51931
- * @returns {Object|undefined} The popped node
51932
- */
51933
- pop() {
51934
- if (this.path.length === 0) return void 0;
51935
- this._pathStringCache = null;
51936
- const node = this.path.pop();
51937
- if (this.siblingStacks.length > this.path.length + 1) this.siblingStacks.length = this.path.length + 1;
51938
- const poppedDepth = this.path.length + 1;
51939
- while (this._keptAttrs.length > 0 && this._keptAttrs[this._keptAttrs.length - 1].depth >= poppedDepth) this._keptAttrs.pop();
51940
- return node;
51941
- }
51942
- /**
51943
- * Update current node's attribute values.
51944
- * Useful when attributes are parsed after push.
51945
- * @param {Object} attrValues
51946
- */
51947
- updateCurrent(attrValues) {
51948
- if (this.path.length > 0) {
51949
- const current = this.path[this.path.length - 1];
51950
- if (attrValues !== null && attrValues !== void 0) current.values = attrValues;
51951
- }
51952
- }
51953
- /**
51954
- * Get current tag name.
51955
- * @returns {string|undefined}
51956
- */
51957
- getCurrentTag() {
51958
- return this.path.length > 0 ? this.path[this.path.length - 1].tag : void 0;
51959
- }
51960
- /**
51961
- * Get current namespace.
51962
- * @returns {string|undefined}
51963
- */
51964
- getCurrentNamespace() {
51965
- return this.path.length > 0 ? this.path[this.path.length - 1].namespace : void 0;
51966
- }
51967
- /**
51968
- * Get current node's attribute value.
51969
- * @param {string} attrName
51970
- * @returns {*}
51971
- */
51972
- getAttrValue(attrName) {
51973
- if (this.path.length === 0) return void 0;
51974
- return this.path[this.path.length - 1].values?.[attrName];
51975
- }
51976
- /**
51977
- * Check if current node has an attribute.
51978
- * @param {string} attrName
51979
- * @returns {boolean}
51980
- */
51981
- hasAttr(attrName) {
51982
- if (this.path.length === 0) return false;
51983
- const current = this.path[this.path.length - 1];
51984
- return current.values !== void 0 && attrName in current.values;
51985
- }
51986
- /**
51987
- * Get the value of a "kept" attribute from the nearest ancestor (or
51988
- * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
51989
- * Unlike getAttrValue(), this works regardless of how deep the path has
51990
- * gone since the attribute was pushed — but only for attribute names that
51991
- * were explicitly marked with `keep` at push time. Cost is proportional to
51992
- * the number of currently-kept attributes (typically 0-3), not path depth.
51993
- * @param {string} attrName
51994
- * @returns {*} the value, or undefined if no ancestor kept this attribute
51995
- */
51996
- getAnyParentAttr(attrName) {
51997
- const kept = this._keptAttrs;
51998
- for (let i = kept.length - 1; i >= 0; i--) if (kept[i].name === attrName) return kept[i].value;
51999
- }
52000
- /**
52001
- * Check whether any ancestor (or the current node) kept the given
52002
- * attribute via `push(tag, attrs, ns, { keep: [...] })`.
52003
- * @param {string} attrName
52004
- * @returns {boolean}
52005
- */
52006
- hasAnyParentAttr(attrName) {
52007
- const kept = this._keptAttrs;
52008
- for (let i = kept.length - 1; i >= 0; i--) if (kept[i].name === attrName) return true;
52009
- return false;
52010
- }
52011
- /**
52012
- * Get current node's sibling position (child index in parent).
52013
- * @returns {number}
52014
- */
52015
- getPosition() {
52016
- if (this.path.length === 0) return -1;
52017
- return this.path[this.path.length - 1].position ?? 0;
52018
- }
52019
- /**
52020
- * Get current node's repeat counter (occurrence count of this tag name).
52021
- * @returns {number}
52022
- */
52023
- getCounter() {
52024
- if (this.path.length === 0) return -1;
52025
- return this.path[this.path.length - 1].counter ?? 0;
52026
- }
52027
- /**
52028
- * Get current node's sibling index (alias for getPosition).
52029
- * @returns {number}
52030
- * @deprecated Use getPosition() or getCounter() instead
52031
- */
52032
- getIndex() {
52033
- return this.getPosition();
52034
- }
52035
- /**
52036
- * Get current path depth.
52037
- * @returns {number}
52038
- */
52039
- getDepth() {
52040
- return this.path.length;
52041
- }
52042
- /**
52043
- * Get path as string.
52044
- * @param {string} [separator] - Optional separator (uses default if not provided)
52045
- * @param {boolean} [includeNamespace=true]
52046
- * @returns {string}
52047
- */
52048
- toString(separator, includeNamespace = true) {
52049
- const sep = separator || this.separator;
52050
- if (sep === this.separator && includeNamespace === true) {
52051
- if (this._pathStringCache !== null) return this._pathStringCache;
52052
- const result = this.path.map((n) => n.namespace ? `${n.namespace}:${n.tag}` : n.tag).join(sep);
52053
- this._pathStringCache = result;
52054
- return result;
52055
- }
52056
- return this.path.map((n) => includeNamespace && n.namespace ? `${n.namespace}:${n.tag}` : n.tag).join(sep);
52057
- }
52058
- /**
52059
- * Get path as array of tag names.
52060
- * @returns {string[]}
52061
- */
52062
- toArray() {
52063
- return this.path.map((n) => n.tag);
52064
- }
52065
- /**
52066
- * Reset the path to empty.
52067
- */
52068
- reset() {
52069
- this._pathStringCache = null;
52070
- this.path = [];
52071
- this.siblingStacks = [];
52072
- this._keptAttrs = [];
52073
- }
52074
- /**
52075
- * Match current path against an Expression.
52076
- * @param {Expression} expression
52077
- * @returns {boolean}
52078
- */
52079
- matches(expression) {
52080
- const segments = expression.segments;
52081
- if (segments.length === 0) return false;
52082
- if (expression.hasDeepWildcard()) return this._matchWithDeepWildcard(segments);
52083
- return this._matchSimple(segments);
52084
- }
52085
- /**
52086
- * @private
52087
- */
52088
- _matchSimple(segments) {
52089
- if (this.path.length !== segments.length) return false;
52090
- for (let i = 0; i < segments.length; i++) if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) return false;
52091
- return true;
52092
- }
52093
- /**
52094
- * @private
52095
- */
52096
- _matchWithDeepWildcard(segments) {
52097
- let pathIdx = this.path.length - 1;
52098
- let segIdx = segments.length - 1;
52099
- while (segIdx >= 0 && pathIdx >= 0) {
52100
- const segment = segments[segIdx];
52101
- if (segment.type === "deep-wildcard") {
52102
- segIdx--;
52103
- if (segIdx < 0) return true;
52104
- const nextSeg = segments[segIdx];
52105
- let found = false;
52106
- for (let i = pathIdx; i >= 0; i--) if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) {
52107
- pathIdx = i - 1;
52108
- segIdx--;
52109
- found = true;
52110
- break;
52111
- }
52112
- if (!found) return false;
52113
- } else {
52114
- if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) return false;
52115
- pathIdx--;
52116
- segIdx--;
52117
- }
52118
- }
52119
- return segIdx < 0;
52120
- }
52121
- /**
52122
- * @private
52123
- */
52124
- _matchSegment(segment, node, isCurrentNode) {
52125
- if (segment.tag !== "*" && segment.tag !== node.tag) return false;
52126
- if (segment.namespace !== void 0) {
52127
- if (segment.namespace !== "*" && segment.namespace !== node.namespace) return false;
52128
- }
52129
- if (segment.attrName !== void 0) {
52130
- if (!isCurrentNode) return false;
52131
- if (!node.values || !(segment.attrName in node.values)) return false;
52132
- if (segment.attrValue !== void 0) {
52133
- if (String(node.values[segment.attrName]) !== String(segment.attrValue)) return false;
52134
- }
52135
- }
52136
- if (segment.position !== void 0) {
52137
- if (!isCurrentNode) return false;
52138
- const counter = node.counter ?? 0;
52139
- if (segment.position === "first" && counter !== 0) return false;
52140
- else if (segment.position === "odd" && counter % 2 !== 1) return false;
52141
- else if (segment.position === "even" && counter % 2 !== 0) return false;
52142
- else if (segment.position === "nth" && counter !== segment.positionValue) return false;
52143
- }
52144
- return true;
52145
- }
52146
- /**
52147
- * Match any expression in the given set against the current path.
52148
- * @param {ExpressionSet} exprSet
52149
- * @returns {boolean}
52150
- */
52151
- matchesAny(exprSet) {
52152
- return exprSet.matchesAny(this);
52153
- }
52154
- /**
52155
- * Create a snapshot of current state.
52156
- * @returns {Object}
52157
- */
52158
- snapshot() {
52159
- return {
52160
- path: this.path.map((node) => ({ ...node })),
52161
- siblingStacks: this.siblingStacks.map((level) => level ? {
52162
- counts: new Map(level.counts),
52163
- total: level.total
52164
- } : level),
52165
- keptAttrs: this._keptAttrs.map((entry) => ({ ...entry }))
52166
- };
52167
- }
52168
- /**
52169
- * Restore state from snapshot.
52170
- * @param {Object} snapshot
52171
- */
52172
- restore(snapshot) {
52173
- this._pathStringCache = null;
52174
- this.path = snapshot.path.map((node) => ({ ...node }));
52175
- this.siblingStacks = snapshot.siblingStacks.map((level) => level ? {
52176
- counts: new Map(level.counts),
52177
- total: level.total
52178
- } : level);
52179
- this._keptAttrs = (snapshot.keptAttrs || []).map((entry) => ({ ...entry }));
52180
- }
52181
- /**
52182
- * Return the read-only {@link MatcherView} for this matcher.
52183
- *
52184
- * The same instance is returned on every call — no allocation occurs.
52185
- * It always reflects the current parser state and is safe to pass to
52186
- * user callbacks without risk of accidental mutation.
52187
- *
52188
- * @returns {MatcherView}
52189
- *
52190
- * @example
52191
- * const view = matcher.readOnly();
52192
- * // pass view to callbacks — it stays in sync automatically
52193
- * view.matches(expr); // ✓
52194
- * view.getCurrentTag(); // ✓
52195
- * // view.push(...) // ✗ method does not exist — caught by TypeScript
52196
- */
52197
- readOnly() {
52198
- return this._view;
52199
- }
52200
- };
52201
- //#endregion
52202
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/html.js
52203
- /**
52204
- * HTML context patterns.
52205
- *
52206
- * Detects XSS vectors that are dangerous when a string ends up rendered as HTML.
52207
- * All patterns use bounded quantifiers to ensure linear-time matching (ReDoS-safe).
52208
- *
52209
- * Each entry is { pattern: RegExp, id: string, description: string }
52210
- * so callers can inspect which rule fired if they need to.
52211
- */
52212
- const HTML_PATTERNS = [
52213
- {
52214
- id: "html-script-open",
52215
- description: "<script opening tag",
52216
- pattern: /<script[\s>/]/i
52217
- },
52218
- {
52219
- id: "html-script-close",
52220
- description: "<\/script closing tag",
52221
- pattern: /<\/script[\s>]/i
52222
- },
52223
- {
52224
- id: "html-javascript-protocol",
52225
- description: "javascript: URI scheme (with optional whitespace/encoding)",
52226
- 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
52227
- },
52228
- {
52229
- id: "html-vbscript-protocol",
52230
- description: "vbscript: URI scheme",
52231
- pattern: /vbscript[\t\n\r ]*:/i
52232
- },
52233
- {
52234
- id: "html-data-html",
52235
- description: "data:text/html URI — can execute scripts in browsers",
52236
- pattern: /data[\t\n\r ]*:[\t\n\r ]*text\/html/i
52237
- },
52238
- {
52239
- id: "html-data-xhtml",
52240
- description: "data:application/xhtml+xml URI",
52241
- pattern: /data[\t\n\r ]*:[\t\n\r ]*application\/xhtml/i
52242
- },
52243
- {
52244
- id: "html-data-svg",
52245
- description: "data:image/svg+xml URI — can execute scripts",
52246
- pattern: /data[\t\n\r ]*:[\t\n\r ]*image\/svg\+xml/i
52247
- },
52248
- {
52249
- id: "html-inline-event-handler",
52250
- description: "Inline event handler attributes: onclick=, onerror=, onload=, etc.",
52251
- pattern: /\bon\w{1,30}\s*=/i
52252
- },
52253
- {
52254
- id: "html-entity-obfuscated-script",
52255
- description: "HTML-entity-encoded <script (e.g. &#x3C;script or &lt;script)",
52256
- pattern: /(?:&#x0*3[Cc];?|&#0*60;?|&lt;)\s*script/i
52257
- },
52258
- {
52259
- id: "html-entity-obfuscated-javascript",
52260
- description: "HTML-entity-encoded javascript: (partial — catches common &#106; or &#x6a; for \"j\")",
52261
- pattern: /(?:&#x0*6[Aa];?|&#0*106;?)\s*(?:&#x0*61;?|a)[\s\S]{0,80}script\s*:/i
52262
- },
52263
- {
52264
- id: "html-style-expression",
52265
- description: "CSS expression() — IE-era code execution in style attributes",
52266
- pattern: /style[\s\S]{0,20}expression\s*\(/i
52267
- },
52268
- {
52269
- id: "html-object-embed",
52270
- description: "<object or <embed tags that can load active content",
52271
- pattern: /<(?:object|embed)[\s>/]/i
52272
- },
52273
- {
52274
- id: "html-base-tag",
52275
- description: "<base href= — can hijack all relative URLs on a page",
52276
- pattern: /<base[\s>]/i
52277
- },
52278
- {
52279
- id: "html-meta-refresh",
52280
- description: "<meta http-equiv=\"refresh\" — can redirect users",
52281
- pattern: /<meta[\s\S]{0,40}http-equiv[\s\S]{0,20}refresh/i
52282
- },
52283
- {
52284
- id: "html-srcdoc",
52285
- description: "srcdoc= attribute on iframes — embeds HTML that can run scripts",
52286
- pattern: /srcdoc\s*=/i
52287
- },
52288
- {
52289
- id: "html-iframe",
52290
- description: "<iframe tag",
52291
- pattern: /<iframe[\s>/]/i
52292
- },
52293
- {
52294
- id: "html-form",
52295
- description: "<form tag — can be used for phishing / credential harvesting injection",
52296
- pattern: /<form[\s>/]/i
52297
- }
52298
- ];
52299
- //#endregion
52300
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/xml.js
52301
- /**
52302
- * XML context patterns.
52303
- *
52304
- * Detects injection vectors that are specifically dangerous when a string
52305
- * is inserted into an XML document (not HTML rendering context).
52306
- *
52307
- * Key distinction from HTML: these patterns target parser-level attacks —
52308
- * things that can confuse or subvert an XML parser, trigger external entity
52309
- * resolution, or inject DTD content. HTML rendering concerns (XSS) belong
52310
- * in the HTML context.
52311
- */
52312
- const XML_PATTERNS = [
52313
- {
52314
- id: "xml-cdata-injection",
52315
- description: "CDATA section injection: <![CDATA[ breaks out of text node context",
52316
- pattern: /<!\[CDATA\[/i
52317
- },
52318
- {
52319
- id: "xml-cdata-close",
52320
- description: "CDATA close sequence: ]]> can terminate an enclosing CDATA section",
52321
- pattern: /\]\]>/
52322
- },
52323
- {
52324
- id: "xml-processing-instruction",
52325
- description: "XML processing instruction: <?xml-stylesheet or <?php etc.",
52326
- pattern: /<\?(?:xml[\- ]|php|asp)/i
52327
- },
52328
- {
52329
- id: "xml-doctype-injection",
52330
- description: "DOCTYPE declaration embedded in content — can define entities",
52331
- pattern: /<!DOCTYPE(?:[\s[]|$)/i
52332
- },
52333
- {
52334
- id: "xml-entity-system",
52335
- description: "SYSTEM keyword — used in external entity declarations (XXE)",
52336
- pattern: /\bSYSTEM\s+["']/i
52337
- },
52338
- {
52339
- id: "xml-entity-public",
52340
- description: "PUBLIC keyword — used in external entity declarations (XXE)",
52341
- pattern: /\bPUBLIC\s+["']/i
52342
- },
52343
- {
52344
- id: "xml-entity-declaration",
52345
- description: "<!ENTITY declaration — defines entities, potential XXE or entity expansion",
52346
- pattern: /<!ENTITY[\s%]/i
52347
- },
52348
- {
52349
- id: "xml-billion-laughs",
52350
- description: "Entity reference chaining / billion laughs: repeated &eX; style references",
52351
- pattern: /(?:&\w{1,20};){3,}/
52352
- },
52353
- {
52354
- id: "xml-namespace-confusion",
52355
- description: "xmlns: attribute injection — can redefine namespaces to confuse parsers",
52356
- pattern: /\bxmlns\s*(?::\w{1,40})?\s*=/i
52357
- },
52358
- {
52359
- id: "xml-comment-injection",
52360
- description: "<!-- comment injection — can hide content from some parsers",
52361
- pattern: /<!--/
52362
- },
52363
- {
52364
- id: "xml-comment-close",
52365
- description: "--> closes an enclosing XML comment",
52366
- pattern: /-->/
52367
- },
52368
- {
52369
- id: "xml-pi-close",
52370
- description: "?> closes an enclosing processing instruction",
52371
- pattern: /\?>/
52372
- }
52373
- ];
52374
- //#endregion
52375
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/svg.js
52376
- /**
52377
- * SVG context patterns.
52378
- *
52379
- * SVG is XML-based but renders in browsers, giving it a unique attack surface
52380
- * that combines XML parser behaviour with browser rendering and JavaScript execution.
52381
- *
52382
- * Many of these vectors bypass HTML sanitizers that don't understand SVG semantics
52383
- * (DOMPurify has documented bypass vulnerabilities specifically in SVG/XML context).
52384
- */
52385
- const SVG_PATTERNS = [
52386
- {
52387
- id: "svg-script-element",
52388
- description: "<script element inside SVG executes JavaScript",
52389
- pattern: /<script[\s>/]/i
52390
- },
52391
- {
52392
- id: "svg-xlink-href-javascript",
52393
- description: "xlink:href with javascript: — classic SVG XSS via <a> or <use>",
52394
- pattern: /xlink\s*:\s*href\s*=\s*["']?\s*javascript\s*:/i
52395
- },
52396
- {
52397
- id: "svg-href-javascript",
52398
- description: "href= with javascript: in SVG context (<a>, <animate>, etc.)",
52399
- pattern: /href\s*=\s*["']?\s*javascript\s*:/i
52400
- },
52401
- {
52402
- id: "svg-foreignobject",
52403
- description: "<foreignObject embeds HTML inside SVG — can execute scripts",
52404
- pattern: /<foreignObject[\s>/]/i
52405
- },
52406
- {
52407
- id: "svg-use-external",
52408
- description: "<use xlink:href or href pointing to external resource (non-fragment URL)",
52409
- pattern: /<use[\s\S]{0,60}(?:xlink\s*:\s*)?href\s*=\s*(?:["'][^#]|[^"'#\s>])/i
52410
- },
52411
- {
52412
- id: "svg-animate-href",
52413
- description: "<animate attributeName=\"href\" — can dynamically change href to javascript:",
52414
- pattern: /<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*href["']/i
52415
- },
52416
- {
52417
- id: "svg-animate-xlinkhref",
52418
- description: "<animate attributeName=\"xlink:href\"",
52419
- pattern: /<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*xlink\s*:\s*href["']/i
52420
- },
52421
- {
52422
- id: "svg-set-javascript",
52423
- description: "<set to=\"javascript:...\" — sets an attribute to a javascript: URI",
52424
- pattern: /<set[\s\S]{0,80}to\s*=\s*["']?\s*javascript\s*:/i
52425
- },
52426
- {
52427
- id: "svg-event-handler",
52428
- description: "SVG-specific event handler attributes: onload=, onerror=, onactivate=, etc.",
52429
- pattern: /\bon(?:load|error|activate|begin|end|repeat|focus|blur|click|mouse\w{1,20}|key\w{1,20})\s*=/i
52430
- },
52431
- {
52432
- id: "svg-handler-generic",
52433
- description: "Generic on* handler catch-all for SVG attributes",
52434
- pattern: /\bon\w{1,30}\s*=/i
52435
- },
52436
- {
52437
- id: "svg-filter-feimage",
52438
- description: "<feImage href= — filter primitive that can load external resources",
52439
- pattern: /<feImage[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=/i
52440
- },
52441
- {
52442
- id: "svg-image-external",
52443
- description: "<image xlink:href with http/https or javascript protocol",
52444
- pattern: /<image[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=\s*["']?\s*(?:https?|javascript)\s*:/i
52445
- },
52446
- {
52447
- id: "svg-style-javascript",
52448
- description: "style= attribute containing javascript: (e.g. background:url(javascript:...))",
52449
- pattern: /style\s*=[\s\S]{0,60}javascript\s*:/i
52450
- }
52451
- ];
52452
- //#endregion
52453
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/sql.js
52454
- /**
52455
- * SQL context patterns — high-precision rules only.
52456
- *
52457
- * These rules have very low false-positive risk and are safe to apply to
52458
- * general user text (names, descriptions, search queries, etc.).
52459
- * All patterns are ReDoS-safe — unlike the `sql-injection` npm package
52460
- * which has an active CVE on its own detection regexes.
52461
- *
52462
- * For exhaustive coverage including noisier heuristics (comment sequences,
52463
- * hex literals, stacked queries with semicolons), use 'SQL-STRICT' instead.
52464
- * Apply 'SQL-STRICT' only to strings that are specifically SQL fragments,
52465
- * not to general free-text fields.
52466
- */
52467
- const SQL_PATTERNS = [
52468
- {
52469
- id: "sql-block-comment-open",
52470
- description: "SQL block comment open: /* ... */ — unusual in legitimate user text",
52471
- pattern: /\/\*/
52472
- },
52473
- {
52474
- id: "sql-union-select",
52475
- description: "UNION SELECT — most common SQL injection aggregation attack",
52476
- pattern: /\bUNION\s{1,20}(?:ALL\s{1,20})?SELECT\b/i
52477
- },
52478
- {
52479
- id: "sql-drop-table",
52480
- description: "DROP TABLE — destructive DDL injection",
52481
- pattern: /\bDROP\s{1,20}TABLE\b/i
52482
- },
52483
- {
52484
- id: "sql-drop-database",
52485
- description: "DROP DATABASE — destructive DDL injection",
52486
- pattern: /\bDROP\s{1,20}DATABASE\b/i
52487
- },
52488
- {
52489
- id: "sql-insert-into",
52490
- description: "INSERT INTO — data injection",
52491
- pattern: /\bINSERT\s{1,20}INTO\b/i
52492
- },
52493
- {
52494
- id: "sql-delete-from",
52495
- description: "DELETE FROM — data deletion injection",
52496
- pattern: /\bDELETE\s{1,20}FROM\b/i
52497
- },
52498
- {
52499
- id: "sql-update-set",
52500
- description: "UPDATE ... SET — data modification injection",
52501
- pattern: /\bUPDATE\b[\s\S]{1,60}\bSET\b/i
52502
- },
52503
- {
52504
- id: "sql-exec-xp",
52505
- description: "EXEC xp_ — MSSQL extended stored procedure execution",
52506
- pattern: /\bEXEC(?:UTE)?\s{1,20}xp_/i
52507
- },
52508
- {
52509
- id: "sql-tautology-string",
52510
- description: "Classic string tautology: ' OR '1'='1 or \" OR \"1\"=\"1\"",
52511
- pattern: /'\s{0,10}OR\s{0,10}'[^']{0,20}'\s*=\s*'[^']{0,20}/i
52512
- },
52513
- {
52514
- id: "sql-tautology-numeric",
52515
- description: "Numeric tautology: OR 1=1",
52516
- pattern: /\bOR\s{1,10}1\s*=\s*1\b/i
52517
- },
52518
- {
52519
- id: "sql-always-true-zero",
52520
- description: "Numeric tautology: OR 0=0",
52521
- pattern: /\bOR\s{1,10}0\s*=\s*0\b/i
52522
- },
52523
- {
52524
- id: "sql-sleep-benchmark",
52525
- description: "Time-based blind injection: SLEEP() or BENCHMARK()",
52526
- pattern: /\b(?:SLEEP|BENCHMARK)\s*\(/i
52527
- },
52528
- {
52529
- id: "sql-waitfor-delay",
52530
- description: "MSSQL time-based blind injection: WAITFOR DELAY",
52531
- pattern: /\bWAITFOR\s{1,20}DELAY\b/i
52532
- },
52533
- {
52534
- id: "sql-char-function",
52535
- description: "CHAR() function — used to obfuscate injected strings",
52536
- pattern: /\bCHAR\s*\(\s*\d{1,3}/i
52537
- },
52538
- {
52539
- id: "sql-information-schema",
52540
- description: "INFORMATION_SCHEMA — reconnaissance query for table/column enumeration",
52541
- pattern: /\bINFORMATION_SCHEMA\b/i
52542
- }
52543
- ];
52544
- //#endregion
52545
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/shell.js
52546
- /**
52547
- * SHELL context patterns.
52548
- *
52549
- * Detects shell injection vectors and path traversal patterns.
52550
- * Designed for use when a string will be passed to a shell command,
52551
- * used as a file path, or interpolated into OS-level operations.
52552
- */
52553
- const SHELL_PATTERNS = [
52554
- {
52555
- id: "shell-path-traversal-unix",
52556
- description: "Unix path traversal: ../ — climbing the directory tree",
52557
- pattern: /\.\.\//
52558
- },
52559
- {
52560
- id: "shell-path-traversal-windows",
52561
- description: "Windows path traversal: ..\\ — climbing the directory tree",
52562
- pattern: /\.\.\\/
52563
- },
52564
- {
52565
- id: "shell-path-traversal-encoded",
52566
- description: "URL-encoded path traversal: %2e%2e or %2f variants",
52567
- pattern: /%2e%2e|%2f\.\.|\.\.%2f/i
52568
- },
52569
- {
52570
- id: "shell-null-byte",
52571
- description: "Null byte injection: \\x00 or %00 — truncates strings in C-backed functions",
52572
- pattern: /\x00|%00/
52573
- },
52574
- {
52575
- id: "shell-semicolon",
52576
- description: "Semicolon command separator: cmd1; cmd2",
52577
- pattern: /;/
52578
- },
52579
- {
52580
- id: "shell-pipe",
52581
- description: "Pipe operator: cmd1 | cmd2",
52582
- pattern: /\|/
52583
- },
52584
- {
52585
- id: "shell-and-operator",
52586
- description: "AND operator: cmd1 && cmd2",
52587
- pattern: /&&/
52588
- },
52589
- {
52590
- id: "shell-or-operator",
52591
- description: "OR operator: cmd1 || cmd2",
52592
- pattern: /\|\|/
52593
- },
52594
- {
52595
- id: "shell-backtick",
52596
- description: "Backtick command substitution: `cmd`",
52597
- pattern: /`/
52598
- },
52599
- {
52600
- id: "shell-dollar-paren",
52601
- description: "Dollar-paren command substitution: $(cmd)",
52602
- pattern: /\$\(/
52603
- },
52604
- {
52605
- id: "shell-dollar-brace",
52606
- description: "Dollar-brace variable expansion: ${var} — can be abused for injection",
52607
- pattern: /\$\{/
52608
- },
52609
- {
52610
- id: "shell-redirect-out",
52611
- description: "Output redirection: cmd > file or cmd >> file",
52612
- pattern: />{1,2}/
52613
- },
52614
- {
52615
- id: "shell-redirect-in",
52616
- description: "Input redirection: cmd < file",
52617
- pattern: /</
52618
- },
52619
- {
52620
- id: "shell-newline-injection",
52621
- description: "Newline injection: \\n or \\r — can inject new shell commands",
52622
- pattern: /[\n\r]/
52623
- },
52624
- {
52625
- id: "shell-glob-star",
52626
- description: "Glob expansion: * or ? — can expand to unintended files",
52627
- pattern: /[/\\][*?]/
52628
- },
52629
- {
52630
- id: "shell-absolute-root",
52631
- description: "Absolute root path injection: string starting with / or \\ (Windows UNC)",
52632
- pattern: /^(?:\/|\\\\)/
52633
- },
52634
- {
52635
- id: "shell-windows-drive",
52636
- description: "Windows drive letter path injection: C:\\ or D:/",
52637
- pattern: /^[a-zA-Z]:[/\\]/
52638
- },
52639
- {
52640
- id: "shell-curl-wget",
52641
- description: "curl/wget with URL or flags — can exfiltrate data or download payloads",
52642
- pattern: /\b(?:curl|wget)\s+(?:https?:\/\/|ftp:\/\/|-)/i
52643
- }
52644
- ];
52645
- //#endregion
52646
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/redos.js
52647
- /**
52648
- * REDOS context patterns.
52649
- *
52650
- * Detects strings that, if used as regular expressions, could cause
52651
- * catastrophic backtracking (ReDoS — Regular Expression Denial of Service).
52652
- *
52653
- * These patterns detect the structural forms that lead to exponential or
52654
- * polynomial backtracking in NFA-based regex engines (V8, PCRE, Java, etc.).
52655
- *
52656
- * Use this context when user-supplied strings will be compiled into RegExp objects.
52657
- */
52658
- const REDOS_PATTERNS = [
52659
- {
52660
- id: "redos-nested-quantifier-plus",
52661
- description: "Nested + quantifier inside a group with outer quantifier: (a+)+, (.+b)*, etc.",
52662
- pattern: /\([^)]*\+[^)]*\)[+*]/
52663
- },
52664
- {
52665
- id: "redos-nested-quantifier-star",
52666
- description: "Nested * quantifier: (a*)* or (a*)+ — catastrophic backtracking",
52667
- pattern: /\([^)]*\*[^)]*\)[*+]/
52668
- },
52669
- {
52670
- id: "redos-nested-groups",
52671
- description: "Doubly nested quantified groups: ((a+)+) — guaranteed catastrophic",
52672
- pattern: /\(\([^)]{0,40}\)[+*]\)[+*]/
52673
- },
52674
- {
52675
- id: "redos-alternation-overlap",
52676
- description: "Overlapping alternation under quantifier: (a|a)+ — ambiguous NFA paths",
52677
- pattern: /\(([^|()]{1,20})\|(?:\1)(?:\|[^|()]{1,20}){0,5}\)[+*?]{1,2}/
52678
- },
52679
- {
52680
- id: "redos-star-plus-concat",
52681
- description: "(x*x)+ pattern — triggers super-linear backtracking",
52682
- pattern: /\([^)]{0,10}\*[^)]{0,10}\)[+*]/
52683
- },
52684
- {
52685
- id: "redos-dot-star-greedy",
52686
- description: "(.*){n,} or (.+){n,} — repeated greedy dot quantifiers",
52687
- pattern: /\(\.[*+]\)\{?\d/
52688
- },
52689
- {
52690
- id: "redos-large-repetition",
52691
- description: "Very large fixed or range repetition count {1000,} or {1000,n} — denial of service via backtracking",
52692
- pattern: /\{\d{4,}(?:,\d*)?\}/
52693
- },
52694
- {
52695
- id: "redos-catastrophic-alternation",
52696
- description: "Long alternation with many similar branches — polynomial backtracking risk",
52697
- pattern: /\([^)]{0,200}(?:\|[^|)]{0,50}){9,}\)/
52698
- }
52699
- ];
52700
- //#endregion
52701
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/nosql.js
52702
- const sep$1 = "[\"'\\s]*:";
52703
- const NOSQL_PATTERNS = [
52704
- {
52705
- id: "nosql-where-operator",
52706
- description: "$where — executes arbitrary JavaScript server-side in MongoDB",
52707
- pattern: new RegExp(`\\$where${sep$1}`, "i")
52708
- },
52709
- {
52710
- id: "nosql-ne-operator",
52711
- description: "$ne — \"not equal\" operator used to bypass equality checks",
52712
- pattern: new RegExp(`\\$ne${sep$1}`, "i")
52713
- },
52714
- {
52715
- id: "nosql-gt-operator",
52716
- description: "$gt — \"greater than\" used to bypass password/value checks",
52717
- pattern: new RegExp(`\\$gte?${sep$1}`, "i")
52718
- },
52719
- {
52720
- id: "nosql-lt-operator",
52721
- description: "$lt / $lte — \"less than\" bypass variants",
52722
- pattern: new RegExp(`\\$lte?${sep$1}`, "i")
52723
- },
52724
- {
52725
- id: "nosql-regex-operator",
52726
- description: "$regex — can be used to extract data character by character (blind injection)",
52727
- pattern: new RegExp(`\\$regex${sep$1}`, "i")
52728
- },
52729
- {
52730
- id: "nosql-or-operator",
52731
- description: "$or — logical OR; used to create always-true conditions",
52732
- pattern: new RegExp(`\\$or${sep$1}\\s*\\[`, "i")
52733
- },
52734
- {
52735
- id: "nosql-and-operator",
52736
- description: "$and — logical AND operator injection",
52737
- pattern: new RegExp(`\\$and${sep$1}\\s*\\[`, "i")
52738
- },
52739
- {
52740
- id: "nosql-nor-operator",
52741
- description: "$nor — logical NOR operator injection",
52742
- pattern: new RegExp(`\\$nor${sep$1}\\s*\\[`, "i")
52743
- },
52744
- {
52745
- id: "nosql-exists-operator",
52746
- description: "$exists — can enumerate fields to determine schema",
52747
- pattern: new RegExp(`\\$exists${sep$1}`, "i")
52748
- },
52749
- {
52750
- id: "nosql-in-operator",
52751
- description: "$in — matches any value in a list; can enumerate values",
52752
- pattern: new RegExp(`\\$in${sep$1}\\s*\\[`, "i")
52753
- },
52754
- {
52755
- id: "nosql-expr-operator",
52756
- description: "$expr — allows aggregation expressions in queries (MongoDB 3.6+)",
52757
- pattern: new RegExp(`\\$expr${sep$1}`, "i")
52758
- },
52759
- {
52760
- id: "nosql-function-operator",
52761
- description: "$function — executes arbitrary JavaScript in MongoDB 4.4+",
52762
- pattern: new RegExp(`\\$function${sep$1}`, "i")
52763
- },
52764
- {
52765
- id: "nosql-accumulator-operator",
52766
- description: "$accumulator — custom aggregation with arbitrary JS execution",
52767
- pattern: new RegExp(`\\$accumulator${sep$1}`, "i")
52768
- },
52769
- {
52770
- id: "nosql-proto-pollution",
52771
- description: "__proto__ — prototype pollution via object key injection",
52772
- pattern: /__proto__/
52773
- },
52774
- {
52775
- id: "nosql-constructor-prototype",
52776
- description: "constructor.prototype — alternative prototype pollution vector (dot notation or JSON key)",
52777
- pattern: /constructor[\s"':.,{\[]*prototype/i
52778
- },
52779
- {
52780
- id: "nosql-proto-bracket",
52781
- description: "[\"__proto__\"] — bracket-notation prototype pollution",
52782
- pattern: /\[["']__proto__["']\]/
52783
- }
52784
- ];
52785
- //#endregion
52786
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/log.js
52787
- /**
52788
- * LOG context patterns.
52789
- *
52790
- * Detects injection vectors that are dangerous when a string is written
52791
- * to a log file, passed to a logging framework, or interpolated into
52792
- * a log message that will be parsed or displayed.
52793
- *
52794
- * Attack categories:
52795
- * 1. CRLF injection — injects fake log lines by embedding newlines
52796
- * 2. Log4Shell (CVE-2021-44228) — ${jndi:...} triggers JNDI lookup in Log4j
52797
- * 3. SSTI in log templates — {{...}}, #{...} trigger template evaluation
52798
- * if the log message is passed through a template engine
52799
- * 4. Null byte injection — truncates log entries in some implementations
52800
- * 5. ANSI escape injection — manipulates terminal output when logs are
52801
- * tailed in a terminal (colour codes, cursor movement, etc.)
52802
- *
52803
- * Note: Newline characters (\n, \r) will produce false positives for
52804
- * multi-line legitimate values. Use this context only for single-line
52805
- * log field values (usernames, IDs, request parameters, etc.).
52806
- */
52807
- const LOG_PATTERNS = [
52808
- {
52809
- id: "log-crlf-injection",
52810
- description: "CRLF injection: literal \\r or \\n embeds fake log lines",
52811
- pattern: /[\r\n]/
52812
- },
52813
- {
52814
- id: "log-url-encoded-crlf",
52815
- description: "URL-encoded CRLF: %0d, %0a, %0D, %0A — decoded by some log parsers",
52816
- pattern: /%0[dDaA]/
52817
- },
52818
- {
52819
- id: "log-unicode-newline",
52820
- description: "Unicode newline variants: U+2028 (line separator), U+2029 (paragraph separator)",
52821
- pattern: /[\u2028\u2029]/
52822
- },
52823
- {
52824
- id: "log-log4shell-jndi",
52825
- description: "Log4Shell: ${jndi:...} triggers remote code execution in Apache Log4j",
52826
- pattern: /\$\{jndi\s*:/i
52827
- },
52828
- {
52829
- id: "log-log4shell-obfuscated",
52830
- description: "Obfuscated Log4Shell: ${::-j}... lookup-bypass prefix used to evade WAF detection",
52831
- pattern: /\$\{::-/
52832
- },
52833
- {
52834
- id: "log-log4j-lookup",
52835
- description: "Log4j lookup syntax: ${env:...}, ${sys:...}, ${ctx:...} — data exfiltration",
52836
- pattern: /\$\{(?:env|sys|ctx|main|map|sd|web|docker|k8s|spring)\s*:/i
52837
- },
52838
- {
52839
- id: "log-ssti-double-brace",
52840
- description: "SSTI double-brace: {{expression}} — Jinja2, Twig, Handlebars, etc.",
52841
- pattern: /\{\{[\s\S]{0,80}\}\}/
52842
- },
52843
- {
52844
- id: "log-ssti-hash-brace",
52845
- description: "SSTI hash-brace: #{expression} — Thymeleaf, Velocity, Ruby ERB",
52846
- pattern: /#\{[\s\S]{0,80}\}/
52847
- },
52848
- {
52849
- id: "log-ssti-dollar-brace",
52850
- description: "SSTI/EL injection: ${expression with operators or method calls} — JSP EL, Freemarker, SpEL",
52851
- pattern: /\$\{[^}]*(?:\.|\(|\*|\+|\bclass\b|\bruntime\b|\bprocess\b|\bexec\b)[^}]{0,80}\}/i
52852
- },
52853
- {
52854
- id: "log-ssti-percent-tag",
52855
- description: "SSTI ERB/ASP tag: <%= expression %> — Ruby ERB, ASP",
52856
- pattern: /<%=[\s\S]{0,80}%>/
52857
- },
52858
- {
52859
- id: "log-null-byte",
52860
- description: "Null byte: \\x00 or %00 — can truncate log entries in C-backed loggers",
52861
- pattern: /\x00|%00/
52862
- },
52863
- {
52864
- id: "log-ansi-escape",
52865
- description: "ANSI escape sequence: ESC[ — can manipulate terminal output when logs are tailed",
52866
- pattern: /\x1b\[/
52867
- }
52868
- ];
52869
- //#endregion
52870
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/sql-strict.js
52871
- /**
52872
- * SQL-STRICT context patterns.
52873
- *
52874
- * Extends the base 'SQL' context with three additional rules that are
52875
- * effective at detecting real injections but carry a higher false-positive
52876
- * risk on general free-text input.
52877
- *
52878
- * Use 'SQL-STRICT' when:
52879
- * - The string is specifically a SQL fragment or database identifier
52880
- * - You control the input domain (e.g. a dedicated SQL search field)
52881
- * - You can tolerate occasional false positives in exchange for broader coverage
52882
- *
52883
- * Use 'SQL' (not STRICT) when:
52884
- * - The field is general user text (names, descriptions, comments)
52885
- * - False positives would block legitimate content (e.g. "see note -- above")
52886
- *
52887
- * Rules moved here from 'SQL' due to false-positive risk:
52888
- *
52889
- * sql-line-comment — "--" fires on "see note -- above", "value--", CSS var(--primary)
52890
- * sql-stacked-query — "; SELECT" fires on legitimate prose with semicolons + SQL words
52891
- * sql-hex-encoding — "0xDEAD" fires on hex values in technical docs and log output
52892
- */
52893
- const SQL_STRICT_EXTRA = [
52894
- {
52895
- id: "sql-line-comment",
52896
- description: "SQL line comment: -- followed by whitespace or end of string",
52897
- pattern: /--(?:\s|$)/
52898
- },
52899
- {
52900
- id: "sql-stacked-query",
52901
- description: "Stacked queries: semicolon immediately followed by a SQL keyword",
52902
- pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
52903
- },
52904
- {
52905
- id: "sql-hex-encoding",
52906
- description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
52907
- pattern: /\b0x[0-9a-f]{4,}/i
52908
- }
52909
- ];
52910
- const SQL_STRICT_PATTERNS = [...SQL_PATTERNS, ...SQL_STRICT_EXTRA];
52911
- //#endregion
52912
- //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/index.js
52913
- HTML_PATTERNS.label = "HTML";
52914
- XML_PATTERNS.label = "XML";
52915
- SVG_PATTERNS.label = "SVG";
52916
- SQL_PATTERNS.label = "SQL";
52917
- SQL_STRICT_PATTERNS.label = "SQL-STRICT";
52918
- SHELL_PATTERNS.label = "SHELL";
52919
- REDOS_PATTERNS.label = "REDOS";
52920
- NOSQL_PATTERNS.label = "NOSQL";
52921
- LOG_PATTERNS.label = "LOG";
52922
- Object.freeze({
52923
- HTML: HTML_PATTERNS,
52924
- XML: XML_PATTERNS,
52925
- SVG: SVG_PATTERNS,
52926
- SQL: SQL_PATTERNS,
52927
- "SQL-STRICT": SQL_STRICT_PATTERNS,
52928
- SHELL: SHELL_PATTERNS,
52929
- REDOS: REDOS_PATTERNS,
52930
- NOSQL: NOSQL_PATTERNS,
52931
- LOG: LOG_PATTERNS
52932
- });
52933
- /**
52934
- * @typedef {{ id: string, description: string, pattern: RegExp }} Rule
52935
- */
52936
- /**
52937
- * @typedef {Rule[]} PatternList
52938
- */
52939
- /**
52940
- * @typedef {Object} MatchResult
52941
- * @property {string} context - Label identifying which context matched ('HTML', 'CUSTOM', etc.)
52942
- * @property {string} id - Rule identifier
52943
- * @property {string} description - Human-readable description of what was matched
52944
- * @property {RegExp} pattern - The pattern that matched
52945
- */
52946
- /**
52947
- * @param {unknown} value
52948
- */
52949
- function assertString(value) {
52950
- if (typeof value !== "string") throw new TypeError(`is-unsafe: first argument must be a string, got ${typeof value}`);
52951
- }
52952
- /**
52953
- * @param {unknown} context
52954
- */
52955
- function assertContext(context) {
52956
- if (context instanceof RegExp) return;
52957
- if (Array.isArray(context)) {
52958
- if (context.length === 0) throw new TypeError("is-unsafe: context must not be an empty array");
52959
- if (Array.isArray(context[0])) {
52960
- for (const list of context) if (!Array.isArray(list) || list.length === 0) throw new TypeError("is-unsafe: each context in the array must be a non-empty pattern array (PatternList)");
52961
- }
52962
- return;
52963
- }
52964
- throw new TypeError(`is-unsafe: second argument must be a PatternList (e.g. HTML), an array of PatternLists (e.g. [HTML, XML]), or a RegExp. Got: ${typeof context}`);
52965
- }
52966
- /**
52967
- * Normalise any valid context arg into an array of PatternLists.
52968
- *
52969
- * @param {Rule[]|Rule[][]|RegExp} context
52970
- * @returns {{ lists: Rule[][]|null, regex: RegExp|null }}
52971
- */
52972
- function normalise(context) {
52973
- if (context instanceof RegExp) return {
52974
- lists: null,
52975
- regex: context
52976
- };
52977
- if (Array.isArray(context[0])) return {
52978
- lists: context,
52979
- regex: null
52980
- };
52981
- return {
52982
- lists: [context],
52983
- regex: null
52984
- };
52985
- }
52986
- /**
52987
- * Test value against a single PatternList. Returns the first MatchResult or null.
52988
- *
52989
- * @param {string} value
52990
- * @param {Rule[]} list
52991
- * @returns {MatchResult|null}
52992
- */
52993
- function matchList(value, list) {
52994
- const label = list.label ?? "CUSTOM";
52995
- for (const rule of list) if (rule.pattern.test(value)) return {
52996
- context: label,
52997
- id: rule.id,
52998
- description: rule.description,
52999
- pattern: rule.pattern
53000
- };
53001
- return null;
53002
- }
53003
- /**
53004
- * Returns `true` if `value` is unsafe in the given context(s), `false` otherwise.
53005
- *
53006
- * @param {string} value - The string to test
53007
- * @param {PatternList | PatternList[] | RegExp} context
53008
- * - A PatternList imported from is-unsafe (e.g. `HTML`, `XML`)
53009
- * - An array of PatternLists — returns true if unsafe in **any** of them
53010
- * - A custom RegExp — returns true if the pattern matches
53011
- * @returns {boolean}
53012
- *
53013
- * @example
53014
- * import { isUnsafe, HTML, SQL } from 'is-unsafe';
53015
- *
53016
- * isUnsafe('<script>alert(1)<\/script>', HTML) // true
53017
- * isUnsafe('hello world', HTML) // false
53018
- * isUnsafe('value', [HTML, SQL]) // false
53019
- * isUnsafe('value', /my-pattern/i) // false
53020
- */
53021
- function isUnsafe(value, context) {
53022
- assertString(value);
53023
- assertContext(context);
53024
- const { lists, regex } = normalise(context);
53025
- if (regex) return regex.test(value);
53026
- for (const list of lists) if (matchList(value, list) !== null) return true;
53027
- return false;
53028
- }
53029
- //#endregion
53030
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
53031
- /**
53032
- * Extract raw attributes (without prefix) from prefixed attribute map
53033
- * @param {object} prefixedAttrs - Attributes with prefix from buildAttributesMap
53034
- * @param {object} options - Parser options containing attributeNamePrefix
53035
- * @returns {object} Raw attributes for matcher
53036
- */
53037
- function extractRawAttributes(prefixedAttrs, options) {
53038
- if (!prefixedAttrs) return {};
53039
- const attrs = options.attributesGroupName ? prefixedAttrs[options.attributesGroupName] : prefixedAttrs;
53040
- if (!attrs) return {};
53041
- const rawAttrs = {};
53042
- for (const key in attrs) if (key.startsWith(options.attributeNamePrefix)) {
53043
- const rawName = key.substring(options.attributeNamePrefix.length);
53044
- rawAttrs[rawName] = attrs[key];
53045
- } else rawAttrs[key] = attrs[key];
53046
- return rawAttrs;
53047
- }
53048
- /**
53049
- * Extract namespace from raw tag name
53050
- * @param {string} rawTagName - Tag name possibly with namespace (e.g., "soap:Envelope")
53051
- * @returns {string|undefined} Namespace or undefined
53052
- */
53053
- function extractNamespace(rawTagName) {
53054
- if (!rawTagName || typeof rawTagName !== "string") return void 0;
53055
- const colonIndex = rawTagName.indexOf(":");
53056
- if (colonIndex !== -1 && colonIndex > 0) {
53057
- const ns = rawTagName.substring(0, colonIndex);
53058
- if (ns !== "xmlns") return ns;
53059
- }
53060
- }
53061
- var OrderedObjParser = class {
53062
- constructor(options, externalEntities) {
53063
- this.options = options;
53064
- this.currentNode = null;
53065
- this.tagsNodeStack = [];
53066
- this.parseXml = parseXml;
53067
- this.parseTextData = parseTextData;
53068
- this.resolveNameSpace = resolveNameSpace;
53069
- this.buildAttributesMap = buildAttributesMap;
53070
- this.isItStopNode = isItStopNode;
53071
- this.replaceEntitiesValue = replaceEntitiesValue;
53072
- this.readStopNodeData = readStopNodeData;
53073
- this.saveTextToParentTag = saveTextToParentTag;
53074
- this.addChild = addChild;
53075
- this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
53076
- this.entityExpansionCount = 0;
53077
- this.currentExpandedLength = 0;
53078
- this.doctypefound = false;
53079
- let namedEntities = { ...XML };
53080
- if (this.options.entityDecoder) this.entityDecoder = this.options.entityDecoder;
53081
- else {
53082
- if (typeof this.options.htmlEntities === "object") namedEntities = this.options.htmlEntities;
53083
- else if (this.options.htmlEntities === true) namedEntities = {
53084
- ...COMMON_HTML,
53085
- ...CURRENCY
53086
- };
53087
- this.entityDecoder = new EntityDecoder({
53088
- namedEntities: {
53089
- ...namedEntities,
53090
- ...externalEntities
53091
- },
53092
- numericAllowed: this.options.htmlEntities,
53093
- limit: {
53094
- maxTotalExpansions: this.options.processEntities.maxTotalExpansions,
53095
- maxExpandedLength: this.options.processEntities.maxExpandedLength,
53096
- applyLimitsTo: this.options.processEntities.appliesTo
53097
- },
53098
- onInputEntity: (name, value) => isUnsafe(value, [HTML_PATTERNS, XML_PATTERNS]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
53099
- });
53100
- }
53101
- this.matcher = new Matcher();
53102
- this.readonlyMatcher = this.matcher.readOnly();
53103
- this.isCurrentNodeStopNode = false;
53104
- this.stopNodeExpressionsSet = new ExpressionSet();
53105
- const stopNodesOpts = this.options.stopNodes;
53106
- if (stopNodesOpts && stopNodesOpts.length > 0) {
53107
- for (let i = 0; i < stopNodesOpts.length; i++) {
53108
- const stopNodeExp = stopNodesOpts[i];
53109
- if (typeof stopNodeExp === "string") this.stopNodeExpressionsSet.add(new Expression(stopNodeExp));
53110
- else if (stopNodeExp instanceof Expression) this.stopNodeExpressionsSet.add(stopNodeExp);
53111
- }
53112
- this.stopNodeExpressionsSet.seal();
53113
- }
53114
- }
53115
- };
53116
- /**
53117
- * @param {string} val
53118
- * @param {string} tagName
53119
- * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath
53120
- * @param {boolean} dontTrim
53121
- * @param {boolean} hasAttributes
53122
- * @param {boolean} isLeafNode
53123
- * @param {boolean} escapeEntities
53124
- */
53125
- function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
53126
- const options = this.options;
53127
- if (val !== void 0) {
53128
- if (options.trimValues && !dontTrim) val = val.trim();
53129
- if (val.length > 0) {
53130
- if (!escapeEntities) val = this.replaceEntitiesValue(val, tagName, jPath);
53131
- const jPathOrMatcher = options.jPath ? jPath.toString() : jPath;
53132
- const newval = options.tagValueProcessor(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode);
53133
- if (newval === null || newval === void 0) return val;
53134
- else if (typeof newval !== typeof val || newval !== val) return newval;
53135
- else if (options.trimValues) return parseValue(val, options.parseTagValue, options.numberParseOptions);
53136
- else if (val.trim() === val) return parseValue(val, options.parseTagValue, options.numberParseOptions);
53137
- else return val;
53138
- }
53139
- }
53140
- }
53141
- function resolveNameSpace(tagname) {
53142
- if (this.options.removeNSPrefix) {
53143
- const tags = tagname.split(":");
53144
- const prefix = tagname.charAt(0) === "/" ? "/" : "";
53145
- if (tags[0] === "xmlns") return "";
53146
- if (tags.length === 2) tagname = prefix + tags[1];
53147
- }
53148
- return tagname;
53149
- }
53150
- const attrsRegx = /* @__PURE__ */ new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?", "gm");
53151
- function buildAttributesMap(attrStr, jPath, tagName, force = false) {
53152
- const options = this.options;
53153
- if (force === true || options.ignoreAttributes !== true && typeof attrStr === "string") {
53154
- const matches = getAllMatches(attrStr, attrsRegx);
53155
- const len = matches.length;
53156
- const attrs = {};
53157
- const processedVals = new Array(len);
53158
- let hasRawAttrs = false;
53159
- const rawAttrsForMatcher = {};
53160
- for (let i = 0; i < len; i++) {
53161
- const attrName = this.resolveNameSpace(matches[i][1]);
53162
- const oldVal = matches[i][4];
53163
- if (attrName.length && oldVal !== void 0) {
53164
- let val = oldVal;
53165
- if (options.trimValues) val = val.trim();
53166
- val = this.replaceEntitiesValue(val, tagName, this.readonlyMatcher);
53167
- processedVals[i] = val;
53168
- rawAttrsForMatcher[attrName] = val;
53169
- hasRawAttrs = true;
53170
- }
53171
- }
53172
- if (hasRawAttrs && typeof jPath === "object" && jPath.updateCurrent) jPath.updateCurrent(rawAttrsForMatcher);
53173
- const jPathStr = options.jPath ? jPath.toString() : this.readonlyMatcher;
53174
- let hasAttrs = false;
53175
- for (let i = 0; i < len; i++) {
53176
- const attrName = this.resolveNameSpace(matches[i][1]);
53177
- if (this.ignoreAttributesFn(attrName, jPathStr)) continue;
53178
- let aName = options.attributeNamePrefix + attrName;
53179
- if (attrName.length) {
53180
- if (options.transformAttributeName) aName = options.transformAttributeName(aName);
53181
- aName = sanitizeName(aName, options);
53182
- if (matches[i][4] !== void 0) {
53183
- const oldVal = processedVals[i];
53184
- const newVal = options.attributeValueProcessor(attrName, oldVal, jPathStr);
53185
- if (newVal === null || newVal === void 0) attrs[aName] = oldVal;
53186
- else if (typeof newVal !== typeof oldVal || newVal !== oldVal) attrs[aName] = newVal;
53187
- else attrs[aName] = parseValue(oldVal, options.parseAttributeValue, options.numberParseOptions);
53188
- hasAttrs = true;
53189
- } else if (options.allowBooleanAttributes) {
53190
- attrs[aName] = true;
53191
- hasAttrs = true;
53192
- }
53193
- }
53194
- }
53195
- if (!hasAttrs) return;
53196
- if (options.attributesGroupName && !options.preserveOrder) {
53197
- const attrCollection = {};
53198
- attrCollection[options.attributesGroupName] = attrs;
53199
- return attrCollection;
53200
- }
53201
- return attrs;
53202
- }
53203
- }
53204
- const parseXml = function(xmlData) {
53205
- xmlData = xmlData.replace(/\r\n?/g, "\n");
53206
- const xmlObj = new XmlNode("!xml");
53207
- let currentNode = xmlObj;
53208
- let textData = "";
53209
- this.matcher.reset();
53210
- this.entityDecoder.reset();
53211
- this.entityExpansionCount = 0;
53212
- this.currentExpandedLength = 0;
53213
- this.doctypefound = false;
53214
- const options = this.options;
53215
- const docTypeReader = new DocTypeReader(options.processEntities);
53216
- const xmlLen = xmlData.length;
53217
- for (let i = 0; i < xmlLen; i++) if (xmlData[i] === "<") {
53218
- const c1 = xmlData.charCodeAt(i + 1);
53219
- if (c1 === 47) {
53220
- const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.");
53221
- let tagName = xmlData.substring(i + 2, closeIndex).trim();
53222
- if (options.removeNSPrefix) {
53223
- const colonIndex = tagName.indexOf(":");
53224
- if (colonIndex !== -1) tagName = tagName.substr(colonIndex + 1);
53225
- }
53226
- tagName = transformTagName(options.transformTagName, tagName, "", options).tagName;
53227
- if (currentNode) textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
53228
- const lastTagName = this.matcher.getCurrentTag();
53229
- if (tagName && options.unpairedTagsSet.has(tagName)) throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
53230
- if (lastTagName && options.unpairedTagsSet.has(lastTagName)) {
53231
- this.matcher.pop();
53232
- this.tagsNodeStack.pop();
53233
- }
53234
- this.matcher.pop();
53235
- this.isCurrentNodeStopNode = false;
53236
- currentNode = this.tagsNodeStack.pop();
53237
- textData = "";
53238
- i = closeIndex;
53239
- } else if (c1 === 63) {
53240
- let tagData = readTagExp(xmlData, i, false, "?>");
53241
- if (!tagData) throw new Error("Pi Tag is not closed.");
53242
- textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
53243
- const attsMap = this.buildAttributesMap(tagData.tagExp, this.matcher, tagData.tagName, true);
53244
- if (attsMap) {
53245
- const ver = attsMap[this.options.attributeNamePrefix + "version"];
53246
- this.entityDecoder.setXmlVersion(Number(ver) || 1);
53247
- docTypeReader.setXmlVersion(Number(ver) || 1);
53248
- }
53249
- if (options.ignoreDeclaration && tagData.tagName === "?xml" || options.ignorePiTags) {} else {
53250
- const childNode = new XmlNode(tagData.tagName);
53251
- childNode.add(options.textNodeName, "");
53252
- if (tagData.tagName !== tagData.tagExp && tagData.attrExpPresent && options.ignoreAttributes !== true) childNode[":@"] = attsMap;
53253
- this.addChild(currentNode, childNode, this.readonlyMatcher, i);
53254
- }
53255
- i = tagData.closeIndex + 1;
53256
- } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) {
53257
- const endIndex = findClosingIndex(xmlData, "-->", i + 4, "Comment is not closed.");
53258
- if (options.commentPropName) {
53259
- const comment = xmlData.substring(i + 4, endIndex - 2);
53260
- textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
53261
- currentNode.add(options.commentPropName, [{ [options.textNodeName]: comment }]);
53262
- }
53263
- i = endIndex;
53264
- } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) {
53265
- if (this.doctypefound) throw new Error("Multiple DOCTYPE declarations found.");
53266
- this.doctypefound = true;
53267
- const result = docTypeReader.readDocType(xmlData, i);
53268
- this.entityDecoder.addInputEntities(result.entities);
53269
- i = result.i;
53270
- } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) {
53271
- const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
53272
- const tagExp = xmlData.substring(i + 9, closeIndex);
53273
- textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
53274
- let val = this.parseTextData(tagExp, currentNode.tagname, this.readonlyMatcher, true, false, true, true);
53275
- if (val == void 0) val = "";
53276
- if (options.cdataPropName) currentNode.add(options.cdataPropName, [{ [options.textNodeName]: tagExp }]);
53277
- else currentNode.add(options.textNodeName, val);
53278
- i = closeIndex + 2;
53279
- } else {
53280
- let result = readTagExp(xmlData, i, options.removeNSPrefix);
53281
- if (!result) {
53282
- const context = xmlData.substring(Math.max(0, i - 50), Math.min(xmlLen, i + 50));
53283
- throw new Error(`readTagExp returned undefined at position ${i}. Context: "${context}"`);
53284
- }
53285
- let tagName = result.tagName;
53286
- const rawTagName = result.rawTagName;
53287
- let tagExp = result.tagExp;
53288
- let attrExpPresent = result.attrExpPresent;
53289
- let closeIndex = result.closeIndex;
53290
- ({tagName, tagExp} = transformTagName(options.transformTagName, tagName, tagExp, options));
53291
- if (options.strictReservedNames && (tagName === options.commentPropName || tagName === options.cdataPropName || tagName === options.textNodeName || tagName === options.attributesGroupName)) throw new Error(`Invalid tag name: ${tagName}`);
53292
- if (currentNode && textData) {
53293
- if (currentNode.tagname !== "!xml") textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher, false);
53294
- }
53295
- const lastTag = currentNode;
53296
- if (lastTag && options.unpairedTagsSet.has(lastTag.tagname)) {
53297
- currentNode = this.tagsNodeStack.pop();
53298
- this.matcher.pop();
53299
- }
53300
- let isSelfClosing = false;
53301
- if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
53302
- isSelfClosing = true;
53303
- if (tagName[tagName.length - 1] === "/") {
53304
- tagName = tagName.substr(0, tagName.length - 1);
53305
- tagExp = tagName;
53306
- } else tagExp = tagExp.substr(0, tagExp.length - 1);
53307
- attrExpPresent = tagName !== tagExp;
53308
- }
53309
- let prefixedAttrs = null;
53310
- let namespace = void 0;
53311
- namespace = extractNamespace(rawTagName);
53312
- if (tagName !== xmlObj.tagname) this.matcher.push(tagName, {}, namespace);
53313
- if (tagName !== tagExp && attrExpPresent) {
53314
- prefixedAttrs = this.buildAttributesMap(tagExp, this.matcher, tagName);
53315
- if (prefixedAttrs) extractRawAttributes(prefixedAttrs, options);
53316
- }
53317
- if (tagName !== xmlObj.tagname) this.isCurrentNodeStopNode = this.isItStopNode();
53318
- const startIndex = i;
53319
- if (this.isCurrentNodeStopNode) {
53320
- let tagContent = "";
53321
- if (isSelfClosing) i = result.closeIndex;
53322
- else if (options.unpairedTagsSet.has(tagName)) i = result.closeIndex;
53323
- else {
53324
- const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
53325
- if (!result) throw new Error(`Unexpected end of ${rawTagName}`);
53326
- i = result.i;
53327
- tagContent = result.tagContent;
53328
- }
53329
- const childNode = new XmlNode(tagName);
53330
- if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
53331
- childNode.add(options.textNodeName, tagContent);
53332
- this.matcher.pop();
53333
- this.isCurrentNodeStopNode = false;
53334
- this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
53335
- } else {
53336
- if (isSelfClosing) {
53337
- ({tagName, tagExp} = transformTagName(options.transformTagName, tagName, tagExp, options));
53338
- const childNode = new XmlNode(tagName);
53339
- if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
53340
- this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
53341
- this.matcher.pop();
53342
- this.isCurrentNodeStopNode = false;
53343
- } else if (options.unpairedTagsSet.has(tagName)) {
53344
- const childNode = new XmlNode(tagName);
53345
- if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
53346
- this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
53347
- this.matcher.pop();
53348
- this.isCurrentNodeStopNode = false;
53349
- i = result.closeIndex;
53350
- continue;
53351
- } else {
53352
- const childNode = new XmlNode(tagName);
53353
- if (this.tagsNodeStack.length > options.maxNestedTags) throw new Error("Maximum nested tags exceeded");
53354
- this.tagsNodeStack.push(currentNode);
53355
- if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
53356
- this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
53357
- currentNode = childNode;
53358
- }
53359
- textData = "";
53360
- i = closeIndex;
53361
- }
53362
- }
53363
- } else textData += xmlData[i];
53364
- return xmlObj.child;
53365
- };
53366
- function addChild(currentNode, childNode, matcher, startIndex) {
53367
- if (!this.options.captureMetaData) startIndex = void 0;
53368
- const jPathOrMatcher = this.options.jPath ? matcher.toString() : matcher;
53369
- const result = this.options.updateTag(childNode.tagname, jPathOrMatcher, childNode[":@"]);
53370
- if (result === false) {} else if (typeof result === "string") {
53371
- childNode.tagname = result;
53372
- currentNode.addChild(childNode, startIndex);
53373
- } else currentNode.addChild(childNode, startIndex);
53374
- }
53375
- /**
53376
- * @param {object} val - Entity object with regex and val properties
53377
- * @param {string} tagName - Tag name
53378
- * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath
53379
- */
53380
- function replaceEntitiesValue(val, tagName, jPath) {
53381
- const entityConfig = this.options.processEntities;
53382
- if (!entityConfig || !entityConfig.enabled) return val;
53383
- if (entityConfig.allowedTags) {
53384
- const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath;
53385
- if (!(Array.isArray(entityConfig.allowedTags) ? entityConfig.allowedTags.includes(tagName) : entityConfig.allowedTags(tagName, jPathOrMatcher))) return val;
53386
- }
53387
- if (entityConfig.tagFilter) {
53388
- const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath;
53389
- if (!entityConfig.tagFilter(tagName, jPathOrMatcher)) return val;
53390
- }
53391
- return this.entityDecoder.decode(val);
53392
- }
53393
- function saveTextToParentTag(textData, parentNode, matcher, isLeafNode) {
53394
- if (textData) {
53395
- if (isLeafNode === void 0) isLeafNode = parentNode.child.length === 0;
53396
- textData = this.parseTextData(textData, parentNode.tagname, matcher, false, parentNode[":@"] ? Object.keys(parentNode[":@"]).length !== 0 : false, isLeafNode);
53397
- if (textData !== void 0 && textData !== "") parentNode.add(this.options.textNodeName, textData);
53398
- textData = "";
53399
- }
53400
- return textData;
53401
- }
53402
- /**
53403
- * @param {Array<Expression>} stopNodeExpressions - Array of compiled Expression objects
53404
- * @param {Matcher} matcher - Current path matcher
53405
- */
53406
- function isItStopNode() {
53407
- if (this.stopNodeExpressionsSet.size === 0) return false;
53408
- return this.matcher.matchesAny(this.stopNodeExpressionsSet);
53409
- }
53410
- /**
53411
- * Returns the tag Expression and where it is ending handling single-double quotes situation
53412
- * @param {string} xmlData
53413
- * @param {number} i starting index
53414
- * @returns
53415
- */
53416
- function tagExpWithClosingIndex(xmlData, i, closingChar = ">") {
53417
- let attrBoundary = 0;
53418
- const len = xmlData.length;
53419
- const closeCode0 = closingChar.charCodeAt(0);
53420
- const closeCode1 = closingChar.length > 1 ? closingChar.charCodeAt(1) : -1;
53421
- let result = "";
53422
- let segmentStart = i;
53423
- for (let index = i; index < len; index++) {
53424
- const code = xmlData.charCodeAt(index);
53425
- if (attrBoundary) {
53426
- if (code === attrBoundary) attrBoundary = 0;
53427
- } else if (code === 34 || code === 39) attrBoundary = code;
53428
- else if (code === closeCode0) if (closeCode1 !== -1) {
53429
- if (xmlData.charCodeAt(index + 1) === closeCode1) {
53430
- result += xmlData.substring(segmentStart, index);
53431
- return {
53432
- data: result,
53433
- index
53434
- };
53435
- }
53436
- } else {
53437
- result += xmlData.substring(segmentStart, index);
53438
- return {
53439
- data: result,
53440
- index
53441
- };
53442
- }
53443
- else if (code === 9 && !attrBoundary) {
53444
- result += xmlData.substring(segmentStart, index) + " ";
53445
- segmentStart = index + 1;
53446
- }
53447
- }
53448
- }
53449
- function findClosingIndex(xmlData, str, i, errMsg) {
53450
- const closingIndex = xmlData.indexOf(str, i);
53451
- if (closingIndex === -1) throw new Error(errMsg);
53452
- else return closingIndex + str.length - 1;
53453
- }
53454
- function findClosingChar(xmlData, char, i, errMsg) {
53455
- const closingIndex = xmlData.indexOf(char, i);
53456
- if (closingIndex === -1) throw new Error(errMsg);
53457
- return closingIndex;
53458
- }
53459
- function readTagExp(xmlData, i, removeNSPrefix, closingChar = ">") {
53460
- const result = tagExpWithClosingIndex(xmlData, i + 1, closingChar);
53461
- if (!result) return;
53462
- let tagExp = result.data;
53463
- const closeIndex = result.index;
53464
- const separatorIndex = tagExp.search(/\s/);
53465
- let tagName = tagExp;
53466
- let attrExpPresent = true;
53467
- if (separatorIndex !== -1) {
53468
- tagName = tagExp.substring(0, separatorIndex);
53469
- tagExp = tagExp.substring(separatorIndex + 1).trimStart();
53470
- }
53471
- const rawTagName = tagName;
53472
- if (removeNSPrefix) {
53473
- const colonIndex = tagName.indexOf(":");
53474
- if (colonIndex !== -1) {
53475
- tagName = tagName.substr(colonIndex + 1);
53476
- attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
53477
- }
53478
- }
53479
- return {
53480
- tagName,
53481
- tagExp,
53482
- closeIndex,
53483
- attrExpPresent,
53484
- rawTagName
53485
- };
53486
- }
53487
- /**
53488
- * find paired tag for a stop node
53489
- * @param {string} xmlData
53490
- * @param {string} tagName
53491
- * @param {number} i
53492
- */
53493
- function readStopNodeData(xmlData, tagName, i) {
53494
- const startIndex = i;
53495
- let openTagCount = 1;
53496
- const xmllen = xmlData.length;
53497
- for (; i < xmllen; i++) if (xmlData[i] === "<") {
53498
- const c1 = xmlData.charCodeAt(i + 1);
53499
- if (c1 === 47) {
53500
- const closeIndex = findClosingChar(xmlData, ">", i, `${tagName} is not closed`);
53501
- if (xmlData.substring(i + 2, closeIndex).trim() === tagName) {
53502
- openTagCount--;
53503
- if (openTagCount === 0) return {
53504
- tagContent: xmlData.substring(startIndex, i),
53505
- i: closeIndex
53506
- };
53507
- }
53508
- i = closeIndex;
53509
- } else if (c1 === 63) i = findClosingIndex(xmlData, "?>", i + 1, "StopNode is not closed.");
53510
- else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) i = findClosingIndex(xmlData, "-->", i + 3, "StopNode is not closed.");
53511
- else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) i = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
53512
- else {
53513
- const tagData = readTagExp(xmlData, i, false);
53514
- if (tagData) {
53515
- if ((tagData && tagData.tagName) === tagName && tagData.tagExp[tagData.tagExp.length - 1] !== "/") openTagCount++;
53516
- i = tagData.closeIndex;
53517
- }
53518
- }
53519
- }
53520
- }
53521
- function parseValue(val, shouldParse, options) {
53522
- if (shouldParse && typeof val === "string") {
53523
- const newval = val.trim();
53524
- if (newval === "true") return true;
53525
- else if (newval === "false") return false;
53526
- else return toNumber(val, options);
53527
- } else if (isExist(val)) return val;
53528
- else return "";
53529
- }
53530
- function transformTagName(fn, tagName, tagExp, options) {
53531
- if (fn) {
53532
- const newTagName = fn(tagName);
53533
- if (tagExp === tagName) tagExp = newTagName;
53534
- tagName = newTagName;
53535
- }
53536
- tagName = sanitizeName(tagName, options);
53537
- return {
53538
- tagName,
53539
- tagExp
53540
- };
53541
- }
53542
- function sanitizeName(name, options) {
53543
- if (criticalProperties.includes(name)) throw new Error(`[SECURITY] Invalid name: "${name}" is a reserved JavaScript keyword that could cause prototype pollution`);
53544
- else if (DANGEROUS_PROPERTY_NAMES.includes(name)) return options.onDangerousProperty(name);
53545
- return name;
53546
- }
53547
- //#endregion
53548
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/node2json.js
53549
- const METADATA_SYMBOL = XmlNode.getMetaDataSymbol();
53550
- /**
53551
- * Helper function to strip attribute prefix from attribute map
53552
- * @param {object} attrs - Attributes with prefix (e.g., {"@_class": "code"})
53553
- * @param {string} prefix - Attribute prefix to remove (e.g., "@_")
53554
- * @returns {object} Attributes without prefix (e.g., {"class": "code"})
53555
- */
53556
- function stripAttributePrefix(attrs, prefix) {
53557
- if (!attrs || typeof attrs !== "object") return {};
53558
- if (!prefix) return attrs;
53559
- const rawAttrs = {};
53560
- for (const key in attrs) if (key.startsWith(prefix)) {
53561
- const rawName = key.substring(prefix.length);
53562
- rawAttrs[rawName] = attrs[key];
53563
- } else rawAttrs[key] = attrs[key];
53564
- return rawAttrs;
53565
- }
53566
- /**
53567
- *
53568
- * @param {array} node
53569
- * @param {any} options
53570
- * @param {Matcher} matcher - Path matcher instance
53571
- * @returns
53572
- */
53573
- function prettify(node, options, matcher, readonlyMatcher) {
53574
- return compress(node, options, matcher, readonlyMatcher);
53575
- }
53576
- /**
53577
- * @param {array} arr
53578
- * @param {object} options
53579
- * @param {Matcher} matcher - Path matcher instance
53580
- * @returns object
53581
- */
53582
- function compress(arr, options, matcher, readonlyMatcher) {
53583
- let text;
53584
- const compressedObj = {};
53585
- for (let i = 0; i < arr.length; i++) {
53586
- const tagObj = arr[i];
53587
- const property = propName(tagObj);
53588
- if (property !== void 0 && property !== options.textNodeName) {
53589
- const rawAttrs = stripAttributePrefix(tagObj[":@"] || {}, options.attributeNamePrefix);
53590
- matcher.push(property, rawAttrs);
53591
- }
53592
- if (property === options.textNodeName) if (text === void 0) text = tagObj[property];
53593
- else text += "" + tagObj[property];
53594
- else if (property === void 0) continue;
53595
- else if (tagObj[property]) {
53596
- let val = compress(tagObj[property], options, matcher, readonlyMatcher);
53597
- const isLeaf = isLeafTag(val, options);
53598
- if (Object.keys(val).length === 0 && options.alwaysCreateTextNode) val[options.textNodeName] = "";
53599
- if (tagObj[":@"]) assignAttributes(val, tagObj[":@"], readonlyMatcher, options);
53600
- else if (Object.keys(val).length === 1 && val[options.textNodeName] !== void 0 && !options.alwaysCreateTextNode) val = val[options.textNodeName];
53601
- else if (Object.keys(val).length === 0) if (options.alwaysCreateTextNode) val[options.textNodeName] = "";
53602
- else val = "";
53603
- if (tagObj[METADATA_SYMBOL] !== void 0 && typeof val === "object" && val !== null) val[METADATA_SYMBOL] = tagObj[METADATA_SYMBOL];
53604
- if (compressedObj[property] !== void 0 && Object.prototype.hasOwnProperty.call(compressedObj, property)) {
53605
- if (!Array.isArray(compressedObj[property])) compressedObj[property] = [compressedObj[property]];
53606
- compressedObj[property].push(val);
53607
- } else {
53608
- const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() : readonlyMatcher;
53609
- if (options.isArray(property, jPathOrMatcher, isLeaf)) compressedObj[property] = [val];
53610
- else compressedObj[property] = val;
53611
- }
53612
- if (property !== void 0 && property !== options.textNodeName) matcher.pop();
53613
- }
53614
- }
53615
- if (typeof text === "string") {
53616
- if (text.length > 0) compressedObj[options.textNodeName] = text;
53617
- } else if (text !== void 0) compressedObj[options.textNodeName] = text;
53618
- return compressedObj;
53619
- }
53620
- function propName(obj) {
53621
- const keys = Object.keys(obj);
53622
- for (let i = 0; i < keys.length; i++) {
53623
- const key = keys[i];
53624
- if (key !== ":@") return key;
53625
- }
53626
- }
53627
- function assignAttributes(obj, attrMap, readonlyMatcher, options) {
53628
- if (attrMap) {
53629
- const keys = Object.keys(attrMap);
53630
- const len = keys.length;
53631
- for (let i = 0; i < len; i++) {
53632
- const atrrName = keys[i];
53633
- const rawAttrName = atrrName.startsWith(options.attributeNamePrefix) ? atrrName.substring(options.attributeNamePrefix.length) : atrrName;
53634
- const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() + "." + rawAttrName : readonlyMatcher;
53635
- if (options.isArray(atrrName, jPathOrMatcher, true, true)) obj[atrrName] = [attrMap[atrrName]];
53636
- else obj[atrrName] = attrMap[atrrName];
53637
- }
53638
- }
53639
- }
53640
- function isLeafTag(obj, options) {
53641
- const { textNodeName } = options;
53642
- const propCount = Object.keys(obj).length;
53643
- if (propCount === 0) return true;
53644
- if (propCount === 1 && (obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0)) return true;
53645
- return false;
53646
- }
53647
- //#endregion
53648
- //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
53649
- var XMLParser = class {
53650
- constructor(options) {
53651
- this.externalEntities = {};
53652
- this.options = buildOptions(options);
53653
- }
53654
- /**
53655
- * Parse XML dats to JS object
53656
- * @param {string|Uint8Array} xmlData
53657
- * @param {boolean|Object} validationOption
53658
- */
53659
- parse(xmlData, validationOption) {
53660
- if (typeof xmlData !== "string" && xmlData.toString) xmlData = xmlData.toString();
53661
- else if (typeof xmlData !== "string") throw new Error("XML data is accepted in String or Bytes[] form.");
53662
- if (validationOption) {
53663
- if (validationOption === true) validationOption = {};
53664
- const result = validate(xmlData, validationOption);
53665
- if (result !== true) throw Error(`${result.err.msg}:${result.err.line}:${result.err.col}`);
53666
- }
53667
- const orderedObjParser = new OrderedObjParser(this.options, this.externalEntities);
53668
- const orderedResult = orderedObjParser.parseXml(xmlData);
53669
- if (this.options.preserveOrder || orderedResult === void 0) return orderedResult;
53670
- else return prettify(orderedResult, this.options, orderedObjParser.matcher, orderedObjParser.readonlyMatcher);
53671
- }
53672
- /**
53673
- * Add Entity which is not by default supported by this library
53674
- * @param {string} key
53675
- * @param {string} value
53676
- */
53677
- addEntity(key, value) {
53678
- if (value.indexOf("&") !== -1) throw new Error("Entity value can't have '&'");
53679
- else if (key.indexOf("&") !== -1 || key.indexOf(";") !== -1) throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '&#xD;'");
53680
- else if (value === "&") throw new Error("An entity with value '&' is not permitted");
53681
- else this.externalEntities[key] = value;
53682
- }
53683
- /**
53684
- * Returns a Symbol that can be used to access the metadata
53685
- * property on a node.
53686
- *
53687
- * If Symbol is not available in the environment, an ordinary property is used
53688
- * and the name of the property is here returned.
53689
- *
53690
- * The XMLMetaData property is only present when `captureMetaData`
53691
- * is true in the options.
53692
- */
53693
- static getMetaDataSymbol() {
53694
- return XmlNode.getMetaDataSymbol();
53695
- }
53696
- };
53697
- //#endregion
53698
49837
  //#region ../../node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
53699
49838
  var require$1 = createRequire("/");
53700
49839
  var _a;