From 1a39e8b0f732507c561d7f0d6bb8fe1bacffba07 Mon Sep 17 00:00:00 2001 From: audioscavenger Date: Mon, 1 Sep 2025 18:19:40 -0700 Subject: [PATCH] release 2.87 right-click - finally! right-click any node with IMAGE output adds "Add SaveImageExtended" option - upgraded purify.min.js modified: README.md modified: pyproject.toml modified: save_image_extended.py modified: web/js/contextmenu.js modified: web/js/purify.min.js --- README.md | 24 +++++++++--- assets/ComfyUI-version-tested.png | Bin 0 -> 16783 bytes pyproject.toml | 2 +- save_image_extended.py | 5 ++- web/js/contextmenu.js | 63 ++++++++++++++++++++++++++---- web/js/purify.min.js | 4 +- web/js/purify.min.js.map | 1 + 7 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 assets/ComfyUI-version-tested.png create mode 100644 web/js/purify.min.js.map diff --git a/README.md b/README.md index 36b15cc..c01a6b2 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ Supports those extensions: **JXL AVIF WebP jpg jpeg j2k jp2 png gif tiff bmp**

-## Parameters / Usage +## Parameters / Reserved Keywords | Attribute | Description | | --- | --- | -| `filename_prefix` | Fixed string prefixed to file name. | -| `filename_keys` | Comma separated string with sampler parameters to add to filename. E.g: `sampler_name, scheduler, cfg, denoise` Added to filename in written order. `resolution` also works. `vae_name` `model_name` (upscale model), `ckpt_name` (checkpoint) are others that should work. Here you can try any parameter name of any node. As long as the parameter has the same variable name defined in the `prompt` object, they should work. The same applies to `foldername_keys`. | +| `filename_prefix` | **Static string** prefixed to file name. | +| `filename_keys` | Comma separated string with sampler parameters to add to filename. E.g: `sampler_name, scheduler, cfg, denoise` Added to filename in written order. `vae_name` `model_name` (upscale model), `ckpt_name` (checkpoint) are others that should work. Here you can try any parameter name of any node. As long as the parameter has the same variable name defined in the `prompt` object, they should work. The same applies to `foldername_keys`. | | `foldername_prefix` | Fixed string prefixed to subfolders. | | `foldername_keys` | Same rules as for `filename_keys`. Create subfolders by using `/` or `../` etc. | | `delimiter` | **now a free field** Delimiter = any string you like. You can also use `/` to create subfolders. | @@ -38,11 +38,13 @@ Supports those extensions: **JXL AVIF WebP jpg jpeg j2k jp2 png gif tiff bmp** | `image_preview` | Turns the image preview on and off. | | `output_ext` | File extension: WEBP by default, AVIF, PNG, JXL, JPG, etc. | | `quality` | Quality for JPEG/JXL/WebP/AVIF/J2K formats; Quality is relative to each format. Example: AVIF 60 is same quality as WebP 90. PNG compression is fixed at 4 and not affected by this. PNG compression times skyrocket above level 4 for zero benefits on filesize. | +| `resolution` | Saved image reolution in format `000x000` (pixels). | `named_keys` | Prefix each value by its key name. Example: prefix-seed=123456-width=1024-cfg=5.0-0001.avif | - -- Unknown key names in `filename_keys` and `foldername_keys` are treated as fixed strings - - if you enter `wrongNumber.attribute`, you will get `attribute` in your filename. +- ANY other keyword that exist as a field name in a widget will be resolved. + - That is why I do not list all common keywords like `ckpt_name` etc, as they are virtually infinite and exist only within your workflow. +- Unknown key names not found in any widget's fields are treated as fixed strings + - if you enter `wrongNumber.attribute`, you will also get `attribute` as a fixed string. - Datetime UNIX format is now included! `%Y-%m-%d` or `%F` etc: see [unix datetime formats](https://www.man7.org/linux/man-pages/man1/date.1.html) - default it output only the **name** for `ckpt_name` / `control_net_name` / `lora_name` not the **path** - use `ckpt_path` / `control_net_path` / `lora_path` to get the same subfolders as your models @@ -110,6 +112,12 @@ There is a requirements.txt that will take care of that, but just in case: pip install numpy pillow pillow-avif-plugin pillow-jxl-plugin ``` +### Tested on / up to: +* python 3.10.6 +* pytorch 2.5.1+cu124 +* ComfyUI v0.3.12-1-g7fc3ccdc | Released on '2025-01-16' + + ### Manual Download 1. Open a terminal inside the 'custom_nodes' folder located in your ComfyUI installation dir 2. Use the `git clone` command to clone the [save-image-extended-comfyui](https://github.com/audioscavenger/save-image-extended-comfyui) repo under ComfyUI\custom_nodes\ @@ -216,6 +224,10 @@ TODO: - [x] TODO: test import cv2 / OpenCV: https://github.com/python-pillow/Pillow/issues/5986 -> not faster then PIL +### release 2.87 💾 +- finally! right-click any node with IMAGE output adds "Add SaveImageExtended" option +- upgraded purify.min.js + ### release 2.86 💾 - bugfix in counter_digits which does not accept 0 to disable counter diff --git a/assets/ComfyUI-version-tested.png b/assets/ComfyUI-version-tested.png new file mode 100644 index 0000000000000000000000000000000000000000..1f587e933503cba2da081dad5fa4c3517936875d GIT binary patch literal 16783 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 Rf2MFpQ&mr;O35zt{{gRV!s!42 literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml index 90c85ce..332cf6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "save-image-extended-comfyui" description = "Save as JXL, AVIF, WebP, JPEG, JPEG2k, customize the folder, sub-folders, and filenames of your images!" -version = "2.86" +version = "2.87" license = { file = "LICENSE" } dependencies = ["piexif", "imagecodecs", "pillow", "pillow-avif-plugin", "pillow-jxl-plugin"] diff --git a/save_image_extended.py b/save_image_extended.py index ab6f377..f67af13 100644 --- a/save_image_extended.py +++ b/save_image_extended.py @@ -14,7 +14,7 @@ import numpy # import cv2 # not faster then PIL -version = 2.86 +version = 2.87 avif_supported = False jxl_supported = False @@ -33,8 +33,9 @@ else: avif_supported = True # Jxl requires jxlpy wheel to be compiled, and a valid MSVC environment, which is complex task +# Therefore we use pillow_jxl which makes more sense try: - # jxlpy is in early stages of development. None one has ever compiled it on Windows AFAIK + # jxlpy is in early stages of development. No one has ever compiled it on Windows in 2025 AFAIK, please prove me wrong # from jxlpy import JXLImagePlugin # from imagecodecs import (jpegxl_encode, jpegxl_decode, jpegxl_check, jpegxl_version, JPEGXL) import pillow_jxl diff --git a/web/js/contextmenu.js b/web/js/contextmenu.js index f82e191..aebaad9 100644 --- a/web/js/contextmenu.js +++ b/web/js/contextmenu.js @@ -3,24 +3,28 @@ import { app } from "../../../scripts/app.js"; // Adds context menu entries, code partly from pyssssscustom-scripts function addMenuHandler(nodeType, cb) { + // console.debug("SIE addMenuHandler nodeType:", nodeType); + // console.debug("SIE addMenuHandler cb:", cb); const getOpts = nodeType.prototype.getExtraMenuOptions; + + // the below is never called, i suspect app.js has changed a lot nodeType.prototype.getExtraMenuOptions = function () { const r = getOpts.apply(this, arguments); cb.apply(this, arguments); + // console.debug("SIE addMenuHandler arguments:", arguments); return r; }; } + function addNode(name, nextTo, options) { - console.log("name:", name); - console.log("nextTo:", nextTo); - options = { side: "left", select: true, shiftY: 0, shiftX: 0, ...(options || {}) }; + // console.debug("SIE addNode name:", name); + // console.debug("SIE addNode nextTo:", nextTo); + options = { select: true, shiftY: 0, before: false, ...(options || {}) }; const node = LiteGraph.createNode(name); app.graph.add(node); - node.pos = [ - options.side === "left" ? nextTo.pos[0] - (node.size[0] + options.offset): nextTo.pos[0] + nextTo.size[0] + options.offset, - + options.before ? nextTo.pos[0] - node.size[0] - 30 : nextTo.pos[0] + nextTo.size[0] + 30, nextTo.pos[1] + options.shiftY, ]; if (options.select) { @@ -29,12 +33,49 @@ function addNode(name, nextTo, options) { return node; } +// https://docs.comfy.org/custom-nodes/js/javascript_overview app.registerExtension({ - name: "SIEContextmenu", + name: "SIE.QuickNodes", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if ( + // this could go forever if we want to list all nodes that can output IMAGE + // nodeData.name === "VAEDecode" || + // nodeData.name === "LoadImage" || + + // fortunately, output is an array where "IMAGE" is always the first item. + nodeData.output[0] == "IMAGE" + ) { + // console.debug("SIE.QuickNodes VAEDecode nodeType:", nodeType); + // console.debug("SIE.QuickNodes VAEDecode nodeData:", nodeData); + // console.debug("SIE.QuickNodes VAEDecode app:", app); + + // https://docs.comfy.org/custom-nodes/js/javascript_examples#node-menu + // Code below adds SaveImageExtended option on right-click menu for VAEDecode + addMenuHandler(nodeType, function (_, options) { + options.unshift( + { + content: "💾 Add SaveImageExtended", + callback: () => { + // const saveNode = addNode("SaveImageExtended", this, { before: true }); + const saveNode = addNode("SaveImageExtended", this); + this.connect(0, saveNode, 0); + }, + }, + ); + }); + } + }, +}, + +// https://docs.comfy.org/custom-nodes/walkthrough#write-a-client-extension +// I forgot why I added this one, probably not needed after all +{ + name: "SIE.Contextmenu", async setup(app) { + // console.debug("SIEContextmenu app:", app); app.ui.settings.addSetting({ id: "SIE.helpPopup", - name: "🦛 SIE: Help popups", + name: "💾 SIE: Help popups", defaultValue: true, type: "boolean", options: (value) => [ @@ -42,5 +83,11 @@ app.registerExtension({ { value: false, text: "Off", selected: value === false }, ], }); + + } }); + + + + diff --git a/web/js/purify.min.js b/web/js/purify.min.js index 7fa10b6..709ac41 100644 --- a/web/js/purify.min.js +++ b/web/js/purify.min.js @@ -1,3 +1,3 @@ -/*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.0.8/LICENSE */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).DOMPurify=t()}(this,(function(){"use strict";var e=Object.hasOwnProperty,t=Object.setPrototypeOf,n=Object.isFrozen,r=Object.keys,o=Object.freeze,i=Object.seal,a="undefined"!=typeof Reflect&&Reflect,l=a.apply,c=a.construct;l||(l=function(e,t,n){return e.apply(t,n)}),o||(o=function(e){return e}),i||(i=function(e){return e}),c||(c=function(e,t){return new(Function.prototype.bind.apply(e,[null].concat(function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t1?n-1:0),o=1;o/gm),I=i(/^data-[\-\w.\u00B7-\uFFFF]/),U=i(/^aria-[\-\w]+$/),j=i(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),P=i(/^(?:\w+script|data):/i),G=i(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g),W="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function B(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:q(),n=function(t){return e(t)};if(n.version="2.0.12",n.removed=[],!t||!t.document||9!==t.document.nodeType)return n.isSupported=!1,n;var i=t.document,a=!1,l=t.document,c=t.DocumentFragment,S=t.HTMLTemplateElement,k=t.Node,V=t.NodeFilter,Y=t.NamedNodeMap,X=void 0===Y?t.NamedNodeMap||t.MozNamedAttrMap:Y,$=t.Text,J=t.Comment,Q=t.DOMParser,Z=t.trustedTypes;if("function"==typeof S){var ee=l.createElement("template");ee.content&&ee.content.ownerDocument&&(l=ee.content.ownerDocument)}var te=K(Z,i),ne=te&&He?te.createHTML(""):"",re=l,oe=re.implementation,ie=re.createNodeIterator,ae=re.getElementsByTagName,le=re.createDocumentFragment,ce=i.importNode,se={};n.isSupported=oe&&void 0!==oe.createHTMLDocument&&9!==l.documentMode;var ue=F,de=z,fe=I,pe=U,me=P,ye=G,ge=j,he=null,ve=L({},[].concat(B(E),B(M),B(D),B(R),B(N))),be=null,Te=L({},[].concat(B(O),B(w),B(H),B(C))),Ae=null,xe=null,Se=!0,ke=!0,Le=!1,_e=!1,Ee=!1,Me=!1,De=!1,Re=!1,Ne=!1,Oe=!1,we=!1,He=!1,Ce=!0,Fe=!0,ze=!1,Ie={},Ue=L({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","plaintext","script","style","svg","template","thead","title","video","xmp"]),je=null,Pe=L({},["audio","video","img","source","image","track"]),Ge=null,We=L({},["alt","class","for","id","label","name","pattern","placeholder","summary","title","value","style","xmlns"]),Be=null,qe=l.createElement("form"),Ke=function(e){Be&&Be===e||(e&&"object"===(void 0===e?"undefined":W(e))||(e={}),he="ALLOWED_TAGS"in e?L({},e.ALLOWED_TAGS):ve,be="ALLOWED_ATTR"in e?L({},e.ALLOWED_ATTR):Te,Ge="ADD_URI_SAFE_ATTR"in e?L(_(We),e.ADD_URI_SAFE_ATTR):We,je="ADD_DATA_URI_TAGS"in e?L(_(Pe),e.ADD_DATA_URI_TAGS):Pe,Ae="FORBID_TAGS"in e?L({},e.FORBID_TAGS):{},xe="FORBID_ATTR"in e?L({},e.FORBID_ATTR):{},Ie="USE_PROFILES"in e&&e.USE_PROFILES,Se=!1!==e.ALLOW_ARIA_ATTR,ke=!1!==e.ALLOW_DATA_ATTR,Le=e.ALLOW_UNKNOWN_PROTOCOLS||!1,_e=e.SAFE_FOR_JQUERY||!1,Ee=e.SAFE_FOR_TEMPLATES||!1,Me=e.WHOLE_DOCUMENT||!1,Ne=e.RETURN_DOM||!1,Oe=e.RETURN_DOM_FRAGMENT||!1,we=e.RETURN_DOM_IMPORT||!1,He=e.RETURN_TRUSTED_TYPE||!1,Re=e.FORCE_BODY||!1,Ce=!1!==e.SANITIZE_DOM,Fe=!1!==e.KEEP_CONTENT,ze=e.IN_PLACE||!1,ge=e.ALLOWED_URI_REGEXP||ge,Ee&&(ke=!1),Oe&&(Ne=!0),Ie&&(he=L({},[].concat(B(N))),be=[],!0===Ie.html&&(L(he,E),L(be,O)),!0===Ie.svg&&(L(he,M),L(be,w),L(be,C)),!0===Ie.svgFilters&&(L(he,D),L(be,w),L(be,C)),!0===Ie.mathMl&&(L(he,R),L(be,H),L(be,C))),e.ADD_TAGS&&(he===ve&&(he=_(he)),L(he,e.ADD_TAGS)),e.ADD_ATTR&&(be===Te&&(be=_(be)),L(be,e.ADD_ATTR)),e.ADD_URI_SAFE_ATTR&&L(Ge,e.ADD_URI_SAFE_ATTR),Fe&&(he["#text"]=!0),Me&&L(he,["html","head","body"]),he.table&&(L(he,["tbody"]),delete Ae.tbody),o&&o(e),Be=e)},Ve=function(e){p(n.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.outerHTML=ne}},Ye=function(e,t){try{p(n.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(n.removed,{attribute:null,from:t})}t.removeAttribute(e)},Xe=function(e){var t=void 0,n=void 0;if(Re)e=""+e;else{var r=g(e,/^[\r\n\t ]+/);n=r&&r[0]}var o=te?te.createHTML(e):e;try{t=(new Q).parseFromString(o,"text/html")}catch(e){}if(a&&L(Ae,["title"]),!t||!t.documentElement){var i=(t=oe.createHTMLDocument("")).body;i.parentNode.removeChild(i.parentNode.firstElementChild),i.outerHTML=o}return e&&n&&t.body.insertBefore(l.createTextNode(n),t.body.childNodes[0]||null),ae.call(t,Me?"html":"body")[0]};n.isSupported&&function(){try{var e=Xe("</title><img>");T(/<\/title/,e.querySelector("title").innerHTML)&&(a=!0)}catch(e){}}();var $e=function(e){return ie.call(e.ownerDocument||e,e,V.SHOW_ELEMENT|V.SHOW_COMMENT|V.SHOW_TEXT,(function(){return V.FILTER_ACCEPT}),!1)},Je=function(e){return!(e instanceof $||e instanceof J)&&!("string"==typeof e.nodeName&&"string"==typeof e.textContent&&"function"==typeof e.removeChild&&e.attributes instanceof X&&"function"==typeof e.removeAttribute&&"function"==typeof e.setAttribute&&"string"==typeof e.namespaceURI)},Qe=function(e){return"object"===(void 0===k?"undefined":W(k))?e instanceof k:e&&"object"===(void 0===e?"undefined":W(e))&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},Ze=function(e,t,r){se[e]&&s(se[e],(function(e){e.call(n,t,r,Be)}))},et=function(e){var t=void 0;if(Ze("beforeSanitizeElements",e,null),Je(e))return Ve(e),!0;var r=y(e.nodeName);if(Ze("uponSanitizeElement",e,{tagName:r,allowedTags:he}),("svg"===r||"math"===r)&&0!==e.querySelectorAll("p, br").length)return Ve(e),!0;if(!he[r]||Ae[r]){if(Fe&&!Ue[r]&&"function"==typeof e.insertAdjacentHTML)try{var o=e.innerHTML;e.insertAdjacentHTML("AfterEnd",te?te.createHTML(o):o)}catch(e){}return Ve(e),!0}return"noscript"===r&&T(/<\/noscript/i,e.innerHTML)||"noembed"===r&&T(/<\/noembed/i,e.innerHTML)?(Ve(e),!0):(!_e||e.firstElementChild||e.content&&e.content.firstElementChild||!T(/</g,e.textContent)||(p(n.removed,{element:e.cloneNode()}),e.innerHTML?e.innerHTML=h(e.innerHTML,/</g,"<"):e.innerHTML=h(e.textContent,/</g,"<")),Ee&&3===e.nodeType&&(t=e.textContent,t=h(t,ue," "),t=h(t,de," "),e.textContent!==t&&(p(n.removed,{element:e.cloneNode()}),e.textContent=t)),Ze("afterSanitizeElements",e,null),!1)},tt=function(e,t,n){if(Ce&&("id"===t||"name"===t)&&(n in l||n in qe))return!1;if(ke&&T(fe,t));else if(Se&&T(pe,t));else{if(!be[t]||xe[t])return!1;if(Ge[t]);else if(T(ge,h(n,ye,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==v(n,"data:")||!je[e]){if(Le&&!T(me,h(n,ye,"")));else if(n)return!1}else;}return!0},nt=function(e){var t=void 0,o=void 0,i=void 0,a=void 0,l=void 0;Ze("beforeSanitizeAttributes",e,null);var c=e.attributes;if(c){var s={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:be};for(l=c.length;l--;){var p=t=c[l],g=p.name,v=p.namespaceURI;if(o=b(t.value),i=y(g),s.attrName=i,s.attrValue=o,s.keepAttr=!0,s.forceKeepAttr=void 0,Ze("uponSanitizeAttribute",e,s),o=s.attrValue,!s.forceKeepAttr){if("name"===i&&"IMG"===e.nodeName&&c.id)a=c.id,c=m(c,[]),Ye("id",e),Ye(g,e),u(c,a)>l&&e.setAttribute("id",a.value);else{if("INPUT"===e.nodeName&&"type"===i&&"file"===o&&s.keepAttr&&(be[i]||!xe[i]))continue;"id"===g&&e.setAttribute(g,""),Ye(g,e)}if(s.keepAttr)if(_e&&T(/\/>/i,o))Ye(g,e);else if(T(/svg|math/i,e.namespaceURI)&&T(A("</("+d(r(Ue),"|")+")","i"),o))Ye(g,e);else{Ee&&(o=h(o,ue," "),o=h(o,de," "));var x=e.nodeName.toLowerCase();if(tt(x,i,o))try{v?e.setAttributeNS(v,g,o):e.setAttribute(g,o),f(n.removed)}catch(e){}}}}Ze("afterSanitizeAttributes",e,null)}},rt=function e(t){var n=void 0,r=$e(t);for(Ze("beforeSanitizeShadowDOM",t,null);n=r.nextNode();)Ze("uponSanitizeShadowNode",n,null),et(n)||(n.content instanceof c&&e(n.content),nt(n));Ze("afterSanitizeShadowDOM",t,null)};return n.sanitize=function(e,r){var o=void 0,a=void 0,l=void 0,s=void 0,u=void 0;if(e||(e="\x3c!--\x3e"),"string"!=typeof e&&!Qe(e)){if("function"!=typeof e.toString)throw x("toString is not a function");if("string"!=typeof(e=e.toString()))throw x("dirty is not a string, aborting")}if(!n.isSupported){if("object"===W(t.toStaticHTML)||"function"==typeof t.toStaticHTML){if("string"==typeof e)return t.toStaticHTML(e);if(Qe(e))return t.toStaticHTML(e.outerHTML)}return e}if(De||Ke(r),n.removed=[],"string"==typeof e&&(ze=!1),ze);else if(e instanceof k)1===(a=(o=Xe("\x3c!--\x3e")).ownerDocument.importNode(e,!0)).nodeType&&"BODY"===a.nodeName||"HTML"===a.nodeName?o=a:o.appendChild(a);else{if(!Ne&&!Ee&&!Me&&-1===e.indexOf("<"))return te&&He?te.createHTML(e):e;if(!(o=Xe(e)))return Ne?null:ne}o&&Re&&Ve(o.firstChild);for(var d=$e(ze?e:o);l=d.nextNode();)3===l.nodeType&&l===s||et(l)||(l.content instanceof c&&rt(l.content),nt(l),s=l);if(s=null,ze)return e;if(Ne){if(Oe)for(u=le.call(o.ownerDocument);o.firstChild;)u.appendChild(o.firstChild);else u=o;return we&&(u=ce.call(i,u,!0)),u}var f=Me?o.outerHTML:o.innerHTML;return Ee&&(f=h(f,ue," "),f=h(f,de," ")),te&&He?te.createHTML(f):f},n.setConfig=function(e){Ke(e),De=!0},n.clearConfig=function(){Be=null,De=!1},n.isValidAttribute=function(e,t,n){Be||Ke({});var r=y(e),o=y(t);return tt(r,o,n)},n.addHook=function(e,t){"function"==typeof t&&(se[e]=se[e]||[],p(se[e],t))},n.removeHook=function(e){se[e]&&f(se[e])},n.removeHooks=function(e){se[e]&&(se[e]=[])},n.removeAllHooks=function(){se={}},n}()})); +/*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t){for(var n=arguments.length,o=new Array(n>2?n-2:0),r=2;r<n;r++)o[r-2]=arguments[r];return e.apply(t,o)}),s||(s=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];return new e(...n)});const u=w(Array.prototype.forEach),m=w(Array.prototype.lastIndexOf),p=w(Array.prototype.pop),f=w(Array.prototype.push),d=w(Array.prototype.splice),h=w(String.prototype.toLowerCase),g=w(String.prototype.toString),T=w(String.prototype.match),y=w(String.prototype.replace),E=w(String.prototype.indexOf),A=w(String.prototype.trim),_=w(Object.prototype.hasOwnProperty),S=w(RegExp.prototype.test),b=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return s(N,t)});var N;function w(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return c(e,t,o)}}function R(e,o){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:h;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function O(e){for(let t=0;t<e.length;t++){_(e,t)||(e[t]=null)}return e}function v(t){const n=l(null);for(const[o,r]of e(t)){_(t,o)&&(Array.isArray(r)?n[o]=O(r):r&&"object"==typeof r&&r.constructor===Object?n[o]=v(r):n[o]=r)}return n}function D(e,t){for(;null!==e;){const n=r(e,t);if(n){if(n.get)return w(n.get);if("function"==typeof n.value)return w(n.value)}e=o(e)}return function(){return null}}const x=i(["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"]),L=i(["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","slot","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),C=i(["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"]),k=i(["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"]),I=i(["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"]),M=i(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),U=i(["#text"]),z=i(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","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","slot"]),P=i(["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","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"]),H=i(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","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"]),F=i(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),B=a(/\{\{[\w\W]*|[\w\W]*\}\}/gm),W=a(/<%[\w\W]*|[\w\W]*%>/gm),G=a(/\$\{[\w\W]*/gm),Y=a(/^data-[\-\w.\u00B7-\uFFFF]+$/),j=a(/^aria-[\-\w]+$/),X=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),q=a(/^(?:\w+script|data):/i),$=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=a(/^html$/i),V=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var Z=Object.freeze({__proto__:null,ARIA_ATTR:j,ATTR_WHITESPACE:$,CUSTOM_ELEMENT:V,DATA_ATTR:Y,DOCTYPE_NAME:K,ERB_EXPR:W,IS_ALLOWED_URI:X,IS_SCRIPT_OR_DATA:q,MUSTACHE_EXPR:B,TMPLIT_EXPR:G});const J=1,Q=3,ee=7,te=8,ne=9,oe=function(){return"undefined"==typeof window?null:window};var re=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:oe();const o=e=>t(e);if(o.version="3.2.6",o.removed=[],!n||!n.document||n.document.nodeType!==ne||!n.Element)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:w,Element:O,NodeFilter:B,NamedNodeMap:W=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:G,DOMParser:Y,trustedTypes:j}=n,q=O.prototype,$=D(q,"cloneNode"),V=D(q,"remove"),re=D(q,"nextSibling"),ie=D(q,"childNodes"),ae=D(q,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let le,ce="";const{implementation:se,createNodeIterator:ue,createDocumentFragment:me,getElementsByTagName:pe}=r,{importNode:fe}=a;let de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof e&&"function"==typeof ae&&se&&void 0!==se.createHTMLDocument;const{MUSTACHE_EXPR:he,ERB_EXPR:ge,TMPLIT_EXPR:Te,DATA_ATTR:ye,ARIA_ATTR:Ee,IS_SCRIPT_OR_DATA:Ae,ATTR_WHITESPACE:_e,CUSTOM_ELEMENT:Se}=Z;let{IS_ALLOWED_URI:be}=Z,Ne=null;const we=R({},[...x,...L,...C,...I,...U]);let Re=null;const Oe=R({},[...z,...P,...H,...F]);let ve=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),De=null,xe=null,Le=!0,Ce=!0,ke=!1,Ie=!0,Me=!1,Ue=!0,ze=!1,Pe=!1,He=!1,Fe=!1,Be=!1,We=!1,Ge=!0,Ye=!1,je=!0,Xe=!1,qe={},$e=null;const Ke=R({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Ve=null;const Ze=R({},["audio","video","img","source","image","track"]);let Je=null;const Qe=R({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),et="http://www.w3.org/1998/Math/MathML",tt="http://www.w3.org/2000/svg",nt="http://www.w3.org/1999/xhtml";let ot=nt,rt=!1,it=null;const at=R({},[et,tt,nt],g);let lt=R({},["mi","mo","mn","ms","mtext"]),ct=R({},["annotation-xml"]);const st=R({},["title","style","font","a","script"]);let ut=null;const mt=["application/xhtml+xml","text/html"];let pt=null,ft=null;const dt=r.createElement("form"),ht=function(e){return e instanceof RegExp||e instanceof Function},gt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ft||ft!==e){if(e&&"object"==typeof e||(e={}),e=v(e),ut=-1===mt.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,pt="application/xhtml+xml"===ut?g:h,Ne=_(e,"ALLOWED_TAGS")?R({},e.ALLOWED_TAGS,pt):we,Re=_(e,"ALLOWED_ATTR")?R({},e.ALLOWED_ATTR,pt):Oe,it=_(e,"ALLOWED_NAMESPACES")?R({},e.ALLOWED_NAMESPACES,g):at,Je=_(e,"ADD_URI_SAFE_ATTR")?R(v(Qe),e.ADD_URI_SAFE_ATTR,pt):Qe,Ve=_(e,"ADD_DATA_URI_TAGS")?R(v(Ze),e.ADD_DATA_URI_TAGS,pt):Ze,$e=_(e,"FORBID_CONTENTS")?R({},e.FORBID_CONTENTS,pt):Ke,De=_(e,"FORBID_TAGS")?R({},e.FORBID_TAGS,pt):v({}),xe=_(e,"FORBID_ATTR")?R({},e.FORBID_ATTR,pt):v({}),qe=!!_(e,"USE_PROFILES")&&e.USE_PROFILES,Le=!1!==e.ALLOW_ARIA_ATTR,Ce=!1!==e.ALLOW_DATA_ATTR,ke=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Ie=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Me=e.SAFE_FOR_TEMPLATES||!1,Ue=!1!==e.SAFE_FOR_XML,ze=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,Be=e.RETURN_DOM_FRAGMENT||!1,We=e.RETURN_TRUSTED_TYPE||!1,He=e.FORCE_BODY||!1,Ge=!1!==e.SANITIZE_DOM,Ye=e.SANITIZE_NAMED_PROPS||!1,je=!1!==e.KEEP_CONTENT,Xe=e.IN_PLACE||!1,be=e.ALLOWED_URI_REGEXP||X,ot=e.NAMESPACE||nt,lt=e.MATHML_TEXT_INTEGRATION_POINTS||lt,ct=e.HTML_INTEGRATION_POINTS||ct,ve=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(ve.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(ve.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(ve.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Me&&(Ce=!1),Be&&(Fe=!0),qe&&(Ne=R({},U),Re=[],!0===qe.html&&(R(Ne,x),R(Re,z)),!0===qe.svg&&(R(Ne,L),R(Re,P),R(Re,F)),!0===qe.svgFilters&&(R(Ne,C),R(Re,P),R(Re,F)),!0===qe.mathMl&&(R(Ne,I),R(Re,H),R(Re,F))),e.ADD_TAGS&&(Ne===we&&(Ne=v(Ne)),R(Ne,e.ADD_TAGS,pt)),e.ADD_ATTR&&(Re===Oe&&(Re=v(Re)),R(Re,e.ADD_ATTR,pt)),e.ADD_URI_SAFE_ATTR&&R(Je,e.ADD_URI_SAFE_ATTR,pt),e.FORBID_CONTENTS&&($e===Ke&&($e=v($e)),R($e,e.FORBID_CONTENTS,pt)),je&&(Ne["#text"]=!0),ze&&R(Ne,["html","head","body"]),Ne.table&&(R(Ne,["tbody"]),delete De.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');le=e.TRUSTED_TYPES_POLICY,ce=le.createHTML("")}else void 0===le&&(le=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(j,c)),null!==le&&"string"==typeof ce&&(ce=le.createHTML(""));i&&i(e),ft=e}},Tt=R({},[...L,...C,...k]),yt=R({},[...I,...M]),Et=function(e){f(o.removed,{element:e});try{ae(e).removeChild(e)}catch(t){V(e)}},At=function(e,t){try{f(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){f(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(Fe||Be)try{Et(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},_t=function(e){let t=null,n=null;if(He)e="<remove></remove>"+e;else{const t=T(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===ut&&ot===nt&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=le?le.createHTML(e):e;if(ot===nt)try{t=(new Y).parseFromString(o,ut)}catch(e){}if(!t||!t.documentElement){t=se.createDocument(ot,"template",null);try{t.documentElement.innerHTML=rt?ce:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),ot===nt?pe.call(t,ze?"html":"body")[0]:ze?t.documentElement:i},St=function(e){return ue.call(e.ownerDocument||e,e,B.SHOW_ELEMENT|B.SHOW_COMMENT|B.SHOW_TEXT|B.SHOW_PROCESSING_INSTRUCTION|B.SHOW_CDATA_SECTION,null)},bt=function(e){return e instanceof G&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof W)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof w&&e instanceof w};function wt(e,t,n){u(e,(e=>{e.call(o,t,n,ft)}))}const Rt=function(e){let t=null;if(wt(de.beforeSanitizeElements,e,null),bt(e))return Et(e),!0;const n=pt(e.nodeName);if(wt(de.uponSanitizeElement,e,{tagName:n,allowedTags:Ne}),Ue&&e.hasChildNodes()&&!Nt(e.firstElementChild)&&S(/<[/\w!]/g,e.innerHTML)&&S(/<[/\w!]/g,e.textContent))return Et(e),!0;if(e.nodeType===ee)return Et(e),!0;if(Ue&&e.nodeType===te&&S(/<[/\w]/g,e.data))return Et(e),!0;if(!Ne[n]||De[n]){if(!De[n]&&vt(n)){if(ve.tagNameCheck instanceof RegExp&&S(ve.tagNameCheck,n))return!1;if(ve.tagNameCheck instanceof Function&&ve.tagNameCheck(n))return!1}if(je&&!$e[n]){const t=ae(e)||e.parentNode,n=ie(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=$(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,re(e))}}}return Et(e),!0}return e instanceof O&&!function(e){let t=ae(e);t&&t.tagName||(t={namespaceURI:ot,tagName:"template"});const n=h(e.tagName),o=h(t.tagName);return!!it[e.namespaceURI]&&(e.namespaceURI===tt?t.namespaceURI===nt?"svg"===n:t.namespaceURI===et?"svg"===n&&("annotation-xml"===o||lt[o]):Boolean(Tt[n]):e.namespaceURI===et?t.namespaceURI===nt?"math"===n:t.namespaceURI===tt?"math"===n&&ct[o]:Boolean(yt[n]):e.namespaceURI===nt?!(t.namespaceURI===tt&&!ct[o])&&!(t.namespaceURI===et&&!lt[o])&&!yt[n]&&(st[n]||!Tt[n]):!("application/xhtml+xml"!==ut||!it[e.namespaceURI]))}(e)?(Et(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!S(/<\/no(script|embed|frames)/i,e.innerHTML)?(Me&&e.nodeType===Q&&(t=e.textContent,u([he,ge,Te],(e=>{t=y(t,e," ")})),e.textContent!==t&&(f(o.removed,{element:e.cloneNode()}),e.textContent=t)),wt(de.afterSanitizeElements,e,null),!1):(Et(e),!0)},Ot=function(e,t,n){if(Ge&&("id"===t||"name"===t)&&(n in r||n in dt))return!1;if(Ce&&!xe[t]&&S(ye,t));else if(Le&&S(Ee,t));else if(!Re[t]||xe[t]){if(!(vt(e)&&(ve.tagNameCheck instanceof RegExp&&S(ve.tagNameCheck,e)||ve.tagNameCheck instanceof Function&&ve.tagNameCheck(e))&&(ve.attributeNameCheck instanceof RegExp&&S(ve.attributeNameCheck,t)||ve.attributeNameCheck instanceof Function&&ve.attributeNameCheck(t,e))||"is"===t&&ve.allowCustomizedBuiltInElements&&(ve.tagNameCheck instanceof RegExp&&S(ve.tagNameCheck,n)||ve.tagNameCheck instanceof Function&&ve.tagNameCheck(n))))return!1}else if(Je[t]);else if(S(be,y(n,_e,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==E(n,"data:")||!Ve[e]){if(ke&&!S(Ae,y(n,_e,"")));else if(n)return!1}else;return!0},vt=function(e){return"annotation-xml"!==e&&T(e,Se)},Dt=function(e){wt(de.beforeSanitizeAttributes,e,null);const{attributes:t}=e;if(!t||bt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Re,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=pt(a),m=c;let f="value"===a?m:A(m);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,wt(de.uponSanitizeAttribute,e,n),f=n.attrValue,!Ye||"id"!==s&&"name"!==s||(At(a,e),f="user-content-"+f),Ue&&S(/((--!?|])>)|<\/(style|title|textarea)/i,f)){At(a,e);continue}if("attributename"===s&&T(f,"href")){At(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){At(a,e);continue}if(!Ie&&S(/\/>/i,f)){At(a,e);continue}Me&&u([he,ge,Te],(e=>{f=y(f,e," ")}));const d=pt(e.nodeName);if(Ot(d,s,f)){if(le&&"object"==typeof j&&"function"==typeof j.getAttributeType)if(l);else switch(j.getAttributeType(d,s)){case"TrustedHTML":f=le.createHTML(f);break;case"TrustedScriptURL":f=le.createScriptURL(f)}if(f!==m)try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),bt(e)?Et(e):p(o.removed)}catch(t){At(a,e)}}else At(a,e)}wt(de.afterSanitizeAttributes,e,null)},xt=function e(t){let n=null;const o=St(t);for(wt(de.beforeSanitizeShadowDOM,t,null);n=o.nextNode();)wt(de.uponSanitizeShadowNode,n,null),Rt(n),Dt(n),n.content instanceof s&&e(n.content);wt(de.afterSanitizeShadowDOM,t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(rt=!e,rt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw b("toString is not a function");if("string"!=typeof(e=e.toString()))throw b("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Pe||gt(t),o.removed=[],"string"==typeof e&&(Xe=!1),Xe){if(e.nodeName){const t=pt(e.nodeName);if(!Ne[t]||De[t])throw b("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof w)n=_t("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===J&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!Me&&!ze&&-1===e.indexOf("<"))return le&&We?le.createHTML(e):e;if(n=_t(e),!n)return Fe?null:We?ce:""}n&&He&&Et(n.firstChild);const c=St(Xe?e:n);for(;i=c.nextNode();)Rt(i),Dt(i),i.content instanceof s&&xt(i.content);if(Xe)return e;if(Fe){if(Be)for(l=me.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Re.shadowroot||Re.shadowrootmode)&&(l=fe.call(a,l,!0)),l}let m=ze?n.outerHTML:n.innerHTML;return ze&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&S(K,n.ownerDocument.doctype.name)&&(m="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+m),Me&&u([he,ge,Te],(e=>{m=y(m,e," ")})),le&&We?le.createHTML(m):m},o.setConfig=function(){gt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Pe=!0},o.clearConfig=function(){ft=null,Pe=!1},o.isValidAttribute=function(e,t,n){ft||gt({});const o=pt(e),r=pt(t);return Ot(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&f(de[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=m(de[e],t);return-1===n?void 0:d(de[e],n,1)[0]}return p(de[e])},o.removeHooks=function(e){de[e]=[]},o.removeAllHooks=function(){de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return re})); //# sourceMappingURL=purify.min.js.map diff --git a/web/js/purify.min.js.map b/web/js/purify.min.js.map new file mode 100644 index 0000000..3bd9027 --- /dev/null +++ b/web/js/purify.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"purify.min.js","sources":["../src/utils.ts","../src/tags.ts","../src/attrs.ts","../src/regexp.ts","../src/purify.ts"],"sourcesContent":["const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function <T>(x: T): T {\n return x;\n };\n}\n\nif (!seal) {\n seal = function <T>(x: T): T {\n return x;\n };\n}\n\nif (!apply) {\n apply = function <T>(\n func: (thisArg: any, ...args: any[]) => T,\n thisArg: any,\n ...args: any[]\n ): T {\n return func.apply(thisArg, args);\n };\n}\n\nif (!construct) {\n construct = function <T>(Func: new (...args: any[]) => T, ...args: any[]): T {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\nconst arraySplice = unapply(Array.prototype.splice);\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param func - The function to be wrapped and called.\n * @returns A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply<T>(\n func: (thisArg: any, ...args: any[]) => T\n): (thisArg: any, ...args: any[]) => T {\n return (thisArg: any, ...args: any[]): T => {\n if (thisArg instanceof RegExp) {\n thisArg.lastIndex = 0;\n }\n\n return apply(func, thisArg, args);\n };\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param func - The constructor function to be wrapped and called.\n * @returns A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct<T>(\n Func: new (...args: any[]) => T\n): (...args: any[]) => T {\n return (...args: any[]): T => construct(Func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param set - The set to which elements will be added.\n * @param array - The array containing elements to be added to the set.\n * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns The modified set with added elements.\n */\nfunction addToSet(\n set: Record<string, any>,\n array: readonly any[],\n transformCaseFunc: ReturnType<typeof unapply<string>> = stringToLowerCase\n): Record<string, any> {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n (array as any[])[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param array - The array to be cleaned.\n * @returns The cleaned version of the array\n */\nfunction cleanArray<T>(array: T[]): Array<T | null> {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param object - The object to be cloned.\n * @returns A new object that copies the original.\n */\nfunction clone<T extends Record<string, any>>(object: T): T {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param object - The object to look up the getter function in its prototype chain.\n * @param prop - The property name for which to find the getter function.\n * @returns The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter<T extends Record<string, any>>(\n object: T,\n prop: string\n): ReturnType<typeof unapply<any>> | (() => null) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue(): null {\n return null;\n }\n\n return fallbackValue;\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n arraySplice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n // RegExp\n regExpTest,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'search',\n 'section',\n 'select',\n 'shadow',\n 'slot',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n] as const);\n\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'enterkeyhint',\n 'exportparts',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'inputmode',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'part',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'slot',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n] as const);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n] as const);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n] as const);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n] as const);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n] as const);\n\nexport const text = freeze(['#text'] as const);\n","import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'exportparts',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inert',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'part',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'slot',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n 'slot',\n] as const);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'amplitude',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'exponent',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'intercept',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'slope',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'tablevalues',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n] as const);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnsalign',\n 'columnlines',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lspace',\n 'lquote',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n] as const);\n","import { seal } from './utils.js';\n\n// eslint-disable-next-line unicorn/better-regex\nexport const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nexport const TMPLIT_EXPR = seal(/\\$\\{[\\w\\W]*/gm); // eslint-disable-line unicorn/better-regex\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]+$/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n","/* eslint-disable @typescript-eslint/indent */\n\nimport type { TrustedHTML, TrustedTypesWindow } from 'trusted-types/lib';\nimport type { Config, UseProfilesConfig } from './config';\nimport * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n arrayForEach,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySplice,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n} from './utils.js';\n\nexport type { Config } from './config';\n\ndeclare const VERSION: string;\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function (): WindowLike {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param trustedTypes The policy factory.\n * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (\n trustedTypes: TrustedTypePolicyFactory,\n purifyHostElement: HTMLScriptElement\n) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nconst _createHooksMap = function (): HooksMap {\n return {\n afterSanitizeAttributes: [],\n afterSanitizeElements: [],\n afterSanitizeShadowDOM: [],\n beforeSanitizeAttributes: [],\n beforeSanitizeElements: [],\n beforeSanitizeShadowDOM: [],\n uponSanitizeAttribute: [],\n uponSanitizeElement: [],\n uponSanitizeShadowNode: [],\n };\n};\n\nfunction createDOMPurify(window: WindowLike = getGlobal()): DOMPurify {\n const DOMPurify: DOMPurify = (root: WindowLike) => createDOMPurify(root);\n\n DOMPurify.version = VERSION;\n\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document ||\n !window.Element\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript: HTMLScriptElement =\n originalDocument.currentScript as HTMLScriptElement;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || (window as any).MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = _createHooksMap();\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with <html>... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES: UseProfilesConfig | false = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'thead',\n 'title',\n 'video',\n 'xmp',\n ]);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, [\n 'audio',\n 'video',\n 'img',\n 'source',\n 'image',\n 'track',\n ]);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [\n 'alt',\n 'class',\n 'for',\n 'id',\n 'label',\n 'name',\n 'pattern',\n 'placeholder',\n 'role',\n 'summary',\n 'title',\n 'value',\n 'style',\n 'xmlns',\n ]);\n\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet(\n {},\n [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE],\n stringToString\n );\n\n let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n ]);\n\n let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [\n 'title',\n 'style',\n 'font',\n 'a',\n 'script',\n ]);\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE: null | DOMParserSupportedType = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc: null | Parameters<typeof addToSet>[2] = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG: Config | null = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n\n const isRegexOrFunction = function (\n testValue: unknown\n ): testValue is Function | RegExp {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function (cfg: Config = {}): void {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1\n ? DEFAULT_PARSER_MEDIA_TYPE\n : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc =\n PARSER_MEDIA_TYPE === 'application/xhtml+xml'\n ? stringToString\n : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS')\n ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)\n : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR')\n ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)\n : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES')\n ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString)\n : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR')\n ? addToSet(\n clone(DEFAULT_URI_SAFE_ATTRIBUTES),\n cfg.ADD_URI_SAFE_ATTR,\n transformCaseFunc\n )\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS')\n ? addToSet(\n clone(DEFAULT_DATA_URI_TAGS),\n cfg.ADD_DATA_URI_TAGS,\n transformCaseFunc\n )\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS')\n ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)\n : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS')\n ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)\n : clone({});\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR')\n ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)\n : clone({});\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES')\n ? cfg.USE_PROFILES\n : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI = cfg.ALLOWED_URI_REGEXP || EXPRESSIONS.IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n MATHML_TEXT_INTEGRATION_POINTS =\n cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;\n HTML_INTEGRATION_POINTS =\n cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;\n\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements ===\n 'boolean'\n ) {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =\n cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, TAGS.text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, TAGS.html);\n addToSet(ALLOWED_ATTR, ATTRS.html);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, TAGS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, TAGS.svgFilters);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, TAGS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.'\n );\n }\n\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.'\n );\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.svgDisallowed,\n ]);\n const ALL_MATHML_TAGS = addToSet({}, [\n ...TAGS.mathMl,\n ...TAGS.mathMlDisallowed,\n ]);\n\n /**\n * @param element a DOM element whose namespace is being checked\n * @returns Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function (element: Element): boolean {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template',\n };\n }\n\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via <svg>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either <annotation-xml> or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return (\n tagName === 'svg' &&\n (parentTagName === 'annotation-xml' ||\n MATHML_TEXT_INTEGRATION_POINTS[parentTagName])\n );\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via <math>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // <math> and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (\n parent.namespaceURI === SVG_NAMESPACE &&\n !HTML_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n if (\n parent.namespaceURI === MATHML_NAMESPACE &&\n !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return (\n !ALL_MATHML_TAGS[tagName] &&\n (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName])\n );\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n ALLOWED_NAMESPACES[element.namespaceURI]\n ) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param node a DOM node\n */\n const _forceRemove = function (node: Node): void {\n arrayPush(DOMPurify.removed, { element: node });\n\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n getParentNode(node).removeChild(node);\n } catch (_) {\n remove(node);\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param name an Attribute name\n * @param element a DOM node\n */\n const _removeAttribute = function (name: string, element: Element): void {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: element.getAttributeNode(name),\n from: element,\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: element,\n });\n }\n\n element.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\" attributes\n if (name === 'is') {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(element);\n } catch (_) {}\n } else {\n try {\n element.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param dirty - a string of dirty markup\n * @return a DOM, filled with the dirty markup\n */\n const _initDocument = function (dirty: string): Document {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n\n if (FORCE_BODY) {\n dirty = '<remove></remove>' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n NAMESPACE === HTML_NAMESPACE\n ) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty =\n '<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>' +\n dirty +\n '</body></html>';\n }\n\n const dirtyPayload = trustedTypesPolicy\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT\n ? emptyHTML\n : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n\n const body = doc.body || doc.documentElement;\n\n if (dirty && leadingWhitespace) {\n body.insertBefore(\n document.createTextNode(leadingWhitespace),\n body.childNodes[0] || null\n );\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(\n doc,\n WHOLE_DOCUMENT ? 'html' : 'body'\n )[0];\n }\n\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param root The root element or node to start traversing on.\n * @return The created NodeIterator\n */\n const _createNodeIterator = function (root: Node): NodeIterator {\n return createNodeIterator.call(\n root.ownerDocument || root,\n root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT |\n NodeFilter.SHOW_COMMENT |\n NodeFilter.SHOW_TEXT |\n NodeFilter.SHOW_PROCESSING_INSTRUCTION |\n NodeFilter.SHOW_CDATA_SECTION,\n null\n );\n };\n\n /**\n * _isClobbered\n *\n * @param element element to check for clobbering attacks\n * @return true if clobbered, false if safe\n */\n const _isClobbered = function (element: Element): boolean {\n return (\n element instanceof HTMLFormElement &&\n (typeof element.nodeName !== 'string' ||\n typeof element.textContent !== 'string' ||\n typeof element.removeChild !== 'function' ||\n !(element.attributes instanceof NamedNodeMap) ||\n typeof element.removeAttribute !== 'function' ||\n typeof element.setAttribute !== 'function' ||\n typeof element.namespaceURI !== 'string' ||\n typeof element.insertBefore !== 'function' ||\n typeof element.hasChildNodes !== 'function')\n );\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param value object to check whether it's a DOM node\n * @return true is object is a DOM node\n */\n const _isNode = function (value: unknown): value is Node {\n return typeof Node === 'function' && value instanceof Node;\n };\n\n function _executeHooks<T extends HookFunction>(\n hooks: HookFunction[],\n currentNode: Parameters<T>[0],\n data: Parameters<T>[1]\n ): void {\n arrayForEach(hooks, (hook: T) => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n }\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n * @param currentNode to check for permission to exist\n * @return true if node was killed, false if left alive\n */\n const _sanitizeElements = function (currentNode: any): boolean {\n let content = null;\n\n /* Execute a hook if present */\n _executeHooks(hooks.beforeSanitizeElements, currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHooks(hooks.uponSanitizeElement, currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS,\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (\n SAFE_FOR_XML &&\n currentNode.hasChildNodes() &&\n !_isNode(currentNode.firstElementChild) &&\n regExpTest(/<[/\\w!]/g, currentNode.innerHTML) &&\n regExpTest(/<[/\\w!]/g, currentNode.textContent)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any occurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (\n SAFE_FOR_XML &&\n currentNode.nodeType === NODE_TYPE.comment &&\n regExpTest(/<[/\\w]/g, currentNode.data)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)\n ) {\n return false;\n }\n\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)\n ) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if (\n (tagName === 'noscript' ||\n tagName === 'noembed' ||\n tagName === 'noframes') &&\n regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr: RegExp) => {\n content = stringReplace(content, expr, ' ');\n });\n\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHooks(hooks.afterSanitizeElements, currentNode, null);\n\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param lcTag Lowercase tag name of containing element.\n * @param lcName Lowercase attribute name.\n * @param value Attribute value.\n * @return Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function (\n lcTag: string,\n lcName: string,\n value: string\n ): boolean {\n /* Make sure attribute cannot clobber */\n if (\n SANITIZE_DOM &&\n (lcName === 'id' || lcName === 'name') &&\n (value in document || value in formElement)\n ) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (\n ALLOW_DATA_ATTR &&\n !FORBID_ATTR[lcName] &&\n regExpTest(DATA_ATTR, lcName)\n ) {\n // This attribute is safe\n } else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) {\n // This attribute is safe\n /* Otherwise, check the name is permitted */\n } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n (_isBasicCustomElement(lcTag) &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))) &&\n ((CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName)) ||\n (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)))) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n (lcName === 'is' &&\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))))\n ) {\n // If user has supplied a regexp or function in CUSTOM_ELEMENT_HANDLING.tagNameCheck, we need to also allow derived custom elements using the same tagName test.\n // Additionally, we need to allow attributes passing the CUSTOM_ELEMENT_HANDLING.attributeNameCheck user has configured, as custom elements can define these at their own discretion.\n } else {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) {\n // This attribute is safe\n /* Check no script, data or unknown possibly unsafe URI\n unless we know URI values are safe for that attribute */\n } else if (\n regExpTest(IS_ALLOWED_URI, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Keep image data URIs alive if src/xlink:href is allowed */\n /* Further prevent gadget XSS for dynamically built script tags */\n } else if (\n (lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') &&\n lcTag !== 'script' &&\n stringIndexOf(value, 'data:') === 0 &&\n DATA_URI_TAGS[lcTag]\n ) {\n // This attribute is safe\n /* Allow unknown protocols: This provides support for links that\n are handled by protocol handlers which may be unknown ahead of\n time, e.g. fb:, spotify: */\n } else if (\n ALLOW_UNKNOWN_PROTOCOLS &&\n !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Check for binary attributes */\n } else if (value) {\n return false;\n } else {\n // Binary attributes are safe at this point\n /* Anything else, presume unsafe, do not add it back */\n }\n\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param tagName name of the tag of the node to sanitize\n * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function (tagName: string): RegExpMatchArray {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param currentNode to sanitize\n */\n const _sanitizeAttributes = function (currentNode: Element): void {\n /* Execute a hook if present */\n _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);\n\n const { attributes } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes || _isClobbered(currentNode)) {\n return;\n }\n\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR,\n forceKeepAttr: undefined,\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const { name, namespaceURI, value: attrValue } = attr;\n const lcName = transformCaseFunc(name);\n\n const initValue = attrValue;\n let value = name === 'value' ? initValue : stringTrim(initValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);\n value = hookEvent.attrValue;\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Work around a security issue with comments inside attributes */\n if (\n SAFE_FOR_XML &&\n regExpTest(/((--!?|])>)|<\\/(style|title|textarea)/i, value)\n ) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Make sure we cannot easily use animated hrefs, even if animations are allowed */\n if (lcName === 'attributename' && stringMatch(value, 'href')) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr: RegExp) => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Handle attributes that require Trusted Types */\n if (\n trustedTypesPolicy &&\n typeof trustedTypes === 'object' &&\n typeof trustedTypes.getAttributeType === 'function'\n ) {\n if (namespaceURI) {\n /* Namespaces are not yet supported, see https://bugs.chromium.org/p/chromium/issues/detail?id=1305293 */\n } else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML': {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n\n case 'TrustedScriptURL': {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n\n default: {\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n if (value !== initValue) {\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {\n _removeAttribute(name, currentNode);\n }\n }\n }\n\n /* Execute a hook if present */\n _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function (fragment: DocumentFragment): void {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);\n\n while ((shadowNode = shadowIterator.nextNode())) {\n /* Execute a hook if present */\n _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);\n\n /* Sanitize tags and elements */\n _sanitizeElements(shadowNode);\n\n /* Check attributes next */\n _sanitizeAttributes(shadowNode);\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n }\n\n /* Execute a hook if present */\n _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);\n };\n\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty, cfg = {}) {\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '<!-->';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if ((dirty as Node).nodeName) {\n const tagName = transformCaseFunc((dirty as Node).nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate(\n 'root node is forbidden and cannot be sanitized in-place'\n );\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('<!---->');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (\n importedNode.nodeType === NODE_TYPE.element &&\n importedNode.nodeName === 'BODY'\n ) {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (\n !RETURN_DOM &&\n !SAFE_FOR_TEMPLATES &&\n !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1\n ) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while ((currentNode = nodeIterator.nextNode())) {\n /* Sanitize tags and elements */\n _sanitizeElements(currentNode);\n\n /* Check attributes next */\n _sanitizeAttributes(currentNode);\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n\n return returnNode;\n }\n\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (\n WHOLE_DOCUMENT &&\n ALLOWED_TAGS['!doctype'] &&\n body.ownerDocument &&\n body.ownerDocument.doctype &&\n body.ownerDocument.doctype.name &&\n regExpTest(EXPRESSIONS.DOCTYPE_NAME, body.ownerDocument.doctype.name)\n ) {\n serializedHTML =\n '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr: RegExp) => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(serializedHTML)\n : serializedHTML;\n };\n\n DOMPurify.setConfig = function (cfg = {}) {\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n DOMPurify.addHook = function (\n entryPoint: keyof HooksMap,\n hookFunction: HookFunction\n ) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n DOMPurify.removeHook = function (\n entryPoint: keyof HooksMap,\n hookFunction: HookFunction\n ) {\n if (hookFunction !== undefined) {\n const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);\n\n return index === -1\n ? undefined\n : arraySplice(hooks[entryPoint], index, 1)[0];\n }\n\n return arrayPop(hooks[entryPoint]);\n };\n\n DOMPurify.removeHooks = function (entryPoint: keyof HooksMap) {\n hooks[entryPoint] = [];\n };\n\n DOMPurify.removeAllHooks = function () {\n hooks = _createHooksMap();\n };\n\n return DOMPurify;\n}\n\nexport default createDOMPurify();\n\nexport interface DOMPurify {\n /**\n * Creates a DOMPurify instance using the given window-like object. Defaults to `window`.\n */\n (root?: WindowLike): DOMPurify;\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n version: string;\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n removed: Array<RemovedElement | RemovedAttribute>;\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n isSupported: boolean;\n\n /**\n * Set the configuration once.\n *\n * @param cfg configuration object\n */\n setConfig(cfg?: Config): void;\n\n /**\n * Removes the configuration.\n */\n clearConfig(): void;\n\n /**\n * Provides core sanitation functionality.\n *\n * @param dirty string or DOM node\n * @param cfg object\n * @returns Sanitized TrustedHTML.\n */\n sanitize(\n dirty: string | Node,\n cfg: Config & { RETURN_TRUSTED_TYPE: true }\n ): TrustedHTML;\n\n /**\n * Provides core sanitation functionality.\n *\n * @param dirty DOM node\n * @param cfg object\n * @returns Sanitized DOM node.\n */\n sanitize(dirty: Node, cfg: Config & { IN_PLACE: true }): Node;\n\n /**\n * Provides core sanitation functionality.\n *\n * @param dirty string or DOM node\n * @param cfg object\n * @returns Sanitized DOM node.\n */\n sanitize(dirty: string | Node, cfg: Config & { RETURN_DOM: true }): Node;\n\n /**\n * Provides core sanitation functionality.\n *\n * @param dirty string or DOM node\n * @param cfg object\n * @returns Sanitized document fragment.\n */\n sanitize(\n dirty: string | Node,\n cfg: Config & { RETURN_DOM_FRAGMENT: true }\n ): DocumentFragment;\n\n /**\n * Provides core sanitation functionality.\n *\n * @param dirty string or DOM node\n * @param cfg object\n * @returns Sanitized string.\n */\n sanitize(dirty: string | Node, cfg?: Config): string;\n\n /**\n * Checks if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n *\n * @param tag Tag name of containing element.\n * @param attr Attribute name.\n * @param value Attribute value.\n * @returns Returns true if `value` is valid. Otherwise, returns false.\n */\n isValidAttribute(tag: string, attr: string, value: string): boolean;\n\n /**\n * Adds a DOMPurify hook.\n *\n * @param entryPoint entry point for the hook to add\n * @param hookFunction function to execute\n */\n addHook(entryPoint: BasicHookName, hookFunction: NodeHook): void;\n\n /**\n * Adds a DOMPurify hook.\n *\n * @param entryPoint entry point for the hook to add\n * @param hookFunction function to execute\n */\n addHook(entryPoint: ElementHookName, hookFunction: ElementHook): void;\n\n /**\n * Adds a DOMPurify hook.\n *\n * @param entryPoint entry point for the hook to add\n * @param hookFunction function to execute\n */\n addHook(\n entryPoint: DocumentFragmentHookName,\n hookFunction: DocumentFragmentHook\n ): void;\n\n /**\n * Adds a DOMPurify hook.\n *\n * @param entryPoint entry point for the hook to add\n * @param hookFunction function to execute\n */\n addHook(\n entryPoint: 'uponSanitizeElement',\n hookFunction: UponSanitizeElementHook\n ): void;\n\n /**\n * Adds a DOMPurify hook.\n *\n * @param entryPoint entry point for the hook to add\n * @param hookFunction function to execute\n */\n addHook(\n entryPoint: 'uponSanitizeAttribute',\n hookFunction: UponSanitizeAttributeHook\n ): void;\n\n /**\n * Remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if hook not specified)\n *\n * @param entryPoint entry point for the hook to remove\n * @param hookFunction optional specific hook to remove\n * @returns removed hook\n */\n removeHook(\n entryPoint: BasicHookName,\n hookFunction?: NodeHook\n ): NodeHook | undefined;\n\n /**\n * Remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if hook not specified)\n *\n * @param entryPoint entry point for the hook to remove\n * @param hookFunction optional specific hook to remove\n * @returns removed hook\n */\n removeHook(\n entryPoint: ElementHookName,\n hookFunction?: ElementHook\n ): ElementHook | undefined;\n\n /**\n * Remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if hook not specified)\n *\n * @param entryPoint entry point for the hook to remove\n * @param hookFunction optional specific hook to remove\n * @returns removed hook\n */\n removeHook(\n entryPoint: DocumentFragmentHookName,\n hookFunction?: DocumentFragmentHook\n ): DocumentFragmentHook | undefined;\n\n /**\n * Remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if hook not specified)\n *\n * @param entryPoint entry point for the hook to remove\n * @param hookFunction optional specific hook to remove\n * @returns removed hook\n */\n removeHook(\n entryPoint: 'uponSanitizeElement',\n hookFunction?: UponSanitizeElementHook\n ): UponSanitizeElementHook | undefined;\n\n /**\n * Remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if hook not specified)\n *\n * @param entryPoint entry point for the hook to remove\n * @param hookFunction optional specific hook to remove\n * @returns removed hook\n */\n removeHook(\n entryPoint: 'uponSanitizeAttribute',\n hookFunction?: UponSanitizeAttributeHook\n ): UponSanitizeAttributeHook | undefined;\n\n /**\n * Removes all DOMPurify hooks at a given entryPoint\n *\n * @param entryPoint entry point for the hooks to remove\n */\n removeHooks(entryPoint: HookName): void;\n\n /**\n * Removes all DOMPurify hooks.\n */\n removeAllHooks(): void;\n}\n\n/**\n * An element removed by DOMPurify.\n */\nexport interface RemovedElement {\n /**\n * The element that was removed.\n */\n element: Node;\n}\n\n/**\n * An element removed by DOMPurify.\n */\nexport interface RemovedAttribute {\n /**\n * The attribute that was removed.\n */\n attribute: Attr | null;\n\n /**\n * The element that the attribute was removed.\n */\n from: Node;\n}\n\ntype BasicHookName =\n | 'beforeSanitizeElements'\n | 'afterSanitizeElements'\n | 'uponSanitizeShadowNode';\ntype ElementHookName = 'beforeSanitizeAttributes' | 'afterSanitizeAttributes';\ntype DocumentFragmentHookName =\n | 'beforeSanitizeShadowDOM'\n | 'afterSanitizeShadowDOM';\ntype UponSanitizeElementHookName = 'uponSanitizeElement';\ntype UponSanitizeAttributeHookName = 'uponSanitizeAttribute';\n\ninterface HooksMap {\n beforeSanitizeElements: NodeHook[];\n afterSanitizeElements: NodeHook[];\n beforeSanitizeShadowDOM: DocumentFragmentHook[];\n uponSanitizeShadowNode: NodeHook[];\n afterSanitizeShadowDOM: DocumentFragmentHook[];\n beforeSanitizeAttributes: ElementHook[];\n afterSanitizeAttributes: ElementHook[];\n uponSanitizeElement: UponSanitizeElementHook[];\n uponSanitizeAttribute: UponSanitizeAttributeHook[];\n}\n\ntype ArrayElement<T> = T extends Array<infer U> ? U : never;\n\ntype HookFunction = ArrayElement<HooksMap[keyof HooksMap]>;\n\nexport type HookName =\n | BasicHookName\n | ElementHookName\n | DocumentFragmentHookName\n | UponSanitizeElementHookName\n | UponSanitizeAttributeHookName;\n\nexport type NodeHook = (\n this: DOMPurify,\n currentNode: Node,\n hookEvent: null,\n config: Config\n) => void;\n\nexport type ElementHook = (\n this: DOMPurify,\n currentNode: Element,\n hookEvent: null,\n config: Config\n) => void;\n\nexport type DocumentFragmentHook = (\n this: DOMPurify,\n currentNode: DocumentFragment,\n hookEvent: null,\n config: Config\n) => void;\n\nexport type UponSanitizeElementHook = (\n this: DOMPurify,\n currentNode: Node,\n hookEvent: UponSanitizeElementHookEvent,\n config: Config\n) => void;\n\nexport type UponSanitizeAttributeHook = (\n this: DOMPurify,\n currentNode: Element,\n hookEvent: UponSanitizeAttributeHookEvent,\n config: Config\n) => void;\n\nexport interface UponSanitizeElementHookEvent {\n tagName: string;\n allowedTags: Record<string, boolean>;\n}\n\nexport interface UponSanitizeAttributeHookEvent {\n attrName: string;\n attrValue: string;\n keepAttr: boolean;\n allowedAttributes: Record<string, boolean>;\n forceKeepAttr: boolean | undefined;\n}\n\n/**\n * A `Window`-like object containing the properties and types that DOMPurify requires.\n */\nexport type WindowLike = Pick<\n typeof globalThis,\n | 'DocumentFragment'\n | 'HTMLTemplateElement'\n | 'Node'\n | 'Element'\n | 'NodeFilter'\n | 'NamedNodeMap'\n | 'HTMLFormElement'\n | 'DOMParser'\n> & {\n document?: Document;\n MozNamedAttrMap?: typeof window.NamedNodeMap;\n} & Pick<TrustedTypesWindow, 'trustedTypes'>;\n"],"names":["entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","func","thisArg","_len","arguments","length","args","Array","_key","Func","_len2","_key2","arrayForEach","unapply","prototype","forEach","arrayLastIndexOf","lastIndexOf","arrayPop","pop","arrayPush","push","arraySplice","splice","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","objectHasOwnProperty","hasOwnProperty","regExpTest","RegExp","test","typeErrorCreate","TypeError","_len4","_key4","lastIndex","_len3","_key3","addToSet","set","array","transformCaseFunc","l","element","lcElement","cleanArray","index","clone","object","newObject","property","value","isArray","constructor","lookupGetter","prop","desc","get","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","getGlobal","window","purify","createDOMPurify","undefined","DOMPurify","root","version","VERSION","removed","document","nodeType","Element","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","afterSanitizeAttributes","afterSanitizeElements","afterSanitizeShadowDOM","beforeSanitizeAttributes","beforeSanitizeElements","beforeSanitizeShadowDOM","uponSanitizeAttribute","uponSanitizeElement","uponSanitizeShadowNode","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","ALLOWED_URI_REGEXP","ADD_TAGS","ADD_ATTR","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHooks","currentNode","data","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","__removalCount","parent","parentTagName","Boolean","_checkValidNamespace","expr","_isValidAttribute","lcTag","lcName","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","forceKeepAttr","attr","initValue","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","appendChild","firstChild","nodeIterator","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","entryPoint","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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,UACA,OACA,UACA,QACA,QACA,IACA,MACA,MACA,MACA,QACA,aACA,OACA,KACA,SACA,SACA,UACA,SACA,OACA,OACA,MACA,WACA,UACA,OACA,WACA,KACA,YACA,MACA,UACA,MACA,SACA,MACA,MACA,KACA,KACA,UACA,KACA,WACA,aACA,SACA,OACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,OACA,SACA,SACA,KACA,OACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,MACA,OACA,UACA,OACA,WACA,QACA,MACA,OACA,KACA,WACA,SACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,SACA,UACA,SACA,SACA,OACA,QACA,SACA,SACA,OACA,SACA,SACA,QACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,WACA,QACA,KACA,QACA,OACA,KACA,QACA,KACA,IACA,KACA,MACA,QACA,QAGW4E,EAAM5E,EAAO,CACxB,MACA,IACA,WACA,cACA,eACA,eACA,gBACA,mBACA,SACA,WACA,OACA,OACA,UACA,eACA,cACA,SACA,OACA,IACA,QACA,WACA,QACA,QACA,YACA,OACA,iBACA,SACA,OACA,WACA,QACA,OACA,OACA,UACA,UACA,WACA,iBACA,OACA,OACA,OACA,QACA,SACA,SACA,OACA,WACA,QACA,OACA,QACA,OACA,UAGW6E,EAAa7E,EAAO,CAC/B,UACA,gBACA,sBACA,cACA,mBACA,oBACA,oBACA,iBACA,eACA,UACA,UACA,UACA,UACA,UACA,iBACA,UACA,UACA,cACA,eACA,WACA,eACA,qBACA,cACA,SACA,iBAOW8E,EAAgB9E,EAAO,CAClC,UACA,gBACA,SACA,UACA,YACA,mBACA,iBACA,gBACA,gBACA,gBACA,QACA,YACA,OACA,eACA,YACA,UACA,gBACA,SACA,MACA,aACA,UACA,QAGW+E,EAAS/E,EAAO,CAC3B,OACA,WACA,SACA,UACA,QACA,SACA,KACA,aACA,gBACA,KACA,KACA,QACA,UACA,WACA,QACA,OACA,KACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,gBAKWgF,EAAmBhF,EAAO,CACrC,UACA,cACA,aACA,WACA,YACA,UACA,UACA,SACA,SACA,QACA,YACA,aACA,iBACA,cACA,SAGWiF,EAAOjF,EAAO,CAAC,UC3Rf2E,EAAO3E,EAAO,CACzB,SACA,SACA,QACA,MACA,iBACA,eACA,uBACA,WACA,aACA,UACA,SACA,UACA,cACA,cACA,UACA,OACA,QACA,QACA,QACA,OACA,UACA,WACA,eACA,SACA,cACA,WACA,WACA,UACA,MACA,WACA,0BACA,wBACA,WACA,YACA,UACA,eACA,cACA,OACA,MACA,UACA,SACA,SACA,OACA,OACA,WACA,KACA,QACA,YACA,YACA,QACA,OACA,QACA,OACA,OACA,UACA,OACA,MACA,MACA,YACA,QACA,SACA,MACA,YACA,WACA,QACA,OACA,QACA,UACA,aACA,SACA,OACA,UACA,OACA,UACA,cACA,cACA,UACA,gBACA,sBACA,SACA,UACA,UACA,aACA,WACA,MACA,WACA,MACA,WACA,OACA,OACA,UACA,aACA,QACA,WACA,QACA,OACA,QACA,OACA,OACA,UACA,QACA,MACA,SACA,OACA,QACA,UACA,WACA,QACA,YACA,OACA,SACA,SACA,QACA,QACA,OACA,QACA,SAGW4E,EAAM5E,EAAO,CACxB,gBACA,aACA,WACA,qBACA,YACA,SACA,gBACA,gBACA,UACA,gBACA,iBACA,QACA,OACA,KACA,QACA,OACA,gBACA,YACA,YACA,QACA,sBACA,8BACA,gBACA,kBACA,KACA,KACA,IACA,KACA,KACA,kBACA,YACA,UACA,UACA,MACA,WACA,YACA,MACA,WACA,OACA,eACA,YACA,SACA,cACA,cACA,gBACA,cACA,YACA,mBACA,eACA,aACA,eACA,cACA,KACA,KACA,KACA,KACA,aACA,WACA,gBACA,oBACA,SACA,OACA,KACA,kBACA,KACA,MACA,YACA,IACA,KACA,KACA,KACA,KACA,UACA,YACA,aACA,WACA,OACA,eACA,iBACA,eACA,mBACA,iBACA,QACA,aACA,aACA,eACA,eACA,cACA,cACA,mBACA,YACA,MACA,OACA,QACA,SACA,OACA,MACA,OACA,aACA,SACA,WACA,UACA,QACA,SACA,cACA,SACA,WACA,cACA,OACA,aACA,sBACA,mBACA,eACA,SACA,gBACA,sBACA,iBACA,IACA,KACA,KACA,SACA,OACA,OACA,cACA,YACA,UACA,SACA,SACA,QACA,OACA,kBACA,QACA,mBACA,mBACA,eACA,cACA,eACA,cACA,aACA,eACA,mBACA,oBACA,iBACA,kBACA,oBACA,iBACA,SACA,eACA,QACA,eACA,iBACA,WACA,cACA,UACA,UACA,YACA,mBACA,cACA,kBACA,iBACA,aACA,OACA,KACA,KACA,UACA,SACA,UACA,aACA,UACA,aACA,gBACA,gBACA,QACA,eACA,OACA,eACA,mBACA,mBACA,IACA,KACA,KACA,QACA,IACA,KACA,KACA,IACA,eAGW+E,EAAS/E,EAAO,CAC3B,SACA,cACA,QACA,WACA,QACA,eACA,cACA,aACA,aACA,QACA,MACA,UACA,eACA,WACA,QACA,QACA,SACA,OACA,KACA,UACA,SACA,gBACA,SACA,SACA,iBACA,YACA,WACA,cACA,UACA,UACA,gBACA,WACA,WACA,OACA,WACA,WACA,aACA,UACA,SACA,SACA,cACA,gBACA,uBACA,YACA,YACA,aACA,WACA,iBACA,iBACA,YACA,UACA,QACA,UAGWkF,EAAMlF,EAAO,CACxB,aACA,SACA,cACA,YACA,gBClXWmF,EAAgBlF,EAAK,6BACrBmF,EAAWnF,EAAK,yBAChBoF,EAAcpF,EAAK,iBACnBqF,EAAYrF,EAAK,gCACjBsF,EAAYtF,EAAK,kBACjBuF,EAAiBvF,EAC5B,oGAEWwF,EAAoBxF,EAAK,yBACzByF,EAAkBzF,EAC7B,+DAEW0F,EAAe1F,EAAK,WACpB2F,EAAiB3F,EAAK,0NCmBnC,MAAM4F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"} \ No newline at end of file