UNPKG

hot-updater

Version:

React Native OTA solution for self-hosted

2,041 lines 591 kB
import { createRequire } from "node:module"; import fs from "fs"; import path from "path"; import { colors, getCwd, loadConfig, p } from "@hot-updater/cli-tools"; import crypto from "node:crypto"; import fs$1 from "node:fs/promises"; import path$1 from "node:path"; //#region \0rolldown/runtime.js var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports); var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); var __require = /* @__PURE__ */ createRequire(import.meta.url); //#endregion //#region ../../node_modules/.pnpm/fast-xml-parser@5.7.2/node_modules/fast-xml-parser/src/util.js const nameStartChar = ":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; nameStartChar + ""; const nameRegexp = "[" + nameStartChar + "][:A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*"; const regexName = new RegExp("^" + nameRegexp + "$"); function getAllMatches(string, regex) { const matches = []; let match = regex.exec(string); while (match) { const allmatches = []; allmatches.startIndex = regex.lastIndex - match[0].length; const len = match.length; for (let index = 0; index < len; index++) allmatches.push(match[index]); matches.push(allmatches); match = regex.exec(string); } return matches; } const isName = function(string) { const match = regexName.exec(string); return !(match === null || typeof match === "undefined"); }; function isExist(v) { return typeof v !== "undefined"; } /** * Dangerous property names that could lead to prototype pollution or security issues */ const DANGEROUS_PROPERTY_NAMES = [ "hasOwnProperty", "toString", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__" ]; const criticalProperties = [ "__proto__", "constructor", "prototype" ]; //#endregion //#region ../../node_modules/.pnpm/fast-xml-parser@5.7.2/node_modules/fast-xml-parser/src/validator.js const defaultOptions$2 = { allowBooleanAttributes: false, unpairedTags: [] }; function validate(xmlData, options) { options = Object.assign({}, defaultOptions$2, options); const tags = []; let tagFound = false; let reachedRoot = false; if (xmlData[0] === "") xmlData = xmlData.substr(1); for (let i = 0; i < xmlData.length; i++) if (xmlData[i] === "<" && xmlData[i + 1] === "?") { i += 2; i = readPI(xmlData, i); if (i.err) return i; } else if (xmlData[i] === "<") { let tagStartPos = i; i++; if (xmlData[i] === "!") { i = readCommentAndCDATA(xmlData, i); continue; } else { let closingTag = false; if (xmlData[i] === "/") { closingTag = true; i++; } let tagName = ""; for (; i < xmlData.length && xmlData[i] !== ">" && xmlData[i] !== " " && xmlData[i] !== " " && xmlData[i] !== "\n" && xmlData[i] !== "\r"; i++) tagName += xmlData[i]; tagName = tagName.trim(); if (tagName[tagName.length - 1] === "/") { tagName = tagName.substring(0, tagName.length - 1); i--; } if (!validateTagName(tagName)) { let msg; if (tagName.trim().length === 0) msg = "Invalid space after '<'."; else msg = "Tag '" + tagName + "' is an invalid name."; return getErrorObject("InvalidTag", msg, getLineNumberForPosition(xmlData, i)); } const result = readAttributeStr(xmlData, i); if (result === false) return getErrorObject("InvalidAttr", "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i)); let attrStr = result.value; i = result.index; if (attrStr[attrStr.length - 1] === "/") { const attrStrStart = i - attrStr.length; attrStr = attrStr.substring(0, attrStr.length - 1); const isValid = validateAttributeString(attrStr, options); if (isValid === true) tagFound = true; else return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line)); } else if (closingTag) if (!result.tagClosed) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i)); else if (attrStr.trim().length > 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos)); else if (tags.length === 0) return getErrorObject("InvalidTag", "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos)); else { const otg = tags.pop(); if (tagName !== otg.tagName) { let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos); return getErrorObject("InvalidTag", "Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.", getLineNumberForPosition(xmlData, tagStartPos)); } if (tags.length == 0) reachedRoot = true; } else { const isValid = validateAttributeString(attrStr, options); if (isValid !== true) return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line)); if (reachedRoot === true) return getErrorObject("InvalidXml", "Multiple possible root nodes found.", getLineNumberForPosition(xmlData, i)); else if (options.unpairedTags.indexOf(tagName) !== -1) {} else tags.push({ tagName, tagStartPos }); tagFound = true; } for (i++; i < xmlData.length; i++) if (xmlData[i] === "<") if (xmlData[i + 1] === "!") { i++; i = readCommentAndCDATA(xmlData, i); continue; } else if (xmlData[i + 1] === "?") { i = readPI(xmlData, ++i); if (i.err) return i; } else break; else if (xmlData[i] === "&") { const afterAmp = validateAmpersand(xmlData, i); if (afterAmp == -1) return getErrorObject("InvalidChar", "char '&' is not expected.", getLineNumberForPosition(xmlData, i)); i = afterAmp; } else if (reachedRoot === true && !isWhiteSpace(xmlData[i])) return getErrorObject("InvalidXml", "Extra text at the end", getLineNumberForPosition(xmlData, i)); if (xmlData[i] === "<") i--; } } else { if (isWhiteSpace(xmlData[i])) continue; return getErrorObject("InvalidChar", "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i)); } if (!tagFound) return getErrorObject("InvalidXml", "Start tag expected.", 1); else if (tags.length == 1) return getErrorObject("InvalidTag", "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos)); else if (tags.length > 0) return getErrorObject("InvalidXml", "Invalid '" + JSON.stringify(tags.map((t) => t.tagName), null, 4).replace(/\r?\n/g, "") + "' found.", { line: 1, col: 1 }); return true; } function isWhiteSpace(char) { return char === " " || char === " " || char === "\n" || char === "\r"; } /** * Read Processing insstructions and skip * @param {*} xmlData * @param {*} i */ function readPI(xmlData, i) { const start = i; for (; i < xmlData.length; i++) if (xmlData[i] == "?" || xmlData[i] == " ") { const tagname = xmlData.substr(start, i - start); if (i > 5 && tagname === "xml") return getErrorObject("InvalidXml", "XML declaration allowed only at the start of the document.", getLineNumberForPosition(xmlData, i)); else if (xmlData[i] == "?" && xmlData[i + 1] == ">") { i++; break; } else continue; } return i; } function readCommentAndCDATA(xmlData, i) { if (xmlData.length > i + 5 && xmlData[i + 1] === "-" && xmlData[i + 2] === "-") { for (i += 3; i < xmlData.length; i++) if (xmlData[i] === "-" && xmlData[i + 1] === "-" && xmlData[i + 2] === ">") { i += 2; break; } } 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") { let angleBracketsCount = 1; for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "<") angleBracketsCount++; else if (xmlData[i] === ">") { angleBracketsCount--; if (angleBracketsCount === 0) break; } } 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] === "[") { for (i += 8; i < xmlData.length; i++) if (xmlData[i] === "]" && xmlData[i + 1] === "]" && xmlData[i + 2] === ">") { i += 2; break; } } return i; } const doubleQuote = "\""; const singleQuote = "'"; /** * Keep reading xmlData until '<' is found outside the attribute value. * @param {string} xmlData * @param {number} i */ function readAttributeStr(xmlData, i) { let attrStr = ""; let startChar = ""; let tagClosed = false; for (; i < xmlData.length; i++) { if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) if (startChar === "") startChar = xmlData[i]; else if (startChar !== xmlData[i]) {} else startChar = ""; else if (xmlData[i] === ">") { if (startChar === "") { tagClosed = true; break; } } attrStr += xmlData[i]; } if (startChar !== "") return false; return { value: attrStr, index: i, tagClosed }; } /** * Select all the attributes whether valid or invalid. */ const validAttrStrRegxp = /* @__PURE__ */ new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?", "g"); function validateAttributeString(attrStr, options) { const matches = getAllMatches(attrStr, validAttrStrRegxp); const attrNames = {}; for (let i = 0; i < matches.length; i++) { if (matches[i][1].length === 0) return getErrorObject("InvalidAttr", "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i])); 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])); else if (matches[i][3] === void 0 && !options.allowBooleanAttributes) return getErrorObject("InvalidAttr", "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i])); const attrName = matches[i][2]; if (!validateAttrName(attrName)) return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i])); if (!Object.prototype.hasOwnProperty.call(attrNames, attrName)) attrNames[attrName] = 1; else return getErrorObject("InvalidAttr", "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i])); } return true; } function validateNumberAmpersand(xmlData, i) { let re = /\d/; if (xmlData[i] === "x") { i++; re = /[\da-fA-F]/; } for (; i < xmlData.length; i++) { if (xmlData[i] === ";") return i; if (!xmlData[i].match(re)) break; } return -1; } function validateAmpersand(xmlData, i) { i++; if (xmlData[i] === ";") return -1; if (xmlData[i] === "#") { i++; return validateNumberAmpersand(xmlData, i); } let count = 0; for (; i < xmlData.length; i++, count++) { if (xmlData[i].match(/\w/) && count < 20) continue; if (xmlData[i] === ";") break; return -1; } return i; } function getErrorObject(code, message, lineNumber) { return { err: { code, msg: message, line: lineNumber.line || lineNumber, col: lineNumber.col } }; } function validateAttrName(attrName) { return isName(attrName); } function validateTagName(tagname) { return isName(tagname); } function getLineNumberForPosition(xmlData, index) { const lines = xmlData.substring(0, index).split(/\r?\n/); return { line: lines.length, col: lines[lines.length - 1].length + 1 }; } function getPositionFromMatch(match) { return match.startIndex + match[1].length; } //#endregion //#region ../../node_modules/.pnpm/@nodable+entities@2.1.0/node_modules/@nodable/entities/src/entities.js /** * Basic Latin & Special Characters * @type {Record<string, string>} */ const BASIC_LATIN = { amp: "&", AMP: "&", lt: "<", LT: "<", gt: ">", GT: ">", quot: "\"", QUOT: "\"", apos: "'", lsquo: "‘", rsquo: "’", ldquo: "“", rdquo: "”", lsquor: "‚", rsquor: "’", ldquor: "„", bdquo: "„", comma: ",", period: ".", colon: ":", semi: ";", excl: "!", quest: "?", num: "#", dollar: "$", percent: "%", amp: "&", ast: "*", commat: "@", lowbar: "_", verbar: "|", vert: "|", sol: "/", bsol: "\\", lbrace: "{", rbrace: "}", lbrack: "[", rbrack: "]", lpar: "(", rpar: ")", nbsp: "\xA0", iexcl: "¡", cent: "¢", pound: "£", curren: "¤", yen: "¥", brvbar: "¦", sect: "§", uml: "¨", copy: "©", COPY: "©", ordf: "ª", laquo: "«", not: "¬", shy: "­", reg: "®", REG: "®", macr: "¯", deg: "°", plusmn: "±", sup2: "²", sup3: "³", acute: "´", micro: "µ", para: "¶", middot: "·", cedil: "¸", sup1: "¹", ordm: "º", raquo: "»", frac14: "¼", frac12: "½", half: "½", frac34: "¾", iquest: "¿", times: "×", div: "÷", divide: "÷" }; /** * Latin Extended & Accented Letters (A-Z) * @type {Record<string, string>} */ const LATIN_ACCENTS = { Agrave: "À", agrave: "à", Aacute: "Á", aacute: "á", Acirc: "Â", acirc: "â", Atilde: "Ã", atilde: "ã", Auml: "Ä", auml: "ä", Aring: "Å", aring: "å", AElig: "Æ", aelig: "æ", Ccedil: "Ç", ccedil: "ç", Egrave: "È", egrave: "è", Eacute: "É", eacute: "é", Ecirc: "Ê", ecirc: "ê", Euml: "Ë", euml: "ë", Igrave: "Ì", igrave: "ì", Iacute: "Í", iacute: "í", Icirc: "Î", icirc: "î", Iuml: "Ï", iuml: "ï", ETH: "Ð", eth: "ð", Ntilde: "Ñ", ntilde: "ñ", Ograve: "Ò", ograve: "ò", Oacute: "Ó", oacute: "ó", Ocirc: "Ô", ocirc: "ô", Otilde: "Õ", otilde: "õ", Ouml: "Ö", ouml: "ö", Oslash: "Ø", oslash: "ø", Ugrave: "Ù", ugrave: "ù", Uacute: "Ú", uacute: "ú", Ucirc: "Û", ucirc: "û", Uuml: "Ü", uuml: "ü", Yacute: "Ý", yacute: "ý", THORN: "Þ", thorn: "þ", szlig: "ß", yuml: "ÿ", Yuml: "Ÿ" }; /** * Latin Extended (Letters with diacritics) * @type {Record<string, string>} */ const LATIN_EXTENDED = { Amacr: "Ā", amacr: "ā", Abreve: "Ă", abreve: "ă", Aogon: "Ą", aogon: "ą", Cacute: "Ć", cacute: "ć", Ccirc: "Ĉ", ccirc: "ĉ", Cdot: "Ċ", cdot: "ċ", Ccaron: "Č", ccaron: "č", Dcaron: "Ď", dcaron: "ď", Dstrok: "Đ", dstrok: "đ", Emacr: "Ē", emacr: "ē", Ecaron: "Ě", ecaron: "ě", Edot: "Ė", edot: "ė", Eogon: "Ę", eogon: "ę", Gcirc: "Ĝ", gcirc: "ĝ", Gbreve: "Ğ", gbreve: "ğ", Gdot: "Ġ", gdot: "ġ", Gcedil: "Ģ", Hcirc: "Ĥ", hcirc: "ĥ", Hstrok: "Ħ", hstrok: "ħ", Itilde: "Ĩ", itilde: "ĩ", Imacr: "Ī", imacr: "ī", Iogon: "Į", iogon: "į", Idot: "İ", IJlig: "IJ", ijlig: "ij", Jcirc: "Ĵ", jcirc: "ĵ", Kcedil: "Ķ", kcedil: "ķ", kgreen: "ĸ", Lacute: "Ĺ", lacute: "ĺ", Lcedil: "Ļ", lcedil: "ļ", Lcaron: "Ľ", lcaron: "ľ", Lmidot: "Ŀ", lmidot: "ŀ", Lstrok: "Ł", lstrok: "ł", Nacute: "Ń", nacute: "ń", Ncaron: "Ň", ncaron: "ň", Ncedil: "Ņ", ncedil: "ņ", ENG: "Ŋ", eng: "ŋ", Omacr: "Ō", omacr: "ō", Odblac: "Ő", odblac: "ő", OElig: "Œ", oelig: "œ", Racute: "Ŕ", racute: "ŕ", Rcaron: "Ř", rcaron: "ř", Rcedil: "Ŗ", rcedil: "ŗ", Sacute: "Ś", sacute: "ś", Scirc: "Ŝ", scirc: "ŝ", Scedil: "Ş", scedil: "ş", Scaron: "Š", scaron: "š", Tcedil: "Ţ", tcedil: "ţ", Tcaron: "Ť", tcaron: "ť", Tstrok: "Ŧ", tstrok: "ŧ", Utilde: "Ũ", utilde: "ũ", Umacr: "Ū", umacr: "ū", Ubreve: "Ŭ", ubreve: "ŭ", Uring: "Ů", uring: "ů", Udblac: "Ű", udblac: "ű", Uogon: "Ų", uogon: "ų", Wcirc: "Ŵ", wcirc: "ŵ", Ycirc: "Ŷ", ycirc: "ŷ", Zacute: "Ź", zacute: "ź", Zdot: "Ż", zdot: "ż", Zcaron: "Ž", zcaron: "ž" }; /** * Greek Letters * @type {Record<string, string>} */ const GREEK = { Alpha: "Α", alpha: "α", Beta: "Β", beta: "β", Gamma: "Γ", gamma: "γ", Delta: "Δ", delta: "δ", Epsilon: "Ε", epsilon: "ε", epsiv: "ϵ", varepsilon: "ϵ", Zeta: "Ζ", zeta: "ζ", Eta: "Η", eta: "η", Theta: "Θ", theta: "θ", thetasym: "ϑ", vartheta: "ϑ", Iota: "Ι", iota: "ι", Kappa: "Κ", kappa: "κ", kappav: "ϰ", varkappa: "ϰ", Lambda: "Λ", lambda: "λ", Mu: "Μ", mu: "μ", Nu: "Ν", nu: "ν", Xi: "Ξ", xi: "ξ", Omicron: "Ο", omicron: "ο", Pi: "Π", pi: "π", piv: "ϖ", varpi: "ϖ", Rho: "Ρ", rho: "ρ", rhov: "ϱ", varrho: "ϱ", Sigma: "Σ", sigma: "σ", sigmaf: "ς", sigmav: "ς", varsigma: "ς", Tau: "Τ", tau: "τ", Upsilon: "Υ", upsilon: "υ", upsi: "υ", Upsi: "ϒ", upsih: "ϒ", Phi: "Φ", phi: "φ", phiv: "ϕ", varphi: "ϕ", Chi: "Χ", chi: "χ", Psi: "Ψ", psi: "ψ", Omega: "Ω", omega: "ω", ohm: "Ω", Gammad: "Ϝ", gammad: "ϝ", digamma: "ϝ" }; /** * Cyrillic Letters * @type {Record<string, string>} */ const CYRILLIC = { Afr: "𝔄", afr: "𝔞", Acy: "А", acy: "а", Bcy: "Б", bcy: "б", Vcy: "В", vcy: "в", Gcy: "Г", gcy: "г", Dcy: "Д", dcy: "д", IEcy: "Е", iecy: "е", IOcy: "Ё", iocy: "ё", ZHcy: "Ж", zhcy: "ж", Zcy: "З", zcy: "з", Icy: "И", icy: "и", Jcy: "Й", jcy: "й", Kcy: "К", kcy: "к", Lcy: "Л", lcy: "л", Mcy: "М", mcy: "м", Ncy: "Н", ncy: "н", Ocy: "О", ocy: "о", Pcy: "П", pcy: "п", Rcy: "Р", rcy: "р", Scy: "С", scy: "с", Tcy: "Т", tcy: "т", Ucy: "У", ucy: "у", Fcy: "Ф", fcy: "ф", KHcy: "Х", khcy: "х", TScy: "Ц", tscy: "ц", CHcy: "Ч", chcy: "ч", SHcy: "Ш", shcy: "ш", SHCHcy: "Щ", shchcy: "щ", HARDcy: "Ъ", hardcy: "ъ", Ycy: "Ы", ycy: "ы", SOFTcy: "Ь", softcy: "ь", Ecy: "Э", ecy: "э", YUcy: "Ю", yucy: "ю", YAcy: "Я", yacy: "я", DJcy: "Ђ", djcy: "ђ", GJcy: "Ѓ", gjcy: "ѓ", Jukcy: "Є", jukcy: "є", DScy: "Ѕ", dscy: "ѕ", Iukcy: "І", iukcy: "і", YIcy: "Ї", yicy: "ї", Jsercy: "Ј", jsercy: "ј", LJcy: "Љ", ljcy: "љ", NJcy: "Њ", njcy: "њ", TSHcy: "Ћ", tshcy: "ћ", KJcy: "Ќ", kjcy: "ќ", Ubrcy: "Ў", ubrcy: "ў", DZcy: "Џ", dzcy: "џ" }; /** * Mathematical Operators & Relations * @type {Record<string, string>} */ const MATH = { plus: "+", minus: "−", mnplus: "∓", mp: "∓", pm: "±", times: "×", div: "÷", divide: "÷", sdot: "⋅", star: "☆", starf: "★", bigstar: "★", lowast: "∗", ast: "*", midast: "*", compfn: "∘", smallcircle: "∘", bullet: "•", bull: "•", nbsp: "\xA0", hellip: "…", mldr: "…", prime: "′", Prime: "″", tprime: "‴", bprime: "‵", backprime: "‵", minus: "−", minusd: "∸", dotminus: "∸", plusdo: "∔", dotplus: "∔", plusmn: "±", minusplus: "∓", mnplus: "∓", mp: "∓", setminus: "∖", smallsetminus: "∖", Backslash: "∖", setmn: "∖", ssetmn: "∖", lowbar: "_", verbar: "|", vert: "|", VerticalLine: "|", colon: ":", Colon: "∷", Proportion: "∷", ratio: "∶", equals: "=", ne: "≠", nequiv: "≢", equiv: "≡", Congruent: "≡", sim: "∼", thicksim: "∼", thksim: "∼", sime: "≃", simeq: "≃", TildeEqual: "≃", asymp: "≈", approx: "≈", thickapprox: "≈", thkap: "≈", TildeTilde: "≈", ncong: "≇", cong: "≅", TildeFullEqual: "≅", asympeq: "≍", CupCap: "≍", bump: "≎", Bumpeq: "≎", HumpDownHump: "≎", bumpe: "≏", bumpeq: "≏", HumpEqual: "≏", dotminus: "∸", minusd: "∸", plusdo: "∔", dotplus: "∔", le: "≤", LessEqual: "≤", ge: "≥", GreaterEqual: "≥", lesseqgtr: "⋚", lesseqqgtr: "⪋", greater: ">", less: "<" }; /** * Mathematical Operators (Advanced) * @type {Record<string, string>} */ const MATH_ADVANCED = { alefsym: "ℵ", aleph: "ℵ", beth: "ℶ", gimel: "ℷ", daleth: "ℸ", forall: "∀", ForAll: "∀", part: "∂", PartialD: "∂", exist: "∃", Exists: "∃", nexist: "∄", nexists: "∄", empty: "∅", emptyset: "∅", emptyv: "∅", varnothing: "∅", nabla: "∇", Del: "∇", isin: "∈", isinv: "∈", in: "∈", Element: "∈", notin: "∉", notinva: "∉", ni: "∋", niv: "∋", SuchThat: "∋", ReverseElement: "∋", notni: "∌", notniva: "∌", prod: "∏", Product: "∏", coprod: "∐", Coproduct: "∐", sum: "∑", Sum: "∑", minus: "−", mp: "∓", plusdo: "∔", dotplus: "∔", setminus: "∖", lowast: "∗", radic: "√", Sqrt: "√", prop: "∝", propto: "∝", Proportional: "∝", varpropto: "∝", infin: "∞", infintie: "⧝", ang: "∠", angle: "∠", angmsd: "∡", measuredangle: "∡", angsph: "∢", mid: "∣", VerticalBar: "∣", nmid: "∤", nsmid: "∤", npar: "∦", parallel: "∥", spar: "∥", nparallel: "∦", nspar: "∦", and: "∧", wedge: "∧", or: "∨", vee: "∨", cap: "∩", cup: "∪", int: "∫", Integral: "∫", conint: "∮", ContourIntegral: "∮", Conint: "∯", DoubleContourIntegral: "∯", Cconint: "∰", there4: "∴", therefore: "∴", Therefore: "∴", becaus: "∵", because: "∵", Because: "∵", ratio: "∶", Proportion: "∷", minusd: "∸", dotminus: "∸", mDDot: "∺", homtht: "∻", sim: "∼", bsimg: "∽", backsim: "∽", ac: "∾", mstpos: "∾", acd: "∿", VerticalTilde: "≀", wr: "≀", wreath: "≀", nsime: "≄", nsimeq: "≄", nsimeq: "≄", ncong: "≇", simne: "≆", ncongdot: "⩭̸", ngsim: "≵", nsim: "≁", napprox: "≉", nap: "≉", ngeq: "≱", nge: "≱", nleq: "≰", nle: "≰", ngtr: "≯", ngt: "≯", nless: "≮", nlt: "≮", nprec: "⊀", npr: "⊀", nsucc: "⊁", nsc: "⊁" }; /** * Arrows * @type {Record<string, string>} */ const ARROWS = { larr: "←", leftarrow: "←", LeftArrow: "←", uarr: "↑", uparrow: "↑", UpArrow: "↑", rarr: "→", rightarrow: "→", RightArrow: "→", darr: "↓", downarrow: "↓", DownArrow: "↓", harr: "↔", leftrightarrow: "↔", LeftRightArrow: "↔", varr: "↕", updownarrow: "↕", UpDownArrow: "↕", nwarr: "↖", nwarrow: "↖", UpperLeftArrow: "↖", nearr: "↗", nearrow: "↗", UpperRightArrow: "↗", searr: "↘", searrow: "↘", LowerRightArrow: "↘", swarr: "↙", swarrow: "↙", LowerLeftArrow: "↙", lArr: "⇐", Leftarrow: "⇐", uArr: "⇑", Uparrow: "⇑", rArr: "⇒", Rightarrow: "⇒", dArr: "⇓", Downarrow: "⇓", hArr: "⇔", Leftrightarrow: "⇔", iff: "⇔", vArr: "⇕", Updownarrow: "⇕", lAarr: "⇚", Lleftarrow: "⇚", rAarr: "⇛", Rrightarrow: "⇛", lrarr: "⇆", leftrightarrows: "⇆", rlarr: "⇄", rightleftarrows: "⇄", lrhar: "⇋", leftrightharpoons: "⇋", ReverseEquilibrium: "⇋", rlhar: "⇌", rightleftharpoons: "⇌", Equilibrium: "⇌", udarr: "⇅", UpArrowDownArrow: "⇅", duarr: "⇵", DownArrowUpArrow: "⇵", llarr: "⇇", leftleftarrows: "⇇", rrarr: "⇉", rightrightarrows: "⇉", ddarr: "⇊", downdownarrows: "⇊", har: "↽", lhard: "↽", leftharpoondown: "↽", lharu: "↼", leftharpoonup: "↼", rhard: "⇁", rightharpoondown: "⇁", rharu: "⇀", rightharpoonup: "⇀", lsh: "↰", Lsh: "↰", rsh: "↱", Rsh: "↱", ldsh: "↲", rdsh: "↳", hookleftarrow: "↩", hookrightarrow: "↪", mapstoleft: "↤", mapstoup: "↥", map: "↦", mapsto: "↦", mapstodown: "↧", crarr: "↵", nwarrow: "↖", nearrow: "↗", searrow: "↘", swarrow: "↙", nleftarrow: "↚", nleftrightarrow: "↮", nrightarrow: "↛", nrarr: "↛", larrtl: "↢", rarrtl: "↣", leftarrowtail: "↢", rightarrowtail: "↣", twoheadleftarrow: "↞", twoheadrightarrow: "↠", Larr: "↞", Rarr: "↠", larrhk: "↩", rarrhk: "↪", larrlp: "↫", looparrowleft: "↫", rarrlp: "↬", looparrowright: "↬", harrw: "↭", leftrightsquigarrow: "↭", nrarrw: "↝̸", rarrw: "↝", rightsquigarrow: "↝", larrbfs: "⤟", rarrbfs: "⤠", nvHarr: "⤄", nvlArr: "⤂", nvrArr: "⤃", larrfs: "⤝", rarrfs: "⤞", Map: "⤅", larrsim: "⥳", rarrsim: "⥴", harrcir: "⥈", Uarrocir: "⥉", lurdshar: "⥊", ldrdhar: "⥧", ldrushar: "⥋", rdldhar: "⥩", lrhard: "⥭", rlhar: "⇌", uharr: "↾", uharl: "↿", dharr: "⇂", dharl: "⇃", Uarr: "↟", Darr: "↡", zigrarr: "⇝", nwArr: "⇖", neArr: "⇗", seArr: "⇘", swArr: "⇙", nharr: "↮", nhArr: "⇎", nlarr: "↚", nlArr: "⇍", nrarr: "↛", nrArr: "⇏", larrb: "⇤", LeftArrowBar: "⇤", rarrb: "⇥", RightArrowBar: "⇥" }; /** * Geometric Shapes * @type {Record<string, string>} */ const SHAPES = { square: "□", Square: "□", squ: "□", squf: "▪", squarf: "▪", blacksquar: "▪", blacksquare: "▪", FilledVerySmallSquare: "▪", blk34: "▓", blk12: "▒", blk14: "░", block: "█", srect: "▭", rect: "▭", sdot: "⋅", sdotb: "⊡", dotsquare: "⊡", triangle: "▵", tri: "▵", trine: "▵", utri: "▵", triangledown: "▿", dtri: "▿", tridown: "▿", triangleleft: "◃", ltri: "◃", triangleright: "▹", rtri: "▹", blacktriangle: "▴", utrif: "▴", blacktriangledown: "▾", dtrif: "▾", blacktriangleleft: "◂", ltrif: "◂", blacktriangleright: "▸", rtrif: "▸", loz: "◊", lozenge: "◊", blacklozenge: "⧫", lozf: "⧫", bigcirc: "◯", xcirc: "◯", circ: "ˆ", Circle: "○", cir: "○", o: "○", bullet: "•", bull: "•", hellip: "…", mldr: "…", nldr: "‥", boxh: "─", HorizontalLine: "─", boxv: "│", boxdr: "┌", boxdl: "┐", boxur: "└", boxul: "┘", boxvr: "├", boxvl: "┤", boxhd: "┬", boxhu: "┴", boxvh: "┼", boxH: "═", boxV: "║", boxdR: "╒", boxDr: "╓", boxDR: "╔", boxDl: "╕", boxdL: "╖", boxDL: "╗", boxuR: "╘", boxUr: "╙", boxUR: "╚", boxUl: "╜", boxuL: "╛", boxUL: "╝", boxvR: "╞", boxVr: "╟", boxVR: "╠", boxVl: "╢", boxvL: "╡", boxVL: "╣", boxHd: "╤", boxhD: "╥", boxHD: "╦", boxHu: "╧", boxhU: "╨", boxHU: "╩", boxvH: "╪", boxVh: "╫", boxVH: "╬" }; /** * Punctuation & Diacritics * @type {Record<string, string>} */ const PUNCTUATION = { excl: "!", iexcl: "¡", brvbar: "¦", sect: "§", uml: "¨", copy: "©", ordf: "ª", laquo: "«", not: "¬", shy: "­", reg: "®", macr: "¯", deg: "°", plusmn: "±", sup2: "²", sup3: "³", acute: "´", micro: "µ", para: "¶", middot: "·", cedil: "¸", sup1: "¹", ordm: "º", raquo: "»", frac14: "¼", frac12: "½", frac34: "¾", iquest: "¿", nbsp: "\xA0", comma: ",", period: ".", colon: ":", semi: ";", vert: "|", Verbar: "‖", verbar: "|", dblac: "˝", circ: "ˆ", caron: "ˇ", breve: "˘", dot: "˙", ring: "˚", ogon: "˛", tilde: "˜", DiacriticalGrave: "`", DiacriticalAcute: "´", DiacriticalTilde: "˜", DiacriticalDot: "˙", DiacriticalDoubleAcute: "˝", grave: "`", acute: "´" }; /** * Currency Symbols * @type {Record<string, string>} */ const CURRENCY = { cent: "¢", pound: "£", curren: "¤", yen: "¥", euro: "€", dollar: "$", euro: "€", fnof: "ƒ", inr: "₹", af: "؋", birr: "ብር", peso: "₱", rub: "₽", won: "₩", yuan: "¥", cedil: "¸" }; /** * Fractions * @type {Record<string, string>} */ const FRACTIONS = { frac12: "½", half: "½", frac13: "⅓", frac14: "¼", frac15: "⅕", frac16: "⅙", frac18: "⅛", frac23: "⅔", frac25: "⅖", frac34: "¾", frac35: "⅗", frac38: "⅜", frac45: "⅘", frac56: "⅚", frac58: "⅝", frac78: "⅞", frasl: "⁄" }; /** * Miscellaneous Symbols * @type {Record<string, string>} */ const MISC_SYMBOLS = { trade: "™", TRADE: "™", telrec: "⌕", target: "⌖", ulcorn: "⌜", ulcorner: "⌜", urcorn: "⌝", urcorner: "⌝", dlcorn: "⌞", llcorner: "⌞", drcorn: "⌟", lrcorner: "⌟", intercal: "⊺", intcal: "⊺", oplus: "⊕", CirclePlus: "⊕", ominus: "⊖", CircleMinus: "⊖", otimes: "⊗", CircleTimes: "⊗", osol: "⊘", odot: "⊙", CircleDot: "⊙", oast: "⊛", circledast: "⊛", odash: "⊝", circleddash: "⊝", ocirc: "⊚", circledcirc: "⊚", boxplus: "⊞", plusb: "⊞", boxminus: "⊟", minusb: "⊟", boxtimes: "⊠", timesb: "⊠", boxdot: "⊡", sdotb: "⊡", veebar: "⊻", vee: "∨", barvee: "⊽", and: "∧", wedge: "∧", Cap: "⋒", Cup: "⋓", Fork: "⋔", pitchfork: "⋔", epar: "⋕", ltlarr: "⥶", nvap: "≍⃒", nvsim: "∼⃒", nvge: "≥⃒", nvle: "≤⃒", nvlt: "<⃒", nvgt: ">⃒", nvltrie: "⊴⃒", nvrtrie: "⊵⃒", Vdash: "⊩", dashv: "⊣", vDash: "⊨", Vdash: "⊩", Vvdash: "⊪", nvdash: "⊬", nvDash: "⊭", nVdash: "⊮", nVDash: "⊯" }; ({ ...BASIC_LATIN, ...LATIN_ACCENTS, ...LATIN_EXTENDED, ...GREEK, ...CYRILLIC, ...MATH, ...MATH_ADVANCED, ...ARROWS, ...SHAPES, ...PUNCTUATION, ...CURRENCY, ...FRACTIONS, ...MISC_SYMBOLS }); const XML = { amp: "&", apos: "'", gt: ">", lt: "<", quot: "\"" }; const COMMON_HTML = { nbsp: "\xA0", copy: "©", reg: "®", trade: "™", mdash: "—", ndash: "–", hellip: "…", laquo: "«", raquo: "»", lsquo: "‘", rsquo: "’", ldquo: "“", rdquo: "”", bull: "•", para: "¶", sect: "§", deg: "°", frac12: "½", frac14: "¼", frac34: "¾" }; //#endregion //#region ../../node_modules/.pnpm/@nodable+entities@2.1.0/node_modules/@nodable/entities/src/EntityDecoder.js const SPECIAL_CHARS = /* @__PURE__ */ new Set("!?\\\\/[]$%{}^&*()<>|+"); /** * Validate that an entity name contains no dangerous characters. * @param {string} name * @returns {string} the name, unchanged * @throws {Error} on invalid characters */ function validateEntityName$1(name) { if (name[0] === "#") throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${name}"`); for (const ch of name) if (SPECIAL_CHARS.has(ch)) throw new Error(`[EntityReplacer] Invalid character '${ch}' in entity name: "${name}"`); return name; } /** * Merge one or more entity maps into a flat name→string map. * Accepts either: * - plain string values: { amp: '&' } * - legacy {regex,val} / {regx,val}: { lt: { regex: /.../, val: '<' } } * * Values containing '&' are skipped (recursive expansion risk). * * @param {...object} maps * @returns {Record<string, string>} */ function mergeEntityMaps(...maps) { const out = Object.create(null); for (const map of maps) { if (!map) continue; for (const key of Object.keys(map)) { const raw = map[key]; if (typeof raw === "string") out[key] = raw; else if (raw && typeof raw === "object" && raw.val !== void 0) { const val = raw.val; if (typeof val === "string") out[key] = val; } } } return out; } const LIMIT_TIER_EXTERNAL = "external"; const LIMIT_TIER_BASE = "base"; const LIMIT_TIER_ALL = "all"; /** * Resolve `applyLimitsTo` option into a normalised Set of tier strings. * Accepted values: 'external' | 'base' | 'all' | string[] * Default: 'external' (only untrusted injected entities are counted). * @param {string|string[]|undefined} raw * @returns {Set<string>} */ function parseLimitTiers(raw) { if (!raw || raw === LIMIT_TIER_EXTERNAL) return new Set([LIMIT_TIER_EXTERNAL]); if (raw === LIMIT_TIER_ALL) return new Set([LIMIT_TIER_ALL]); if (raw === LIMIT_TIER_BASE) return new Set([LIMIT_TIER_BASE]); if (Array.isArray(raw)) return new Set(raw); return new Set([LIMIT_TIER_EXTERNAL]); } const NCR_LEVEL = Object.freeze({ allow: 0, leave: 1, remove: 2, throw: 3 }); const XML10_ALLOWED_C0 = new Set([ 9, 10, 13 ]); /** * Parse the `ncr` constructor option into flat, hot-path-friendly fields. * @param {object|undefined} ncr * @returns {{ xmlVersion: number, onLevel: number, nullLevel: number }} */ function parseNCRConfig(ncr) { if (!ncr) return { xmlVersion: 1, onLevel: NCR_LEVEL.allow, nullLevel: NCR_LEVEL.remove }; const xmlVersion = ncr.xmlVersion === 1.1 ? 1.1 : 1; const onLevel = NCR_LEVEL[ncr.onNCR] ?? NCR_LEVEL.allow; const nullLevel = NCR_LEVEL[ncr.nullNCR] ?? NCR_LEVEL.remove; return { xmlVersion, onLevel, nullLevel: Math.max(nullLevel, NCR_LEVEL.remove) }; } /** * Single-pass, zero-regex entity replacer for XML/HTML content. * * Algorithm: scan the string once for '&', read to ';', resolve via map * or direct codepoint conversion, build output chunks, join once at the end. * * Entity lookup priority (highest → lowest): * 1. input / runtime (DOCTYPE entities for current document) * 2. persistent external (survive across documents) * 3. base named map (DEFAULT_XML_ENTITIES + user-supplied namedEntities) * * Both input and external resolve as the 'external' tier for limit purposes. * Base map entities resolve as the 'base' tier. * * Numeric / hex references (&#NNN; / &#xHH;) are resolved directly via * String.fromCodePoint() — no map needed. They count as 'base' tier. * * @example * const replacer = new EntityReplacer({ namedEntities: COMMON_HTML }); * replacer.setExternalEntities({ brand: 'Acme' }); * * const instance = replacer.reset(); * instance.addInputEntities({ version: '1.0' }); * instance.encode('&brand; v&version; &lt;'); // 'Acme v1.0 <' */ var EntityDecoder = class { /** * @param {object} [options] * @param {object|null} [options.namedEntities] — extra named entities merged into base map * @param {object} [options.limit] — security limits * @param {number} [options.limit.maxTotalExpansions=0] — 0 = unlimited * @param {number} [options.limit.maxExpandedLength=0] — 0 = unlimited * @param {'external'|'base'|'all'|string[]} [options.limit.applyLimitsTo='external'] * Which entity tiers count against the security limits: * - 'external' (default) — only input/runtime + persistent external entities * - 'base' — only DEFAULT_XML_ENTITIES + namedEntities * - 'all' — every entity regardless of tier * - string[] — explicit combination, e.g. ['external', 'base'] * @param {((resolved: string, original: string) => string)|null} [options.postCheck=null] * @param {string[]} [options.remove=[]] — entity names (e.g. ['nbsp', '#13']) to delete (replace with empty string) * @param {string[]} [options.leave=[]] — entity names to keep as literal (unchanged in output) * @param {object} [options.ncr] — Numeric Character Reference controls * @param {1.0|1.1} [options.ncr.xmlVersion=1.0] * XML version governing which codepoint ranges are restricted: * - 1.0 — C0 controls U+0001–U+001F (except U+0009/000A/000D) are prohibited * - 1.1 — C0 controls are allowed when written as NCRs; C1 (U+007F–U+009F) decoded as-is * @param {'allow'|'leave'|'remove'|'throw'} [options.ncr.onNCR='allow'] * Base action for numeric references. Severity order: allow < leave < remove < throw. * For codepoint ranges that carry a minimum level (surrogates → remove, XML 1.0 C0 → remove), * the effective action is max(onNCR, rangeMinimum). * @param {'remove'|'throw'} [options.ncr.nullNCR='remove'] * Action for U+0000 (null). 'allow' and 'leave' are clamped to 'remove' since null is never safe. */ constructor(options = {}) { this._limit = options.limit || {}; this._maxTotalExpansions = this._limit.maxTotalExpansions || 0; this._maxExpandedLength = this._limit.maxExpandedLength || 0; this._postCheck = typeof options.postCheck === "function" ? options.postCheck : (r) => r; this._limitTiers = parseLimitTiers(this._limit.applyLimitsTo ?? LIMIT_TIER_EXTERNAL); this._numericAllowed = options.numericAllowed ?? true; this._baseMap = mergeEntityMaps(XML, options.namedEntities || null); /** @type {Record<string, string>} */ this._externalMap = Object.create(null); /** @type {Record<string, string>} */ this._inputMap = Object.create(null); this._totalExpansions = 0; this._expandedLength = 0; /** @type {Set<string>} */ this._removeSet = new Set(options.remove && Array.isArray(options.remove) ? options.remove : []); /** @type {Set<string>} */ this._leaveSet = new Set(options.leave && Array.isArray(options.leave) ? options.leave : []); const ncrCfg = parseNCRConfig(options.ncr); this._ncrXmlVersion = ncrCfg.xmlVersion; this._ncrOnLevel = ncrCfg.onLevel; this._ncrNullLevel = ncrCfg.nullLevel; } /** * Replace the full set of persistent external entities. * All keys are validated — throws on invalid characters. * @param {Record<string, string | { regex?: RegExp, val: string }>} map */ setExternalEntities(map) { if (map) for (const key of Object.keys(map)) validateEntityName$1(key); this._externalMap = mergeEntityMaps(map); } /** * Add a single persistent external entity. * @param {string} key * @param {string} value */ addExternalEntity(key, value) { validateEntityName$1(key); if (typeof value === "string" && value.indexOf("&") === -1) this._externalMap[key] = value; } /** * Inject DOCTYPE entities for the current document. * Also resets per-document expansion counters. * @param {Record<string, string | { regx?: RegExp, regex?: RegExp, val: string }>} map */ addInputEntities(map) { this._totalExpansions = 0; this._expandedLength = 0; this._inputMap = mergeEntityMaps(map); } /** * Wipe input/runtime entities and reset counters. * Call this before processing each new document. * @returns {this} */ reset() { this._inputMap = Object.create(null); this._totalExpansions = 0; this._expandedLength = 0; return this; } /** * Update the XML version used for NCR classification. * Call this as soon as the document's `<?xml version="...">` declaration is parsed. * @param {1.0|1.1|number} version */ setXmlVersion(version) { this._ncrXmlVersion = version === 1.1 ? 1.1 : 1; } /** * Replace all entity references in `str` in a single pass. * * @param {string} str * @returns {string} */ decode(str) { if (typeof str !== "string" || str.length === 0) return str; const original = str; const chunks = []; const len = str.length; let last = 0; let i = 0; const limitExpansions = this._maxTotalExpansions > 0; const limitLength = this._maxExpandedLength > 0; const checkLimits = limitExpansions || limitLength; while (i < len) { if (str.charCodeAt(i) !== 38) { i++; continue; } let j = i + 1; while (j < len && str.charCodeAt(j) !== 59 && j - i <= 32) j++; if (j >= len || str.charCodeAt(j) !== 59) { i++; continue; } const token = str.slice(i + 1, j); if (token.length === 0) { i++; continue; } let replacement; let tier; if (this._removeSet.has(token)) { replacement = ""; if (tier === void 0) tier = LIMIT_TIER_EXTERNAL; } else if (this._leaveSet.has(token)) { i++; continue; } else if (token.charCodeAt(0) === 35) { const ncrResult = this._resolveNCR(token); if (ncrResult === void 0) { i++; continue; } replacement = ncrResult; tier = LIMIT_TIER_BASE; } else { const resolved = this._resolveName(token); replacement = resolved?.value; tier = resolved?.tier; } if (replacement === void 0) { i++; continue; } if (i > last) chunks.push(str.slice(last, i)); chunks.push(replacement); last = j + 1; i = last; if (checkLimits && this._tierCounts(tier)) { if (limitExpansions) { this._totalExpansions++; if (this._totalExpansions > this._maxTotalExpansions) throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`); } if (limitLength) { const delta = replacement.length - (token.length + 2); if (delta > 0) { this._expandedLength += delta; if (this._expandedLength > this._maxExpandedLength) throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`); } } } } if (last < len) chunks.push(str.slice(last)); const result = chunks.length === 0 ? str : chunks.join(""); return this._postCheck(result, original); } /** * Returns true if a resolved entity of the given tier should count * against the expansion/length limits. * @param {string} tier — LIMIT_TIER_EXTERNAL | LIMIT_TIER_BASE * @returns {boolean} */ _tierCounts(tier) { if (this._limitTiers.has(LIMIT_TIER_ALL)) return true; return this._limitTiers.has(tier); } /** * Resolve a named entity token (without & and ;). * Priority: inputMap > externalMap > baseMap * Returns the resolved value tagged with its limit tier. * * @param {string} name * @returns {{ value: string, tier: string }|undefined} */ _resolveName(name) { if (name in this._inputMap) return { value: this._inputMap[name], tier: LIMIT_TIER_EXTERNAL }; if (name in this._externalMap) return { value: this._externalMap[name], tier: LIMIT_TIER_EXTERNAL }; if (name in this._baseMap) return { value: this._baseMap[name], tier: LIMIT_TIER_BASE }; } /** * Classify a codepoint and return the minimum action level that must be applied. * Returns -1 when no minimum is imposed (normal allow path). * * Ranges checked (in priority order): * 1. U+0000 — null, governed by nullNCR (always ≥ remove) * 2. U+D800–U+DFFF — surrogates, always prohibited (min: remove) * 3. U+0001–U+001F \ {0x09,0x0A,0x0D} — XML 1.0 restricted C0 (min: remove) * (skipped in XML 1.1 — C0 controls are allowed when written as NCRs) * * @param {number} cp — codepoint * @returns {number} — minimum NCR_LEVEL value, or -1 for no restriction */ _classifyNCR(cp) { if (cp === 0) return this._ncrNullLevel; if (cp >= 55296 && cp <= 57343) return NCR_LEVEL.remove; if (this._ncrXmlVersion === 1) { if (cp >= 1 && cp <= 31 && !XML10_ALLOWED_C0.has(cp)) return NCR_LEVEL.remove; } return -1; } /** * Execute a resolved NCR action. * * @param {number} action — NCR_LEVEL value * @param {string} token — raw token (e.g. '#38') for error messages * @param {number} cp — codepoint, used only for error messages * @returns {string|undefined} * - decoded character string → 'allow' * - '' → 'remove' * - undefined → 'leave' (caller must skip past '&' only) * - throws Error → 'throw' */ _applyNCRAction(action, token, cp) { switch (action) { case NCR_LEVEL.allow: return String.fromCodePoint(cp); case NCR_LEVEL.remove: return ""; case NCR_LEVEL.leave: return; case NCR_LEVEL.throw: throw new Error(`[EntityDecoder] Prohibited numeric character reference &${token}; (U+${cp.toString(16).toUpperCase().padStart(4, "0")})`); default: return String.fromCodePoint(cp); } } /** * Full NCR resolution pipeline for a numeric token. * * Steps: * 1. Parse the codepoint (decimal or hex). * 2. Validate the raw codepoint range (NaN, <0, >0x10FFFF). * 3. If numericAllowed is false and no minimum restriction applies → leave as-is. * 4. Classify the codepoint to find the minimum required action level. * 5. Resolve effective action = max(onNCR, minimum). * 6. Apply and return. * * @param {string} token — e.g. '#38', '#x26', '#X26' * @returns {string|undefined} * - string (incl. '') — replacement ('' = remove) * - undefined — leave original &token; as-is */ _resolveNCR(token) { const second = token.charCodeAt(1); let cp; if (second === 120 || second === 88) cp = parseInt(token.slice(2), 16); else cp = parseInt(token.slice(1), 10); if (Number.isNaN(cp) || cp < 0 || cp > 1114111) return void 0; const minimum = this._classifyNCR(cp); if (!this._numericAllowed && minimum < NCR_LEVEL.remove) return void 0; const effective = minimum === -1 ? this._ncrOnLevel : Math.max(this._ncrOnLevel, minimum); return this._applyNCRAction(effective, token, cp); } }; //#endregion //#region ../../node_modules/.pnpm/fast-xml-parser@5.7.2/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js const defaultOnDangerousProperty = (name) => { if (DANGEROUS_PROPERTY_NAMES.includes(name)) return "__" + name; return name; }; const defaultOptions$1 = { preserveOrder: false, attributeNamePrefix: "@_", attributesGroupName: false, textNodeName: "#text", ignoreAttributes: true, removeNSPrefix: false, allowBooleanAttributes: false, parseTagValue: true, parseAttributeValue: false, trimValues: true, cdataPropName: false, numberParseOptions: { hex: true, leadingZeros: true, eNotation: true }, tagValueProcessor: function(tagName, val) { return val; }, attributeValueProcessor: function(attrName, val) { return val; }, stopNodes: [], alwaysCreateTextNode: false, isArray: () => false, commentPropName: false, unpairedTags: [], processEntities: true, htmlEntities: false, entityDecoder: null, ignoreDeclaration: false, ignorePiTags: false, transformTagName: false, transformAttributeName: false, updateTag: function(tagName, jPath, attrs) { return tagName; }, captureMetaData: false, maxNestedTags: 100, strictReservedNames: true, jPath: true, onDangerousProperty: defaultOnDangerousProperty }; /** * Validates that a property name is safe to use * @param {string} propertyName - The property name to validate * @param {string} optionName - The option field name (for error message) * @throws {Error} If property name is dangerous */ function validatePropertyName(propertyName, optionName) { if (typeof propertyName !== "string") return; const normalized = propertyName.toLowerCase(); 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`); if (criticalProperties.some((dangerous) => normalized === dangerous.toLowerCase())) throw new Error(`[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution`); } /** * Normalizes processEntities option for backward compatibility * @param {boolean|object} value * @returns {object} Always returns normalized object */ function normalizeProcessEntities(value, htmlEntities) { if (typeof value === "boolean") return { enabled: value, maxEntitySize: 1e4, maxExpansionDepth: 1e4, maxTotalExpansions: Infinity, maxExpandedLength: 1e5, maxEntityCount: 1e3, allowedTags: null, tagFilter: null, appliesTo: "all" }; if (typeof value === "object" && value !== null) return { enabled: value.enabled !== false, maxEntitySize: Math.max(1, value.maxEntitySize ?? 1e4), maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 1e4), maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity), maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 1e5), maxEntityCount: Math.max(1, value.maxEntityCount ?? 1e3), allowedTags: value.allowedTags ?? null, tagFilter: value.tagFilter ?? null, appliesTo: value.appliesTo ?? "all" }; return normalizeProcessEntities(true); } const buildOptions = function(options) { const built = Object.assign({}, defaultOptions$1, options); const propertyNameOptions = [ { value: built.attributeNamePrefix, name: "attributeNamePrefix" }, { value: built.attributesGroupName, name: "attributesGroupName" }, { value: built.textNodeName, name: "textNodeName" }, { value: built.cdataPropName, name: "cdataPropName" }, { value: built.commentPropName, name: "commentPropName" } ]; for (const { value, name } of propertyNameOptions) if (value) validatePropertyName(value, name); if (built.onDangerousProperty === null) built.onDangerousProperty = defaultOnDangerousProperty; built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities); built.unpairedTagsSet = new Set(built.unpairedTags); if (built.stopNodes && Array.isArray(built.stopNodes)) built.stopNodes = built.stopNodes.map((node) => { if (typeof node === "string" && node.startsWith("*.")) return ".." + node.substring(2); return node; }); return built; }; //#endregion //#region ../../node_modules/.pnpm/fast-xml-parser@5.7.2/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js let METADATA_SYMBOL$1; if (typeof Symbol !== "function") METADATA_SYMBOL$1 = "@@xmlMetadata"; else METADATA_SYMBOL$1 = Symbol("XML Node Metadata"); var XmlNode = class { constructor(tagname) { this.tagname = tagname; this.child = []; this[":@"] = Object.create(null); } add(key, val) { if (key === "__proto__") key = "#__proto__"; this.child.push({ [key]: val }); } addChild(node, startIndex) { if (node.tagname === "__proto__") node.tagname = "#__proto__"; if (node[":@"] && Object.keys(node[":@"]).length > 0) this.child.push({ [node.tagname]: node.child, [":@"]: node[":@"] }); else this.child.push({ [node.tagname]: node.child }); if (startIndex !== void 0) this.child[this.child.length - 1][METADATA_SYMBOL$1] = { startIndex }; } /** symbol used for metadata */ static getMetaDataSymbol() { return METADATA_SYMBOL$1; } }; //#endregion //#region ../../node_modules/.pnpm/fast-xml-parser@5.7.2/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js var DocTypeReader = class { constructor(options) { this.suppressValidationErr = !options; this.options = options; } readDocType(xmlData, i) { const entities = Object.create(null); let entityCount = 0; 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") { i = i + 9; let angleBracketsCount = 1; let hasBody = false, comment = false; let exp = ""; for (; i < xmlData.length; i++) if (xmlData[i] === "<" && !comment) { if (hasBody && hasSeq(xmlData, "!ENTITY", i)) { i += 7; let entityName, val; [entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr); if (val.indexOf("&") === -1) { 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})`); entities[entityName] = val; entityCount++; } } else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) { i += 8; const { index } = this.readElementExp(xmlData, i + 1); i = index; } else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) i += 8; else if