'use strict'; let domParser; const isDocumentOrFragment = (el) => el.nodeType === el.DOCUMENT_NODE || el.nodeType === el.DOCUMENT_FRAGMENT_NODE; const isElement = (el) => el.nodeType === el.ELEMENT_NODE; const isComment = (el) => el.nodeType === el.COMMENT_NODE; function getTagName(el) { return isElement(el) ? el.tagName.toLowerCase() : void 0; } const DISALLOWED_FORM_ATTR_TAG_NAMES = "button,fieldset,input,label,meter,object,output,select,textarea".split(","); const DISALLOWED_ATTR_NAMES = "autofocus,datafld,dataformatas,datasrc".split( "," ); const sanitizeAttributes = (el) => { const tagName = getTagName(el); const attrs = el.attributes; for (let i = 0, len = attrs.length; i < len; i++) { const attr = attrs[i]; const { name, value } = attr; if (name === "is") { attr.value = ""; } else if (DISALLOWED_ATTR_NAMES.includes(name) || name === "form" && DISALLOWED_FORM_ATTR_TAG_NAMES.includes(tagName) || /^(?:["'<=>`]|on)/i.test(name) || /\s/.test(name) || /^(?:\w+script|data):/i.test(value.replaceAll(/\r?\n/g, ""))) { el.removeAttributeNode(attr); i--; len--; } } return el; }; const sanitizeChildren = (el) => { for (let i = 0, len = el.childNodes.length; i < len; i++) { const item = el.childNodes[i]; const sanitized = sanitizeNode(item, getTagName(el)); if (sanitized === item) { continue; } if (sanitized == null || typeof sanitized === "string") { item.replaceWith(...sanitized == null ? [] : [sanitized]); i--; len--; } } return el; }; const MathML_TAG_NAMES = "error,frac,i,multiscripts,n,o,over,padded,phantom,root,row,s,space,sqrt,style,sub,subsup,sup,table,td,text,tr,under,underover".split(",").map((it) => `m${it}`); const DANGEROUS_OR_OBSOLETE_TAG_NAMES = "event-source,listing".split(","); function sanitizeNode(el, parentTagName) { if (isDocumentOrFragment(el)) { return sanitizeChildren(el); } if (isComment(el)) { return; } if (!isElement(el)) { return el; } const tagName = getTagName(el); if (parentTagName === "math" && !MathML_TAG_NAMES.includes(tagName) || DANGEROUS_OR_OBSOLETE_TAG_NAMES.includes(tagName) || // unknown HTML element el instanceof HTMLUnknownElement || // unknown SVG element Object.getPrototypeOf(el) === SVGElement.prototype && // https://github.com/jsdom/jsdom/issues/2734 !["defs", "filter", "g", "script"].includes(tagName)) { return el.textContent; } switch (tagName) { case "style": { const { sheet } = el; if ((sheet == null ? void 0 : sheet.ownerRule) || (sheet == null ? void 0 : sheet.cssRules.length)) { break; } } case "embed": case "iframe": case "link": case "meta": case "object": case "parsererror": case "script": case "noembed": case "xmp": { return el.remove(); } case "template": { sanitizeChildren(el.content); } } return sanitizeChildren(sanitizeAttributes(el)); } const TEXT_HTML = "text/html"; const IMAGE_SVG_XML = "image/svg+xml"; const sanitize = (domString, typeOrFragment) => { var _a; const trimmed = domString.trim(); if (!trimmed) { return domString; } if (!domParser) { domParser = new DOMParser(); } const { type = TEXT_HTML, fragment } = typeOrFragment == null || typeof typeOrFragment === "string" ? { type: typeOrFragment } : { fragment: typeOrFragment }; const doc = sanitizeNode( domParser.parseFromString( // make sure the string is wrapped in a body tag fragment ? `${domString}` : domString, type ) ); return fragment && type === TEXT_HTML ? doc.body.innerHTML : ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- https://github.com/microsoft/TypeScript/issues/50078 ((_a = doc.documentElement) == null ? void 0 : _a.outerHTML) || "" ); }; const sanitizeSvg = (svg) => sanitize(svg, IMAGE_SVG_XML); exports.IMAGE_SVG_XML = IMAGE_SVG_XML; exports.TEXT_HTML = TEXT_HTML; exports.sanitize = sanitize; exports.sanitizeSvg = sanitizeSvg;