Files
hydro-builder-app/node_modules/.vite/deps/purify.es-erUxcz-o.js
2026-06-13 17:36:44 -07:00

2101 lines
68 KiB
JavaScript

//#region node_modules/dompurify/dist/purify.es.mjs
/*! @license DOMPurify 3.4.10 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.10/LICENSE */
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _arrayWithHoles(r) {
if (Array.isArray(r)) return r;
}
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e, n, i, u, a = [], f = true, o = false;
try {
if (i = (t = t.call(r)).next, 0 === l);
else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = true, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _slicedToArray(r, e) {
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
var entries = Object.entries, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var freeze = Object.freeze, seal = Object.seal, create = Object.create;
var _ref = typeof Reflect !== "undefined" && Reflect, apply = _ref.apply, construct = _ref.construct;
if (!freeze) freeze = function freeze(x) {
return x;
};
if (!seal) seal = function seal(x) {
return x;
};
if (!apply) apply = function apply(func, thisArg) {
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key];
return func.apply(thisArg, args);
};
if (!construct) construct = function construct(Func) {
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) args[_key2 - 1] = arguments[_key2];
return new Func(...args);
};
var arrayForEach = unapply(Array.prototype.forEach);
var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
var arrayPop = unapply(Array.prototype.pop);
var arrayPush = unapply(Array.prototype.push);
var arraySplice = unapply(Array.prototype.splice);
var arrayIsArray = Array.isArray;
var stringToLowerCase = unapply(String.prototype.toLowerCase);
var stringToString = unapply(String.prototype.toString);
var stringMatch = unapply(String.prototype.match);
var stringReplace = unapply(String.prototype.replace);
var stringIndexOf = unapply(String.prototype.indexOf);
var stringTrim = unapply(String.prototype.trim);
var numberToString = unapply(Number.prototype.toString);
var booleanToString = unapply(Boolean.prototype.toString);
var bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString);
var symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString);
var objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
var objectToString = unapply(Object.prototype.toString);
var regExpTest = unapply(RegExp.prototype.test);
var typeErrorCreate = unconstruct(TypeError);
/**
* Creates a new function that calls the given function with a specified thisArg and arguments.
*
* @param func - The function to be wrapped and called.
* @returns A new function that calls the given function with a specified thisArg and arguments.
*/
function unapply(func) {
return function(thisArg) {
if (thisArg instanceof RegExp) thisArg.lastIndex = 0;
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) args[_key3 - 1] = arguments[_key3];
return apply(func, thisArg, args);
};
}
/**
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
*
* @param func - The constructor function to be wrapped and called.
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
*/
function unconstruct(Func) {
return function() {
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) args[_key4] = arguments[_key4];
return construct(Func, args);
};
}
/**
* Add properties to a lookup table
*
* @param set - The set to which elements will be added.
* @param array - The array containing elements to be added to the set.
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
* @returns The modified set with added elements.
*/
function addToSet(set, array) {
let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase;
if (setPrototypeOf) setPrototypeOf(set, null);
if (!arrayIsArray(array)) return set;
let l = array.length;
while (l--) {
let element = array[l];
if (typeof element === "string") {
const lcElement = transformCaseFunc(element);
if (lcElement !== element) {
if (!isFrozen(array)) array[l] = lcElement;
element = lcElement;
}
}
set[element] = true;
}
return set;
}
/**
* Clean up an array to harden against CSPP
*
* @param array - The array to be cleaned.
* @returns The cleaned version of the array
*/
function cleanArray(array) {
for (let index = 0; index < array.length; index++) if (!objectHasOwnProperty(array, index)) array[index] = null;
return array;
}
/**
* Shallow clone an object
*
* @param object - The object to be cloned.
* @returns A new object that copies the original.
*/
function clone(object) {
const newObject = create(null);
for (const _ref2 of entries(object)) {
var _ref3 = _slicedToArray(_ref2, 2);
const property = _ref3[0];
const value = _ref3[1];
if (objectHasOwnProperty(object, property)) if (arrayIsArray(value)) newObject[property] = cleanArray(value);
else if (value && typeof value === "object" && value.constructor === Object) newObject[property] = clone(value);
else newObject[property] = value;
}
return newObject;
}
/**
* Convert non-node values into strings without depending on direct property access.
*
* @param value - The value to stringify.
* @returns A string representation of the provided value.
*/
function stringifyValue(value) {
switch (typeof value) {
case "string": return value;
case "number": return numberToString(value);
case "boolean": return booleanToString(value);
case "bigint": return bigintToString ? bigintToString(value) : "0";
case "symbol": return symbolToString ? symbolToString(value) : "Symbol()";
case "undefined": return objectToString(value);
case "function":
case "object": {
if (value === null) return objectToString(value);
const valueAsRecord = value;
const valueToString = lookupGetter(valueAsRecord, "toString");
if (typeof valueToString === "function") {
const stringified = valueToString(valueAsRecord);
return typeof stringified === "string" ? stringified : objectToString(stringified);
}
return objectToString(value);
}
default: return objectToString(value);
}
}
/**
* This method automatically checks if the prop is function or getter and behaves accordingly.
*
* @param object - The object to look up the getter function in its prototype chain.
* @param prop - The property name for which to find the getter function.
* @returns The getter function found in the prototype chain or a fallback function.
*/
function lookupGetter(object, prop) {
while (object !== null) {
const desc = getOwnPropertyDescriptor(object, prop);
if (desc) {
if (desc.get) return unapply(desc.get);
if (typeof desc.value === "function") return unapply(desc.value);
}
object = getPrototypeOf(object);
}
function fallbackValue() {
return null;
}
return fallbackValue;
}
function isRegex(value) {
try {
regExpTest(value, "");
return true;
} catch (_unused) {
return false;
}
}
var html$1 = freeze([
"a",
"abbr",
"acronym",
"address",
"area",
"article",
"aside",
"audio",
"b",
"bdi",
"bdo",
"big",
"blink",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"cite",
"code",
"col",
"colgroup",
"content",
"data",
"datalist",
"dd",
"decorator",
"del",
"details",
"dfn",
"dialog",
"dir",
"div",
"dl",
"dt",
"element",
"em",
"fieldset",
"figcaption",
"figure",
"font",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"img",
"input",
"ins",
"kbd",
"label",
"legend",
"li",
"main",
"map",
"mark",
"marquee",
"menu",
"menuitem",
"meter",
"nav",
"nobr",
"ol",
"optgroup",
"option",
"output",
"p",
"picture",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"search",
"section",
"select",
"shadow",
"slot",
"small",
"source",
"spacer",
"span",
"strike",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"tr",
"track",
"tt",
"u",
"ul",
"var",
"video",
"wbr"
]);
var svg$1 = freeze([
"svg",
"a",
"altglyph",
"altglyphdef",
"altglyphitem",
"animatecolor",
"animatemotion",
"animatetransform",
"circle",
"clippath",
"defs",
"desc",
"ellipse",
"enterkeyhint",
"exportparts",
"filter",
"font",
"g",
"glyph",
"glyphref",
"hkern",
"image",
"inputmode",
"line",
"lineargradient",
"marker",
"mask",
"metadata",
"mpath",
"part",
"path",
"pattern",
"polygon",
"polyline",
"radialgradient",
"rect",
"stop",
"style",
"switch",
"symbol",
"text",
"textpath",
"title",
"tref",
"tspan",
"view",
"vkern"
]);
var svgFilters = freeze([
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feDropShadow",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence"
]);
var svgDisallowed = freeze([
"animate",
"color-profile",
"cursor",
"discard",
"font-face",
"font-face-format",
"font-face-name",
"font-face-src",
"font-face-uri",
"foreignobject",
"hatch",
"hatchpath",
"mesh",
"meshgradient",
"meshpatch",
"meshrow",
"missing-glyph",
"script",
"set",
"solidcolor",
"unknown",
"use"
]);
var mathMl$1 = freeze([
"math",
"menclose",
"merror",
"mfenced",
"mfrac",
"mglyph",
"mi",
"mlabeledtr",
"mmultiscripts",
"mn",
"mo",
"mover",
"mpadded",
"mphantom",
"mroot",
"mrow",
"ms",
"mspace",
"msqrt",
"mstyle",
"msub",
"msup",
"msubsup",
"mtable",
"mtd",
"mtext",
"mtr",
"munder",
"munderover",
"mprescripts"
]);
var mathMlDisallowed = freeze([
"maction",
"maligngroup",
"malignmark",
"mlongdiv",
"mscarries",
"mscarry",
"msgroup",
"mstack",
"msline",
"msrow",
"semantics",
"annotation",
"annotation-xml",
"mprescripts",
"none"
]);
var text = freeze(["#text"]);
var html = freeze([
"accept",
"action",
"align",
"alt",
"autocapitalize",
"autocomplete",
"autopictureinpicture",
"autoplay",
"background",
"bgcolor",
"border",
"capture",
"cellpadding",
"cellspacing",
"checked",
"cite",
"class",
"clear",
"color",
"cols",
"colspan",
"command",
"commandfor",
"controls",
"controlslist",
"coords",
"crossorigin",
"datetime",
"decoding",
"default",
"dir",
"disabled",
"disablepictureinpicture",
"disableremoteplayback",
"download",
"draggable",
"enctype",
"enterkeyhint",
"exportparts",
"face",
"for",
"headers",
"height",
"hidden",
"high",
"href",
"hreflang",
"id",
"inert",
"inputmode",
"integrity",
"ismap",
"kind",
"label",
"lang",
"list",
"loading",
"loop",
"low",
"max",
"maxlength",
"media",
"method",
"min",
"minlength",
"multiple",
"muted",
"name",
"nonce",
"noshade",
"novalidate",
"nowrap",
"open",
"optimum",
"part",
"pattern",
"placeholder",
"playsinline",
"popover",
"popovertarget",
"popovertargetaction",
"poster",
"preload",
"pubdate",
"radiogroup",
"readonly",
"rel",
"required",
"rev",
"reversed",
"role",
"rows",
"rowspan",
"spellcheck",
"scope",
"selected",
"shape",
"size",
"sizes",
"slot",
"span",
"srclang",
"start",
"src",
"srcset",
"step",
"style",
"summary",
"tabindex",
"title",
"translate",
"type",
"usemap",
"valign",
"value",
"width",
"wrap",
"xmlns"
]);
var svg = freeze([
"accent-height",
"accumulate",
"additive",
"alignment-baseline",
"amplitude",
"ascent",
"attributename",
"attributetype",
"azimuth",
"basefrequency",
"baseline-shift",
"begin",
"bias",
"by",
"class",
"clip",
"clippathunits",
"clip-path",
"clip-rule",
"color",
"color-interpolation",
"color-interpolation-filters",
"color-profile",
"color-rendering",
"cx",
"cy",
"d",
"dx",
"dy",
"diffuseconstant",
"direction",
"display",
"divisor",
"dur",
"edgemode",
"elevation",
"end",
"exponent",
"fill",
"fill-opacity",
"fill-rule",
"filter",
"filterunits",
"flood-color",
"flood-opacity",
"font-family",
"font-size",
"font-size-adjust",
"font-stretch",
"font-style",
"font-variant",
"font-weight",
"fx",
"fy",
"g1",
"g2",
"glyph-name",
"glyphref",
"gradientunits",
"gradienttransform",
"height",
"href",
"id",
"image-rendering",
"in",
"in2",
"intercept",
"k",
"k1",
"k2",
"k3",
"k4",
"kerning",
"keypoints",
"keysplines",
"keytimes",
"lang",
"lengthadjust",
"letter-spacing",
"kernelmatrix",
"kernelunitlength",
"lighting-color",
"local",
"marker-end",
"marker-mid",
"marker-start",
"markerheight",
"markerunits",
"markerwidth",
"maskcontentunits",
"maskunits",
"max",
"mask",
"mask-type",
"media",
"method",
"mode",
"min",
"name",
"numoctaves",
"offset",
"operator",
"opacity",
"order",
"orient",
"orientation",
"origin",
"overflow",
"paint-order",
"path",
"pathlength",
"patterncontentunits",
"patterntransform",
"patternunits",
"points",
"preservealpha",
"preserveaspectratio",
"primitiveunits",
"r",
"rx",
"ry",
"radius",
"refx",
"refy",
"repeatcount",
"repeatdur",
"restart",
"result",
"rotate",
"scale",
"seed",
"shape-rendering",
"slope",
"specularconstant",
"specularexponent",
"spreadmethod",
"startoffset",
"stddeviation",
"stitchtiles",
"stop-color",
"stop-opacity",
"stroke-dasharray",
"stroke-dashoffset",
"stroke-linecap",
"stroke-linejoin",
"stroke-miterlimit",
"stroke-opacity",
"stroke",
"stroke-width",
"style",
"surfacescale",
"systemlanguage",
"tabindex",
"tablevalues",
"targetx",
"targety",
"transform",
"transform-origin",
"text-anchor",
"text-decoration",
"text-rendering",
"textlength",
"type",
"u1",
"u2",
"unicode",
"values",
"viewbox",
"visibility",
"version",
"vert-adv-y",
"vert-origin-x",
"vert-origin-y",
"width",
"word-spacing",
"wrap",
"writing-mode",
"xchannelselector",
"ychannelselector",
"x",
"x1",
"x2",
"xmlns",
"y",
"y1",
"y2",
"z",
"zoomandpan"
]);
var mathMl = freeze([
"accent",
"accentunder",
"align",
"bevelled",
"close",
"columnalign",
"columnlines",
"columnspacing",
"columnspan",
"denomalign",
"depth",
"dir",
"display",
"displaystyle",
"encoding",
"fence",
"frame",
"height",
"href",
"id",
"largeop",
"length",
"linethickness",
"lquote",
"lspace",
"mathbackground",
"mathcolor",
"mathsize",
"mathvariant",
"maxsize",
"minsize",
"movablelimits",
"notation",
"numalign",
"open",
"rowalign",
"rowlines",
"rowspacing",
"rowspan",
"rspace",
"rquote",
"scriptlevel",
"scriptminsize",
"scriptsizemultiplier",
"selection",
"separator",
"separators",
"stretchy",
"subscriptshift",
"supscriptshift",
"symmetric",
"voffset",
"width",
"xmlns"
]);
var xml = freeze([
"xlink:href",
"xml:id",
"xlink:title",
"xml:space",
"xmlns:xlink"
]);
var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
var ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
var TMPLIT_EXPR = seal(/\${[\w\W]*/g);
var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/);
var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
var DOCTYPE_NAME = seal(/^html$/i);
var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
var ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
var COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
var FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
var SELF_CLOSING_TAG = seal(/\/>/i);
var NODE_TYPE = {
element: 1,
attribute: 2,
text: 3,
cdataSection: 4,
entityReference: 5,
entityNode: 6,
processingInstruction: 7,
comment: 8,
document: 9,
documentType: 10,
documentFragment: 11,
notation: 12
};
var getGlobal = function getGlobal() {
return typeof window === "undefined" ? null : window;
};
/**
* Creates a no-op policy for internal use only.
* Don't export this function outside this module!
* @param trustedTypes The policy factory.
* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
* @return The policy created (or null, if Trusted Types
* are not supported or creating the policy failed).
*/
var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") return null;
let suffix = null;
const ATTR_NAME = "data-tt-policy-suffix";
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) suffix = purifyHostElement.getAttribute(ATTR_NAME);
const policyName = "dompurify" + (suffix ? "#" + suffix : "");
try {
return trustedTypes.createPolicy(policyName, {
createHTML(html) {
return html;
},
createScriptURL(scriptUrl) {
return scriptUrl;
}
});
} catch (_) {
console.warn("TrustedTypes policy " + policyName + " could not be created.");
return null;
}
};
var _createHooksMap = function _createHooksMap() {
return {
afterSanitizeAttributes: [],
afterSanitizeElements: [],
afterSanitizeShadowDOM: [],
beforeSanitizeAttributes: [],
beforeSanitizeElements: [],
beforeSanitizeShadowDOM: [],
uponSanitizeAttribute: [],
uponSanitizeElement: [],
uponSanitizeShadowNode: []
};
};
/**
* Resolve a set-valued configuration option: a fresh set built from
* cfg[key] when it is an own array property (seeded with a clone of
* options.base when given, case-normalized via options.transform),
* the fallback set otherwise.
*
* @param cfg the cloned, prototype-free configuration object
* @param key the configuration property to read
* @param fallback the set to use when the option is absent or not an array
* @param options transform and optional base set to merge into
* @returns the resolved set
*/
var _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
};
function createDOMPurify() {
let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
const DOMPurify = (root) => createDOMPurify(root);
DOMPurify.version = "3.4.10";
DOMPurify.removed = [];
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
DOMPurify.isSupported = false;
return DOMPurify;
}
let document = window.document;
const originalDocument = document;
const currentScript = originalDocument.currentScript;
window.DocumentFragment;
const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter;
window.NamedNodeMap === void 0 && (window.NamedNodeMap || window.MozNamedAttrMap);
window.HTMLFormElement;
const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes;
const ElementPrototype = Element.prototype;
const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
const remove = lookupGetter(ElementPrototype, "remove");
const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
const getChildNodes = lookupGetter(ElementPrototype, "childNodes");
const getParentNode = lookupGetter(ElementPrototype, "parentNode");
const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot");
const getAttributes = lookupGetter(ElementPrototype, "attributes");
const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null;
const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null;
if (typeof HTMLTemplateElement === "function") {
const template = document.createElement("template");
if (template.content && template.content.ownerDocument) document = template.content.ownerDocument;
}
let trustedTypesPolicy;
let emptyHTML = "";
let defaultTrustedTypesPolicy;
let defaultTrustedTypesPolicyResolved = false;
let IN_TRUSTED_TYPES_POLICY = 0;
const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() {
if (IN_TRUSTED_TYPES_POLICY > 0) throw typeErrorCreate("A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted Types\" section of the README.");
};
const _createTrustedHTML = function _createTrustedHTML(html) {
_assertNotInTrustedTypesPolicy();
IN_TRUSTED_TYPES_POLICY++;
try {
return trustedTypesPolicy.createHTML(html);
} finally {
IN_TRUSTED_TYPES_POLICY--;
}
};
const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) {
_assertNotInTrustedTypesPolicy();
IN_TRUSTED_TYPES_POLICY++;
try {
return trustedTypesPolicy.createScriptURL(scriptUrl);
} finally {
IN_TRUSTED_TYPES_POLICY--;
}
};
const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() {
if (!defaultTrustedTypesPolicyResolved) {
defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
defaultTrustedTypesPolicyResolved = true;
}
return defaultTrustedTypesPolicy;
};
const _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
const importNode = originalDocument.importNode;
let hooks = _createHooksMap();
/**
* Expose whether this browser supports running the full DOMPurify.
*/
DOMPurify.isSupported = typeof entries === "function" && typeof getParentNode === "function" && implementation && implementation.createHTMLDocument !== void 0;
const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
/**
* We consider the elements and attributes below to be safe. Ideally
* don't add any new ones but feel free to remove unwanted ones.
*/
let ALLOWED_TAGS = null;
const DEFAULT_ALLOWED_TAGS = addToSet({}, [
...html$1,
...svg$1,
...svgFilters,
...mathMl$1,
...text
]);
let ALLOWED_ATTR = null;
const DEFAULT_ALLOWED_ATTR = addToSet({}, [
...html,
...svg,
...mathMl,
...xml
]);
let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
tagNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
allowCustomizedBuiltInElements: {
writable: true,
configurable: false,
enumerable: true,
value: false
}
}));
let FORBID_TAGS = null;
let FORBID_ATTR = null;
const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
tagCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
}
}));
let ALLOW_ARIA_ATTR = true;
let ALLOW_DATA_ATTR = true;
let ALLOW_UNKNOWN_PROTOCOLS = false;
let ALLOW_SELF_CLOSE_IN_ATTR = true;
let SAFE_FOR_TEMPLATES = false;
let SAFE_FOR_XML = true;
let WHOLE_DOCUMENT = false;
let SET_CONFIG = false;
let FORCE_BODY = false;
let RETURN_DOM = false;
let RETURN_DOM_FRAGMENT = false;
let RETURN_TRUSTED_TYPE = false;
let SANITIZE_DOM = true;
let SANITIZE_NAMED_PROPS = false;
const SANITIZE_NAMED_PROPS_PREFIX = "user-content-";
let KEEP_CONTENT = true;
let IN_PLACE = false;
let USE_PROFILES = {};
let FORBID_CONTENTS = null;
const DEFAULT_FORBID_CONTENTS = addToSet({}, [
"annotation-xml",
"audio",
"colgroup",
"desc",
"foreignobject",
"head",
"iframe",
"math",
"mi",
"mn",
"mo",
"ms",
"mtext",
"noembed",
"noframes",
"noscript",
"plaintext",
"script",
"selectedcontent",
"style",
"svg",
"template",
"thead",
"title",
"video",
"xmp"
]);
let DATA_URI_TAGS = null;
const DEFAULT_DATA_URI_TAGS = addToSet({}, [
"audio",
"video",
"img",
"source",
"image",
"track"
]);
let URI_SAFE_ATTRIBUTES = null;
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
"alt",
"class",
"for",
"id",
"label",
"name",
"pattern",
"placeholder",
"role",
"summary",
"title",
"value",
"style",
"xmlns"
]);
const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
let NAMESPACE = HTML_NAMESPACE;
let IS_EMPTY_INPUT = false;
let ALLOWED_NAMESPACES = null;
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
MATHML_NAMESPACE,
SVG_NAMESPACE,
HTML_NAMESPACE
], stringToString);
const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze([
"mi",
"mo",
"mn",
"ms",
"mtext"
]);
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]);
let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
"title",
"style",
"font",
"a",
"script"
]);
let PARSER_MEDIA_TYPE = null;
const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"];
const DEFAULT_PARSER_MEDIA_TYPE = "text/html";
let transformCaseFunc = null;
let CONFIG = null;
const formElement = document.createElement("form");
const isRegexOrFunction = function isRegexOrFunction(testValue) {
return testValue instanceof RegExp || testValue instanceof Function;
};
/**
* _parseConfig
*
* @param cfg optional config literal
*/
const _parseConfig = function _parseConfig() {
let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
if (CONFIG && CONFIG === cfg) return;
if (!cfg || typeof cfg !== "object") cfg = {};
cfg = clone(cfg);
PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase;
ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, { transform: transformCaseFunc });
ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, { transform: transformCaseFunc });
ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, { transform: stringToString });
URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, {
transform: transformCaseFunc,
base: DEFAULT_URI_SAFE_ATTRIBUTES
});
DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, {
transform: transformCaseFunc,
base: DEFAULT_DATA_URI_TAGS
});
FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, { transform: transformCaseFunc });
FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), { transform: transformCaseFunc });
FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), { transform: transformCaseFunc });
USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false;
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false;
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
RETURN_DOM = cfg.RETURN_DOM || false;
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
FORCE_BODY = cfg.FORCE_BODY || false;
SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false;
KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
IN_PLACE = cfg.IN_PLACE || false;
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
const customElementHandling = objectHasOwnProperty(cfg, "CUSTOM_ELEMENT_HANDLING") && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === "object" ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
CUSTOM_ELEMENT_HANDLING = create(null);
if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck;
if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements;
seal(CUSTOM_ELEMENT_HANDLING);
if (SAFE_FOR_TEMPLATES) ALLOW_DATA_ATTR = false;
if (RETURN_DOM_FRAGMENT) RETURN_DOM = true;
if (USE_PROFILES) {
ALLOWED_TAGS = addToSet({}, text);
ALLOWED_ATTR = create(null);
if (USE_PROFILES.html === true) {
addToSet(ALLOWED_TAGS, html$1);
addToSet(ALLOWED_ATTR, html);
}
if (USE_PROFILES.svg === true) {
addToSet(ALLOWED_TAGS, svg$1);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.svgFilters === true) {
addToSet(ALLOWED_TAGS, svgFilters);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.mathMl === true) {
addToSet(ALLOWED_TAGS, mathMl$1);
addToSet(ALLOWED_ATTR, mathMl);
addToSet(ALLOWED_ATTR, xml);
}
}
EXTRA_ELEMENT_HANDLING.tagCheck = null;
EXTRA_ELEMENT_HANDLING.attributeCheck = null;
if (objectHasOwnProperty(cfg, "ADD_TAGS")) {
if (typeof cfg.ADD_TAGS === "function") EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
else if (arrayIsArray(cfg.ADD_TAGS)) {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) ALLOWED_TAGS = clone(ALLOWED_TAGS);
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}
}
if (objectHasOwnProperty(cfg, "ADD_ATTR")) {
if (typeof cfg.ADD_ATTR === "function") EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
else if (arrayIsArray(cfg.ADD_ATTR)) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) ALLOWED_ATTR = clone(ALLOWED_ATTR);
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}
}
if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
}
if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
}
if (KEEP_CONTENT) ALLOWED_TAGS["#text"] = true;
if (WHOLE_DOCUMENT) addToSet(ALLOWED_TAGS, [
"html",
"head",
"body"
]);
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ["tbody"]);
delete FORBID_TAGS.tbody;
}
if (cfg.TRUSTED_TYPES_POLICY) {
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.");
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.");
const previousTrustedTypesPolicy = trustedTypesPolicy;
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
try {
emptyHTML = _createTrustedHTML("");
} catch (error) {
trustedTypesPolicy = previousTrustedTypesPolicy;
throw error;
}
} else if (cfg.TRUSTED_TYPES_POLICY === null) {
trustedTypesPolicy = void 0;
emptyHTML = "";
} else {
if (trustedTypesPolicy === void 0) trustedTypesPolicy = _getDefaultTrustedTypesPolicy();
if (trustedTypesPolicy && typeof emptyHTML === "string") emptyHTML = _createTrustedHTML("");
}
if ((hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) && ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) ALLOWED_TAGS = clone(ALLOWED_TAGS);
if (hooks.uponSanitizeAttribute.length > 0 && ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) ALLOWED_ATTR = clone(ALLOWED_ATTR);
if (freeze) freeze(cfg);
CONFIG = cfg;
};
const ALL_SVG_TAGS = addToSet({}, [
...svg$1,
...svgFilters,
...svgDisallowed
]);
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
/**
* Namespace rules for an element in the SVG namespace.
*
* @param tagName the element's lowercase tag name
* @param parent the (possibly simulated) parent node
* @param parentTagName the parent's lowercase tag name
* @returns true if a spec-compliant parser could produce this element
*/
const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) {
if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "svg";
if (parent.namespaceURI === MATHML_NAMESPACE) return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
return Boolean(ALL_SVG_TAGS[tagName]);
};
/**
* Namespace rules for an element in the MathML namespace.
*
* @param tagName the element's lowercase tag name
* @param parent the (possibly simulated) parent node
* @param parentTagName the parent's lowercase tag name
* @returns true if a spec-compliant parser could produce this element
*/
const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) {
if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "math";
if (parent.namespaceURI === SVG_NAMESPACE) return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName];
return Boolean(ALL_MATHML_TAGS[tagName]);
};
/**
* Namespace rules for an element in the HTML namespace.
*
* @param tagName the element's lowercase tag name
* @param parent the (possibly simulated) parent node
* @param parentTagName the parent's lowercase tag name
* @returns true if a spec-compliant parser could produce this element
*/
const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) {
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) return false;
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) return false;
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
};
/**
* @param element a DOM element whose namespace is being checked
* @returns Return false if the element has a
* namespace that a spec-compliant parser would never
* return. Return true otherwise.
*/
const _checkValidNamespace = function _checkValidNamespace(element) {
let parent = getParentNode(element);
if (!parent || !parent.tagName) parent = {
namespaceURI: NAMESPACE,
tagName: "template"
};
const tagName = stringToLowerCase(element.tagName);
const parentTagName = stringToLowerCase(parent.tagName);
if (!ALLOWED_NAMESPACES[element.namespaceURI]) return false;
if (element.namespaceURI === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName);
if (element.namespaceURI === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName);
if (element.namespaceURI === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName);
if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) return true;
return false;
};
/**
* _forceRemove
*
* @param node a DOM node
*/
const _forceRemove = function _forceRemove(node) {
arrayPush(DOMPurify.removed, { element: node });
try {
getParentNode(node).removeChild(node);
} catch (_) {
remove(node);
if (!getParentNode(node)) throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place");
}
};
/**
* _neutralizeRoot
*
* Fail-closed teardown of an in-place root after the sanitize walk aborts
* (campaign-3 F2). An internal throw mid-walk — e.g. a page-registered
* custom element's reaction detaches a node so `_forceRemove`'s deliberate
* parentless guard throws, or any other re-entrant engine mutation — would
* otherwise leave the caller's *live* tree half-sanitized, with everything
* after the abort point still carrying its handlers. There is no safe way
* to resume the walk (the tree mutated under us), so we strip the root bare:
* remove every child and every attribute, then let the caller's catch see
* the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes`
* getters; the root was already clobber-pre-flighted at the IN_PLACE entry).
*
* @param root the in-place root to empty
*/
const _neutralizeRoot = function _neutralizeRoot(root) {
const childNodes = getChildNodes(root);
if (childNodes) {
const snapshot = [];
arrayForEach(childNodes, (child) => {
arrayPush(snapshot, child);
});
arrayForEach(snapshot, (child) => {
try {
remove(child);
} catch (_) {}
});
}
const attributes = getAttributes(root);
if (attributes) for (let i = attributes.length - 1; i >= 0; --i) {
const attribute = attributes[i];
const name = attribute && attribute.name;
if (typeof name === "string") try {
root.removeAttribute(name);
} catch (_) {}
}
};
/**
* _removeAttribute
*
* @param name an Attribute name
* @param element a DOM node
*/
const _removeAttribute = function _removeAttribute(name, element) {
try {
arrayPush(DOMPurify.removed, {
attribute: element.getAttributeNode(name),
from: element
});
} catch (_) {
arrayPush(DOMPurify.removed, {
attribute: null,
from: element
});
}
element.removeAttribute(name);
if (name === "is") if (RETURN_DOM || RETURN_DOM_FRAGMENT) try {
_forceRemove(element);
} catch (_) {}
else try {
element.setAttribute(name, "");
} catch (_) {}
};
/**
* _stripDisallowedAttributes
*
* Removes every attribute the active configuration does not allow from a
* single element, using the same allowlist as the main attribute pass (so
* `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to
* neutralise nodes that are being discarded from an in-place tree.
*
* @param element the element to strip
*/
const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) {
const attributes = getAttributes(element);
if (!attributes) return;
for (let i = attributes.length - 1; i >= 0; --i) {
const attribute = attributes[i];
const name = attribute && attribute.name;
if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue;
try {
element.removeAttribute(name);
} catch (_) {}
}
};
/**
* _neutralizeSubtree
*
* Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT
* move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary,
* namespace, comment, processing-instruction and KEEP_CONTENT:false removals
* all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path
* those dropped nodes are detached from the caller's LIVE tree but a
* handler-bearing original among them (an `<img onerror>`/`<video>` that was
* loading) keeps its queued resource event, which fires in page scope after
* sanitize returns. This walks a removed subtree and strips every attribute
* the active configuration does not allow — so `on*` handlers are cancelled
* through the SAME allowlist that governs kept nodes, not a separate `/^on/`
* blocklist. Run synchronously before sanitize returns, i.e. before any
* queued event can fire. Hook-free by design: these nodes leave the output,
* so firing attribute hooks for them would be surprising. Clobber-safe reads;
* a doomed clobbered node may shadow `removeAttribute` (its own attributes are
* irrelevant — it is discarded — while its non-clobbered descendants, e.g.
* the `<img>`, are reached and scrubbed).
*
* @param root the root of a removed subtree to neutralise
*/
const _neutralizeSubtree = function _neutralizeSubtree(root) {
const stack = [root];
while (stack.length > 0) {
const node = stack.pop();
if ((getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element) _stripDisallowedAttributes(node);
const childNodes = getChildNodes(node);
if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
}
};
/**
* _initDocument
*
* @param dirty - a string of dirty markup
* @return a DOM, filled with the dirty markup
*/
const _initDocument = function _initDocument(dirty) {
let doc = null;
let leadingWhitespace = null;
if (FORCE_BODY) dirty = "<remove></remove>" + dirty;
else {
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
leadingWhitespace = matches && matches[0];
}
if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) dirty = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>" + dirty + "</body></html>";
const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
if (NAMESPACE === HTML_NAMESPACE) try {
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
} catch (_) {}
if (!doc || !doc.documentElement) {
doc = implementation.createDocument(NAMESPACE, "template", null);
try {
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
} catch (_) {}
}
const body = doc.body || doc.documentElement;
if (dirty && leadingWhitespace) body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
if (NAMESPACE === HTML_NAMESPACE) return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0];
return WHOLE_DOCUMENT ? doc.documentElement : body;
};
/**
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
*
* @param root The root element or node to start traversing on.
* @return The created NodeIterator
*/
const _createNodeIterator = function _createNodeIterator(root) {
return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
};
/**
* Replace template expression syntax (mustache, ERB, template
* literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub
* sites. Order matters: mustache, then ERB, then template literal.
*
* @param value the string to scrub
* @returns the scrubbed string
*/
const _stripTemplateExpressions = function _stripTemplateExpressions(value) {
value = stringReplace(value, MUSTACHE_EXPR$1, " ");
value = stringReplace(value, ERB_EXPR$1, " ");
value = stringReplace(value, TMPLIT_EXPR$1, " ");
return value;
};
/**
* Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
* character data of an element subtree. Used as the final safety net for
* SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
* which only form after text-node normalization (e.g. fragments split across
* stripped elements) cannot survive into a template-evaluating framework.
*
* Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
* in place rather than round-tripping through innerHTML. This preserves
* descendant node references (important for IN_PLACE callers), avoids a
* serialize/reparse cycle, and reads literal character data — which means
* `<%...%>` in text content matches the ERB regex against its real bytes
* instead of the HTML-entity-escaped form innerHTML would produce.
*
* Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
* attributes is performed during the per-node `_sanitizeAttributes` pass.
*
* @param node The root element whose character data should be scrubbed.
*/
const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
var _node$querySelectorAl;
node.normalize();
const walker = createNodeIterator.call(node.ownerDocument || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
let currentNode = walker.nextNode();
while (currentNode) {
currentNode.data = _stripTemplateExpressions(currentNode.data);
currentNode = walker.nextNode();
}
const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template");
if (templates) arrayForEach(templates, (tmpl) => {
if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content);
});
};
/**
* _isClobbered
*
* Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
* interface with [LegacyOverrideBuiltIns]; a descendant element with a
* `name` attribute matching a prototype property shadows that property
* on direct reads. We use this check at the IN_PLACE entry-point and
* during attribute sanitization to refuse clobbered forms.
*
* @param element element to check for clobbering attacks
* @return true if clobbered, false if safe
*/
const _isClobbered = function _isClobbered(element) {
const realTagName = getNodeName ? getNodeName(element) : null;
if (typeof realTagName !== "string") return false;
if (transformCaseFunc(realTagName) !== "form") return false;
return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || element.nodeType !== getNodeType(element) || element.childNodes !== getChildNodes(element);
};
/**
* Checks whether the given value is a DocumentFragment from any realm.
*
* The realm-independent replacement reads `nodeType` through the cached
* Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
* constant (11). nodeType is a numeric value resolved from the node's
* internal slot, identical across realms for the same kind of node.
*
* @param value object to check
* @return true if value is a DocumentFragment-shaped node from any realm
*/
const _isDocumentFragment = function _isDocumentFragment(value) {
if (!getNodeType || typeof value !== "object" || value === null) return false;
try {
return getNodeType(value) === NODE_TYPE.documentFragment;
} catch (_) {
return false;
}
};
/**
* Checks whether the given object is a DOM node, including nodes that
* originate from a different window/realm (e.g. an iframe's
* contentDocument). The previous `value instanceof Node` check was
* realm-bound: nodes from a different window failed it, causing
* sanitize() to silently stringify them and reset IN_PLACE to false,
* returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
*
* @param value object to check whether it's a DOM node
* @return true if value is a DOM node from any realm
*/
const _isNode = function _isNode(value) {
if (!getNodeType || typeof value !== "object" || value === null) return false;
try {
return typeof getNodeType(value) === "number";
} catch (_) {
return false;
}
};
function _executeHooks(hooks, currentNode, data) {
if (hooks.length === 0) return;
arrayForEach(hooks, (hook) => {
hook.call(DOMPurify, currentNode, data, CONFIG);
});
}
/**
* Structural-threat checks that condemn a node regardless of the
* allowlists: mXSS via namespace confusion, risky CSS construction,
* processing instructions, markup-bearing comments. Pure predicate;
* the caller removes. Check order is load-bearing.
*
* @param currentNode the node to inspect
* @param tagName the node's transformCaseFunc'd tag name
* @return true if the node must be removed
*/
const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true;
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) return true;
if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true;
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true;
return false;
};
/**
* Handle a node whose tag is forbidden or not allowlisted: keep
* allowed custom elements (false return exits _sanitizeElements
* early - namespace/fallback checks and the afterSanitizeElements
* hook are intentionally skipped for kept custom elements), else
* hoist content per KEEP_CONTENT and remove.
*
* @param currentNode the disallowed node
* @param tagName the node's transformCaseFunc'd tag name
* @return true if the node was removed, false if kept
*/
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) {
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
}
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
const parentNode = getParentNode(currentNode);
const childNodes = getChildNodes(currentNode);
if (childNodes && parentNode) {
const childCount = childNodes.length;
for (let i = childCount - 1; i >= 0; --i) {
const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true);
parentNode.insertBefore(hoisted, getNextSibling(currentNode));
}
}
}
_forceRemove(currentNode);
return true;
};
/**
* _sanitizeElements
*
* @protect nodeName
* @protect textContent
* @protect removeChild
* @param currentNode to check for permission to exist
* @return true if node was killed, false if left alive
*/
const _sanitizeElements = function _sanitizeElements(currentNode) {
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
if (_isClobbered(currentNode)) {
_forceRemove(currentNode);
return true;
}
const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
_executeHooks(hooks.uponSanitizeElement, currentNode, {
tagName,
allowedTags: ALLOWED_TAGS
});
if (_isUnsafeNode(currentNode, tagName)) {
_forceRemove(currentNode);
return true;
}
if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) return _sanitizeDisallowedNode(currentNode, tagName);
if ((getNodeType ? getNodeType(currentNode) : currentNode.nodeType) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
_forceRemove(currentNode);
return true;
}
if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) {
_forceRemove(currentNode);
return true;
}
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
const content = _stripTemplateExpressions(currentNode.textContent);
if (currentNode.textContent !== content) {
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
currentNode.textContent = content;
}
}
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
return false;
};
/**
* _isValidAttribute
*
* @param lcTag Lowercase tag name of containing element.
* @param lcName Lowercase attribute name.
* @param value Attribute value.
* @return Returns true if `value` is valid, otherwise false.
*/
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
if (FORBID_ATTR[lcName]) return false;
if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false;
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName));
else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName));
else if (!nameIsPermitted) if (_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));
else return false;
else if (URI_SAFE_ATTRIBUTES[lcName]);
else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, "")));
else if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]);
else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, "")));
else if (value) return false;
return true;
};
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [
"annotation-xml",
"color-profile",
"font-face",
"font-face-format",
"font-face-name",
"font-face-src",
"font-face-uri",
"missing-glyph"
]);
/**
* _isBasicCustomElement
* checks if at least one dash is included in tagName, and it's not the first char
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
*
* @param tagName name of the tag of the node to sanitize
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
*/
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
};
/**
* Wrap an attribute value in the matching Trusted Types object when
* the active policy requires it. Namespaced attributes pass through
* unchanged (no TT support yet, see
* https://bugs.chromium.org/p/chromium/issues/detail?id=1305293).
*
* @param lcTag lowercase tag name of the containing element
* @param lcName lowercase attribute name
* @param namespaceURI the attribute's namespace, if any
* @param value the attribute value to wrap
* @return the value, wrapped when Trusted Types demand it
*/
const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) {
if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) switch (trustedTypes.getAttributeType(lcTag, lcName)) {
case "TrustedHTML": return _createTrustedHTML(value);
case "TrustedScriptURL": return _createTrustedScriptURL(value);
}
return value;
};
/**
* Write a modified attribute value back onto the element. On
* success, re-probe for clobbering introduced by the new value and
* remove the element when found; otherwise pop the removal entry
* recorded by the earlier _removeAttribute (long-standing pairing
* with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On
* failure, remove the attribute instead.
*
* @param currentNode the element carrying the attribute
* @param name the attribute name as present on the element
* @param namespaceURI the attribute's namespace, if any
* @param value the new attribute value
*/
const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) {
try {
if (namespaceURI) currentNode.setAttributeNS(namespaceURI, name, value);
else currentNode.setAttribute(name, value);
if (_isClobbered(currentNode)) _forceRemove(currentNode);
else arrayPop(DOMPurify.removed);
} catch (_) {
_removeAttribute(name, currentNode);
}
};
/**
* _sanitizeAttributes
*
* @protect attributes
* @protect nodeName
* @protect removeAttribute
* @protect setAttribute
*
* @param currentNode to sanitize
*/
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
const attributes = currentNode.attributes;
if (!attributes || _isClobbered(currentNode)) return;
const hookEvent = {
attrName: "",
attrValue: "",
keepAttr: true,
allowedAttributes: ALLOWED_ATTR,
forceKeepAttr: void 0
};
let l = attributes.length;
const lcTag = transformCaseFunc(currentNode.nodeName);
while (l--) {
const attr = attributes[l];
const name = attr.name, namespaceURI = attr.namespaceURI, attrValue = attr.value;
const lcName = transformCaseFunc(name);
const initValue = attrValue;
let value = name === "value" ? initValue : stringTrim(initValue);
hookEvent.attrName = lcName;
hookEvent.attrValue = value;
hookEvent.keepAttr = true;
hookEvent.forceKeepAttr = void 0;
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
value = hookEvent.attrValue;
if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
_removeAttribute(name, currentNode);
value = SANITIZE_NAMED_PROPS_PREFIX + value;
}
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
_removeAttribute(name, currentNode);
continue;
}
if (lcName === "attributename" && stringMatch(value, "href")) {
_removeAttribute(name, currentNode);
continue;
}
if (hookEvent.forceKeepAttr) continue;
if (!hookEvent.keepAttr) {
_removeAttribute(name, currentNode);
continue;
}
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
_removeAttribute(name, currentNode);
continue;
}
if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value);
if (!_isValidAttribute(lcTag, lcName, value)) {
_removeAttribute(name, currentNode);
continue;
}
value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
if (value !== initValue) _setAttributeValue(currentNode, name, namespaceURI, value);
}
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
};
/**
* _sanitizeShadowDOM
*
* @param fragment to iterate over recursively
*/
const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
let shadowNode = null;
const shadowIterator = _createNodeIterator(fragment);
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
while (shadowNode = shadowIterator.nextNode()) {
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
_sanitizeElements(shadowNode);
_sanitizeAttributes(shadowNode);
if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content);
if ((getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType) === NODE_TYPE.element) {
const innerSr = getShadowRoot(shadowNode);
if (_isDocumentFragment(innerSr)) {
_sanitizeAttachedShadowRoots(innerSr);
_sanitizeShadowDOM2(innerSr);
}
}
}
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
};
/**
* _sanitizeAttachedShadowRoots
*
* Walks `root` and feeds every attached shadow root we encounter into
* the existing _sanitizeShadowDOM pipeline. The default node iterator
* does not descend into shadow trees, so nodes inside an attached
* shadow root would otherwise be skipped entirely.
*
* Two real input paths put attached shadow roots in front of us:
* 1. IN_PLACE on a DOM node that already has shadow roots attached.
* 2. DOM-node input where importNode(dirty, true) deep-clones the
* shadow root because it was created with `clonable: true`.
*
* This pass runs once, up front, so the main iteration loop (and the
* existing _sanitizeShadowDOM template-content recursion) stay
* untouched — string-input paths are not affected.
*
* @param root the subtree root to walk for attached shadow roots
*/
const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) {
const stack = [{
node: root,
shadow: null
}];
while (stack.length > 0) {
const item = stack.pop();
if (item.shadow) {
_sanitizeShadowDOM2(item.shadow);
continue;
}
const node = item.node;
const isElement = (getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element;
const childNodes = getChildNodes(node);
if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({
node: childNodes[i],
shadow: null
});
if (isElement) {
const rootName = getNodeName ? getNodeName(node) : null;
if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") {
const content = node.content;
if (_isDocumentFragment(content)) stack.push({
node: content,
shadow: null
});
}
}
if (isElement) {
const sr = getShadowRoot(node);
if (_isDocumentFragment(sr)) stack.push({
node: null,
shadow: sr
}, {
node: sr,
shadow: null
});
}
}
};
DOMPurify.sanitize = function(dirty) {
let cfg = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
let body = null;
let importedNode = null;
let currentNode = null;
let returnNode = null;
IS_EMPTY_INPUT = !dirty;
if (IS_EMPTY_INPUT) dirty = "<!-->";
if (typeof dirty !== "string" && !_isNode(dirty)) {
dirty = stringifyValue(dirty);
if (typeof dirty !== "string") throw typeErrorCreate("dirty is not a string, aborting");
}
if (!DOMPurify.isSupported) return dirty;
if (!SET_CONFIG) _parseConfig(cfg);
DOMPurify.removed = [];
const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
if (inPlace) {
const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
if (typeof nn === "string") {
const tagName = transformCaseFunc(nn);
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place");
}
if (_isClobbered(dirty)) throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place");
try {
_sanitizeAttachedShadowRoots(dirty);
} catch (error) {
_neutralizeRoot(dirty);
throw error;
}
} else if (_isNode(dirty)) {
body = _initDocument("<!---->");
importedNode = body.ownerDocument.importNode(dirty, true);
if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") body = importedNode;
else if (importedNode.nodeName === "HTML") body = importedNode;
else body.appendChild(importedNode);
_sanitizeAttachedShadowRoots(importedNode);
} else {
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
body = _initDocument(dirty);
if (!body) return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : "";
}
if (body && FORCE_BODY) _forceRemove(body.firstChild);
const nodeIterator = _createNodeIterator(inPlace ? dirty : body);
try {
while (currentNode = nodeIterator.nextNode()) {
_sanitizeElements(currentNode);
_sanitizeAttributes(currentNode);
if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content);
}
} catch (error) {
if (inPlace) _neutralizeRoot(dirty);
throw error;
}
if (inPlace) {
arrayForEach(DOMPurify.removed, (entry) => {
if (entry.element) _neutralizeSubtree(entry.element);
});
if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty);
return dirty;
}
if (RETURN_DOM) {
if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(body);
if (RETURN_DOM_FRAGMENT) {
returnNode = createDocumentFragment.call(body.ownerDocument);
while (body.firstChild) returnNode.appendChild(body.firstChild);
} else returnNode = body;
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) returnNode = importNode.call(originalDocument, returnNode, true);
return returnNode;
}
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML;
if (SAFE_FOR_TEMPLATES) serializedHTML = _stripTemplateExpressions(serializedHTML);
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
};
DOMPurify.setConfig = function() {
_parseConfig(arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {});
SET_CONFIG = true;
};
DOMPurify.clearConfig = function() {
CONFIG = null;
SET_CONFIG = false;
trustedTypesPolicy = defaultTrustedTypesPolicy;
emptyHTML = "";
};
DOMPurify.isValidAttribute = function(tag, attr, value) {
if (!CONFIG) _parseConfig({});
return _isValidAttribute(transformCaseFunc(tag), transformCaseFunc(attr), value);
};
DOMPurify.addHook = function(entryPoint, hookFunction) {
if (typeof hookFunction !== "function") return;
arrayPush(hooks[entryPoint], hookFunction);
};
DOMPurify.removeHook = function(entryPoint, hookFunction) {
if (hookFunction !== void 0) {
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0];
}
return arrayPop(hooks[entryPoint]);
};
DOMPurify.removeHooks = function(entryPoint) {
hooks[entryPoint] = [];
};
DOMPurify.removeAllHooks = function() {
hooks = _createHooksMap();
};
return DOMPurify;
}
var purify = createDOMPurify();
//#endregion
export { purify as default };
//# sourceMappingURL=purify.es-erUxcz-o.js.map