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.
@@ -0,0 +1,3956 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
3
+ import { dirname as __cjsShimDirname } from 'node:path';
4
+ const __filename = __cjsShimFileURLToPath(import.meta.url);
5
+ const __dirname = __cjsShimDirname(__filename);
6
+ import { t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
7
+ //#region ../../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
8
+ var require_base64_js = /* @__PURE__ */ __commonJSMin(((exports) => {
9
+ exports.byteLength = byteLength;
10
+ exports.toByteArray = toByteArray;
11
+ exports.fromByteArray = fromByteArray;
12
+ var lookup = [];
13
+ var revLookup = [];
14
+ var Arr = typeof Uint8Array !== "undefined" ? Uint8Array : Array;
15
+ var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16
+ for (var i = 0, len = code.length; i < len; ++i) {
17
+ lookup[i] = code[i];
18
+ revLookup[code.charCodeAt(i)] = i;
19
+ }
20
+ revLookup["-".charCodeAt(0)] = 62;
21
+ revLookup["_".charCodeAt(0)] = 63;
22
+ function getLens(b64) {
23
+ var len = b64.length;
24
+ if (len % 4 > 0) throw new Error("Invalid string. Length must be a multiple of 4");
25
+ var validLen = b64.indexOf("=");
26
+ if (validLen === -1) validLen = len;
27
+ var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;
28
+ return [validLen, placeHoldersLen];
29
+ }
30
+ function byteLength(b64) {
31
+ var lens = getLens(b64);
32
+ var validLen = lens[0];
33
+ var placeHoldersLen = lens[1];
34
+ return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
35
+ }
36
+ function _byteLength(b64, validLen, placeHoldersLen) {
37
+ return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
38
+ }
39
+ function toByteArray(b64) {
40
+ var tmp;
41
+ var lens = getLens(b64);
42
+ var validLen = lens[0];
43
+ var placeHoldersLen = lens[1];
44
+ var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
45
+ var curByte = 0;
46
+ var len = placeHoldersLen > 0 ? validLen - 4 : validLen;
47
+ var i;
48
+ for (i = 0; i < len; i += 4) {
49
+ tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
50
+ arr[curByte++] = tmp >> 16 & 255;
51
+ arr[curByte++] = tmp >> 8 & 255;
52
+ arr[curByte++] = tmp & 255;
53
+ }
54
+ if (placeHoldersLen === 2) {
55
+ tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
56
+ arr[curByte++] = tmp & 255;
57
+ }
58
+ if (placeHoldersLen === 1) {
59
+ tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
60
+ arr[curByte++] = tmp >> 8 & 255;
61
+ arr[curByte++] = tmp & 255;
62
+ }
63
+ return arr;
64
+ }
65
+ function tripletToBase64(num) {
66
+ return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
67
+ }
68
+ function encodeChunk(uint8, start, end) {
69
+ var tmp;
70
+ var output = [];
71
+ for (var i = start; i < end; i += 3) {
72
+ tmp = (uint8[i] << 16 & 16711680) + (uint8[i + 1] << 8 & 65280) + (uint8[i + 2] & 255);
73
+ output.push(tripletToBase64(tmp));
74
+ }
75
+ return output.join("");
76
+ }
77
+ function fromByteArray(uint8) {
78
+ var tmp;
79
+ var len = uint8.length;
80
+ var extraBytes = len % 3;
81
+ var parts = [];
82
+ var maxChunkLength = 16383;
83
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
84
+ if (extraBytes === 1) {
85
+ tmp = uint8[len - 1];
86
+ parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "==");
87
+ } else if (extraBytes === 2) {
88
+ tmp = (uint8[len - 2] << 8) + uint8[len - 1];
89
+ parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "=");
90
+ }
91
+ return parts.join("");
92
+ }
93
+ }));
94
+ //#endregion
95
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/util.js
96
+ 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]*$");
97
+ function getAllMatches(string, regex) {
98
+ const matches = [];
99
+ let match = regex.exec(string);
100
+ while (match) {
101
+ const allmatches = [];
102
+ allmatches.startIndex = regex.lastIndex - match[0].length;
103
+ const len = match.length;
104
+ for (let index = 0; index < len; index++) allmatches.push(match[index]);
105
+ matches.push(allmatches);
106
+ match = regex.exec(string);
107
+ }
108
+ return matches;
109
+ }
110
+ const isName = function(string) {
111
+ const match = regexName.exec(string);
112
+ return !(match === null || typeof match === "undefined");
113
+ };
114
+ function isExist(v) {
115
+ return typeof v !== "undefined";
116
+ }
117
+ /**
118
+ * Dangerous property names that could lead to prototype pollution or security issues
119
+ */
120
+ const DANGEROUS_PROPERTY_NAMES = [
121
+ "hasOwnProperty",
122
+ "toString",
123
+ "valueOf",
124
+ "__defineGetter__",
125
+ "__defineSetter__",
126
+ "__lookupGetter__",
127
+ "__lookupSetter__"
128
+ ];
129
+ const criticalProperties = [
130
+ "__proto__",
131
+ "constructor",
132
+ "prototype"
133
+ ];
134
+ //#endregion
135
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/validator.js
136
+ const defaultOptions$1 = {
137
+ allowBooleanAttributes: false,
138
+ unpairedTags: []
139
+ };
140
+ function validate(xmlData, options) {
141
+ options = Object.assign({}, defaultOptions$1, options);
142
+ const tags = [];
143
+ let tagFound = false;
144
+ let reachedRoot = false;
145
+ if (xmlData[0] === "") xmlData = xmlData.substr(1);
146
+ for (let i = 0; i < xmlData.length; i++) if (xmlData[i] === "<" && xmlData[i + 1] === "?") {
147
+ i += 2;
148
+ i = readPI(xmlData, i);
149
+ if (i.err) return i;
150
+ } else if (xmlData[i] === "<") {
151
+ let tagStartPos = i;
152
+ i++;
153
+ if (xmlData[i] === "!") {
154
+ i = readCommentAndCDATA(xmlData, i);
155
+ continue;
156
+ } else {
157
+ let closingTag = false;
158
+ if (xmlData[i] === "/") {
159
+ closingTag = true;
160
+ i++;
161
+ }
162
+ let tagName = "";
163
+ for (; i < xmlData.length && xmlData[i] !== ">" && xmlData[i] !== " " && xmlData[i] !== " " && xmlData[i] !== "\n" && xmlData[i] !== "\r"; i++) tagName += xmlData[i];
164
+ tagName = tagName.trim();
165
+ if (tagName[tagName.length - 1] === "/") {
166
+ tagName = tagName.substring(0, tagName.length - 1);
167
+ i--;
168
+ }
169
+ if (!validateTagName(tagName)) {
170
+ let msg;
171
+ if (tagName.trim().length === 0) msg = "Invalid space after '<'.";
172
+ else msg = "Tag '" + tagName + "' is an invalid name.";
173
+ return getErrorObject("InvalidTag", msg, getLineNumberForPosition(xmlData, i));
174
+ }
175
+ const result = readAttributeStr(xmlData, i);
176
+ if (result === false) return getErrorObject("InvalidAttr", "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i));
177
+ let attrStr = result.value;
178
+ i = result.index;
179
+ if (attrStr[attrStr.length - 1] === "/") {
180
+ const attrStrStart = i - attrStr.length;
181
+ attrStr = attrStr.substring(0, attrStr.length - 1);
182
+ const isValid = validateAttributeString(attrStr, options);
183
+ if (isValid === true) tagFound = true;
184
+ else return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
185
+ } else if (closingTag) if (!result.tagClosed) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
186
+ else if (attrStr.trim().length > 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
187
+ else if (tags.length === 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
188
+ else {
189
+ const otg = tags.pop();
190
+ if (tagName !== otg.tagName) {
191
+ let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
192
+ return getErrorObject("InvalidTag", "Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.", getLineNumberForPosition(xmlData, tagStartPos));
193
+ }
194
+ if (tags.length == 0) reachedRoot = true;
195
+ }
196
+ else {
197
+ const isValid = validateAttributeString(attrStr, options);
198
+ if (isValid !== true) return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
199
+ if (reachedRoot === true) return getErrorObject("InvalidXml", "Multiple possible root nodes found.", getLineNumberForPosition(xmlData, i));
200
+ else if (options.unpairedTags.indexOf(tagName) !== -1) {} else tags.push({
201
+ tagName,
202
+ tagStartPos
203
+ });
204
+ tagFound = true;
205
+ }
206
+ for (i++; i < xmlData.length; i++) if (xmlData[i] === "<") if (xmlData[i + 1] === "!") {
207
+ i++;
208
+ i = readCommentAndCDATA(xmlData, i);
209
+ continue;
210
+ } else if (xmlData[i + 1] === "?") {
211
+ i = readPI(xmlData, ++i);
212
+ if (i.err) return i;
213
+ } else break;
214
+ else if (xmlData[i] === "&") {
215
+ const afterAmp = validateAmpersand(xmlData, i);
216
+ if (afterAmp == -1) return getErrorObject("InvalidChar", "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
217
+ i = afterAmp;
218
+ } else if (reachedRoot === true && !isWhiteSpace(xmlData[i])) return getErrorObject("InvalidXml", "Extra text at the end", getLineNumberForPosition(xmlData, i));
219
+ if (xmlData[i] === "<") i--;
220
+ }
221
+ } else {
222
+ if (isWhiteSpace(xmlData[i])) continue;
223
+ return getErrorObject("InvalidChar", "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i));
224
+ }
225
+ if (!tagFound) return getErrorObject("InvalidXml", "Start tag expected.", 1);
226
+ else if (tags.length == 1) return getErrorObject("InvalidTag", "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
227
+ else if (tags.length > 0) return getErrorObject("InvalidXml", "Invalid '" + JSON.stringify(tags.map((t) => t.tagName), null, 4).replace(/\r?\n/g, "") + "' found.", {
228
+ line: 1,
229
+ col: 1
230
+ });
231
+ return true;
232
+ }
233
+ function isWhiteSpace(char) {
234
+ return char === " " || char === " " || char === "\n" || char === "\r";
235
+ }
236
+ /**
237
+ * Read Processing insstructions and skip
238
+ * @param {*} xmlData
239
+ * @param {*} i
240
+ */
241
+ function readPI(xmlData, i) {
242
+ const start = i;
243
+ for (; i < xmlData.length; i++) if (xmlData[i] == "?" || xmlData[i] == " ") {
244
+ const tagname = xmlData.substr(start, i - start);
245
+ if (i > 5 && tagname === "xml") return getErrorObject("InvalidXml", "XML declaration allowed only at the start of the document.", getLineNumberForPosition(xmlData, i));
246
+ else if (xmlData[i] == "?" && xmlData[i + 1] == ">") {
247
+ i++;
248
+ break;
249
+ } else continue;
250
+ }
251
+ return i;
252
+ }
253
+ function readCommentAndCDATA(xmlData, i) {
254
+ if (xmlData.length > i + 5 && xmlData[i + 1] === "-" && xmlData[i + 2] === "-") {
255
+ for (i += 3; i < xmlData.length; i++) if (xmlData[i] === "-" && xmlData[i + 1] === "-" && xmlData[i + 2] === ">") {
256
+ i += 2;
257
+ break;
258
+ }
259
+ } 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") {
260
+ let angleBracketsCount = 1;
261
+ for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "<") angleBracketsCount++;
262
+ else if (xmlData[i] === ">") {
263
+ angleBracketsCount--;
264
+ if (angleBracketsCount === 0) break;
265
+ }
266
+ } 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] === "[") {
267
+ for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "]" && xmlData[i + 1] === "]" && xmlData[i + 2] === ">") {
268
+ i += 2;
269
+ break;
270
+ }
271
+ }
272
+ return i;
273
+ }
274
+ const doubleQuote = "\"";
275
+ const singleQuote = "'";
276
+ /**
277
+ * Keep reading xmlData until '<' is found outside the attribute value.
278
+ * @param {string} xmlData
279
+ * @param {number} i
280
+ */
281
+ function readAttributeStr(xmlData, i) {
282
+ let attrStr = "";
283
+ let startChar = "";
284
+ let tagClosed = false;
285
+ for (; i < xmlData.length; i++) {
286
+ if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) if (startChar === "") startChar = xmlData[i];
287
+ else if (startChar !== xmlData[i]) {} else startChar = "";
288
+ else if (xmlData[i] === ">") {
289
+ if (startChar === "") {
290
+ tagClosed = true;
291
+ break;
292
+ }
293
+ }
294
+ attrStr += xmlData[i];
295
+ }
296
+ if (startChar !== "") return false;
297
+ return {
298
+ value: attrStr,
299
+ index: i,
300
+ tagClosed
301
+ };
302
+ }
303
+ /**
304
+ * Select all the attributes whether valid or invalid.
305
+ */
306
+ const validAttrStrRegxp = /* @__PURE__ */ new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?", "g");
307
+ function validateAttributeString(attrStr, options) {
308
+ const matches = getAllMatches(attrStr, validAttrStrRegxp);
309
+ const attrNames = {};
310
+ for (let i = 0; i < matches.length; i++) {
311
+ if (matches[i][1].length === 0) return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i]));
312
+ 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]));
313
+ else if (matches[i][3] === void 0 && !options.allowBooleanAttributes) return getErrorObject("InvalidAttr", "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i]));
314
+ const attrName = matches[i][2];
315
+ if (!validateAttrName(attrName)) return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i]));
316
+ if (!Object.prototype.hasOwnProperty.call(attrNames, attrName)) attrNames[attrName] = 1;
317
+ else return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i]));
318
+ }
319
+ return true;
320
+ }
321
+ function validateNumberAmpersand(xmlData, i) {
322
+ let re = /\d/;
323
+ if (xmlData[i] === "x") {
324
+ i++;
325
+ re = /[\da-fA-F]/;
326
+ }
327
+ for (; i < xmlData.length; i++) {
328
+ if (xmlData[i] === ";") return i;
329
+ if (!xmlData[i].match(re)) break;
330
+ }
331
+ return -1;
332
+ }
333
+ function validateAmpersand(xmlData, i) {
334
+ i++;
335
+ if (xmlData[i] === ";") return -1;
336
+ if (xmlData[i] === "#") {
337
+ i++;
338
+ return validateNumberAmpersand(xmlData, i);
339
+ }
340
+ let count = 0;
341
+ for (; i < xmlData.length; i++, count++) {
342
+ if (xmlData[i].match(/\w/) && count < 20) continue;
343
+ if (xmlData[i] === ";") break;
344
+ return -1;
345
+ }
346
+ return i;
347
+ }
348
+ function getErrorObject(code, message, lineNumber) {
349
+ return { err: {
350
+ code,
351
+ msg: message,
352
+ line: lineNumber.line || lineNumber,
353
+ col: lineNumber.col
354
+ } };
355
+ }
356
+ function validateAttrName(attrName) {
357
+ return isName(attrName);
358
+ }
359
+ function validateTagName(tagname) {
360
+ return isName(tagname);
361
+ }
362
+ function getLineNumberForPosition(xmlData, index) {
363
+ const lines = xmlData.substring(0, index).split(/\r?\n/);
364
+ return {
365
+ line: lines.length,
366
+ col: lines[lines.length - 1].length + 1
367
+ };
368
+ }
369
+ function getPositionFromMatch(match) {
370
+ return match.startIndex + match[1].length;
371
+ }
372
+ //#endregion
373
+ //#region ../../node_modules/.pnpm/@nodable+entities@3.0.0/node_modules/@nodable/entities/src/entities.js
374
+ /**
375
+ * Currency Symbols
376
+ * @type {Record<string, string>}
377
+ */
378
+ const CURRENCY = {
379
+ cent: "¢",
380
+ pound: "£",
381
+ curren: "¤",
382
+ yen: "¥",
383
+ euro: "€",
384
+ dollar: "$",
385
+ fnof: "ƒ",
386
+ inr: "₹",
387
+ af: "؋",
388
+ birr: "ብር",
389
+ peso: "₱",
390
+ rub: "₽",
391
+ won: "₩",
392
+ yuan: "¥",
393
+ cedil: "¸"
394
+ };
395
+ const XML = {
396
+ amp: "&",
397
+ apos: "'",
398
+ gt: ">",
399
+ lt: "<",
400
+ quot: "\""
401
+ };
402
+ const COMMON_HTML = {
403
+ nbsp: "\xA0",
404
+ copy: "©",
405
+ reg: "®",
406
+ trade: "™",
407
+ mdash: "—",
408
+ ndash: "–",
409
+ hellip: "…",
410
+ laquo: "«",
411
+ raquo: "»",
412
+ lsquo: "‘",
413
+ rsquo: "’",
414
+ ldquo: "“",
415
+ rdquo: "”",
416
+ bull: "•",
417
+ para: "¶",
418
+ sect: "§",
419
+ deg: "°",
420
+ frac12: "½",
421
+ frac14: "¼",
422
+ frac34: "¾"
423
+ };
424
+ //#endregion
425
+ //#region ../../node_modules/.pnpm/@nodable+entities@3.0.0/node_modules/@nodable/entities/src/EntityDecoder.js
426
+ /**
427
+ * Action constants for `onExternalEntity` and `onInputEntity` hooks.
428
+ *
429
+ * Use these instead of raw strings to avoid typos:
430
+ *
431
+ * @example
432
+ * import EntityDecoder, { ENTITY_ACTION } from './EntityDecoder.js';
433
+ * const dec = new EntityDecoder({
434
+ * onInputEntity: (name, value) => ENTITY_ACTION.BLOCK,
435
+ * });
436
+ */
437
+ const ENTITY_ACTION = Object.freeze({
438
+ /** Resolve and expand the entity normally. */
439
+ ALLOW: "allow",
440
+ /** Silently skip this entity — it will not be registered. */
441
+ BLOCK: "block",
442
+ /** Throw an error, aborting entity registration entirely. */
443
+ THROW: "throw"
444
+ });
445
+ const SPECIAL_CHARS = /* @__PURE__ */ new Set("!?\\\\/[]$%{}^&*()<>|+");
446
+ /**
447
+ * Validate that an entity name contains no dangerous characters.
448
+ * @param {string} name
449
+ * @returns {string} the name, unchanged
450
+ * @throws {Error} on invalid characters
451
+ */
452
+ function validateEntityName$1(name) {
453
+ if (name[0] === "#") throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${name}"`);
454
+ for (const ch of name) if (SPECIAL_CHARS.has(ch)) throw new Error(`[EntityReplacer] Invalid character '${ch}' in entity name: "${name}"`);
455
+ return name;
456
+ }
457
+ /**
458
+ * Merge one or more entity maps into a flat name→string map.
459
+ * Accepts either:
460
+ * - plain string values: { amp: '&' }
461
+ * - legacy {regex,val} / {regx,val}: { lt: { regex: /.../, val: '<' } }
462
+ *
463
+ * Values containing '&' are skipped (recursive expansion risk).
464
+ *
465
+ * @param {...object} maps
466
+ * @returns {Record<string, string>}
467
+ */
468
+ function mergeEntityMaps(...maps) {
469
+ const out = Object.create(null);
470
+ for (const map of maps) {
471
+ if (!map) continue;
472
+ for (const key of Object.keys(map)) {
473
+ const raw = map[key];
474
+ if (typeof raw === "string") out[key] = raw;
475
+ else if (raw && typeof raw === "object" && raw.val !== void 0) {
476
+ const val = raw.val;
477
+ if (typeof val === "string") out[key] = val;
478
+ }
479
+ }
480
+ }
481
+ return out;
482
+ }
483
+ const LIMIT_TIER_EXTERNAL = "external";
484
+ const LIMIT_TIER_BASE = "base";
485
+ const LIMIT_TIER_ALL = "all";
486
+ /**
487
+ * Resolve `applyLimitsTo` option into a normalised Set of tier strings.
488
+ * Accepted values: 'external' | 'base' | 'all' | string[]
489
+ * Default: 'external' (only untrusted injected entities are counted).
490
+ * @param {string|string[]|undefined} raw
491
+ * @returns {Set<string>}
492
+ */
493
+ function parseLimitTiers(raw) {
494
+ if (!raw || raw === LIMIT_TIER_EXTERNAL) return new Set([LIMIT_TIER_EXTERNAL]);
495
+ if (raw === LIMIT_TIER_ALL) return new Set([LIMIT_TIER_ALL]);
496
+ if (raw === LIMIT_TIER_BASE) return new Set([LIMIT_TIER_BASE]);
497
+ if (Array.isArray(raw)) return new Set(raw);
498
+ return new Set([LIMIT_TIER_EXTERNAL]);
499
+ }
500
+ const NCR_LEVEL = Object.freeze({
501
+ allow: 0,
502
+ leave: 1,
503
+ remove: 2,
504
+ throw: 3
505
+ });
506
+ const XML10_ALLOWED_C0 = new Set([
507
+ 9,
508
+ 10,
509
+ 13
510
+ ]);
511
+ /**
512
+ * Parse the `ncr` constructor option into flat, hot-path-friendly fields.
513
+ * @param {object|undefined} ncr
514
+ * @returns {{ xmlVersion: number, onLevel: number, nullLevel: number }}
515
+ */
516
+ function parseNCRConfig(ncr) {
517
+ if (!ncr) return {
518
+ xmlVersion: 1,
519
+ onLevel: NCR_LEVEL.allow,
520
+ nullLevel: NCR_LEVEL.remove
521
+ };
522
+ const xmlVersion = ncr.xmlVersion === 1.1 ? 1.1 : 1;
523
+ const onLevel = NCR_LEVEL[ncr.onNCR] ?? NCR_LEVEL.allow;
524
+ const nullLevel = NCR_LEVEL[ncr.nullNCR] ?? NCR_LEVEL.remove;
525
+ return {
526
+ xmlVersion,
527
+ onLevel,
528
+ nullLevel: Math.max(nullLevel, NCR_LEVEL.remove)
529
+ };
530
+ }
531
+ /**
532
+ * Single-pass, zero-regex entity replacer for XML/HTML content.
533
+ *
534
+ * Algorithm: scan the string once for '&', read to ';', resolve via map
535
+ * or direct codepoint conversion, build output chunks, join once at the end.
536
+ *
537
+ * Entity lookup priority (highest → lowest):
538
+ * 1. input / runtime (DOCTYPE entities for current document)
539
+ * 2. persistent external (survive across documents)
540
+ * 3. base named map (DEFAULT_XML_ENTITIES + user-supplied namedEntities)
541
+ *
542
+ * Both input and external resolve as the 'external' tier for limit purposes.
543
+ * Base map entities resolve as the 'base' tier.
544
+ *
545
+ * Numeric / hex references (&#NNN; / &#xHH;) are resolved directly via
546
+ * String.fromCodePoint() — no map needed. They count as 'base' tier.
547
+ *
548
+ * @example
549
+ * const replacer = new EntityReplacer({ namedEntities: COMMON_HTML });
550
+ * replacer.setExternalEntities({ brand: 'Acme' });
551
+ *
552
+ * const instance = replacer.reset();
553
+ * instance.addInputEntities({ version: '1.0' });
554
+ * instance.encode('&brand; v&version; &lt;'); // 'Acme v1.0 <'
555
+ */
556
+ var EntityDecoder = class {
557
+ /**
558
+ * @param {object} [options]
559
+ * @param {object|null} [options.namedEntities] — extra named entities merged into base map
560
+ * @param {object} [options.limit] — security limits
561
+ * @param {number} [options.limit.maxTotalExpansions=0] — 0 = unlimited
562
+ * @param {number} [options.limit.maxExpandedLength=0] — 0 = unlimited
563
+ * @param {'external'|'base'|'all'|string[]} [options.limit.applyLimitsTo='external']
564
+ * Which entity tiers count against the security limits:
565
+ * - 'external' (default) — only input/runtime + persistent external entities
566
+ * - 'base' — only DEFAULT_XML_ENTITIES + namedEntities
567
+ * - 'all' — every entity regardless of tier
568
+ * - string[] — explicit combination, e.g. ['external', 'base']
569
+ * @param {((resolved: string, original: string) => string)|null} [options.postCheck=null]
570
+ * @param {string[]} [options.remove=[]] — entity names (e.g. ['nbsp', '#13']) to delete (replace with empty string)
571
+ * @param {string[]} [options.leave=[]] — entity names to keep as literal (unchanged in output)
572
+ * @param {object} [options.ncr] — Numeric Character Reference controls
573
+ * @param {1.0|1.1} [options.ncr.xmlVersion=1.0]
574
+ * XML version governing which codepoint ranges are restricted:
575
+ * - 1.0 — C0 controls U+0001–U+001F (except U+0009/000A/000D) are prohibited
576
+ * - 1.1 — C0 controls are allowed when written as NCRs; C1 (U+007F–U+009F) decoded as-is
577
+ * @param {'allow'|'leave'|'remove'|'throw'} [options.ncr.onNCR='allow']
578
+ * Base action for numeric references. Severity order: allow < leave < remove < throw.
579
+ * For codepoint ranges that carry a minimum level (surrogates → remove, XML 1.0 C0 → remove),
580
+ * the effective action is max(onNCR, rangeMinimum).
581
+ * @param {'remove'|'throw'} [options.ncr.nullNCR='remove']
582
+ * Action for U+0000 (null). 'allow' and 'leave' are clamped to 'remove' since null is never safe.
583
+ * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onExternalEntity=null]
584
+ * Hook called when an external entity is registered via `setExternalEntities()` or
585
+ * `addExternalEntity()`. Return `ENTITY_ACTION.ALLOW` to accept the entity,
586
+ * `ENTITY_ACTION.BLOCK` to silently skip it, or `ENTITY_ACTION.THROW` to abort with an error.
587
+ * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onInputEntity=null]
588
+ * Hook called when an input entity is registered via `addInputEntities()`. Return
589
+ * `ENTITY_ACTION.ALLOW` to accept, `ENTITY_ACTION.BLOCK` to silently skip, or
590
+ * `ENTITY_ACTION.THROW` to abort with an error.
591
+ */
592
+ constructor(options = {}) {
593
+ this._limit = options.limit || {};
594
+ this._maxTotalExpansions = this._limit.maxTotalExpansions || 0;
595
+ this._maxExpandedLength = this._limit.maxExpandedLength || 0;
596
+ this._postCheck = typeof options.postCheck === "function" ? options.postCheck : (r) => r;
597
+ this._limitTiers = parseLimitTiers(this._limit.applyLimitsTo ?? LIMIT_TIER_EXTERNAL);
598
+ this._numericAllowed = options.numericAllowed ?? true;
599
+ this._baseMap = mergeEntityMaps(XML, options.namedEntities || null);
600
+ /** @type {Record<string, string>} */
601
+ this._externalMap = Object.create(null);
602
+ /** @type {Record<string, string>} */
603
+ this._inputMap = Object.create(null);
604
+ this._totalExpansions = 0;
605
+ this._expandedLength = 0;
606
+ /** @type {Set<string>} */
607
+ this._removeSet = new Set(options.remove && Array.isArray(options.remove) ? options.remove : []);
608
+ /** @type {Set<string>} */
609
+ this._leaveSet = new Set(options.leave && Array.isArray(options.leave) ? options.leave : []);
610
+ const ncrCfg = parseNCRConfig(options.ncr);
611
+ this._ncrXmlVersion = ncrCfg.xmlVersion;
612
+ this._ncrOnLevel = ncrCfg.onLevel;
613
+ this._ncrNullLevel = ncrCfg.nullLevel;
614
+ /** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
615
+ this._onExternalEntity = typeof options.onExternalEntity === "function" ? options.onExternalEntity : null;
616
+ /** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
617
+ this._onInputEntity = typeof options.onInputEntity === "function" ? options.onInputEntity : null;
618
+ }
619
+ /**
620
+ * Invoke a registration hook for a single entity name/value pair.
621
+ * Returns true when the entity should be accepted, false when it should be
622
+ * silently skipped (BLOCK), and throws when the hook returns THROW.
623
+ *
624
+ * @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} hook
625
+ * @param {string} name
626
+ * @param {string} value
627
+ * @param {string} context — used in error messages ('external' | 'input')
628
+ * @returns {boolean} true = accept, false = skip
629
+ */
630
+ _applyRegistrationHook(hook, name, value, context) {
631
+ if (!hook) return true;
632
+ const action = hook(name, value);
633
+ if (action === ENTITY_ACTION.BLOCK) return false;
634
+ if (action === ENTITY_ACTION.THROW) throw new Error(`[EntityDecoder] Registration of ${context} entity "&${name};" was rejected by hook`);
635
+ return true;
636
+ }
637
+ /**
638
+ * Replace the full set of persistent external entities.
639
+ * All keys are validated — throws on invalid characters.
640
+ * If `onExternalEntity` is set, it is called once per entry; entries that
641
+ * return `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW`
642
+ * aborts the whole call.
643
+ * @param {Record<string, string | { regex?: RegExp, val: string }>} map
644
+ */
645
+ setExternalEntities(map) {
646
+ if (map) for (const key of Object.keys(map)) validateEntityName$1(key);
647
+ if (!this._onExternalEntity) {
648
+ this._externalMap = mergeEntityMaps(map);
649
+ return;
650
+ }
651
+ const flat = mergeEntityMaps(map);
652
+ const filtered = Object.create(null);
653
+ for (const [name, value] of Object.entries(flat)) if (this._applyRegistrationHook(this._onExternalEntity, name, value, "external")) filtered[name] = value;
654
+ this._externalMap = filtered;
655
+ }
656
+ /**
657
+ * Add a single persistent external entity.
658
+ * If `onExternalEntity` is set it is called before the entity is stored;
659
+ * `ENTITY_ACTION.BLOCK` silently skips storage, `ENTITY_ACTION.THROW` raises.
660
+ * @param {string} key
661
+ * @param {string} value
662
+ */
663
+ addExternalEntity(key, value) {
664
+ validateEntityName$1(key);
665
+ if (typeof value === "string" && value.indexOf("&") === -1) {
666
+ if (this._applyRegistrationHook(this._onExternalEntity, key, value, "external")) this._externalMap[key] = value;
667
+ }
668
+ }
669
+ /**
670
+ * Inject DOCTYPE entities for the current document.
671
+ * Also resets per-document expansion counters.
672
+ * If `onInputEntity` is set it is called once per entry; entries returning
673
+ * `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW` aborts.
674
+ * @param {Record<string, string | { regx?: RegExp, regex?: RegExp, val: string }>} map
675
+ */
676
+ addInputEntities(map) {
677
+ this._totalExpansions = 0;
678
+ this._expandedLength = 0;
679
+ if (!this._onInputEntity) {
680
+ this._inputMap = mergeEntityMaps(map);
681
+ return;
682
+ }
683
+ const flat = mergeEntityMaps(map);
684
+ const filtered = Object.create(null);
685
+ for (const [name, value] of Object.entries(flat)) if (this._applyRegistrationHook(this._onInputEntity, name, value, "input")) filtered[name] = value;
686
+ this._inputMap = filtered;
687
+ }
688
+ /**
689
+ * Wipe input/runtime entities and reset counters.
690
+ * Call this before processing each new document.
691
+ * @returns {this}
692
+ */
693
+ reset() {
694
+ this._inputMap = Object.create(null);
695
+ this._totalExpansions = 0;
696
+ this._expandedLength = 0;
697
+ return this;
698
+ }
699
+ /**
700
+ * Update the XML version used for NCR classification.
701
+ * Call this as soon as the document's `<?xml version="...">` declaration is parsed.
702
+ * @param {1.0|1.1|number} version
703
+ */
704
+ setXmlVersion(version) {
705
+ this._ncrXmlVersion = version === 1.1 ? 1.1 : 1;
706
+ }
707
+ /**
708
+ * Replace all entity references in `str` in a single pass.
709
+ *
710
+ * @param {string} str
711
+ * @returns {string}
712
+ */
713
+ decode(str) {
714
+ if (typeof str !== "string" || str.length === 0) return str;
715
+ if (str.indexOf("&") === -1) return str;
716
+ const original = str;
717
+ const chunks = [];
718
+ const len = str.length;
719
+ let last = 0;
720
+ let i = 0;
721
+ const limitExpansions = this._maxTotalExpansions > 0;
722
+ const limitLength = this._maxExpandedLength > 0;
723
+ const checkLimits = limitExpansions || limitLength;
724
+ while (i < len) {
725
+ if (str.charCodeAt(i) !== 38) {
726
+ i++;
727
+ continue;
728
+ }
729
+ let j = i + 1;
730
+ while (j < len && str.charCodeAt(j) !== 59 && j - i <= 32) j++;
731
+ if (j >= len || str.charCodeAt(j) !== 59) {
732
+ i++;
733
+ continue;
734
+ }
735
+ const token = str.slice(i + 1, j);
736
+ if (token.length === 0) {
737
+ i++;
738
+ continue;
739
+ }
740
+ let replacement;
741
+ let tier;
742
+ if (this._removeSet.has(token)) {
743
+ replacement = "";
744
+ if (tier === void 0) tier = LIMIT_TIER_EXTERNAL;
745
+ } else if (this._leaveSet.has(token)) {
746
+ i++;
747
+ continue;
748
+ } else if (token.charCodeAt(0) === 35) {
749
+ const ncrResult = this._resolveNCR(token);
750
+ if (ncrResult === void 0) {
751
+ i++;
752
+ continue;
753
+ }
754
+ replacement = ncrResult;
755
+ tier = LIMIT_TIER_BASE;
756
+ } else {
757
+ const resolved = this._resolveName(token);
758
+ replacement = resolved?.value;
759
+ tier = resolved?.tier;
760
+ }
761
+ if (replacement === void 0) {
762
+ i++;
763
+ continue;
764
+ }
765
+ if (i > last) chunks.push(str.slice(last, i));
766
+ chunks.push(replacement);
767
+ last = j + 1;
768
+ i = last;
769
+ if (checkLimits && this._tierCounts(tier)) {
770
+ if (limitExpansions) {
771
+ this._totalExpansions++;
772
+ if (this._totalExpansions > this._maxTotalExpansions) throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`);
773
+ }
774
+ if (limitLength) {
775
+ const delta = replacement.length - (token.length + 2);
776
+ if (delta > 0) {
777
+ this._expandedLength += delta;
778
+ if (this._expandedLength > this._maxExpandedLength) throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`);
779
+ }
780
+ }
781
+ }
782
+ }
783
+ if (last < len) chunks.push(str.slice(last));
784
+ const result = chunks.length === 0 ? str : chunks.join("");
785
+ return this._postCheck(result, original);
786
+ }
787
+ /**
788
+ * Returns true if a resolved entity of the given tier should count
789
+ * against the expansion/length limits.
790
+ * @param {string} tier — LIMIT_TIER_EXTERNAL | LIMIT_TIER_BASE
791
+ * @returns {boolean}
792
+ */
793
+ _tierCounts(tier) {
794
+ if (this._limitTiers.has(LIMIT_TIER_ALL)) return true;
795
+ return this._limitTiers.has(tier);
796
+ }
797
+ /**
798
+ * Resolve a named entity token (without & and ;).
799
+ * Priority: inputMap > externalMap > baseMap
800
+ * Returns the resolved value tagged with its limit tier.
801
+ *
802
+ * @param {string} name
803
+ * @returns {{ value: string, tier: string }|undefined}
804
+ */
805
+ _resolveName(name) {
806
+ if (name in this._inputMap) return {
807
+ value: this._inputMap[name],
808
+ tier: LIMIT_TIER_EXTERNAL
809
+ };
810
+ if (name in this._externalMap) return {
811
+ value: this._externalMap[name],
812
+ tier: LIMIT_TIER_EXTERNAL
813
+ };
814
+ if (name in this._baseMap) return {
815
+ value: this._baseMap[name],
816
+ tier: LIMIT_TIER_BASE
817
+ };
818
+ }
819
+ /**
820
+ * Classify a codepoint and return the minimum action level that must be applied.
821
+ * Returns -1 when no minimum is imposed (normal allow path).
822
+ *
823
+ * Ranges checked (in priority order):
824
+ * 1. U+0000 — null, governed by nullNCR (always ≥ remove)
825
+ * 2. U+D800–U+DFFF — surrogates, always prohibited (min: remove)
826
+ * 3. U+0001–U+001F \ {0x09,0x0A,0x0D} — XML 1.0 restricted C0 (min: remove)
827
+ * (skipped in XML 1.1 — C0 controls are allowed when written as NCRs)
828
+ *
829
+ * @param {number} cp — codepoint
830
+ * @returns {number} — minimum NCR_LEVEL value, or -1 for no restriction
831
+ */
832
+ _classifyNCR(cp) {
833
+ if (cp === 0) return this._ncrNullLevel;
834
+ if (cp >= 55296 && cp <= 57343) return NCR_LEVEL.remove;
835
+ if (this._ncrXmlVersion === 1) {
836
+ if (cp >= 1 && cp <= 31 && !XML10_ALLOWED_C0.has(cp)) return NCR_LEVEL.remove;
837
+ }
838
+ return -1;
839
+ }
840
+ /**
841
+ * Execute a resolved NCR action.
842
+ *
843
+ * @param {number} action — NCR_LEVEL value
844
+ * @param {string} token — raw token (e.g. '#38') for error messages
845
+ * @param {number} cp — codepoint, used only for error messages
846
+ * @returns {string|undefined}
847
+ * - decoded character string → 'allow'
848
+ * - '' → 'remove'
849
+ * - undefined → 'leave' (caller must skip past '&' only)
850
+ * - throws Error → 'throw'
851
+ */
852
+ _applyNCRAction(action, token, cp) {
853
+ switch (action) {
854
+ case NCR_LEVEL.allow: return String.fromCodePoint(cp);
855
+ case NCR_LEVEL.remove: return "";
856
+ case NCR_LEVEL.leave: return;
857
+ case NCR_LEVEL.throw: throw new Error(`[EntityDecoder] Prohibited numeric character reference &${token}; (U+${cp.toString(16).toUpperCase().padStart(4, "0")})`);
858
+ default: return String.fromCodePoint(cp);
859
+ }
860
+ }
861
+ /**
862
+ * Full NCR resolution pipeline for a numeric token.
863
+ *
864
+ * Steps:
865
+ * 1. Parse the codepoint (decimal or hex).
866
+ * 2. Validate the raw codepoint range (NaN, <0, >0x10FFFF).
867
+ * 3. If numericAllowed is false and no minimum restriction applies → leave as-is.
868
+ * 4. Classify the codepoint to find the minimum required action level.
869
+ * 5. Resolve effective action = max(onNCR, minimum).
870
+ * 6. Apply and return.
871
+ *
872
+ * @param {string} token — e.g. '#38', '#x26', '#X26'
873
+ * @returns {string|undefined}
874
+ * - string (incl. '') — replacement ('' = remove)
875
+ * - undefined — leave original &token; as-is
876
+ */
877
+ _resolveNCR(token) {
878
+ const second = token.charCodeAt(1);
879
+ let cp;
880
+ if (second === 120 || second === 88) cp = parseInt(token.slice(2), 16);
881
+ else cp = parseInt(token.slice(1), 10);
882
+ if (Number.isNaN(cp) || cp < 0 || cp > 1114111) return void 0;
883
+ const minimum = this._classifyNCR(cp);
884
+ if (!this._numericAllowed && minimum < NCR_LEVEL.remove) return void 0;
885
+ const effective = minimum === -1 ? this._ncrOnLevel : Math.max(this._ncrOnLevel, minimum);
886
+ return this._applyNCRAction(effective, token, cp);
887
+ }
888
+ };
889
+ //#endregion
890
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
891
+ const defaultOnDangerousProperty = (name) => {
892
+ if (DANGEROUS_PROPERTY_NAMES.includes(name)) return "__" + name;
893
+ return name;
894
+ };
895
+ const defaultOptions = {
896
+ preserveOrder: false,
897
+ attributeNamePrefix: "@_",
898
+ attributesGroupName: false,
899
+ textNodeName: "#text",
900
+ ignoreAttributes: true,
901
+ removeNSPrefix: false,
902
+ allowBooleanAttributes: false,
903
+ parseTagValue: true,
904
+ parseAttributeValue: false,
905
+ trimValues: true,
906
+ cdataPropName: false,
907
+ numberParseOptions: {
908
+ hex: true,
909
+ leadingZeros: true,
910
+ eNotation: true,
911
+ unicode: false
912
+ },
913
+ tagValueProcessor: function(tagName, val) {
914
+ return val;
915
+ },
916
+ attributeValueProcessor: function(attrName, val) {
917
+ return val;
918
+ },
919
+ stopNodes: [],
920
+ alwaysCreateTextNode: false,
921
+ isArray: () => false,
922
+ commentPropName: false,
923
+ unpairedTags: [],
924
+ processEntities: true,
925
+ htmlEntities: false,
926
+ entityDecoder: null,
927
+ ignoreDeclaration: false,
928
+ ignorePiTags: false,
929
+ transformTagName: false,
930
+ transformAttributeName: false,
931
+ updateTag: function(tagName, jPath, attrs) {
932
+ return tagName;
933
+ },
934
+ captureMetaData: false,
935
+ maxNestedTags: 100,
936
+ strictReservedNames: true,
937
+ jPath: true,
938
+ onDangerousProperty: defaultOnDangerousProperty
939
+ };
940
+ /**
941
+ * Validates that a property name is safe to use
942
+ * @param {string} propertyName - The property name to validate
943
+ * @param {string} optionName - The option field name (for error message)
944
+ * @throws {Error} If property name is dangerous
945
+ */
946
+ function validatePropertyName(propertyName, optionName) {
947
+ if (typeof propertyName !== "string") return;
948
+ const normalized = propertyName.toLowerCase();
949
+ 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`);
950
+ if (criticalProperties.some((dangerous) => normalized === dangerous.toLowerCase())) throw new Error(`[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`);
951
+ }
952
+ /**
953
+ * Normalizes processEntities option for backward compatibility
954
+ * @param {boolean|object} value
955
+ * @returns {object} Always returns normalized object
956
+ */
957
+ function normalizeProcessEntities(value, htmlEntities) {
958
+ if (typeof value === "boolean") return {
959
+ enabled: value,
960
+ maxEntitySize: 1e4,
961
+ maxExpansionDepth: 1e4,
962
+ maxTotalExpansions: Infinity,
963
+ maxExpandedLength: 1e5,
964
+ maxEntityCount: 1e3,
965
+ allowedTags: null,
966
+ tagFilter: null,
967
+ appliesTo: "all"
968
+ };
969
+ if (typeof value === "object" && value !== null) return {
970
+ enabled: value.enabled !== false,
971
+ maxEntitySize: Math.max(1, value.maxEntitySize ?? 1e4),
972
+ maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 1e4),
973
+ maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity),
974
+ maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 1e5),
975
+ maxEntityCount: Math.max(1, value.maxEntityCount ?? 1e3),
976
+ allowedTags: value.allowedTags ?? null,
977
+ tagFilter: value.tagFilter ?? null,
978
+ appliesTo: value.appliesTo ?? "all"
979
+ };
980
+ return normalizeProcessEntities(true);
981
+ }
982
+ const buildOptions = function(options) {
983
+ const built = Object.assign({}, defaultOptions, options);
984
+ const propertyNameOptions = [
985
+ {
986
+ value: built.attributeNamePrefix,
987
+ name: "attributeNamePrefix"
988
+ },
989
+ {
990
+ value: built.attributesGroupName,
991
+ name: "attributesGroupName"
992
+ },
993
+ {
994
+ value: built.textNodeName,
995
+ name: "textNodeName"
996
+ },
997
+ {
998
+ value: built.cdataPropName,
999
+ name: "cdataPropName"
1000
+ },
1001
+ {
1002
+ value: built.commentPropName,
1003
+ name: "commentPropName"
1004
+ }
1005
+ ];
1006
+ for (const { value, name } of propertyNameOptions) if (value) validatePropertyName(value, name);
1007
+ if (built.onDangerousProperty === null) built.onDangerousProperty = defaultOnDangerousProperty;
1008
+ built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities);
1009
+ built.unpairedTagsSet = new Set(built.unpairedTags);
1010
+ if (built.stopNodes && Array.isArray(built.stopNodes)) built.stopNodes = built.stopNodes.map((node) => {
1011
+ if (typeof node === "string" && node.startsWith("*.")) return ".." + node.substring(2);
1012
+ return node;
1013
+ });
1014
+ return built;
1015
+ };
1016
+ //#endregion
1017
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
1018
+ let METADATA_SYMBOL$1;
1019
+ if (typeof Symbol !== "function") METADATA_SYMBOL$1 = "@@xmlMetadata";
1020
+ else METADATA_SYMBOL$1 = Symbol("XML Node Metadata");
1021
+ var XmlNode = class {
1022
+ constructor(tagname) {
1023
+ this.tagname = tagname;
1024
+ this.child = [];
1025
+ this[":@"] = Object.create(null);
1026
+ }
1027
+ add(key, val) {
1028
+ if (key === "__proto__") key = "#__proto__";
1029
+ this.child.push({ [key]: val });
1030
+ }
1031
+ addChild(node, startIndex) {
1032
+ if (node.tagname === "__proto__") node.tagname = "#__proto__";
1033
+ if (node[":@"] && Object.keys(node[":@"]).length > 0) this.child.push({
1034
+ [node.tagname]: node.child,
1035
+ [":@"]: node[":@"]
1036
+ });
1037
+ else this.child.push({ [node.tagname]: node.child });
1038
+ if (startIndex !== void 0) this.child[this.child.length - 1][METADATA_SYMBOL$1] = { startIndex };
1039
+ }
1040
+ /** symbol used for metadata */
1041
+ static getMetaDataSymbol() {
1042
+ return METADATA_SYMBOL$1;
1043
+ }
1044
+ };
1045
+ //#endregion
1046
+ //#region ../../node_modules/.pnpm/xml-naming@0.3.0/node_modules/xml-naming/src/index.js
1047
+ /**
1048
+ * xml-naming
1049
+ * Validates XML Name productions as defined in the XML 1.0 and 1.1 specifications.
1050
+ * Covers: Name, NCName, QName, NMToken, NMTokens
1051
+ *
1052
+ * XML 1.0 spec: https://www.w3.org/TR/xml/#NT-Name
1053
+ * XML 1.1 spec: https://www.w3.org/TR/xml11/#NT-NameStartChar
1054
+ * XML NS spec: https://www.w3.org/TR/xml-names/#NT-NCName
1055
+ */
1056
+ const nameStartChar10 = ":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�";
1057
+ const nameChar10 = ":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�\\-\\.\\d·̀-ͯ‿-⁀";
1058
+ const nameStartChar11 = ":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿";
1059
+ const nameChar11 = ":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿\\-\\.\\d·̀-ͯ҇‿-⁀";
1060
+ const buildRegexes = (startChar, char, flags = "") => {
1061
+ const ncNamePat = `[${startChar.replace(":", "")}][${char.replace(":", "")}]*`;
1062
+ return {
1063
+ name: new RegExp(`^[${startChar}][${char}]*$`, flags),
1064
+ ncName: new RegExp(`^${ncNamePat}$`, flags),
1065
+ qName: new RegExp(`^${ncNamePat}(?::${ncNamePat})?$`, flags),
1066
+ nmToken: new RegExp(`^[${char}]+$`, flags),
1067
+ nmTokens: new RegExp(`^[${char}]+(?:\\s+[${char}]+)*$`, flags)
1068
+ };
1069
+ };
1070
+ const regexes10 = buildRegexes(nameStartChar10, nameChar10);
1071
+ const regexes11 = buildRegexes(nameStartChar11, nameChar11, "u");
1072
+ const regexesAscii = buildRegexes(":A-Za-z_", ":A-Za-z_\\-\\.\\d");
1073
+ const getRegexes = (xmlVersion = "1.0", asciiOnly = false) => {
1074
+ if (asciiOnly) return regexesAscii;
1075
+ return xmlVersion === "1.1" ? regexes11 : regexes10;
1076
+ };
1077
+ /**
1078
+ * Returns true if the string is a valid QName (Qualified Name).
1079
+ * Allows exactly one colon as a prefix separator: prefix:localName.
1080
+ * Used for: element and attribute names in namespace-aware XML/SVG.
1081
+ *
1082
+ * @param {{ xmlVersion?: '1.0'|'1.1', asciiOnly?: boolean }} [opts]
1083
+ * asciiOnly: skip unicode-aware matching, ASCII names only (default false).
1084
+ */
1085
+ const qName = (str, { xmlVersion = "1.0", asciiOnly = false } = {}) => getRegexes(xmlVersion, asciiOnly).qName.test(str);
1086
+ //#endregion
1087
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
1088
+ var DocTypeReader = class {
1089
+ constructor(options, xmlVersion) {
1090
+ this.suppressValidationErr = !options;
1091
+ this.options = options;
1092
+ this.xmlVersion = xmlVersion || 1;
1093
+ }
1094
+ setXmlVersion(xmlVersion = 1) {
1095
+ this.xmlVersion = xmlVersion;
1096
+ }
1097
+ readDocType(xmlData, i) {
1098
+ const entities = Object.create(null);
1099
+ let entityCount = 0;
1100
+ 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") {
1101
+ i = i + 9;
1102
+ let angleBracketsCount = 1;
1103
+ let hasBody = false, comment = false;
1104
+ let exp = "";
1105
+ for (; i < xmlData.length; i++) if (xmlData[i] === "<" && !comment) {
1106
+ if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
1107
+ i += 7;
1108
+ let entityName, val;
1109
+ [entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
1110
+ if (val.indexOf("&") === -1) {
1111
+ 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})`);
1112
+ entities[entityName] = val;
1113
+ entityCount++;
1114
+ }
1115
+ } else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
1116
+ i += 8;
1117
+ const { index } = this.readElementExp(xmlData, i + 1);
1118
+ i = index;
1119
+ } else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) i += 8;
1120
+ else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) {
1121
+ i += 9;
1122
+ const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr);
1123
+ i = index;
1124
+ } else if (hasSeq(xmlData, "!--", i)) comment = true;
1125
+ else throw new Error(`Invalid DOCTYPE`);
1126
+ angleBracketsCount++;
1127
+ exp = "";
1128
+ } else if (xmlData[i] === ">") {
1129
+ if (comment) {
1130
+ if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") {
1131
+ comment = false;
1132
+ angleBracketsCount--;
1133
+ }
1134
+ } else angleBracketsCount--;
1135
+ if (angleBracketsCount === 0) break;
1136
+ } else if (xmlData[i] === "[") hasBody = true;
1137
+ else exp += xmlData[i];
1138
+ if (angleBracketsCount !== 0) throw new Error(`Unclosed DOCTYPE`);
1139
+ } else throw new Error(`Invalid Tag instead of DOCTYPE`);
1140
+ return {
1141
+ entities,
1142
+ i
1143
+ };
1144
+ }
1145
+ readEntityExp(xmlData, i) {
1146
+ i = skipWhitespace(xmlData, i);
1147
+ const startIndex = i;
1148
+ while (i < xmlData.length && !/\s/.test(xmlData[i]) && xmlData[i] !== "\"" && xmlData[i] !== "'") i++;
1149
+ let entityName = xmlData.substring(startIndex, i);
1150
+ validateEntityName(entityName, { xmlVersion: this.xmlVersion });
1151
+ i = skipWhitespace(xmlData, i);
1152
+ if (!this.suppressValidationErr) {
1153
+ if (xmlData.substring(i, i + 6).toUpperCase() === "SYSTEM") throw new Error("External entities are not supported");
1154
+ else if (xmlData[i] === "%") throw new Error("Parameter entities are not supported");
1155
+ }
1156
+ let entityValue = "";
1157
+ [i, entityValue] = this.readIdentifierVal(xmlData, i, "entity");
1158
+ 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})`);
1159
+ i--;
1160
+ return [
1161
+ entityName,
1162
+ entityValue,
1163
+ i
1164
+ ];
1165
+ }
1166
+ readNotationExp(xmlData, i) {
1167
+ i = skipWhitespace(xmlData, i);
1168
+ const startIndex = i;
1169
+ while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
1170
+ let notationName = xmlData.substring(startIndex, i);
1171
+ !this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion });
1172
+ i = skipWhitespace(xmlData, i);
1173
+ const identifierType = xmlData.substring(i, i + 6).toUpperCase();
1174
+ if (!this.suppressValidationErr && identifierType !== "SYSTEM" && identifierType !== "PUBLIC") throw new Error(`Expected SYSTEM or PUBLIC, found "${identifierType}"`);
1175
+ i += identifierType.length;
1176
+ i = skipWhitespace(xmlData, i);
1177
+ let publicIdentifier = null;
1178
+ let systemIdentifier = null;
1179
+ if (identifierType === "PUBLIC") {
1180
+ [i, publicIdentifier] = this.readIdentifierVal(xmlData, i, "publicIdentifier");
1181
+ i = skipWhitespace(xmlData, i);
1182
+ if (xmlData[i] === "\"" || xmlData[i] === "'") [i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
1183
+ } else if (identifierType === "SYSTEM") {
1184
+ [i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
1185
+ if (!this.suppressValidationErr && !systemIdentifier) throw new Error("Missing mandatory system identifier for SYSTEM notation");
1186
+ }
1187
+ return {
1188
+ notationName,
1189
+ publicIdentifier,
1190
+ systemIdentifier,
1191
+ index: --i
1192
+ };
1193
+ }
1194
+ readIdentifierVal(xmlData, i, type) {
1195
+ let identifierVal = "";
1196
+ const startChar = xmlData[i];
1197
+ if (startChar !== "\"" && startChar !== "'") throw new Error(`Expected quoted string, found "${startChar}"`);
1198
+ i++;
1199
+ const startIndex = i;
1200
+ while (i < xmlData.length && xmlData[i] !== startChar) i++;
1201
+ identifierVal = xmlData.substring(startIndex, i);
1202
+ if (xmlData[i] !== startChar) throw new Error(`Unterminated ${type} value`);
1203
+ i++;
1204
+ return [i, identifierVal];
1205
+ }
1206
+ readElementExp(xmlData, i) {
1207
+ i = skipWhitespace(xmlData, i);
1208
+ const startIndex = i;
1209
+ while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
1210
+ let elementName = xmlData.substring(startIndex, i);
1211
+ if (!this.suppressValidationErr && !qName(elementName, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid element name: "${elementName}"`);
1212
+ i = skipWhitespace(xmlData, i);
1213
+ let contentModel = "";
1214
+ if (xmlData[i] === "E" && hasSeq(xmlData, "MPTY", i)) i += 4;
1215
+ else if (xmlData[i] === "A" && hasSeq(xmlData, "NY", i)) i += 2;
1216
+ else if (xmlData[i] === "(") {
1217
+ i++;
1218
+ const startIndex = i;
1219
+ while (i < xmlData.length && xmlData[i] !== ")") i++;
1220
+ contentModel = xmlData.substring(startIndex, i);
1221
+ if (xmlData[i] !== ")") throw new Error("Unterminated content model");
1222
+ } else if (!this.suppressValidationErr) throw new Error(`Invalid Element Expression, found "${xmlData[i]}"`);
1223
+ return {
1224
+ elementName,
1225
+ contentModel: contentModel.trim(),
1226
+ index: i
1227
+ };
1228
+ }
1229
+ readAttlistExp(xmlData, i) {
1230
+ i = skipWhitespace(xmlData, i);
1231
+ let startIndex = i;
1232
+ while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
1233
+ let elementName = xmlData.substring(startIndex, i);
1234
+ validateEntityName(elementName, { xmlVersion: this.xmlVersion });
1235
+ i = skipWhitespace(xmlData, i);
1236
+ startIndex = i;
1237
+ while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
1238
+ let attributeName = xmlData.substring(startIndex, i);
1239
+ if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid attribute name: "${attributeName}"`);
1240
+ i = skipWhitespace(xmlData, i);
1241
+ let attributeType = "";
1242
+ if (xmlData.substring(i, i + 8).toUpperCase() === "NOTATION") {
1243
+ attributeType = "NOTATION";
1244
+ i += 8;
1245
+ i = skipWhitespace(xmlData, i);
1246
+ if (xmlData[i] !== "(") throw new Error(`Expected '(', found "${xmlData[i]}"`);
1247
+ i++;
1248
+ let allowedNotations = [];
1249
+ while (i < xmlData.length && xmlData[i] !== ")") {
1250
+ const startIndex = i;
1251
+ while (i < xmlData.length && xmlData[i] !== "|" && xmlData[i] !== ")") i++;
1252
+ let notation = xmlData.substring(startIndex, i);
1253
+ notation = notation.trim();
1254
+ if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) throw new Error(`Invalid notation name: "${notation}"`);
1255
+ allowedNotations.push(notation);
1256
+ if (xmlData[i] === "|") {
1257
+ i++;
1258
+ i = skipWhitespace(xmlData, i);
1259
+ }
1260
+ }
1261
+ if (xmlData[i] !== ")") throw new Error("Unterminated list of notations");
1262
+ i++;
1263
+ attributeType += " (" + allowedNotations.join("|") + ")";
1264
+ } else {
1265
+ const startIndex = i;
1266
+ while (i < xmlData.length && !/\s/.test(xmlData[i])) i++;
1267
+ attributeType += xmlData.substring(startIndex, i);
1268
+ if (!this.suppressValidationErr && ![
1269
+ "CDATA",
1270
+ "ID",
1271
+ "IDREF",
1272
+ "IDREFS",
1273
+ "ENTITY",
1274
+ "ENTITIES",
1275
+ "NMTOKEN",
1276
+ "NMTOKENS"
1277
+ ].includes(attributeType.toUpperCase())) throw new Error(`Invalid attribute type: "${attributeType}"`);
1278
+ }
1279
+ i = skipWhitespace(xmlData, i);
1280
+ let defaultValue = "";
1281
+ if (xmlData.substring(i, i + 8).toUpperCase() === "#REQUIRED") {
1282
+ defaultValue = "#REQUIRED";
1283
+ i += 8;
1284
+ } else if (xmlData.substring(i, i + 7).toUpperCase() === "#IMPLIED") {
1285
+ defaultValue = "#IMPLIED";
1286
+ i += 7;
1287
+ } else [i, defaultValue] = this.readIdentifierVal(xmlData, i, "ATTLIST");
1288
+ return {
1289
+ elementName,
1290
+ attributeName,
1291
+ attributeType,
1292
+ defaultValue,
1293
+ index: i
1294
+ };
1295
+ }
1296
+ };
1297
+ const skipWhitespace = (data, index) => {
1298
+ while (index < data.length && /\s/.test(data[index])) index++;
1299
+ return index;
1300
+ };
1301
+ function hasSeq(data, seq, i) {
1302
+ for (let j = 0; j < seq.length; j++) if (seq[j] !== data[i + j + 1]) return false;
1303
+ return true;
1304
+ }
1305
+ function validateEntityName(name, xmlVersion) {
1306
+ if (qName(name, { xmlVersion })) return name;
1307
+ else throw new Error(`Invalid entity name ${name}`);
1308
+ }
1309
+ //#endregion
1310
+ //#region ../../node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/digitTable.js
1311
+ /**
1312
+ * Flat lookup table: maps Unicode code point → ASCII digit (0-9).
1313
+ * Only decimal digit characters (Unicode category Nd) are included.
1314
+ *
1315
+ * Strategy: Int32Array of size (maxCodePoint - minCodePoint + 1).
1316
+ * Value 0xFF means "not a digit". Value 0-9 is the ASCII digit value.
1317
+ * This gives O(1) lookup with no branching, no bisect, no loop.
1318
+ *
1319
+ * Memory: range is 0x0660 to 0x1FBF0 → ~129,936 entries × 1 byte = ~127 KB.
1320
+ * Acceptable for a one-time init; lookup is a single array index.
1321
+ */
1322
+ const SCRIPT_ZEROS = [
1323
+ 48,
1324
+ 1632,
1325
+ 1776,
1326
+ 2406,
1327
+ 2534,
1328
+ 2662,
1329
+ 2790,
1330
+ 2918,
1331
+ 3046,
1332
+ 3174,
1333
+ 3302,
1334
+ 3430,
1335
+ 3558,
1336
+ 3664,
1337
+ 3792,
1338
+ 3872,
1339
+ 4160,
1340
+ 4240,
1341
+ 6112,
1342
+ 6160,
1343
+ 6470,
1344
+ 6608,
1345
+ 6784,
1346
+ 6800,
1347
+ 6992,
1348
+ 7088,
1349
+ 7232,
1350
+ 7248,
1351
+ 65296,
1352
+ 120782,
1353
+ 120792,
1354
+ 120802,
1355
+ 120812,
1356
+ 120822,
1357
+ 66720,
1358
+ 68912,
1359
+ 69734,
1360
+ 69872,
1361
+ 69942,
1362
+ 70096,
1363
+ 70384,
1364
+ 70736,
1365
+ 70864,
1366
+ 71248,
1367
+ 71360,
1368
+ 71472,
1369
+ 71904,
1370
+ 72016,
1371
+ 72688,
1372
+ 72784,
1373
+ 73040,
1374
+ 73120,
1375
+ 73552,
1376
+ 92768,
1377
+ 92864,
1378
+ 93008,
1379
+ 123200,
1380
+ 123632,
1381
+ 124144,
1382
+ 125264,
1383
+ 130032
1384
+ ];
1385
+ const HIGH_MAP = /* @__PURE__ */ new Map();
1386
+ const LOW_MAX = 65535;
1387
+ const TABLE_OFFSET = 1632;
1388
+ const TABLE = new Uint8Array(63904).fill(255);
1389
+ for (const zero of SCRIPT_ZEROS) for (let d = 0; d < 10; d++) {
1390
+ const cp = zero + d;
1391
+ if (cp <= LOW_MAX) TABLE[cp - TABLE_OFFSET] = d;
1392
+ else HIGH_MAP.set(cp, d);
1393
+ }
1394
+ //#endregion
1395
+ //#region ../../node_modules/.pnpm/anynum@1.0.1/node_modules/anynum/anynum.js
1396
+ const CHAR_0 = 48;
1397
+ const CHAR_9 = 57;
1398
+ const CHAR_MINUS = 45;
1399
+ const MINUS_SET = new Set([
1400
+ 8722,
1401
+ 65293,
1402
+ 65123
1403
+ ]);
1404
+ /**
1405
+ * Normalize all Unicode decimal digit characters in a string to ASCII (0-9),
1406
+ * and normalize Unicode minus variants to ASCII '-' (U+002D).
1407
+ *
1408
+ * Non-digit, non-minus characters are passed through unchanged.
1409
+ *
1410
+ * Performance design:
1411
+ * - Fast path: if the string has no convertible characters, return it unchanged
1412
+ * (zero allocation).
1413
+ * - BMP digits (0x0660..0xFFFF excl. surrogates): flat Uint8Array lookup (O(1)).
1414
+ * - Supplementary plane digits (> 0xFFFF, encoded as surrogate pairs): Map lookup.
1415
+ * - Minus variants: checked inline with a small fixed Set.
1416
+ *
1417
+ * @param {string} str
1418
+ * @returns {string}
1419
+ */
1420
+ function anynum(str) {
1421
+ if (typeof str !== "string") return str;
1422
+ const len = str.length;
1423
+ if (len === 0) return str;
1424
+ let firstHit = -1;
1425
+ for (let i = 0; i < len; i++) {
1426
+ const cc = str.charCodeAt(i);
1427
+ if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) continue;
1428
+ if (cc < 1632) {
1429
+ if (MINUS_SET.has(cc)) {
1430
+ firstHit = i;
1431
+ break;
1432
+ }
1433
+ continue;
1434
+ }
1435
+ if (cc >= 55296 && cc <= 56319) {
1436
+ if (i + 1 < len) {
1437
+ const low = str.charCodeAt(i + 1);
1438
+ if (low >= 56320 && low <= 57343) {
1439
+ const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
1440
+ if (HIGH_MAP.has(cp)) {
1441
+ firstHit = i;
1442
+ break;
1443
+ }
1444
+ }
1445
+ }
1446
+ continue;
1447
+ }
1448
+ if (TABLE[cc - 1632] !== 255 || MINUS_SET.has(cc)) {
1449
+ firstHit = i;
1450
+ break;
1451
+ }
1452
+ }
1453
+ if (firstHit === -1) return str;
1454
+ const chars = [];
1455
+ if (firstHit > 0) chars.push(str.slice(0, firstHit));
1456
+ for (let i = firstHit; i < len; i++) {
1457
+ const cc = str.charCodeAt(i);
1458
+ if (cc >= CHAR_0 && cc <= CHAR_9 || cc === CHAR_MINUS) {
1459
+ chars.push(str[i]);
1460
+ continue;
1461
+ }
1462
+ if (cc < 1632) {
1463
+ chars.push(MINUS_SET.has(cc) ? "-" : str[i]);
1464
+ continue;
1465
+ }
1466
+ if (cc >= 55296 && cc <= 56319) {
1467
+ if (i + 1 < len) {
1468
+ const low = str.charCodeAt(i + 1);
1469
+ if (low >= 56320 && low <= 57343) {
1470
+ const cp = 65536 + (cc - 55296 << 10) + (low - 56320);
1471
+ const d = HIGH_MAP.get(cp);
1472
+ if (d !== void 0) {
1473
+ chars.push(String.fromCharCode(d + 48));
1474
+ i++;
1475
+ continue;
1476
+ }
1477
+ }
1478
+ }
1479
+ chars.push(str[i]);
1480
+ continue;
1481
+ }
1482
+ if (MINUS_SET.has(cc)) {
1483
+ chars.push("-");
1484
+ continue;
1485
+ }
1486
+ const d = TABLE[cc - TABLE_OFFSET];
1487
+ chars.push(d !== 255 ? String.fromCharCode(d + 48) : str[i]);
1488
+ }
1489
+ return chars.join("");
1490
+ }
1491
+ //#endregion
1492
+ //#region ../../node_modules/.pnpm/strnum@2.4.1/node_modules/strnum/strnum.js
1493
+ const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
1494
+ const binRegex = /^0b[01]+$/;
1495
+ const octRegex = /^0o[0-7]+$/;
1496
+ const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
1497
+ const consider = {
1498
+ hex: true,
1499
+ binary: false,
1500
+ octal: false,
1501
+ leadingZeros: true,
1502
+ decimalPoint: ".",
1503
+ eNotation: true,
1504
+ infinity: "original",
1505
+ unicode: false
1506
+ };
1507
+ function toNumber(str, options = {}) {
1508
+ options = Object.assign({}, consider, options);
1509
+ if (!str || typeof str !== "string") return str;
1510
+ let trimmedStr = str.trim();
1511
+ if (trimmedStr.length === 0) return str;
1512
+ else if (options.skipLike !== void 0 && options.skipLike.test(trimmedStr)) return str;
1513
+ else if (trimmedStr === "0") return 0;
1514
+ if (options.unicode) {
1515
+ trimmedStr = anynum(trimmedStr);
1516
+ if (trimmedStr === "0") return 0;
1517
+ }
1518
+ if (options.hex && hexRegex.test(trimmedStr)) return parse_int(trimmedStr, 16);
1519
+ else if (options.binary && binRegex.test(trimmedStr)) return parse_int(trimmedStr, 2);
1520
+ else if (options.octal && octRegex.test(trimmedStr)) return parse_int(trimmedStr, 8);
1521
+ else if (!isFinite(trimmedStr)) return handleInfinity(str, Number(trimmedStr), options);
1522
+ else if (trimmedStr.includes("e") || trimmedStr.includes("E")) return resolveEnotation(str, trimmedStr, options);
1523
+ else {
1524
+ const match = numRegex.exec(trimmedStr);
1525
+ if (match) {
1526
+ const sign = match[1] || "";
1527
+ const leadingZeros = match[2];
1528
+ let numTrimmedByZeros = trimZeros(match[3]);
1529
+ const decimalAdjacentToLeadingZeros = sign ? str[leadingZeros.length + 1] === "." : str[leadingZeros.length] === ".";
1530
+ if (!options.leadingZeros && (leadingZeros.length > 1 || leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros)) return str;
1531
+ else {
1532
+ const num = Number(trimmedStr);
1533
+ const parsedStr = String(num);
1534
+ if (num === 0) return num;
1535
+ if (parsedStr.search(/[eE]/) !== -1) if (options.eNotation) return num;
1536
+ else return str;
1537
+ else if (trimmedStr.indexOf(".") !== -1) if (parsedStr === "0") return num;
1538
+ else if (parsedStr === numTrimmedByZeros) return num;
1539
+ else if (parsedStr === `${sign}${numTrimmedByZeros}`) return num;
1540
+ else return str;
1541
+ let n = leadingZeros ? numTrimmedByZeros : trimmedStr;
1542
+ if (leadingZeros) return n === parsedStr || sign + n === parsedStr ? num : str;
1543
+ else return n === parsedStr || n === sign + parsedStr ? num : str;
1544
+ }
1545
+ } else return str;
1546
+ }
1547
+ }
1548
+ const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
1549
+ function resolveEnotation(str, trimmedStr, options) {
1550
+ if (!options.eNotation) return str;
1551
+ const notation = trimmedStr.match(eNotationRegx);
1552
+ if (notation) {
1553
+ let sign = notation[1] || "";
1554
+ const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
1555
+ const leadingZeros = notation[2];
1556
+ const eAdjacentToLeadingZeros = sign ? str[leadingZeros.length + 1] === eChar : str[leadingZeros.length] === eChar;
1557
+ if (leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
1558
+ else if (leadingZeros.length === 1 && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)) return Number(trimmedStr);
1559
+ else if (leadingZeros.length > 0) if (options.leadingZeros && !eAdjacentToLeadingZeros) {
1560
+ trimmedStr = (notation[1] || "") + notation[3];
1561
+ return Number(trimmedStr);
1562
+ } else return str;
1563
+ else return Number(trimmedStr);
1564
+ } else return str;
1565
+ }
1566
+ /**
1567
+ *
1568
+ * @param {string} numStr without leading zeros
1569
+ * @returns
1570
+ */
1571
+ function trimZeros(numStr) {
1572
+ if (numStr && numStr.indexOf(".") !== -1) {
1573
+ numStr = numStr.replace(/0+$/, "");
1574
+ if (numStr === ".") numStr = "0";
1575
+ else if (numStr[0] === ".") numStr = "0" + numStr;
1576
+ else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
1577
+ return numStr;
1578
+ }
1579
+ return numStr;
1580
+ }
1581
+ function parse_int(numStr, base) {
1582
+ const str = numStr.trim();
1583
+ if (base === 2 || base === 8) numStr = str.substring(2);
1584
+ if (parseInt) return parseInt(numStr, base);
1585
+ else if (Number.parseInt) return Number.parseInt(numStr, base);
1586
+ else if (window && window.parseInt) return window.parseInt(numStr, base);
1587
+ else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported");
1588
+ }
1589
+ /**
1590
+ * Handle infinite values based on user option
1591
+ * @param {string} str - original input string
1592
+ * @param {number} num - parsed number (Infinity or -Infinity)
1593
+ * @param {object} options - user options
1594
+ * @returns {string|number|null} based on infinity option
1595
+ */
1596
+ function handleInfinity(str, num, options) {
1597
+ const isPositive = num === Infinity;
1598
+ switch (options.infinity.toLowerCase()) {
1599
+ case "null": return null;
1600
+ case "infinity": return num;
1601
+ case "string": return isPositive ? "Infinity" : "-Infinity";
1602
+ default: return str;
1603
+ }
1604
+ }
1605
+ //#endregion
1606
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/ignoreAttributes.js
1607
+ function getIgnoreAttributesFn(ignoreAttributes) {
1608
+ if (typeof ignoreAttributes === "function") return ignoreAttributes;
1609
+ if (Array.isArray(ignoreAttributes)) return (attrName) => {
1610
+ for (const pattern of ignoreAttributes) {
1611
+ if (typeof pattern === "string" && attrName === pattern) return true;
1612
+ if (pattern instanceof RegExp && pattern.test(attrName)) return true;
1613
+ }
1614
+ };
1615
+ return () => false;
1616
+ }
1617
+ //#endregion
1618
+ //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/Expression.js
1619
+ /**
1620
+ * Expression - Parses and stores a tag pattern expression
1621
+ *
1622
+ * Patterns are parsed once and stored in an optimized structure for fast matching.
1623
+ *
1624
+ * @example
1625
+ * const expr = new Expression("root.users.user");
1626
+ * const expr2 = new Expression("..user[id]:first");
1627
+ * const expr3 = new Expression("root/users/user", { separator: '/' });
1628
+ */
1629
+ var Expression = class {
1630
+ /**
1631
+ * Create a new Expression
1632
+ * @param {string} pattern - Pattern string (e.g., "root.users.user", "..user[id]")
1633
+ * @param {Object} options - Configuration options
1634
+ * @param {string} options.separator - Path separator (default: '.')
1635
+ */
1636
+ constructor(pattern, options = {}, data) {
1637
+ this.pattern = pattern;
1638
+ this.separator = options.separator || ".";
1639
+ this.segments = this._parse(pattern);
1640
+ this.data = data;
1641
+ this._hasDeepWildcard = this.segments.some((seg) => seg.type === "deep-wildcard");
1642
+ this._hasAttributeCondition = this.segments.some((seg) => seg.attrName !== void 0);
1643
+ this._hasPositionSelector = this.segments.some((seg) => seg.position !== void 0);
1644
+ }
1645
+ /**
1646
+ * Parse pattern string into segments
1647
+ * @private
1648
+ * @param {string} pattern - Pattern to parse
1649
+ * @returns {Array} Array of segment objects
1650
+ */
1651
+ _parse(pattern) {
1652
+ const segments = [];
1653
+ let i = 0;
1654
+ let currentPart = "";
1655
+ while (i < pattern.length) if (pattern[i] === this.separator) if (i + 1 < pattern.length && pattern[i + 1] === this.separator) {
1656
+ if (currentPart.trim()) {
1657
+ segments.push(this._parseSegment(currentPart.trim()));
1658
+ currentPart = "";
1659
+ }
1660
+ segments.push({ type: "deep-wildcard" });
1661
+ i += 2;
1662
+ } else {
1663
+ if (currentPart.trim()) segments.push(this._parseSegment(currentPart.trim()));
1664
+ currentPart = "";
1665
+ i++;
1666
+ }
1667
+ else {
1668
+ currentPart += pattern[i];
1669
+ i++;
1670
+ }
1671
+ if (currentPart.trim()) segments.push(this._parseSegment(currentPart.trim()));
1672
+ return segments;
1673
+ }
1674
+ /**
1675
+ * Parse a single segment
1676
+ * @private
1677
+ * @param {string} part - Segment string (e.g., "user", "ns::user", "user[id]", "ns::user:first")
1678
+ * @returns {Object} Segment object
1679
+ */
1680
+ _parseSegment(part) {
1681
+ const segment = { type: "tag" };
1682
+ let bracketContent = null;
1683
+ let withoutBrackets = part;
1684
+ const bracketMatch = part.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);
1685
+ if (bracketMatch) {
1686
+ withoutBrackets = bracketMatch[1] + bracketMatch[3];
1687
+ if (bracketMatch[2]) {
1688
+ const content = bracketMatch[2].slice(1, -1);
1689
+ if (content) bracketContent = content;
1690
+ }
1691
+ }
1692
+ let namespace = void 0;
1693
+ let tagAndPosition = withoutBrackets;
1694
+ if (withoutBrackets.includes("::")) {
1695
+ const nsIndex = withoutBrackets.indexOf("::");
1696
+ namespace = withoutBrackets.substring(0, nsIndex).trim();
1697
+ tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim();
1698
+ if (!namespace) throw new Error(`Invalid namespace in pattern: ${part}`);
1699
+ }
1700
+ let tag = void 0;
1701
+ let positionMatch = null;
1702
+ if (tagAndPosition.includes(":")) {
1703
+ const colonIndex = tagAndPosition.lastIndexOf(":");
1704
+ const tagPart = tagAndPosition.substring(0, colonIndex).trim();
1705
+ const posPart = tagAndPosition.substring(colonIndex + 1).trim();
1706
+ if ([
1707
+ "first",
1708
+ "last",
1709
+ "odd",
1710
+ "even"
1711
+ ].includes(posPart) || /^nth\(\d+\)$/.test(posPart)) {
1712
+ tag = tagPart;
1713
+ positionMatch = posPart;
1714
+ } else tag = tagAndPosition;
1715
+ } else tag = tagAndPosition;
1716
+ if (!tag) throw new Error(`Invalid segment pattern: ${part}`);
1717
+ segment.tag = tag;
1718
+ if (namespace) segment.namespace = namespace;
1719
+ if (bracketContent) if (bracketContent.includes("=")) {
1720
+ const eqIndex = bracketContent.indexOf("=");
1721
+ segment.attrName = bracketContent.substring(0, eqIndex).trim();
1722
+ segment.attrValue = bracketContent.substring(eqIndex + 1).trim();
1723
+ } else segment.attrName = bracketContent.trim();
1724
+ if (positionMatch) {
1725
+ const nthMatch = positionMatch.match(/^nth\((\d+)\)$/);
1726
+ if (nthMatch) {
1727
+ segment.position = "nth";
1728
+ segment.positionValue = parseInt(nthMatch[1], 10);
1729
+ } else segment.position = positionMatch;
1730
+ }
1731
+ return segment;
1732
+ }
1733
+ /**
1734
+ * Get the number of segments
1735
+ * @returns {number}
1736
+ */
1737
+ get length() {
1738
+ return this.segments.length;
1739
+ }
1740
+ /**
1741
+ * Check if expression contains deep wildcard
1742
+ * @returns {boolean}
1743
+ */
1744
+ hasDeepWildcard() {
1745
+ return this._hasDeepWildcard;
1746
+ }
1747
+ /**
1748
+ * Check if expression has attribute conditions
1749
+ * @returns {boolean}
1750
+ */
1751
+ hasAttributeCondition() {
1752
+ return this._hasAttributeCondition;
1753
+ }
1754
+ /**
1755
+ * Check if expression has position selectors
1756
+ * @returns {boolean}
1757
+ */
1758
+ hasPositionSelector() {
1759
+ return this._hasPositionSelector;
1760
+ }
1761
+ /**
1762
+ * Get string representation
1763
+ * @returns {string}
1764
+ */
1765
+ toString() {
1766
+ return this.pattern;
1767
+ }
1768
+ };
1769
+ //#endregion
1770
+ //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/ExpressionSet.js
1771
+ /**
1772
+ * ExpressionSet - An indexed collection of Expressions for efficient bulk matching
1773
+ *
1774
+ * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes
1775
+ * them at insertion time by depth and terminal tag name. At match time, only
1776
+ * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1)
1777
+ * lookup plus O(small bucket) matches.
1778
+ *
1779
+ * Three buckets are maintained:
1780
+ * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first)
1781
+ * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only)
1782
+ * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed)
1783
+ *
1784
+ * @example
1785
+ * import { Expression, ExpressionSet } from 'fast-xml-tagger';
1786
+ *
1787
+ * // Build once at config time
1788
+ * const stopNodes = new ExpressionSet();
1789
+ * stopNodes.add(new Expression('root.users.user'));
1790
+ * stopNodes.add(new Expression('root.config.setting'));
1791
+ * stopNodes.add(new Expression('..script'));
1792
+ *
1793
+ * // Query on every tag — hot path
1794
+ * if (stopNodes.matchesAny(matcher)) { ... }
1795
+ */
1796
+ var ExpressionSet = class {
1797
+ constructor() {
1798
+ /** @type {Map<string, import('./Expression.js').default[]>} depth:tag → expressions */
1799
+ this._byDepthAndTag = /* @__PURE__ */ new Map();
1800
+ /** @type {Map<number, import('./Expression.js').default[]>} depth → wildcard-tag expressions */
1801
+ this._wildcardByDepth = /* @__PURE__ */ new Map();
1802
+ /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */
1803
+ this._deepWildcards = [];
1804
+ /** @type {Map<string, import('./Expression.js').default[]>} terminalTag → deep wildcard expressions */
1805
+ this._deepByTerminalTag = /* @__PURE__ */ new Map();
1806
+ /** @type {Set<string>} pattern strings already added — used for deduplication */
1807
+ this._patterns = /* @__PURE__ */ new Set();
1808
+ /** @type {boolean} whether the set is sealed against further additions */
1809
+ this._sealed = false;
1810
+ }
1811
+ /**
1812
+ * Add an Expression to the set.
1813
+ * Duplicate patterns (same pattern string) are silently ignored.
1814
+ *
1815
+ * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance
1816
+ * @returns {this} for chaining
1817
+ * @throws {TypeError} if called after seal()
1818
+ *
1819
+ * @example
1820
+ * set.add(new Expression('root.users.user'));
1821
+ * set.add(new Expression('..script'));
1822
+ */
1823
+ add(expression) {
1824
+ if (this._sealed) throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");
1825
+ if (this._patterns.has(expression.pattern)) return this;
1826
+ this._patterns.add(expression.pattern);
1827
+ if (expression.hasDeepWildcard()) {
1828
+ const lastSeg = expression.segments[expression.segments.length - 1];
1829
+ if (lastSeg && lastSeg.type !== "deep-wildcard" && lastSeg.tag !== "*") {
1830
+ const tag = lastSeg.tag;
1831
+ if (!this._deepByTerminalTag.has(tag)) this._deepByTerminalTag.set(tag, []);
1832
+ this._deepByTerminalTag.get(tag).push(expression);
1833
+ } else this._deepWildcards.push(expression);
1834
+ return this;
1835
+ }
1836
+ const depth = expression.length;
1837
+ const tag = expression.segments[expression.segments.length - 1]?.tag;
1838
+ if (!tag || tag === "*") {
1839
+ if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []);
1840
+ this._wildcardByDepth.get(depth).push(expression);
1841
+ } else {
1842
+ const key = `${depth}:${tag}`;
1843
+ if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []);
1844
+ this._byDepthAndTag.get(key).push(expression);
1845
+ }
1846
+ return this;
1847
+ }
1848
+ /**
1849
+ * Add multiple expressions at once.
1850
+ *
1851
+ * @param {import('./Expression.js').default[]} expressions - Array of Expression instances
1852
+ * @returns {this} for chaining
1853
+ *
1854
+ * @example
1855
+ * set.addAll([
1856
+ * new Expression('root.users.user'),
1857
+ * new Expression('root.config.setting'),
1858
+ * ]);
1859
+ */
1860
+ addAll(expressions) {
1861
+ for (const expr of expressions) this.add(expr);
1862
+ return this;
1863
+ }
1864
+ /**
1865
+ * Check whether a pattern string is already present in the set.
1866
+ *
1867
+ * @param {import('./Expression.js').default} expression
1868
+ * @returns {boolean}
1869
+ */
1870
+ has(expression) {
1871
+ return this._patterns.has(expression.pattern);
1872
+ }
1873
+ /**
1874
+ * Number of expressions in the set.
1875
+ * @type {number}
1876
+ */
1877
+ get size() {
1878
+ return this._patterns.size;
1879
+ }
1880
+ /**
1881
+ * Seal the set against further modifications.
1882
+ * Useful to prevent accidental mutations after config is built.
1883
+ * Calling add() or addAll() on a sealed set throws a TypeError.
1884
+ *
1885
+ * @returns {this}
1886
+ */
1887
+ seal() {
1888
+ this._sealed = true;
1889
+ return this;
1890
+ }
1891
+ /**
1892
+ * Whether the set has been sealed.
1893
+ * @type {boolean}
1894
+ */
1895
+ get isSealed() {
1896
+ return this._sealed;
1897
+ }
1898
+ /**
1899
+ * Test whether the matcher's current path matches any expression in the set.
1900
+ *
1901
+ * Evaluation order (cheapest → most expensive):
1902
+ * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions
1903
+ * 2. Depth-only wildcard bucket — O(1) lookup, rare
1904
+ * 3. Deep-wildcard list — always checked, but usually small
1905
+ *
1906
+ * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
1907
+ * @returns {boolean} true if any expression matches the current path
1908
+ *
1909
+ * @example
1910
+ * if (stopNodes.matchesAny(matcher)) {
1911
+ * // handle stop node
1912
+ * }
1913
+ */
1914
+ matchesAny(matcher) {
1915
+ return this.findMatch(matcher) !== null;
1916
+ }
1917
+ /**
1918
+ * Find and return the first Expression that matches the matcher's current path.
1919
+ *
1920
+ * Uses the same evaluation order as matchesAny (cheapest → most expensive):
1921
+ * 1. Exact depth + tag bucket
1922
+ * 2. Depth-only wildcard bucket
1923
+ * 3. Deep-wildcard list
1924
+ *
1925
+ * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view)
1926
+ * @returns {import('./Expression.js').default | null} the first matching Expression, or null
1927
+ *
1928
+ * @example
1929
+ * const expr = stopNodes.findMatch(matcher);
1930
+ * if (expr) {
1931
+ * // access expr.config, expr.pattern, etc.
1932
+ * }
1933
+ */
1934
+ findMatch(matcher) {
1935
+ const depth = matcher.getDepth();
1936
+ const tag = matcher.getCurrentTag();
1937
+ const exactKey = `${depth}:${tag}`;
1938
+ const exactBucket = this._byDepthAndTag.get(exactKey);
1939
+ if (exactBucket) {
1940
+ for (let i = 0; i < exactBucket.length; i++) if (matcher.matches(exactBucket[i])) return exactBucket[i];
1941
+ }
1942
+ const wildcardBucket = this._wildcardByDepth.get(depth);
1943
+ if (wildcardBucket) {
1944
+ for (let i = 0; i < wildcardBucket.length; i++) if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i];
1945
+ }
1946
+ const deepBucket = this._deepByTerminalTag.get(tag);
1947
+ if (deepBucket) {
1948
+ for (let i = 0; i < deepBucket.length; i++) if (matcher.matches(deepBucket[i])) return deepBucket[i];
1949
+ }
1950
+ for (let i = 0; i < this._deepWildcards.length; i++) if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i];
1951
+ return null;
1952
+ }
1953
+ };
1954
+ //#endregion
1955
+ //#region ../../node_modules/.pnpm/path-expression-matcher@1.6.2/node_modules/path-expression-matcher/src/Matcher.js
1956
+ /**
1957
+ * MatcherView - A lightweight read-only view over a Matcher's internal state.
1958
+ *
1959
+ * Created once by Matcher and reused across all callbacks. Holds a direct
1960
+ * reference to the parent Matcher so it always reflects current parser state
1961
+ * with zero copying or freezing overhead.
1962
+ *
1963
+ * Users receive this via {@link Matcher#readOnly} or directly from parser
1964
+ * callbacks. It exposes all query and matching methods but has no mutation
1965
+ * methods — misuse is caught at the TypeScript level rather than at runtime.
1966
+ *
1967
+ * @example
1968
+ * const matcher = new Matcher();
1969
+ * const view = matcher.readOnly();
1970
+ *
1971
+ * matcher.push("root", {});
1972
+ * view.getCurrentTag(); // "root"
1973
+ * view.getDepth(); // 1
1974
+ */
1975
+ var MatcherView = class {
1976
+ /**
1977
+ * @param {Matcher} matcher - The parent Matcher instance to read from.
1978
+ */
1979
+ constructor(matcher) {
1980
+ this._matcher = matcher;
1981
+ }
1982
+ /**
1983
+ * Get the path separator used by the parent matcher.
1984
+ * @returns {string}
1985
+ */
1986
+ get separator() {
1987
+ return this._matcher.separator;
1988
+ }
1989
+ /**
1990
+ * Get current tag name.
1991
+ * @returns {string|undefined}
1992
+ */
1993
+ getCurrentTag() {
1994
+ const path = this._matcher.path;
1995
+ return path.length > 0 ? path[path.length - 1].tag : void 0;
1996
+ }
1997
+ /**
1998
+ * Get current namespace.
1999
+ * @returns {string|undefined}
2000
+ */
2001
+ getCurrentNamespace() {
2002
+ const path = this._matcher.path;
2003
+ return path.length > 0 ? path[path.length - 1].namespace : void 0;
2004
+ }
2005
+ /**
2006
+ * Get current node's attribute value.
2007
+ * @param {string} attrName
2008
+ * @returns {*}
2009
+ */
2010
+ getAttrValue(attrName) {
2011
+ const path = this._matcher.path;
2012
+ if (path.length === 0) return void 0;
2013
+ return path[path.length - 1].values?.[attrName];
2014
+ }
2015
+ /**
2016
+ * Check if current node has an attribute.
2017
+ * @param {string} attrName
2018
+ * @returns {boolean}
2019
+ */
2020
+ hasAttr(attrName) {
2021
+ const path = this._matcher.path;
2022
+ if (path.length === 0) return false;
2023
+ const current = path[path.length - 1];
2024
+ return current.values !== void 0 && attrName in current.values;
2025
+ }
2026
+ /**
2027
+ * Get the value of a "kept" attribute from the nearest ancestor (or
2028
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
2029
+ * @param {string} attrName
2030
+ * @returns {*}
2031
+ */
2032
+ getAnyParentAttr(attrName) {
2033
+ return this._matcher.getAnyParentAttr(attrName);
2034
+ }
2035
+ /**
2036
+ * Check whether any ancestor (or the current node) kept the given
2037
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
2038
+ * @param {string} attrName
2039
+ * @returns {boolean}
2040
+ */
2041
+ hasAnyParentAttr(attrName) {
2042
+ return this._matcher.hasAnyParentAttr(attrName);
2043
+ }
2044
+ /**
2045
+ * Get current node's sibling position (child index in parent).
2046
+ * @returns {number}
2047
+ */
2048
+ getPosition() {
2049
+ const path = this._matcher.path;
2050
+ if (path.length === 0) return -1;
2051
+ return path[path.length - 1].position ?? 0;
2052
+ }
2053
+ /**
2054
+ * Get current node's repeat counter (occurrence count of this tag name).
2055
+ * @returns {number}
2056
+ */
2057
+ getCounter() {
2058
+ const path = this._matcher.path;
2059
+ if (path.length === 0) return -1;
2060
+ return path[path.length - 1].counter ?? 0;
2061
+ }
2062
+ /**
2063
+ * Get current node's sibling index (alias for getPosition).
2064
+ * @returns {number}
2065
+ * @deprecated Use getPosition() or getCounter() instead
2066
+ */
2067
+ getIndex() {
2068
+ return this.getPosition();
2069
+ }
2070
+ /**
2071
+ * Get current path depth.
2072
+ * @returns {number}
2073
+ */
2074
+ getDepth() {
2075
+ return this._matcher.path.length;
2076
+ }
2077
+ /**
2078
+ * Get path as string.
2079
+ * @param {string} [separator] - Optional separator (uses default if not provided)
2080
+ * @param {boolean} [includeNamespace=true]
2081
+ * @returns {string}
2082
+ */
2083
+ toString(separator, includeNamespace = true) {
2084
+ return this._matcher.toString(separator, includeNamespace);
2085
+ }
2086
+ /**
2087
+ * Get path as array of tag names.
2088
+ * @returns {string[]}
2089
+ */
2090
+ toArray() {
2091
+ return this._matcher.path.map((n) => n.tag);
2092
+ }
2093
+ /**
2094
+ * Match current path against an Expression.
2095
+ * @param {Expression} expression
2096
+ * @returns {boolean}
2097
+ */
2098
+ matches(expression) {
2099
+ return this._matcher.matches(expression);
2100
+ }
2101
+ /**
2102
+ * Match any expression in the given set against the current path.
2103
+ * @param {ExpressionSet} exprSet
2104
+ * @returns {boolean}
2105
+ */
2106
+ matchesAny(exprSet) {
2107
+ return exprSet.matchesAny(this._matcher);
2108
+ }
2109
+ };
2110
+ /**
2111
+ * Matcher - Tracks current path in XML/JSON tree and matches against Expressions.
2112
+ *
2113
+ * The matcher maintains a stack of nodes representing the current path from root to
2114
+ * current tag. It only stores attribute values for the current (top) node to minimize
2115
+ * memory usage. Sibling tracking is used to auto-calculate position and counter.
2116
+ *
2117
+ * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to
2118
+ * user callbacks — it always reflects current state with no Proxy overhead.
2119
+ *
2120
+ * @example
2121
+ * const matcher = new Matcher();
2122
+ * matcher.push("root", {});
2123
+ * matcher.push("users", {});
2124
+ * matcher.push("user", { id: "123", type: "admin" });
2125
+ *
2126
+ * const expr = new Expression("root.users.user");
2127
+ * matcher.matches(expr); // true
2128
+ */
2129
+ var Matcher = class {
2130
+ /**
2131
+ * Create a new Matcher.
2132
+ * @param {Object} [options={}]
2133
+ * @param {string} [options.separator='.'] - Default path separator
2134
+ */
2135
+ constructor(options = {}) {
2136
+ this.separator = options.separator || ".";
2137
+ this.path = [];
2138
+ this.siblingStacks = [];
2139
+ this._pathStringCache = null;
2140
+ this._view = new MatcherView(this);
2141
+ this._keptAttrs = [];
2142
+ }
2143
+ /**
2144
+ * Push a new tag onto the path.
2145
+ * @param {string} tagName
2146
+ * @param {Object|null} [attrValues=null]
2147
+ * @param {string|null} [namespace=null]
2148
+ * @param {Object|null} [options=null]
2149
+ * @param {string[]} [options.keep] - Names of attributes (from attrValues)
2150
+ */
2151
+ push(tagName, attrValues = null, namespace = null, options = null) {
2152
+ this._pathStringCache = null;
2153
+ if (this.path.length > 0) this.path[this.path.length - 1].values = void 0;
2154
+ const currentLevel = this.path.length;
2155
+ let level = this.siblingStacks[currentLevel];
2156
+ if (!level) {
2157
+ level = {
2158
+ counts: /* @__PURE__ */ new Map(),
2159
+ total: 0
2160
+ };
2161
+ this.siblingStacks[currentLevel] = level;
2162
+ }
2163
+ const siblingKey = namespace ? `${namespace}:${tagName}` : tagName;
2164
+ const counter = level.counts.get(siblingKey) || 0;
2165
+ const position = level.total;
2166
+ level.counts.set(siblingKey, counter + 1);
2167
+ level.total++;
2168
+ const node = {
2169
+ tag: tagName,
2170
+ position,
2171
+ counter
2172
+ };
2173
+ if (namespace !== null && namespace !== void 0) node.namespace = namespace;
2174
+ if (attrValues !== null && attrValues !== void 0) node.values = attrValues;
2175
+ this.path.push(node);
2176
+ const depth = this.path.length;
2177
+ const keep = options !== null ? options.keep : null;
2178
+ if (keep !== null && keep !== void 0 && keep.length > 0 && attrValues) for (let i = 0; i < keep.length; i++) {
2179
+ const name = keep[i];
2180
+ if (attrValues[name] !== void 0) this._keptAttrs.push({
2181
+ depth,
2182
+ name,
2183
+ value: attrValues[name]
2184
+ });
2185
+ }
2186
+ }
2187
+ /**
2188
+ * Pop the last tag from the path.
2189
+ * @returns {Object|undefined} The popped node
2190
+ */
2191
+ pop() {
2192
+ if (this.path.length === 0) return void 0;
2193
+ this._pathStringCache = null;
2194
+ const node = this.path.pop();
2195
+ if (this.siblingStacks.length > this.path.length + 1) this.siblingStacks.length = this.path.length + 1;
2196
+ const poppedDepth = this.path.length + 1;
2197
+ while (this._keptAttrs.length > 0 && this._keptAttrs[this._keptAttrs.length - 1].depth >= poppedDepth) this._keptAttrs.pop();
2198
+ return node;
2199
+ }
2200
+ /**
2201
+ * Update current node's attribute values.
2202
+ * Useful when attributes are parsed after push.
2203
+ * @param {Object} attrValues
2204
+ */
2205
+ updateCurrent(attrValues) {
2206
+ if (this.path.length > 0) {
2207
+ const current = this.path[this.path.length - 1];
2208
+ if (attrValues !== null && attrValues !== void 0) current.values = attrValues;
2209
+ }
2210
+ }
2211
+ /**
2212
+ * Get current tag name.
2213
+ * @returns {string|undefined}
2214
+ */
2215
+ getCurrentTag() {
2216
+ return this.path.length > 0 ? this.path[this.path.length - 1].tag : void 0;
2217
+ }
2218
+ /**
2219
+ * Get current namespace.
2220
+ * @returns {string|undefined}
2221
+ */
2222
+ getCurrentNamespace() {
2223
+ return this.path.length > 0 ? this.path[this.path.length - 1].namespace : void 0;
2224
+ }
2225
+ /**
2226
+ * Get current node's attribute value.
2227
+ * @param {string} attrName
2228
+ * @returns {*}
2229
+ */
2230
+ getAttrValue(attrName) {
2231
+ if (this.path.length === 0) return void 0;
2232
+ return this.path[this.path.length - 1].values?.[attrName];
2233
+ }
2234
+ /**
2235
+ * Check if current node has an attribute.
2236
+ * @param {string} attrName
2237
+ * @returns {boolean}
2238
+ */
2239
+ hasAttr(attrName) {
2240
+ if (this.path.length === 0) return false;
2241
+ const current = this.path[this.path.length - 1];
2242
+ return current.values !== void 0 && attrName in current.values;
2243
+ }
2244
+ /**
2245
+ * Get the value of a "kept" attribute from the nearest ancestor (or
2246
+ * current node) that declared it via `push(tag, attrs, ns, { keep: [...] })`.
2247
+ * Unlike getAttrValue(), this works regardless of how deep the path has
2248
+ * gone since the attribute was pushed — but only for attribute names that
2249
+ * were explicitly marked with `keep` at push time. Cost is proportional to
2250
+ * the number of currently-kept attributes (typically 0-3), not path depth.
2251
+ * @param {string} attrName
2252
+ * @returns {*} the value, or undefined if no ancestor kept this attribute
2253
+ */
2254
+ getAnyParentAttr(attrName) {
2255
+ const kept = this._keptAttrs;
2256
+ for (let i = kept.length - 1; i >= 0; i--) if (kept[i].name === attrName) return kept[i].value;
2257
+ }
2258
+ /**
2259
+ * Check whether any ancestor (or the current node) kept the given
2260
+ * attribute via `push(tag, attrs, ns, { keep: [...] })`.
2261
+ * @param {string} attrName
2262
+ * @returns {boolean}
2263
+ */
2264
+ hasAnyParentAttr(attrName) {
2265
+ const kept = this._keptAttrs;
2266
+ for (let i = kept.length - 1; i >= 0; i--) if (kept[i].name === attrName) return true;
2267
+ return false;
2268
+ }
2269
+ /**
2270
+ * Get current node's sibling position (child index in parent).
2271
+ * @returns {number}
2272
+ */
2273
+ getPosition() {
2274
+ if (this.path.length === 0) return -1;
2275
+ return this.path[this.path.length - 1].position ?? 0;
2276
+ }
2277
+ /**
2278
+ * Get current node's repeat counter (occurrence count of this tag name).
2279
+ * @returns {number}
2280
+ */
2281
+ getCounter() {
2282
+ if (this.path.length === 0) return -1;
2283
+ return this.path[this.path.length - 1].counter ?? 0;
2284
+ }
2285
+ /**
2286
+ * Get current node's sibling index (alias for getPosition).
2287
+ * @returns {number}
2288
+ * @deprecated Use getPosition() or getCounter() instead
2289
+ */
2290
+ getIndex() {
2291
+ return this.getPosition();
2292
+ }
2293
+ /**
2294
+ * Get current path depth.
2295
+ * @returns {number}
2296
+ */
2297
+ getDepth() {
2298
+ return this.path.length;
2299
+ }
2300
+ /**
2301
+ * Get path as string.
2302
+ * @param {string} [separator] - Optional separator (uses default if not provided)
2303
+ * @param {boolean} [includeNamespace=true]
2304
+ * @returns {string}
2305
+ */
2306
+ toString(separator, includeNamespace = true) {
2307
+ const sep = separator || this.separator;
2308
+ if (sep === this.separator && includeNamespace === true) {
2309
+ if (this._pathStringCache !== null) return this._pathStringCache;
2310
+ const result = this.path.map((n) => n.namespace ? `${n.namespace}:${n.tag}` : n.tag).join(sep);
2311
+ this._pathStringCache = result;
2312
+ return result;
2313
+ }
2314
+ return this.path.map((n) => includeNamespace && n.namespace ? `${n.namespace}:${n.tag}` : n.tag).join(sep);
2315
+ }
2316
+ /**
2317
+ * Get path as array of tag names.
2318
+ * @returns {string[]}
2319
+ */
2320
+ toArray() {
2321
+ return this.path.map((n) => n.tag);
2322
+ }
2323
+ /**
2324
+ * Reset the path to empty.
2325
+ */
2326
+ reset() {
2327
+ this._pathStringCache = null;
2328
+ this.path = [];
2329
+ this.siblingStacks = [];
2330
+ this._keptAttrs = [];
2331
+ }
2332
+ /**
2333
+ * Match current path against an Expression.
2334
+ * @param {Expression} expression
2335
+ * @returns {boolean}
2336
+ */
2337
+ matches(expression) {
2338
+ const segments = expression.segments;
2339
+ if (segments.length === 0) return false;
2340
+ if (expression.hasDeepWildcard()) return this._matchWithDeepWildcard(segments);
2341
+ return this._matchSimple(segments);
2342
+ }
2343
+ /**
2344
+ * @private
2345
+ */
2346
+ _matchSimple(segments) {
2347
+ if (this.path.length !== segments.length) return false;
2348
+ for (let i = 0; i < segments.length; i++) if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) return false;
2349
+ return true;
2350
+ }
2351
+ /**
2352
+ * @private
2353
+ */
2354
+ _matchWithDeepWildcard(segments) {
2355
+ let pathIdx = this.path.length - 1;
2356
+ let segIdx = segments.length - 1;
2357
+ while (segIdx >= 0 && pathIdx >= 0) {
2358
+ const segment = segments[segIdx];
2359
+ if (segment.type === "deep-wildcard") {
2360
+ segIdx--;
2361
+ if (segIdx < 0) return true;
2362
+ const nextSeg = segments[segIdx];
2363
+ let found = false;
2364
+ for (let i = pathIdx; i >= 0; i--) if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) {
2365
+ pathIdx = i - 1;
2366
+ segIdx--;
2367
+ found = true;
2368
+ break;
2369
+ }
2370
+ if (!found) return false;
2371
+ } else {
2372
+ if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) return false;
2373
+ pathIdx--;
2374
+ segIdx--;
2375
+ }
2376
+ }
2377
+ return segIdx < 0;
2378
+ }
2379
+ /**
2380
+ * @private
2381
+ */
2382
+ _matchSegment(segment, node, isCurrentNode) {
2383
+ if (segment.tag !== "*" && segment.tag !== node.tag) return false;
2384
+ if (segment.namespace !== void 0) {
2385
+ if (segment.namespace !== "*" && segment.namespace !== node.namespace) return false;
2386
+ }
2387
+ if (segment.attrName !== void 0) {
2388
+ if (!isCurrentNode) return false;
2389
+ if (!node.values || !(segment.attrName in node.values)) return false;
2390
+ if (segment.attrValue !== void 0) {
2391
+ if (String(node.values[segment.attrName]) !== String(segment.attrValue)) return false;
2392
+ }
2393
+ }
2394
+ if (segment.position !== void 0) {
2395
+ if (!isCurrentNode) return false;
2396
+ const counter = node.counter ?? 0;
2397
+ if (segment.position === "first" && counter !== 0) return false;
2398
+ else if (segment.position === "odd" && counter % 2 !== 1) return false;
2399
+ else if (segment.position === "even" && counter % 2 !== 0) return false;
2400
+ else if (segment.position === "nth" && counter !== segment.positionValue) return false;
2401
+ }
2402
+ return true;
2403
+ }
2404
+ /**
2405
+ * Match any expression in the given set against the current path.
2406
+ * @param {ExpressionSet} exprSet
2407
+ * @returns {boolean}
2408
+ */
2409
+ matchesAny(exprSet) {
2410
+ return exprSet.matchesAny(this);
2411
+ }
2412
+ /**
2413
+ * Create a snapshot of current state.
2414
+ * @returns {Object}
2415
+ */
2416
+ snapshot() {
2417
+ return {
2418
+ path: this.path.map((node) => ({ ...node })),
2419
+ siblingStacks: this.siblingStacks.map((level) => level ? {
2420
+ counts: new Map(level.counts),
2421
+ total: level.total
2422
+ } : level),
2423
+ keptAttrs: this._keptAttrs.map((entry) => ({ ...entry }))
2424
+ };
2425
+ }
2426
+ /**
2427
+ * Restore state from snapshot.
2428
+ * @param {Object} snapshot
2429
+ */
2430
+ restore(snapshot) {
2431
+ this._pathStringCache = null;
2432
+ this.path = snapshot.path.map((node) => ({ ...node }));
2433
+ this.siblingStacks = snapshot.siblingStacks.map((level) => level ? {
2434
+ counts: new Map(level.counts),
2435
+ total: level.total
2436
+ } : level);
2437
+ this._keptAttrs = (snapshot.keptAttrs || []).map((entry) => ({ ...entry }));
2438
+ }
2439
+ /**
2440
+ * Return the read-only {@link MatcherView} for this matcher.
2441
+ *
2442
+ * The same instance is returned on every call — no allocation occurs.
2443
+ * It always reflects the current parser state and is safe to pass to
2444
+ * user callbacks without risk of accidental mutation.
2445
+ *
2446
+ * @returns {MatcherView}
2447
+ *
2448
+ * @example
2449
+ * const view = matcher.readOnly();
2450
+ * // pass view to callbacks — it stays in sync automatically
2451
+ * view.matches(expr); // ✓
2452
+ * view.getCurrentTag(); // ✓
2453
+ * // view.push(...) // ✗ method does not exist — caught by TypeScript
2454
+ */
2455
+ readOnly() {
2456
+ return this._view;
2457
+ }
2458
+ };
2459
+ //#endregion
2460
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/html.js
2461
+ /**
2462
+ * HTML context patterns.
2463
+ *
2464
+ * Detects XSS vectors that are dangerous when a string ends up rendered as HTML.
2465
+ * All patterns use bounded quantifiers to ensure linear-time matching (ReDoS-safe).
2466
+ *
2467
+ * Each entry is { pattern: RegExp, id: string, description: string }
2468
+ * so callers can inspect which rule fired if they need to.
2469
+ */
2470
+ const HTML_PATTERNS = [
2471
+ {
2472
+ id: "html-script-open",
2473
+ description: "<script opening tag",
2474
+ pattern: /<script[\s>/]/i
2475
+ },
2476
+ {
2477
+ id: "html-script-close",
2478
+ description: "<\/script closing tag",
2479
+ pattern: /<\/script[\s>]/i
2480
+ },
2481
+ {
2482
+ id: "html-javascript-protocol",
2483
+ description: "javascript: URI scheme (with optional whitespace/encoding)",
2484
+ 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
2485
+ },
2486
+ {
2487
+ id: "html-vbscript-protocol",
2488
+ description: "vbscript: URI scheme",
2489
+ pattern: /vbscript[\t\n\r ]*:/i
2490
+ },
2491
+ {
2492
+ id: "html-data-html",
2493
+ description: "data:text/html URI — can execute scripts in browsers",
2494
+ pattern: /data[\t\n\r ]*:[\t\n\r ]*text\/html/i
2495
+ },
2496
+ {
2497
+ id: "html-data-xhtml",
2498
+ description: "data:application/xhtml+xml URI",
2499
+ pattern: /data[\t\n\r ]*:[\t\n\r ]*application\/xhtml/i
2500
+ },
2501
+ {
2502
+ id: "html-data-svg",
2503
+ description: "data:image/svg+xml URI — can execute scripts",
2504
+ pattern: /data[\t\n\r ]*:[\t\n\r ]*image\/svg\+xml/i
2505
+ },
2506
+ {
2507
+ id: "html-inline-event-handler",
2508
+ description: "Inline event handler attributes: onclick=, onerror=, onload=, etc.",
2509
+ pattern: /\bon\w{1,30}\s*=/i
2510
+ },
2511
+ {
2512
+ id: "html-entity-obfuscated-script",
2513
+ description: "HTML-entity-encoded <script (e.g. &#x3C;script or &lt;script)",
2514
+ pattern: /(?:&#x0*3[Cc];?|&#0*60;?|&lt;)\s*script/i
2515
+ },
2516
+ {
2517
+ id: "html-entity-obfuscated-javascript",
2518
+ description: "HTML-entity-encoded javascript: (partial — catches common &#106; or &#x6a; for \"j\")",
2519
+ pattern: /(?:&#x0*6[Aa];?|&#0*106;?)\s*(?:&#x0*61;?|a)[\s\S]{0,80}script\s*:/i
2520
+ },
2521
+ {
2522
+ id: "html-style-expression",
2523
+ description: "CSS expression() — IE-era code execution in style attributes",
2524
+ pattern: /style[\s\S]{0,20}expression\s*\(/i
2525
+ },
2526
+ {
2527
+ id: "html-object-embed",
2528
+ description: "<object or <embed tags that can load active content",
2529
+ pattern: /<(?:object|embed)[\s>/]/i
2530
+ },
2531
+ {
2532
+ id: "html-base-tag",
2533
+ description: "<base href= — can hijack all relative URLs on a page",
2534
+ pattern: /<base[\s>]/i
2535
+ },
2536
+ {
2537
+ id: "html-meta-refresh",
2538
+ description: "<meta http-equiv=\"refresh\" — can redirect users",
2539
+ pattern: /<meta[\s\S]{0,40}http-equiv[\s\S]{0,20}refresh/i
2540
+ },
2541
+ {
2542
+ id: "html-srcdoc",
2543
+ description: "srcdoc= attribute on iframes — embeds HTML that can run scripts",
2544
+ pattern: /srcdoc\s*=/i
2545
+ },
2546
+ {
2547
+ id: "html-iframe",
2548
+ description: "<iframe tag",
2549
+ pattern: /<iframe[\s>/]/i
2550
+ },
2551
+ {
2552
+ id: "html-form",
2553
+ description: "<form tag — can be used for phishing / credential harvesting injection",
2554
+ pattern: /<form[\s>/]/i
2555
+ }
2556
+ ];
2557
+ //#endregion
2558
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/xml.js
2559
+ /**
2560
+ * XML context patterns.
2561
+ *
2562
+ * Detects injection vectors that are specifically dangerous when a string
2563
+ * is inserted into an XML document (not HTML rendering context).
2564
+ *
2565
+ * Key distinction from HTML: these patterns target parser-level attacks —
2566
+ * things that can confuse or subvert an XML parser, trigger external entity
2567
+ * resolution, or inject DTD content. HTML rendering concerns (XSS) belong
2568
+ * in the HTML context.
2569
+ */
2570
+ const XML_PATTERNS = [
2571
+ {
2572
+ id: "xml-cdata-injection",
2573
+ description: "CDATA section injection: <![CDATA[ breaks out of text node context",
2574
+ pattern: /<!\[CDATA\[/i
2575
+ },
2576
+ {
2577
+ id: "xml-cdata-close",
2578
+ description: "CDATA close sequence: ]]> can terminate an enclosing CDATA section",
2579
+ pattern: /\]\]>/
2580
+ },
2581
+ {
2582
+ id: "xml-processing-instruction",
2583
+ description: "XML processing instruction: <?xml-stylesheet or <?php etc.",
2584
+ pattern: /<\?(?:xml[\- ]|php|asp)/i
2585
+ },
2586
+ {
2587
+ id: "xml-doctype-injection",
2588
+ description: "DOCTYPE declaration embedded in content — can define entities",
2589
+ pattern: /<!DOCTYPE(?:[\s[]|$)/i
2590
+ },
2591
+ {
2592
+ id: "xml-entity-system",
2593
+ description: "SYSTEM keyword — used in external entity declarations (XXE)",
2594
+ pattern: /\bSYSTEM\s+["']/i
2595
+ },
2596
+ {
2597
+ id: "xml-entity-public",
2598
+ description: "PUBLIC keyword — used in external entity declarations (XXE)",
2599
+ pattern: /\bPUBLIC\s+["']/i
2600
+ },
2601
+ {
2602
+ id: "xml-entity-declaration",
2603
+ description: "<!ENTITY declaration — defines entities, potential XXE or entity expansion",
2604
+ pattern: /<!ENTITY[\s%]/i
2605
+ },
2606
+ {
2607
+ id: "xml-billion-laughs",
2608
+ description: "Entity reference chaining / billion laughs: repeated &eX; style references",
2609
+ pattern: /(?:&\w{1,20};){3,}/
2610
+ },
2611
+ {
2612
+ id: "xml-namespace-confusion",
2613
+ description: "xmlns: attribute injection — can redefine namespaces to confuse parsers",
2614
+ pattern: /\bxmlns\s*(?::\w{1,40})?\s*=/i
2615
+ },
2616
+ {
2617
+ id: "xml-comment-injection",
2618
+ description: "<!-- comment injection — can hide content from some parsers",
2619
+ pattern: /<!--/
2620
+ },
2621
+ {
2622
+ id: "xml-comment-close",
2623
+ description: "--> closes an enclosing XML comment",
2624
+ pattern: /-->/
2625
+ },
2626
+ {
2627
+ id: "xml-pi-close",
2628
+ description: "?> closes an enclosing processing instruction",
2629
+ pattern: /\?>/
2630
+ }
2631
+ ];
2632
+ //#endregion
2633
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/svg.js
2634
+ /**
2635
+ * SVG context patterns.
2636
+ *
2637
+ * SVG is XML-based but renders in browsers, giving it a unique attack surface
2638
+ * that combines XML parser behaviour with browser rendering and JavaScript execution.
2639
+ *
2640
+ * Many of these vectors bypass HTML sanitizers that don't understand SVG semantics
2641
+ * (DOMPurify has documented bypass vulnerabilities specifically in SVG/XML context).
2642
+ */
2643
+ const SVG_PATTERNS = [
2644
+ {
2645
+ id: "svg-script-element",
2646
+ description: "<script element inside SVG executes JavaScript",
2647
+ pattern: /<script[\s>/]/i
2648
+ },
2649
+ {
2650
+ id: "svg-xlink-href-javascript",
2651
+ description: "xlink:href with javascript: — classic SVG XSS via <a> or <use>",
2652
+ pattern: /xlink\s*:\s*href\s*=\s*["']?\s*javascript\s*:/i
2653
+ },
2654
+ {
2655
+ id: "svg-href-javascript",
2656
+ description: "href= with javascript: in SVG context (<a>, <animate>, etc.)",
2657
+ pattern: /href\s*=\s*["']?\s*javascript\s*:/i
2658
+ },
2659
+ {
2660
+ id: "svg-foreignobject",
2661
+ description: "<foreignObject embeds HTML inside SVG — can execute scripts",
2662
+ pattern: /<foreignObject[\s>/]/i
2663
+ },
2664
+ {
2665
+ id: "svg-use-external",
2666
+ description: "<use xlink:href or href pointing to external resource (non-fragment URL)",
2667
+ pattern: /<use[\s\S]{0,60}(?:xlink\s*:\s*)?href\s*=\s*(?:["'][^#]|[^"'#\s>])/i
2668
+ },
2669
+ {
2670
+ id: "svg-animate-href",
2671
+ description: "<animate attributeName=\"href\" — can dynamically change href to javascript:",
2672
+ pattern: /<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*href["']/i
2673
+ },
2674
+ {
2675
+ id: "svg-animate-xlinkhref",
2676
+ description: "<animate attributeName=\"xlink:href\"",
2677
+ pattern: /<animate[\s\S]{0,80}attributeName\s*=\s*["'][\s]*xlink\s*:\s*href["']/i
2678
+ },
2679
+ {
2680
+ id: "svg-set-javascript",
2681
+ description: "<set to=\"javascript:...\" — sets an attribute to a javascript: URI",
2682
+ pattern: /<set[\s\S]{0,80}to\s*=\s*["']?\s*javascript\s*:/i
2683
+ },
2684
+ {
2685
+ id: "svg-event-handler",
2686
+ description: "SVG-specific event handler attributes: onload=, onerror=, onactivate=, etc.",
2687
+ pattern: /\bon(?:load|error|activate|begin|end|repeat|focus|blur|click|mouse\w{1,20}|key\w{1,20})\s*=/i
2688
+ },
2689
+ {
2690
+ id: "svg-handler-generic",
2691
+ description: "Generic on* handler catch-all for SVG attributes",
2692
+ pattern: /\bon\w{1,30}\s*=/i
2693
+ },
2694
+ {
2695
+ id: "svg-filter-feimage",
2696
+ description: "<feImage href= — filter primitive that can load external resources",
2697
+ pattern: /<feImage[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=/i
2698
+ },
2699
+ {
2700
+ id: "svg-image-external",
2701
+ description: "<image xlink:href with http/https or javascript protocol",
2702
+ pattern: /<image[\s\S]{0,80}(?:xlink\s*:\s*)?href\s*=\s*["']?\s*(?:https?|javascript)\s*:/i
2703
+ },
2704
+ {
2705
+ id: "svg-style-javascript",
2706
+ description: "style= attribute containing javascript: (e.g. background:url(javascript:...))",
2707
+ pattern: /style\s*=[\s\S]{0,60}javascript\s*:/i
2708
+ }
2709
+ ];
2710
+ //#endregion
2711
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/sql.js
2712
+ /**
2713
+ * SQL context patterns — high-precision rules only.
2714
+ *
2715
+ * These rules have very low false-positive risk and are safe to apply to
2716
+ * general user text (names, descriptions, search queries, etc.).
2717
+ * All patterns are ReDoS-safe — unlike the `sql-injection` npm package
2718
+ * which has an active CVE on its own detection regexes.
2719
+ *
2720
+ * For exhaustive coverage including noisier heuristics (comment sequences,
2721
+ * hex literals, stacked queries with semicolons), use 'SQL-STRICT' instead.
2722
+ * Apply 'SQL-STRICT' only to strings that are specifically SQL fragments,
2723
+ * not to general free-text fields.
2724
+ */
2725
+ const SQL_PATTERNS = [
2726
+ {
2727
+ id: "sql-block-comment-open",
2728
+ description: "SQL block comment open: /* ... */ — unusual in legitimate user text",
2729
+ pattern: /\/\*/
2730
+ },
2731
+ {
2732
+ id: "sql-union-select",
2733
+ description: "UNION SELECT — most common SQL injection aggregation attack",
2734
+ pattern: /\bUNION\s{1,20}(?:ALL\s{1,20})?SELECT\b/i
2735
+ },
2736
+ {
2737
+ id: "sql-drop-table",
2738
+ description: "DROP TABLE — destructive DDL injection",
2739
+ pattern: /\bDROP\s{1,20}TABLE\b/i
2740
+ },
2741
+ {
2742
+ id: "sql-drop-database",
2743
+ description: "DROP DATABASE — destructive DDL injection",
2744
+ pattern: /\bDROP\s{1,20}DATABASE\b/i
2745
+ },
2746
+ {
2747
+ id: "sql-insert-into",
2748
+ description: "INSERT INTO — data injection",
2749
+ pattern: /\bINSERT\s{1,20}INTO\b/i
2750
+ },
2751
+ {
2752
+ id: "sql-delete-from",
2753
+ description: "DELETE FROM — data deletion injection",
2754
+ pattern: /\bDELETE\s{1,20}FROM\b/i
2755
+ },
2756
+ {
2757
+ id: "sql-update-set",
2758
+ description: "UPDATE ... SET — data modification injection",
2759
+ pattern: /\bUPDATE\b[\s\S]{1,60}\bSET\b/i
2760
+ },
2761
+ {
2762
+ id: "sql-exec-xp",
2763
+ description: "EXEC xp_ — MSSQL extended stored procedure execution",
2764
+ pattern: /\bEXEC(?:UTE)?\s{1,20}xp_/i
2765
+ },
2766
+ {
2767
+ id: "sql-tautology-string",
2768
+ description: "Classic string tautology: ' OR '1'='1 or \" OR \"1\"=\"1\"",
2769
+ pattern: /'\s{0,10}OR\s{0,10}'[^']{0,20}'\s*=\s*'[^']{0,20}/i
2770
+ },
2771
+ {
2772
+ id: "sql-tautology-numeric",
2773
+ description: "Numeric tautology: OR 1=1",
2774
+ pattern: /\bOR\s{1,10}1\s*=\s*1\b/i
2775
+ },
2776
+ {
2777
+ id: "sql-always-true-zero",
2778
+ description: "Numeric tautology: OR 0=0",
2779
+ pattern: /\bOR\s{1,10}0\s*=\s*0\b/i
2780
+ },
2781
+ {
2782
+ id: "sql-sleep-benchmark",
2783
+ description: "Time-based blind injection: SLEEP() or BENCHMARK()",
2784
+ pattern: /\b(?:SLEEP|BENCHMARK)\s*\(/i
2785
+ },
2786
+ {
2787
+ id: "sql-waitfor-delay",
2788
+ description: "MSSQL time-based blind injection: WAITFOR DELAY",
2789
+ pattern: /\bWAITFOR\s{1,20}DELAY\b/i
2790
+ },
2791
+ {
2792
+ id: "sql-char-function",
2793
+ description: "CHAR() function — used to obfuscate injected strings",
2794
+ pattern: /\bCHAR\s*\(\s*\d{1,3}/i
2795
+ },
2796
+ {
2797
+ id: "sql-information-schema",
2798
+ description: "INFORMATION_SCHEMA — reconnaissance query for table/column enumeration",
2799
+ pattern: /\bINFORMATION_SCHEMA\b/i
2800
+ }
2801
+ ];
2802
+ //#endregion
2803
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/shell.js
2804
+ /**
2805
+ * SHELL context patterns.
2806
+ *
2807
+ * Detects shell injection vectors and path traversal patterns.
2808
+ * Designed for use when a string will be passed to a shell command,
2809
+ * used as a file path, or interpolated into OS-level operations.
2810
+ */
2811
+ const SHELL_PATTERNS = [
2812
+ {
2813
+ id: "shell-path-traversal-unix",
2814
+ description: "Unix path traversal: ../ — climbing the directory tree",
2815
+ pattern: /\.\.\//
2816
+ },
2817
+ {
2818
+ id: "shell-path-traversal-windows",
2819
+ description: "Windows path traversal: ..\\ — climbing the directory tree",
2820
+ pattern: /\.\.\\/
2821
+ },
2822
+ {
2823
+ id: "shell-path-traversal-encoded",
2824
+ description: "URL-encoded path traversal: %2e%2e or %2f variants",
2825
+ pattern: /%2e%2e|%2f\.\.|\.\.%2f/i
2826
+ },
2827
+ {
2828
+ id: "shell-null-byte",
2829
+ description: "Null byte injection: \\x00 or %00 — truncates strings in C-backed functions",
2830
+ pattern: /\x00|%00/
2831
+ },
2832
+ {
2833
+ id: "shell-semicolon",
2834
+ description: "Semicolon command separator: cmd1; cmd2",
2835
+ pattern: /;/
2836
+ },
2837
+ {
2838
+ id: "shell-pipe",
2839
+ description: "Pipe operator: cmd1 | cmd2",
2840
+ pattern: /\|/
2841
+ },
2842
+ {
2843
+ id: "shell-and-operator",
2844
+ description: "AND operator: cmd1 && cmd2",
2845
+ pattern: /&&/
2846
+ },
2847
+ {
2848
+ id: "shell-or-operator",
2849
+ description: "OR operator: cmd1 || cmd2",
2850
+ pattern: /\|\|/
2851
+ },
2852
+ {
2853
+ id: "shell-backtick",
2854
+ description: "Backtick command substitution: `cmd`",
2855
+ pattern: /`/
2856
+ },
2857
+ {
2858
+ id: "shell-dollar-paren",
2859
+ description: "Dollar-paren command substitution: $(cmd)",
2860
+ pattern: /\$\(/
2861
+ },
2862
+ {
2863
+ id: "shell-dollar-brace",
2864
+ description: "Dollar-brace variable expansion: ${var} — can be abused for injection",
2865
+ pattern: /\$\{/
2866
+ },
2867
+ {
2868
+ id: "shell-redirect-out",
2869
+ description: "Output redirection: cmd > file or cmd >> file",
2870
+ pattern: />{1,2}/
2871
+ },
2872
+ {
2873
+ id: "shell-redirect-in",
2874
+ description: "Input redirection: cmd < file",
2875
+ pattern: /</
2876
+ },
2877
+ {
2878
+ id: "shell-newline-injection",
2879
+ description: "Newline injection: \\n or \\r — can inject new shell commands",
2880
+ pattern: /[\n\r]/
2881
+ },
2882
+ {
2883
+ id: "shell-glob-star",
2884
+ description: "Glob expansion: * or ? — can expand to unintended files",
2885
+ pattern: /[/\\][*?]/
2886
+ },
2887
+ {
2888
+ id: "shell-absolute-root",
2889
+ description: "Absolute root path injection: string starting with / or \\ (Windows UNC)",
2890
+ pattern: /^(?:\/|\\\\)/
2891
+ },
2892
+ {
2893
+ id: "shell-windows-drive",
2894
+ description: "Windows drive letter path injection: C:\\ or D:/",
2895
+ pattern: /^[a-zA-Z]:[/\\]/
2896
+ },
2897
+ {
2898
+ id: "shell-curl-wget",
2899
+ description: "curl/wget with URL or flags — can exfiltrate data or download payloads",
2900
+ pattern: /\b(?:curl|wget)\s+(?:https?:\/\/|ftp:\/\/|-)/i
2901
+ }
2902
+ ];
2903
+ //#endregion
2904
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/redos.js
2905
+ /**
2906
+ * REDOS context patterns.
2907
+ *
2908
+ * Detects strings that, if used as regular expressions, could cause
2909
+ * catastrophic backtracking (ReDoS — Regular Expression Denial of Service).
2910
+ *
2911
+ * These patterns detect the structural forms that lead to exponential or
2912
+ * polynomial backtracking in NFA-based regex engines (V8, PCRE, Java, etc.).
2913
+ *
2914
+ * Use this context when user-supplied strings will be compiled into RegExp objects.
2915
+ */
2916
+ const REDOS_PATTERNS = [
2917
+ {
2918
+ id: "redos-nested-quantifier-plus",
2919
+ description: "Nested + quantifier inside a group with outer quantifier: (a+)+, (.+b)*, etc.",
2920
+ pattern: /\([^)]*\+[^)]*\)[+*]/
2921
+ },
2922
+ {
2923
+ id: "redos-nested-quantifier-star",
2924
+ description: "Nested * quantifier: (a*)* or (a*)+ — catastrophic backtracking",
2925
+ pattern: /\([^)]*\*[^)]*\)[*+]/
2926
+ },
2927
+ {
2928
+ id: "redos-nested-groups",
2929
+ description: "Doubly nested quantified groups: ((a+)+) — guaranteed catastrophic",
2930
+ pattern: /\(\([^)]{0,40}\)[+*]\)[+*]/
2931
+ },
2932
+ {
2933
+ id: "redos-alternation-overlap",
2934
+ description: "Overlapping alternation under quantifier: (a|a)+ — ambiguous NFA paths",
2935
+ pattern: /\(([^|()]{1,20})\|(?:\1)(?:\|[^|()]{1,20}){0,5}\)[+*?]{1,2}/
2936
+ },
2937
+ {
2938
+ id: "redos-star-plus-concat",
2939
+ description: "(x*x)+ pattern — triggers super-linear backtracking",
2940
+ pattern: /\([^)]{0,10}\*[^)]{0,10}\)[+*]/
2941
+ },
2942
+ {
2943
+ id: "redos-dot-star-greedy",
2944
+ description: "(.*){n,} or (.+){n,} — repeated greedy dot quantifiers",
2945
+ pattern: /\(\.[*+]\)\{?\d/
2946
+ },
2947
+ {
2948
+ id: "redos-large-repetition",
2949
+ description: "Very large fixed or range repetition count {1000,} or {1000,n} — denial of service via backtracking",
2950
+ pattern: /\{\d{4,}(?:,\d*)?\}/
2951
+ },
2952
+ {
2953
+ id: "redos-catastrophic-alternation",
2954
+ description: "Long alternation with many similar branches — polynomial backtracking risk",
2955
+ pattern: /\([^)]{0,200}(?:\|[^|)]{0,50}){9,}\)/
2956
+ }
2957
+ ];
2958
+ //#endregion
2959
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/nosql.js
2960
+ const sep = "[\"'\\s]*:";
2961
+ const NOSQL_PATTERNS = [
2962
+ {
2963
+ id: "nosql-where-operator",
2964
+ description: "$where — executes arbitrary JavaScript server-side in MongoDB",
2965
+ pattern: new RegExp(`\\$where${sep}`, "i")
2966
+ },
2967
+ {
2968
+ id: "nosql-ne-operator",
2969
+ description: "$ne — \"not equal\" operator used to bypass equality checks",
2970
+ pattern: new RegExp(`\\$ne${sep}`, "i")
2971
+ },
2972
+ {
2973
+ id: "nosql-gt-operator",
2974
+ description: "$gt — \"greater than\" used to bypass password/value checks",
2975
+ pattern: new RegExp(`\\$gte?${sep}`, "i")
2976
+ },
2977
+ {
2978
+ id: "nosql-lt-operator",
2979
+ description: "$lt / $lte — \"less than\" bypass variants",
2980
+ pattern: new RegExp(`\\$lte?${sep}`, "i")
2981
+ },
2982
+ {
2983
+ id: "nosql-regex-operator",
2984
+ description: "$regex — can be used to extract data character by character (blind injection)",
2985
+ pattern: new RegExp(`\\$regex${sep}`, "i")
2986
+ },
2987
+ {
2988
+ id: "nosql-or-operator",
2989
+ description: "$or — logical OR; used to create always-true conditions",
2990
+ pattern: new RegExp(`\\$or${sep}\\s*\\[`, "i")
2991
+ },
2992
+ {
2993
+ id: "nosql-and-operator",
2994
+ description: "$and — logical AND operator injection",
2995
+ pattern: new RegExp(`\\$and${sep}\\s*\\[`, "i")
2996
+ },
2997
+ {
2998
+ id: "nosql-nor-operator",
2999
+ description: "$nor — logical NOR operator injection",
3000
+ pattern: new RegExp(`\\$nor${sep}\\s*\\[`, "i")
3001
+ },
3002
+ {
3003
+ id: "nosql-exists-operator",
3004
+ description: "$exists — can enumerate fields to determine schema",
3005
+ pattern: new RegExp(`\\$exists${sep}`, "i")
3006
+ },
3007
+ {
3008
+ id: "nosql-in-operator",
3009
+ description: "$in — matches any value in a list; can enumerate values",
3010
+ pattern: new RegExp(`\\$in${sep}\\s*\\[`, "i")
3011
+ },
3012
+ {
3013
+ id: "nosql-expr-operator",
3014
+ description: "$expr — allows aggregation expressions in queries (MongoDB 3.6+)",
3015
+ pattern: new RegExp(`\\$expr${sep}`, "i")
3016
+ },
3017
+ {
3018
+ id: "nosql-function-operator",
3019
+ description: "$function — executes arbitrary JavaScript in MongoDB 4.4+",
3020
+ pattern: new RegExp(`\\$function${sep}`, "i")
3021
+ },
3022
+ {
3023
+ id: "nosql-accumulator-operator",
3024
+ description: "$accumulator — custom aggregation with arbitrary JS execution",
3025
+ pattern: new RegExp(`\\$accumulator${sep}`, "i")
3026
+ },
3027
+ {
3028
+ id: "nosql-proto-pollution",
3029
+ description: "__proto__ — prototype pollution via object key injection",
3030
+ pattern: /__proto__/
3031
+ },
3032
+ {
3033
+ id: "nosql-constructor-prototype",
3034
+ description: "constructor.prototype — alternative prototype pollution vector (dot notation or JSON key)",
3035
+ pattern: /constructor[\s"':.,{\[]*prototype/i
3036
+ },
3037
+ {
3038
+ id: "nosql-proto-bracket",
3039
+ description: "[\"__proto__\"] — bracket-notation prototype pollution",
3040
+ pattern: /\[["']__proto__["']\]/
3041
+ }
3042
+ ];
3043
+ //#endregion
3044
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/log.js
3045
+ /**
3046
+ * LOG context patterns.
3047
+ *
3048
+ * Detects injection vectors that are dangerous when a string is written
3049
+ * to a log file, passed to a logging framework, or interpolated into
3050
+ * a log message that will be parsed or displayed.
3051
+ *
3052
+ * Attack categories:
3053
+ * 1. CRLF injection — injects fake log lines by embedding newlines
3054
+ * 2. Log4Shell (CVE-2021-44228) — ${jndi:...} triggers JNDI lookup in Log4j
3055
+ * 3. SSTI in log templates — {{...}}, #{...} trigger template evaluation
3056
+ * if the log message is passed through a template engine
3057
+ * 4. Null byte injection — truncates log entries in some implementations
3058
+ * 5. ANSI escape injection — manipulates terminal output when logs are
3059
+ * tailed in a terminal (colour codes, cursor movement, etc.)
3060
+ *
3061
+ * Note: Newline characters (\n, \r) will produce false positives for
3062
+ * multi-line legitimate values. Use this context only for single-line
3063
+ * log field values (usernames, IDs, request parameters, etc.).
3064
+ */
3065
+ const LOG_PATTERNS = [
3066
+ {
3067
+ id: "log-crlf-injection",
3068
+ description: "CRLF injection: literal \\r or \\n embeds fake log lines",
3069
+ pattern: /[\r\n]/
3070
+ },
3071
+ {
3072
+ id: "log-url-encoded-crlf",
3073
+ description: "URL-encoded CRLF: %0d, %0a, %0D, %0A — decoded by some log parsers",
3074
+ pattern: /%0[dDaA]/
3075
+ },
3076
+ {
3077
+ id: "log-unicode-newline",
3078
+ description: "Unicode newline variants: U+2028 (line separator), U+2029 (paragraph separator)",
3079
+ pattern: /[\u2028\u2029]/
3080
+ },
3081
+ {
3082
+ id: "log-log4shell-jndi",
3083
+ description: "Log4Shell: ${jndi:...} triggers remote code execution in Apache Log4j",
3084
+ pattern: /\$\{jndi\s*:/i
3085
+ },
3086
+ {
3087
+ id: "log-log4shell-obfuscated",
3088
+ description: "Obfuscated Log4Shell: ${::-j}... lookup-bypass prefix used to evade WAF detection",
3089
+ pattern: /\$\{::-/
3090
+ },
3091
+ {
3092
+ id: "log-log4j-lookup",
3093
+ description: "Log4j lookup syntax: ${env:...}, ${sys:...}, ${ctx:...} — data exfiltration",
3094
+ pattern: /\$\{(?:env|sys|ctx|main|map|sd|web|docker|k8s|spring)\s*:/i
3095
+ },
3096
+ {
3097
+ id: "log-ssti-double-brace",
3098
+ description: "SSTI double-brace: {{expression}} — Jinja2, Twig, Handlebars, etc.",
3099
+ pattern: /\{\{[\s\S]{0,80}\}\}/
3100
+ },
3101
+ {
3102
+ id: "log-ssti-hash-brace",
3103
+ description: "SSTI hash-brace: #{expression} — Thymeleaf, Velocity, Ruby ERB",
3104
+ pattern: /#\{[\s\S]{0,80}\}/
3105
+ },
3106
+ {
3107
+ id: "log-ssti-dollar-brace",
3108
+ description: "SSTI/EL injection: ${expression with operators or method calls} — JSP EL, Freemarker, SpEL",
3109
+ pattern: /\$\{[^}]*(?:\.|\(|\*|\+|\bclass\b|\bruntime\b|\bprocess\b|\bexec\b)[^}]{0,80}\}/i
3110
+ },
3111
+ {
3112
+ id: "log-ssti-percent-tag",
3113
+ description: "SSTI ERB/ASP tag: <%= expression %> — Ruby ERB, ASP",
3114
+ pattern: /<%=[\s\S]{0,80}%>/
3115
+ },
3116
+ {
3117
+ id: "log-null-byte",
3118
+ description: "Null byte: \\x00 or %00 — can truncate log entries in C-backed loggers",
3119
+ pattern: /\x00|%00/
3120
+ },
3121
+ {
3122
+ id: "log-ansi-escape",
3123
+ description: "ANSI escape sequence: ESC[ — can manipulate terminal output when logs are tailed",
3124
+ pattern: /\x1b\[/
3125
+ }
3126
+ ];
3127
+ //#endregion
3128
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/contexts/sql-strict.js
3129
+ /**
3130
+ * SQL-STRICT context patterns.
3131
+ *
3132
+ * Extends the base 'SQL' context with three additional rules that are
3133
+ * effective at detecting real injections but carry a higher false-positive
3134
+ * risk on general free-text input.
3135
+ *
3136
+ * Use 'SQL-STRICT' when:
3137
+ * - The string is specifically a SQL fragment or database identifier
3138
+ * - You control the input domain (e.g. a dedicated SQL search field)
3139
+ * - You can tolerate occasional false positives in exchange for broader coverage
3140
+ *
3141
+ * Use 'SQL' (not STRICT) when:
3142
+ * - The field is general user text (names, descriptions, comments)
3143
+ * - False positives would block legitimate content (e.g. "see note -- above")
3144
+ *
3145
+ * Rules moved here from 'SQL' due to false-positive risk:
3146
+ *
3147
+ * sql-line-comment — "--" fires on "see note -- above", "value--", CSS var(--primary)
3148
+ * sql-stacked-query — "; SELECT" fires on legitimate prose with semicolons + SQL words
3149
+ * sql-hex-encoding — "0xDEAD" fires on hex values in technical docs and log output
3150
+ */
3151
+ const SQL_STRICT_EXTRA = [
3152
+ {
3153
+ id: "sql-line-comment",
3154
+ description: "SQL line comment: -- followed by whitespace or end of string",
3155
+ pattern: /--(?:\s|$)/
3156
+ },
3157
+ {
3158
+ id: "sql-stacked-query",
3159
+ description: "Stacked queries: semicolon immediately followed by a SQL keyword",
3160
+ pattern: /;\s{0,10}(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)\b/i
3161
+ },
3162
+ {
3163
+ id: "sql-hex-encoding",
3164
+ description: "Hex-encoded string injection: 0x41414141 style (MySQL)",
3165
+ pattern: /\b0x[0-9a-f]{4,}/i
3166
+ }
3167
+ ];
3168
+ const SQL_STRICT_PATTERNS = [...SQL_PATTERNS, ...SQL_STRICT_EXTRA];
3169
+ //#endregion
3170
+ //#region ../../node_modules/.pnpm/is-unsafe@2.0.0/node_modules/is-unsafe/src/index.js
3171
+ HTML_PATTERNS.label = "HTML";
3172
+ XML_PATTERNS.label = "XML";
3173
+ SVG_PATTERNS.label = "SVG";
3174
+ SQL_PATTERNS.label = "SQL";
3175
+ SQL_STRICT_PATTERNS.label = "SQL-STRICT";
3176
+ SHELL_PATTERNS.label = "SHELL";
3177
+ REDOS_PATTERNS.label = "REDOS";
3178
+ NOSQL_PATTERNS.label = "NOSQL";
3179
+ LOG_PATTERNS.label = "LOG";
3180
+ Object.freeze({
3181
+ HTML: HTML_PATTERNS,
3182
+ XML: XML_PATTERNS,
3183
+ SVG: SVG_PATTERNS,
3184
+ SQL: SQL_PATTERNS,
3185
+ "SQL-STRICT": SQL_STRICT_PATTERNS,
3186
+ SHELL: SHELL_PATTERNS,
3187
+ REDOS: REDOS_PATTERNS,
3188
+ NOSQL: NOSQL_PATTERNS,
3189
+ LOG: LOG_PATTERNS
3190
+ });
3191
+ /**
3192
+ * @typedef {{ id: string, description: string, pattern: RegExp }} Rule
3193
+ */
3194
+ /**
3195
+ * @typedef {Rule[]} PatternList
3196
+ */
3197
+ /**
3198
+ * @typedef {Object} MatchResult
3199
+ * @property {string} context - Label identifying which context matched ('HTML', 'CUSTOM', etc.)
3200
+ * @property {string} id - Rule identifier
3201
+ * @property {string} description - Human-readable description of what was matched
3202
+ * @property {RegExp} pattern - The pattern that matched
3203
+ */
3204
+ /**
3205
+ * @param {unknown} value
3206
+ */
3207
+ function assertString(value) {
3208
+ if (typeof value !== "string") throw new TypeError(`is-unsafe: first argument must be a string, got ${typeof value}`);
3209
+ }
3210
+ /**
3211
+ * @param {unknown} context
3212
+ */
3213
+ function assertContext(context) {
3214
+ if (context instanceof RegExp) return;
3215
+ if (Array.isArray(context)) {
3216
+ if (context.length === 0) throw new TypeError("is-unsafe: context must not be an empty array");
3217
+ if (Array.isArray(context[0])) {
3218
+ 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)");
3219
+ }
3220
+ return;
3221
+ }
3222
+ 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}`);
3223
+ }
3224
+ /**
3225
+ * Normalise any valid context arg into an array of PatternLists.
3226
+ *
3227
+ * @param {Rule[]|Rule[][]|RegExp} context
3228
+ * @returns {{ lists: Rule[][]|null, regex: RegExp|null }}
3229
+ */
3230
+ function normalise(context) {
3231
+ if (context instanceof RegExp) return {
3232
+ lists: null,
3233
+ regex: context
3234
+ };
3235
+ if (Array.isArray(context[0])) return {
3236
+ lists: context,
3237
+ regex: null
3238
+ };
3239
+ return {
3240
+ lists: [context],
3241
+ regex: null
3242
+ };
3243
+ }
3244
+ /**
3245
+ * Test value against a single PatternList. Returns the first MatchResult or null.
3246
+ *
3247
+ * @param {string} value
3248
+ * @param {Rule[]} list
3249
+ * @returns {MatchResult|null}
3250
+ */
3251
+ function matchList(value, list) {
3252
+ const label = list.label ?? "CUSTOM";
3253
+ for (const rule of list) if (rule.pattern.test(value)) return {
3254
+ context: label,
3255
+ id: rule.id,
3256
+ description: rule.description,
3257
+ pattern: rule.pattern
3258
+ };
3259
+ return null;
3260
+ }
3261
+ /**
3262
+ * Returns `true` if `value` is unsafe in the given context(s), `false` otherwise.
3263
+ *
3264
+ * @param {string} value - The string to test
3265
+ * @param {PatternList | PatternList[] | RegExp} context
3266
+ * - A PatternList imported from is-unsafe (e.g. `HTML`, `XML`)
3267
+ * - An array of PatternLists — returns true if unsafe in **any** of them
3268
+ * - A custom RegExp — returns true if the pattern matches
3269
+ * @returns {boolean}
3270
+ *
3271
+ * @example
3272
+ * import { isUnsafe, HTML, SQL } from 'is-unsafe';
3273
+ *
3274
+ * isUnsafe('<script>alert(1)<\/script>', HTML) // true
3275
+ * isUnsafe('hello world', HTML) // false
3276
+ * isUnsafe('value', [HTML, SQL]) // false
3277
+ * isUnsafe('value', /my-pattern/i) // false
3278
+ */
3279
+ function isUnsafe(value, context) {
3280
+ assertString(value);
3281
+ assertContext(context);
3282
+ const { lists, regex } = normalise(context);
3283
+ if (regex) return regex.test(value);
3284
+ for (const list of lists) if (matchList(value, list) !== null) return true;
3285
+ return false;
3286
+ }
3287
+ //#endregion
3288
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
3289
+ /**
3290
+ * Extract raw attributes (without prefix) from prefixed attribute map
3291
+ * @param {object} prefixedAttrs - Attributes with prefix from buildAttributesMap
3292
+ * @param {object} options - Parser options containing attributeNamePrefix
3293
+ * @returns {object} Raw attributes for matcher
3294
+ */
3295
+ function extractRawAttributes(prefixedAttrs, options) {
3296
+ if (!prefixedAttrs) return {};
3297
+ const attrs = options.attributesGroupName ? prefixedAttrs[options.attributesGroupName] : prefixedAttrs;
3298
+ if (!attrs) return {};
3299
+ const rawAttrs = {};
3300
+ for (const key in attrs) if (key.startsWith(options.attributeNamePrefix)) {
3301
+ const rawName = key.substring(options.attributeNamePrefix.length);
3302
+ rawAttrs[rawName] = attrs[key];
3303
+ } else rawAttrs[key] = attrs[key];
3304
+ return rawAttrs;
3305
+ }
3306
+ /**
3307
+ * Extract namespace from raw tag name
3308
+ * @param {string} rawTagName - Tag name possibly with namespace (e.g., "soap:Envelope")
3309
+ * @returns {string|undefined} Namespace or undefined
3310
+ */
3311
+ function extractNamespace(rawTagName) {
3312
+ if (!rawTagName || typeof rawTagName !== "string") return void 0;
3313
+ const colonIndex = rawTagName.indexOf(":");
3314
+ if (colonIndex !== -1 && colonIndex > 0) {
3315
+ const ns = rawTagName.substring(0, colonIndex);
3316
+ if (ns !== "xmlns") return ns;
3317
+ }
3318
+ }
3319
+ var OrderedObjParser = class {
3320
+ constructor(options, externalEntities) {
3321
+ this.options = options;
3322
+ this.currentNode = null;
3323
+ this.tagsNodeStack = [];
3324
+ this.parseXml = parseXml;
3325
+ this.parseTextData = parseTextData;
3326
+ this.resolveNameSpace = resolveNameSpace;
3327
+ this.buildAttributesMap = buildAttributesMap;
3328
+ this.isItStopNode = isItStopNode;
3329
+ this.replaceEntitiesValue = replaceEntitiesValue;
3330
+ this.readStopNodeData = readStopNodeData;
3331
+ this.saveTextToParentTag = saveTextToParentTag;
3332
+ this.addChild = addChild;
3333
+ this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
3334
+ this.entityExpansionCount = 0;
3335
+ this.currentExpandedLength = 0;
3336
+ this.doctypefound = false;
3337
+ let namedEntities = { ...XML };
3338
+ if (this.options.entityDecoder) this.entityDecoder = this.options.entityDecoder;
3339
+ else {
3340
+ if (typeof this.options.htmlEntities === "object") namedEntities = this.options.htmlEntities;
3341
+ else if (this.options.htmlEntities === true) namedEntities = {
3342
+ ...COMMON_HTML,
3343
+ ...CURRENCY
3344
+ };
3345
+ this.entityDecoder = new EntityDecoder({
3346
+ namedEntities: {
3347
+ ...namedEntities,
3348
+ ...externalEntities
3349
+ },
3350
+ numericAllowed: this.options.htmlEntities,
3351
+ limit: {
3352
+ maxTotalExpansions: this.options.processEntities.maxTotalExpansions,
3353
+ maxExpandedLength: this.options.processEntities.maxExpandedLength,
3354
+ applyLimitsTo: this.options.processEntities.appliesTo
3355
+ },
3356
+ onInputEntity: (name, value) => isUnsafe(value, [HTML_PATTERNS, XML_PATTERNS]) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW
3357
+ });
3358
+ }
3359
+ this.matcher = new Matcher();
3360
+ this.readonlyMatcher = this.matcher.readOnly();
3361
+ this.isCurrentNodeStopNode = false;
3362
+ this.stopNodeExpressionsSet = new ExpressionSet();
3363
+ const stopNodesOpts = this.options.stopNodes;
3364
+ if (stopNodesOpts && stopNodesOpts.length > 0) {
3365
+ for (let i = 0; i < stopNodesOpts.length; i++) {
3366
+ const stopNodeExp = stopNodesOpts[i];
3367
+ if (typeof stopNodeExp === "string") this.stopNodeExpressionsSet.add(new Expression(stopNodeExp));
3368
+ else if (stopNodeExp instanceof Expression) this.stopNodeExpressionsSet.add(stopNodeExp);
3369
+ }
3370
+ this.stopNodeExpressionsSet.seal();
3371
+ }
3372
+ }
3373
+ };
3374
+ /**
3375
+ * @param {string} val
3376
+ * @param {string} tagName
3377
+ * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath
3378
+ * @param {boolean} dontTrim
3379
+ * @param {boolean} hasAttributes
3380
+ * @param {boolean} isLeafNode
3381
+ * @param {boolean} escapeEntities
3382
+ */
3383
+ function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
3384
+ const options = this.options;
3385
+ if (val !== void 0) {
3386
+ if (options.trimValues && !dontTrim) val = val.trim();
3387
+ if (val.length > 0) {
3388
+ if (!escapeEntities) val = this.replaceEntitiesValue(val, tagName, jPath);
3389
+ const jPathOrMatcher = options.jPath ? jPath.toString() : jPath;
3390
+ const newval = options.tagValueProcessor(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode);
3391
+ if (newval === null || newval === void 0) return val;
3392
+ else if (typeof newval !== typeof val || newval !== val) return newval;
3393
+ else if (options.trimValues) return parseValue(val, options.parseTagValue, options.numberParseOptions);
3394
+ else if (val.trim() === val) return parseValue(val, options.parseTagValue, options.numberParseOptions);
3395
+ else return val;
3396
+ }
3397
+ }
3398
+ }
3399
+ function resolveNameSpace(tagname) {
3400
+ if (this.options.removeNSPrefix) {
3401
+ const tags = tagname.split(":");
3402
+ const prefix = tagname.charAt(0) === "/" ? "/" : "";
3403
+ if (tags[0] === "xmlns") return "";
3404
+ if (tags.length === 2) tagname = prefix + tags[1];
3405
+ }
3406
+ return tagname;
3407
+ }
3408
+ const attrsRegx = /* @__PURE__ */ new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?", "gm");
3409
+ function buildAttributesMap(attrStr, jPath, tagName, force = false) {
3410
+ const options = this.options;
3411
+ if (force === true || options.ignoreAttributes !== true && typeof attrStr === "string") {
3412
+ const matches = getAllMatches(attrStr, attrsRegx);
3413
+ const len = matches.length;
3414
+ const attrs = {};
3415
+ const processedVals = new Array(len);
3416
+ let hasRawAttrs = false;
3417
+ const rawAttrsForMatcher = {};
3418
+ for (let i = 0; i < len; i++) {
3419
+ const attrName = this.resolveNameSpace(matches[i][1]);
3420
+ const oldVal = matches[i][4];
3421
+ if (attrName.length && oldVal !== void 0) {
3422
+ let val = oldVal;
3423
+ if (options.trimValues) val = val.trim();
3424
+ val = this.replaceEntitiesValue(val, tagName, this.readonlyMatcher);
3425
+ processedVals[i] = val;
3426
+ rawAttrsForMatcher[attrName] = val;
3427
+ hasRawAttrs = true;
3428
+ }
3429
+ }
3430
+ if (hasRawAttrs && typeof jPath === "object" && jPath.updateCurrent) jPath.updateCurrent(rawAttrsForMatcher);
3431
+ const jPathStr = options.jPath ? jPath.toString() : this.readonlyMatcher;
3432
+ let hasAttrs = false;
3433
+ for (let i = 0; i < len; i++) {
3434
+ const attrName = this.resolveNameSpace(matches[i][1]);
3435
+ if (this.ignoreAttributesFn(attrName, jPathStr)) continue;
3436
+ let aName = options.attributeNamePrefix + attrName;
3437
+ if (attrName.length) {
3438
+ if (options.transformAttributeName) aName = options.transformAttributeName(aName);
3439
+ aName = sanitizeName(aName, options);
3440
+ if (matches[i][4] !== void 0) {
3441
+ const oldVal = processedVals[i];
3442
+ const newVal = options.attributeValueProcessor(attrName, oldVal, jPathStr);
3443
+ if (newVal === null || newVal === void 0) attrs[aName] = oldVal;
3444
+ else if (typeof newVal !== typeof oldVal || newVal !== oldVal) attrs[aName] = newVal;
3445
+ else attrs[aName] = parseValue(oldVal, options.parseAttributeValue, options.numberParseOptions);
3446
+ hasAttrs = true;
3447
+ } else if (options.allowBooleanAttributes) {
3448
+ attrs[aName] = true;
3449
+ hasAttrs = true;
3450
+ }
3451
+ }
3452
+ }
3453
+ if (!hasAttrs) return;
3454
+ if (options.attributesGroupName && !options.preserveOrder) {
3455
+ const attrCollection = {};
3456
+ attrCollection[options.attributesGroupName] = attrs;
3457
+ return attrCollection;
3458
+ }
3459
+ return attrs;
3460
+ }
3461
+ }
3462
+ const parseXml = function(xmlData) {
3463
+ xmlData = xmlData.replace(/\r\n?/g, "\n");
3464
+ const xmlObj = new XmlNode("!xml");
3465
+ let currentNode = xmlObj;
3466
+ let textData = "";
3467
+ this.matcher.reset();
3468
+ this.entityDecoder.reset();
3469
+ this.entityExpansionCount = 0;
3470
+ this.currentExpandedLength = 0;
3471
+ this.doctypefound = false;
3472
+ const options = this.options;
3473
+ const docTypeReader = new DocTypeReader(options.processEntities);
3474
+ const xmlLen = xmlData.length;
3475
+ for (let i = 0; i < xmlLen; i++) if (xmlData[i] === "<") {
3476
+ const c1 = xmlData.charCodeAt(i + 1);
3477
+ if (c1 === 47) {
3478
+ const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.");
3479
+ let tagName = xmlData.substring(i + 2, closeIndex).trim();
3480
+ if (options.removeNSPrefix) {
3481
+ const colonIndex = tagName.indexOf(":");
3482
+ if (colonIndex !== -1) tagName = tagName.substr(colonIndex + 1);
3483
+ }
3484
+ tagName = transformTagName(options.transformTagName, tagName, "", options).tagName;
3485
+ if (currentNode) textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
3486
+ const lastTagName = this.matcher.getCurrentTag();
3487
+ if (tagName && options.unpairedTagsSet.has(tagName)) throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
3488
+ if (lastTagName && options.unpairedTagsSet.has(lastTagName)) {
3489
+ this.matcher.pop();
3490
+ this.tagsNodeStack.pop();
3491
+ }
3492
+ this.matcher.pop();
3493
+ this.isCurrentNodeStopNode = false;
3494
+ currentNode = this.tagsNodeStack.pop();
3495
+ textData = "";
3496
+ i = closeIndex;
3497
+ } else if (c1 === 63) {
3498
+ let tagData = readTagExp(xmlData, i, false, "?>");
3499
+ if (!tagData) throw new Error("Pi Tag is not closed.");
3500
+ textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
3501
+ const attsMap = this.buildAttributesMap(tagData.tagExp, this.matcher, tagData.tagName, true);
3502
+ if (attsMap) {
3503
+ const ver = attsMap[this.options.attributeNamePrefix + "version"];
3504
+ this.entityDecoder.setXmlVersion(Number(ver) || 1);
3505
+ docTypeReader.setXmlVersion(Number(ver) || 1);
3506
+ }
3507
+ if (options.ignoreDeclaration && tagData.tagName === "?xml" || options.ignorePiTags) {} else {
3508
+ const childNode = new XmlNode(tagData.tagName);
3509
+ childNode.add(options.textNodeName, "");
3510
+ if (tagData.tagName !== tagData.tagExp && tagData.attrExpPresent && options.ignoreAttributes !== true) childNode[":@"] = attsMap;
3511
+ this.addChild(currentNode, childNode, this.readonlyMatcher, i);
3512
+ }
3513
+ i = tagData.closeIndex + 1;
3514
+ } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) {
3515
+ const endIndex = findClosingIndex(xmlData, "-->", i + 4, "Comment is not closed.");
3516
+ if (options.commentPropName) {
3517
+ const comment = xmlData.substring(i + 4, endIndex - 2);
3518
+ textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
3519
+ currentNode.add(options.commentPropName, [{ [options.textNodeName]: comment }]);
3520
+ }
3521
+ i = endIndex;
3522
+ } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) {
3523
+ if (this.doctypefound) throw new Error("Multiple DOCTYPE declarations found.");
3524
+ this.doctypefound = true;
3525
+ const result = docTypeReader.readDocType(xmlData, i);
3526
+ this.entityDecoder.addInputEntities(result.entities);
3527
+ i = result.i;
3528
+ } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) {
3529
+ const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
3530
+ const tagExp = xmlData.substring(i + 9, closeIndex);
3531
+ textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher);
3532
+ let val = this.parseTextData(tagExp, currentNode.tagname, this.readonlyMatcher, true, false, true, true);
3533
+ if (val == void 0) val = "";
3534
+ if (options.cdataPropName) currentNode.add(options.cdataPropName, [{ [options.textNodeName]: tagExp }]);
3535
+ else currentNode.add(options.textNodeName, val);
3536
+ i = closeIndex + 2;
3537
+ } else {
3538
+ let result = readTagExp(xmlData, i, options.removeNSPrefix);
3539
+ if (!result) {
3540
+ const context = xmlData.substring(Math.max(0, i - 50), Math.min(xmlLen, i + 50));
3541
+ throw new Error(`readTagExp returned undefined at position ${i}. Context: "${context}"`);
3542
+ }
3543
+ let tagName = result.tagName;
3544
+ const rawTagName = result.rawTagName;
3545
+ let tagExp = result.tagExp;
3546
+ let attrExpPresent = result.attrExpPresent;
3547
+ let closeIndex = result.closeIndex;
3548
+ ({tagName, tagExp} = transformTagName(options.transformTagName, tagName, tagExp, options));
3549
+ if (options.strictReservedNames && (tagName === options.commentPropName || tagName === options.cdataPropName || tagName === options.textNodeName || tagName === options.attributesGroupName)) throw new Error(`Invalid tag name: ${tagName}`);
3550
+ if (currentNode && textData) {
3551
+ if (currentNode.tagname !== "!xml") textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher, false);
3552
+ }
3553
+ const lastTag = currentNode;
3554
+ if (lastTag && options.unpairedTagsSet.has(lastTag.tagname)) {
3555
+ currentNode = this.tagsNodeStack.pop();
3556
+ this.matcher.pop();
3557
+ }
3558
+ let isSelfClosing = false;
3559
+ if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
3560
+ isSelfClosing = true;
3561
+ if (tagName[tagName.length - 1] === "/") {
3562
+ tagName = tagName.substr(0, tagName.length - 1);
3563
+ tagExp = tagName;
3564
+ } else tagExp = tagExp.substr(0, tagExp.length - 1);
3565
+ attrExpPresent = tagName !== tagExp;
3566
+ }
3567
+ let prefixedAttrs = null;
3568
+ let namespace = void 0;
3569
+ namespace = extractNamespace(rawTagName);
3570
+ if (tagName !== xmlObj.tagname) this.matcher.push(tagName, {}, namespace);
3571
+ if (tagName !== tagExp && attrExpPresent) {
3572
+ prefixedAttrs = this.buildAttributesMap(tagExp, this.matcher, tagName);
3573
+ if (prefixedAttrs) extractRawAttributes(prefixedAttrs, options);
3574
+ }
3575
+ if (tagName !== xmlObj.tagname) this.isCurrentNodeStopNode = this.isItStopNode();
3576
+ const startIndex = i;
3577
+ if (this.isCurrentNodeStopNode) {
3578
+ let tagContent = "";
3579
+ if (isSelfClosing) i = result.closeIndex;
3580
+ else if (options.unpairedTagsSet.has(tagName)) i = result.closeIndex;
3581
+ else {
3582
+ const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
3583
+ if (!result) throw new Error(`Unexpected end of ${rawTagName}`);
3584
+ i = result.i;
3585
+ tagContent = result.tagContent;
3586
+ }
3587
+ const childNode = new XmlNode(tagName);
3588
+ if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
3589
+ childNode.add(options.textNodeName, tagContent);
3590
+ this.matcher.pop();
3591
+ this.isCurrentNodeStopNode = false;
3592
+ this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
3593
+ } else {
3594
+ if (isSelfClosing) {
3595
+ ({tagName, tagExp} = transformTagName(options.transformTagName, tagName, tagExp, options));
3596
+ const childNode = new XmlNode(tagName);
3597
+ if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
3598
+ this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
3599
+ this.matcher.pop();
3600
+ this.isCurrentNodeStopNode = false;
3601
+ } else if (options.unpairedTagsSet.has(tagName)) {
3602
+ const childNode = new XmlNode(tagName);
3603
+ if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
3604
+ this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
3605
+ this.matcher.pop();
3606
+ this.isCurrentNodeStopNode = false;
3607
+ i = result.closeIndex;
3608
+ continue;
3609
+ } else {
3610
+ const childNode = new XmlNode(tagName);
3611
+ if (this.tagsNodeStack.length > options.maxNestedTags) throw new Error("Maximum nested tags exceeded");
3612
+ this.tagsNodeStack.push(currentNode);
3613
+ if (prefixedAttrs) childNode[":@"] = prefixedAttrs;
3614
+ this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
3615
+ currentNode = childNode;
3616
+ }
3617
+ textData = "";
3618
+ i = closeIndex;
3619
+ }
3620
+ }
3621
+ } else textData += xmlData[i];
3622
+ return xmlObj.child;
3623
+ };
3624
+ function addChild(currentNode, childNode, matcher, startIndex) {
3625
+ if (!this.options.captureMetaData) startIndex = void 0;
3626
+ const jPathOrMatcher = this.options.jPath ? matcher.toString() : matcher;
3627
+ const result = this.options.updateTag(childNode.tagname, jPathOrMatcher, childNode[":@"]);
3628
+ if (result === false) {} else if (typeof result === "string") {
3629
+ childNode.tagname = result;
3630
+ currentNode.addChild(childNode, startIndex);
3631
+ } else currentNode.addChild(childNode, startIndex);
3632
+ }
3633
+ /**
3634
+ * @param {object} val - Entity object with regex and val properties
3635
+ * @param {string} tagName - Tag name
3636
+ * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath
3637
+ */
3638
+ function replaceEntitiesValue(val, tagName, jPath) {
3639
+ const entityConfig = this.options.processEntities;
3640
+ if (!entityConfig || !entityConfig.enabled) return val;
3641
+ if (entityConfig.allowedTags) {
3642
+ const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath;
3643
+ if (!(Array.isArray(entityConfig.allowedTags) ? entityConfig.allowedTags.includes(tagName) : entityConfig.allowedTags(tagName, jPathOrMatcher))) return val;
3644
+ }
3645
+ if (entityConfig.tagFilter) {
3646
+ const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath;
3647
+ if (!entityConfig.tagFilter(tagName, jPathOrMatcher)) return val;
3648
+ }
3649
+ return this.entityDecoder.decode(val);
3650
+ }
3651
+ function saveTextToParentTag(textData, parentNode, matcher, isLeafNode) {
3652
+ if (textData) {
3653
+ if (isLeafNode === void 0) isLeafNode = parentNode.child.length === 0;
3654
+ textData = this.parseTextData(textData, parentNode.tagname, matcher, false, parentNode[":@"] ? Object.keys(parentNode[":@"]).length !== 0 : false, isLeafNode);
3655
+ if (textData !== void 0 && textData !== "") parentNode.add(this.options.textNodeName, textData);
3656
+ textData = "";
3657
+ }
3658
+ return textData;
3659
+ }
3660
+ /**
3661
+ * @param {Array<Expression>} stopNodeExpressions - Array of compiled Expression objects
3662
+ * @param {Matcher} matcher - Current path matcher
3663
+ */
3664
+ function isItStopNode() {
3665
+ if (this.stopNodeExpressionsSet.size === 0) return false;
3666
+ return this.matcher.matchesAny(this.stopNodeExpressionsSet);
3667
+ }
3668
+ /**
3669
+ * Returns the tag Expression and where it is ending handling single-double quotes situation
3670
+ * @param {string} xmlData
3671
+ * @param {number} i starting index
3672
+ * @returns
3673
+ */
3674
+ function tagExpWithClosingIndex(xmlData, i, closingChar = ">") {
3675
+ let attrBoundary = 0;
3676
+ const len = xmlData.length;
3677
+ const closeCode0 = closingChar.charCodeAt(0);
3678
+ const closeCode1 = closingChar.length > 1 ? closingChar.charCodeAt(1) : -1;
3679
+ let result = "";
3680
+ let segmentStart = i;
3681
+ for (let index = i; index < len; index++) {
3682
+ const code = xmlData.charCodeAt(index);
3683
+ if (attrBoundary) {
3684
+ if (code === attrBoundary) attrBoundary = 0;
3685
+ } else if (code === 34 || code === 39) attrBoundary = code;
3686
+ else if (code === closeCode0) if (closeCode1 !== -1) {
3687
+ if (xmlData.charCodeAt(index + 1) === closeCode1) {
3688
+ result += xmlData.substring(segmentStart, index);
3689
+ return {
3690
+ data: result,
3691
+ index
3692
+ };
3693
+ }
3694
+ } else {
3695
+ result += xmlData.substring(segmentStart, index);
3696
+ return {
3697
+ data: result,
3698
+ index
3699
+ };
3700
+ }
3701
+ else if (code === 9 && !attrBoundary) {
3702
+ result += xmlData.substring(segmentStart, index) + " ";
3703
+ segmentStart = index + 1;
3704
+ }
3705
+ }
3706
+ }
3707
+ function findClosingIndex(xmlData, str, i, errMsg) {
3708
+ const closingIndex = xmlData.indexOf(str, i);
3709
+ if (closingIndex === -1) throw new Error(errMsg);
3710
+ else return closingIndex + str.length - 1;
3711
+ }
3712
+ function findClosingChar(xmlData, char, i, errMsg) {
3713
+ const closingIndex = xmlData.indexOf(char, i);
3714
+ if (closingIndex === -1) throw new Error(errMsg);
3715
+ return closingIndex;
3716
+ }
3717
+ function readTagExp(xmlData, i, removeNSPrefix, closingChar = ">") {
3718
+ const result = tagExpWithClosingIndex(xmlData, i + 1, closingChar);
3719
+ if (!result) return;
3720
+ let tagExp = result.data;
3721
+ const closeIndex = result.index;
3722
+ const separatorIndex = tagExp.search(/\s/);
3723
+ let tagName = tagExp;
3724
+ let attrExpPresent = true;
3725
+ if (separatorIndex !== -1) {
3726
+ tagName = tagExp.substring(0, separatorIndex);
3727
+ tagExp = tagExp.substring(separatorIndex + 1).trimStart();
3728
+ }
3729
+ const rawTagName = tagName;
3730
+ if (removeNSPrefix) {
3731
+ const colonIndex = tagName.indexOf(":");
3732
+ if (colonIndex !== -1) {
3733
+ tagName = tagName.substr(colonIndex + 1);
3734
+ attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
3735
+ }
3736
+ }
3737
+ return {
3738
+ tagName,
3739
+ tagExp,
3740
+ closeIndex,
3741
+ attrExpPresent,
3742
+ rawTagName
3743
+ };
3744
+ }
3745
+ /**
3746
+ * find paired tag for a stop node
3747
+ * @param {string} xmlData
3748
+ * @param {string} tagName
3749
+ * @param {number} i
3750
+ */
3751
+ function readStopNodeData(xmlData, tagName, i) {
3752
+ const startIndex = i;
3753
+ let openTagCount = 1;
3754
+ const xmllen = xmlData.length;
3755
+ for (; i < xmllen; i++) if (xmlData[i] === "<") {
3756
+ const c1 = xmlData.charCodeAt(i + 1);
3757
+ if (c1 === 47) {
3758
+ const closeIndex = findClosingChar(xmlData, ">", i, `${tagName} is not closed`);
3759
+ if (xmlData.substring(i + 2, closeIndex).trim() === tagName) {
3760
+ openTagCount--;
3761
+ if (openTagCount === 0) return {
3762
+ tagContent: xmlData.substring(startIndex, i),
3763
+ i: closeIndex
3764
+ };
3765
+ }
3766
+ i = closeIndex;
3767
+ } else if (c1 === 63) i = findClosingIndex(xmlData, "?>", i + 1, "StopNode is not closed.");
3768
+ else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) i = findClosingIndex(xmlData, "-->", i + 3, "StopNode is not closed.");
3769
+ else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) i = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
3770
+ else {
3771
+ const tagData = readTagExp(xmlData, i, false);
3772
+ if (tagData) {
3773
+ if ((tagData && tagData.tagName) === tagName && tagData.tagExp[tagData.tagExp.length - 1] !== "/") openTagCount++;
3774
+ i = tagData.closeIndex;
3775
+ }
3776
+ }
3777
+ }
3778
+ }
3779
+ function parseValue(val, shouldParse, options) {
3780
+ if (shouldParse && typeof val === "string") {
3781
+ const newval = val.trim();
3782
+ if (newval === "true") return true;
3783
+ else if (newval === "false") return false;
3784
+ else return toNumber(val, options);
3785
+ } else if (isExist(val)) return val;
3786
+ else return "";
3787
+ }
3788
+ function transformTagName(fn, tagName, tagExp, options) {
3789
+ if (fn) {
3790
+ const newTagName = fn(tagName);
3791
+ if (tagExp === tagName) tagExp = newTagName;
3792
+ tagName = newTagName;
3793
+ }
3794
+ tagName = sanitizeName(tagName, options);
3795
+ return {
3796
+ tagName,
3797
+ tagExp
3798
+ };
3799
+ }
3800
+ function sanitizeName(name, options) {
3801
+ if (criticalProperties.includes(name)) throw new Error(`[SECURITY] Invalid name: "${name}" is a reserved JavaScript keyword that could cause prototype pollution`);
3802
+ else if (DANGEROUS_PROPERTY_NAMES.includes(name)) return options.onDangerousProperty(name);
3803
+ return name;
3804
+ }
3805
+ //#endregion
3806
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/node2json.js
3807
+ const METADATA_SYMBOL = XmlNode.getMetaDataSymbol();
3808
+ /**
3809
+ * Helper function to strip attribute prefix from attribute map
3810
+ * @param {object} attrs - Attributes with prefix (e.g., {"@_class": "code"})
3811
+ * @param {string} prefix - Attribute prefix to remove (e.g., "@_")
3812
+ * @returns {object} Attributes without prefix (e.g., {"class": "code"})
3813
+ */
3814
+ function stripAttributePrefix(attrs, prefix) {
3815
+ if (!attrs || typeof attrs !== "object") return {};
3816
+ if (!prefix) return attrs;
3817
+ const rawAttrs = {};
3818
+ for (const key in attrs) if (key.startsWith(prefix)) {
3819
+ const rawName = key.substring(prefix.length);
3820
+ rawAttrs[rawName] = attrs[key];
3821
+ } else rawAttrs[key] = attrs[key];
3822
+ return rawAttrs;
3823
+ }
3824
+ /**
3825
+ *
3826
+ * @param {array} node
3827
+ * @param {any} options
3828
+ * @param {Matcher} matcher - Path matcher instance
3829
+ * @returns
3830
+ */
3831
+ function prettify(node, options, matcher, readonlyMatcher) {
3832
+ return compress(node, options, matcher, readonlyMatcher);
3833
+ }
3834
+ /**
3835
+ * @param {array} arr
3836
+ * @param {object} options
3837
+ * @param {Matcher} matcher - Path matcher instance
3838
+ * @returns object
3839
+ */
3840
+ function compress(arr, options, matcher, readonlyMatcher) {
3841
+ let text;
3842
+ const compressedObj = {};
3843
+ for (let i = 0; i < arr.length; i++) {
3844
+ const tagObj = arr[i];
3845
+ const property = propName(tagObj);
3846
+ if (property !== void 0 && property !== options.textNodeName) {
3847
+ const rawAttrs = stripAttributePrefix(tagObj[":@"] || {}, options.attributeNamePrefix);
3848
+ matcher.push(property, rawAttrs);
3849
+ }
3850
+ if (property === options.textNodeName) if (text === void 0) text = tagObj[property];
3851
+ else text += "" + tagObj[property];
3852
+ else if (property === void 0) continue;
3853
+ else if (tagObj[property]) {
3854
+ let val = compress(tagObj[property], options, matcher, readonlyMatcher);
3855
+ const isLeaf = isLeafTag(val, options);
3856
+ if (Object.keys(val).length === 0 && options.alwaysCreateTextNode) val[options.textNodeName] = "";
3857
+ if (tagObj[":@"]) assignAttributes(val, tagObj[":@"], readonlyMatcher, options);
3858
+ else if (Object.keys(val).length === 1 && val[options.textNodeName] !== void 0 && !options.alwaysCreateTextNode) val = val[options.textNodeName];
3859
+ else if (Object.keys(val).length === 0) if (options.alwaysCreateTextNode) val[options.textNodeName] = "";
3860
+ else val = "";
3861
+ if (tagObj[METADATA_SYMBOL] !== void 0 && typeof val === "object" && val !== null) val[METADATA_SYMBOL] = tagObj[METADATA_SYMBOL];
3862
+ if (compressedObj[property] !== void 0 && Object.prototype.hasOwnProperty.call(compressedObj, property)) {
3863
+ if (!Array.isArray(compressedObj[property])) compressedObj[property] = [compressedObj[property]];
3864
+ compressedObj[property].push(val);
3865
+ } else {
3866
+ const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() : readonlyMatcher;
3867
+ if (options.isArray(property, jPathOrMatcher, isLeaf)) compressedObj[property] = [val];
3868
+ else compressedObj[property] = val;
3869
+ }
3870
+ if (property !== void 0 && property !== options.textNodeName) matcher.pop();
3871
+ }
3872
+ }
3873
+ if (typeof text === "string") {
3874
+ if (text.length > 0) compressedObj[options.textNodeName] = text;
3875
+ } else if (text !== void 0) compressedObj[options.textNodeName] = text;
3876
+ return compressedObj;
3877
+ }
3878
+ function propName(obj) {
3879
+ const keys = Object.keys(obj);
3880
+ for (let i = 0; i < keys.length; i++) {
3881
+ const key = keys[i];
3882
+ if (key !== ":@") return key;
3883
+ }
3884
+ }
3885
+ function assignAttributes(obj, attrMap, readonlyMatcher, options) {
3886
+ if (attrMap) {
3887
+ const keys = Object.keys(attrMap);
3888
+ const len = keys.length;
3889
+ for (let i = 0; i < len; i++) {
3890
+ const atrrName = keys[i];
3891
+ const rawAttrName = atrrName.startsWith(options.attributeNamePrefix) ? atrrName.substring(options.attributeNamePrefix.length) : atrrName;
3892
+ const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() + "." + rawAttrName : readonlyMatcher;
3893
+ if (options.isArray(atrrName, jPathOrMatcher, true, true)) obj[atrrName] = [attrMap[atrrName]];
3894
+ else obj[atrrName] = attrMap[atrrName];
3895
+ }
3896
+ }
3897
+ }
3898
+ function isLeafTag(obj, options) {
3899
+ const { textNodeName } = options;
3900
+ const propCount = Object.keys(obj).length;
3901
+ if (propCount === 0) return true;
3902
+ if (propCount === 1 && (obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0)) return true;
3903
+ return false;
3904
+ }
3905
+ //#endregion
3906
+ //#region ../../node_modules/.pnpm/fast-xml-parser@5.10.1/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
3907
+ var XMLParser = class {
3908
+ constructor(options) {
3909
+ this.externalEntities = {};
3910
+ this.options = buildOptions(options);
3911
+ }
3912
+ /**
3913
+ * Parse XML dats to JS object
3914
+ * @param {string|Uint8Array} xmlData
3915
+ * @param {boolean|Object} validationOption
3916
+ */
3917
+ parse(xmlData, validationOption) {
3918
+ if (typeof xmlData !== "string" && xmlData.toString) xmlData = xmlData.toString();
3919
+ else if (typeof xmlData !== "string") throw new Error("XML data is accepted in String or Bytes[] form.");
3920
+ if (validationOption) {
3921
+ if (validationOption === true) validationOption = {};
3922
+ const result = validate(xmlData, validationOption);
3923
+ if (result !== true) throw Error(`${result.err.msg}:${result.err.line}:${result.err.col}`);
3924
+ }
3925
+ const orderedObjParser = new OrderedObjParser(this.options, this.externalEntities);
3926
+ const orderedResult = orderedObjParser.parseXml(xmlData);
3927
+ if (this.options.preserveOrder || orderedResult === void 0) return orderedResult;
3928
+ else return prettify(orderedResult, this.options, orderedObjParser.matcher, orderedObjParser.readonlyMatcher);
3929
+ }
3930
+ /**
3931
+ * Add Entity which is not by default supported by this library
3932
+ * @param {string} key
3933
+ * @param {string} value
3934
+ */
3935
+ addEntity(key, value) {
3936
+ if (value.indexOf("&") !== -1) throw new Error("Entity value can't have '&'");
3937
+ else if (key.indexOf("&") !== -1 || key.indexOf(";") !== -1) throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '&#xD;'");
3938
+ else if (value === "&") throw new Error("An entity with value '&' is not permitted");
3939
+ else this.externalEntities[key] = value;
3940
+ }
3941
+ /**
3942
+ * Returns a Symbol that can be used to access the metadata
3943
+ * property on a node.
3944
+ *
3945
+ * If Symbol is not available in the environment, an ordinary property is used
3946
+ * and the name of the property is here returned.
3947
+ *
3948
+ * The XMLMetaData property is only present when `captureMetaData`
3949
+ * is true in the options.
3950
+ */
3951
+ static getMetaDataSymbol() {
3952
+ return XmlNode.getMetaDataSymbol();
3953
+ }
3954
+ };
3955
+ //#endregion
3956
+ export { require_base64_js as n, XMLParser as t };