damus.io

damus.io website
git clone git://jb55.com/damus.io
Log | Files | Refs | README | LICENSE

purify.js (65585B)


      1 /*! @license DOMPurify 2.4.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.4.1/LICENSE */
      2 
      3 (function (global, factory) {
      4   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
      5   typeof define === 'function' && define.amd ? define(factory) :
      6   (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DOMPurify = factory());
      7 })(this, (function () { 'use strict';
      8 
      9   function _typeof(obj) {
     10     "@babel/helpers - typeof";
     11 
     12     return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
     13       return typeof obj;
     14     } : function (obj) {
     15       return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
     16     }, _typeof(obj);
     17   }
     18 
     19   function _setPrototypeOf(o, p) {
     20     _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
     21       o.__proto__ = p;
     22       return o;
     23     };
     24 
     25     return _setPrototypeOf(o, p);
     26   }
     27 
     28   function _isNativeReflectConstruct() {
     29     if (typeof Reflect === "undefined" || !Reflect.construct) return false;
     30     if (Reflect.construct.sham) return false;
     31     if (typeof Proxy === "function") return true;
     32 
     33     try {
     34       Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
     35       return true;
     36     } catch (e) {
     37       return false;
     38     }
     39   }
     40 
     41   function _construct(Parent, args, Class) {
     42     if (_isNativeReflectConstruct()) {
     43       _construct = Reflect.construct;
     44     } else {
     45       _construct = function _construct(Parent, args, Class) {
     46         var a = [null];
     47         a.push.apply(a, args);
     48         var Constructor = Function.bind.apply(Parent, a);
     49         var instance = new Constructor();
     50         if (Class) _setPrototypeOf(instance, Class.prototype);
     51         return instance;
     52       };
     53     }
     54 
     55     return _construct.apply(null, arguments);
     56   }
     57 
     58   function _toConsumableArray(arr) {
     59     return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
     60   }
     61 
     62   function _arrayWithoutHoles(arr) {
     63     if (Array.isArray(arr)) return _arrayLikeToArray(arr);
     64   }
     65 
     66   function _iterableToArray(iter) {
     67     if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
     68   }
     69 
     70   function _unsupportedIterableToArray(o, minLen) {
     71     if (!o) return;
     72     if (typeof o === "string") return _arrayLikeToArray(o, minLen);
     73     var n = Object.prototype.toString.call(o).slice(8, -1);
     74     if (n === "Object" && o.constructor) n = o.constructor.name;
     75     if (n === "Map" || n === "Set") return Array.from(o);
     76     if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
     77   }
     78 
     79   function _arrayLikeToArray(arr, len) {
     80     if (len == null || len > arr.length) len = arr.length;
     81 
     82     for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
     83 
     84     return arr2;
     85   }
     86 
     87   function _nonIterableSpread() {
     88     throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
     89   }
     90 
     91   var hasOwnProperty = Object.hasOwnProperty,
     92       setPrototypeOf = Object.setPrototypeOf,
     93       isFrozen = Object.isFrozen,
     94       getPrototypeOf = Object.getPrototypeOf,
     95       getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
     96   var freeze = Object.freeze,
     97       seal = Object.seal,
     98       create = Object.create; // eslint-disable-line import/no-mutable-exports
     99 
    100   var _ref = typeof Reflect !== 'undefined' && Reflect,
    101       apply = _ref.apply,
    102       construct = _ref.construct;
    103 
    104   if (!apply) {
    105     apply = function apply(fun, thisValue, args) {
    106       return fun.apply(thisValue, args);
    107     };
    108   }
    109 
    110   if (!freeze) {
    111     freeze = function freeze(x) {
    112       return x;
    113     };
    114   }
    115 
    116   if (!seal) {
    117     seal = function seal(x) {
    118       return x;
    119     };
    120   }
    121 
    122   if (!construct) {
    123     construct = function construct(Func, args) {
    124       return _construct(Func, _toConsumableArray(args));
    125     };
    126   }
    127 
    128   var arrayForEach = unapply(Array.prototype.forEach);
    129   var arrayPop = unapply(Array.prototype.pop);
    130   var arrayPush = unapply(Array.prototype.push);
    131   var stringToLowerCase = unapply(String.prototype.toLowerCase);
    132   var stringToString = unapply(String.prototype.toString);
    133   var stringMatch = unapply(String.prototype.match);
    134   var stringReplace = unapply(String.prototype.replace);
    135   var stringIndexOf = unapply(String.prototype.indexOf);
    136   var stringTrim = unapply(String.prototype.trim);
    137   var regExpTest = unapply(RegExp.prototype.test);
    138   var typeErrorCreate = unconstruct(TypeError);
    139   function unapply(func) {
    140     return function (thisArg) {
    141       for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    142         args[_key - 1] = arguments[_key];
    143       }
    144 
    145       return apply(func, thisArg, args);
    146     };
    147   }
    148   function unconstruct(func) {
    149     return function () {
    150       for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
    151         args[_key2] = arguments[_key2];
    152       }
    153 
    154       return construct(func, args);
    155     };
    156   }
    157   /* Add properties to a lookup table */
    158 
    159   function addToSet(set, array, transformCaseFunc) {
    160     transformCaseFunc = transformCaseFunc ? transformCaseFunc : stringToLowerCase;
    161 
    162     if (setPrototypeOf) {
    163       // Make 'in' and truthy checks like Boolean(set.constructor)
    164       // independent of any properties defined on Object.prototype.
    165       // Prevent prototype setters from intercepting set as a this value.
    166       setPrototypeOf(set, null);
    167     }
    168 
    169     var l = array.length;
    170 
    171     while (l--) {
    172       var element = array[l];
    173 
    174       if (typeof element === 'string') {
    175         var lcElement = transformCaseFunc(element);
    176 
    177         if (lcElement !== element) {
    178           // Config presets (e.g. tags.js, attrs.js) are immutable.
    179           if (!isFrozen(array)) {
    180             array[l] = lcElement;
    181           }
    182 
    183           element = lcElement;
    184         }
    185       }
    186 
    187       set[element] = true;
    188     }
    189 
    190     return set;
    191   }
    192   /* Shallow clone an object */
    193 
    194   function clone(object) {
    195     var newObject = create(null);
    196     var property;
    197 
    198     for (property in object) {
    199       if (apply(hasOwnProperty, object, [property])) {
    200         newObject[property] = object[property];
    201       }
    202     }
    203 
    204     return newObject;
    205   }
    206   /* IE10 doesn't support __lookupGetter__ so lets'
    207    * simulate it. It also automatically checks
    208    * if the prop is function or getter and behaves
    209    * accordingly. */
    210 
    211   function lookupGetter(object, prop) {
    212     while (object !== null) {
    213       var desc = getOwnPropertyDescriptor(object, prop);
    214 
    215       if (desc) {
    216         if (desc.get) {
    217           return unapply(desc.get);
    218         }
    219 
    220         if (typeof desc.value === 'function') {
    221           return unapply(desc.value);
    222         }
    223       }
    224 
    225       object = getPrototypeOf(object);
    226     }
    227 
    228     function fallbackValue(element) {
    229       console.warn('fallback value for', element);
    230       return null;
    231     }
    232 
    233     return fallbackValue;
    234   }
    235 
    236   var html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', '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']); // SVG
    237 
    238   var svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
    239   var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); // List of SVG elements that are disallowed by default.
    240   // We still need to know them so that we can do namespace
    241   // checks properly in case one wants to add them to
    242   // allow-list.
    243 
    244   var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', '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']);
    245   var mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']); // Similarly to SVG, we want to know all MathML elements,
    246   // even those that we disallow by default.
    247 
    248   var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
    249   var text = freeze(['#text']);
    250 
    251   var html = freeze(['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', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', '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', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
    252   var svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', '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', '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', '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', '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', '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']);
    253   var mathMl = freeze(['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']);
    254   var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
    255 
    256   var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
    257 
    258   var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
    259   var TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
    260   var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
    261 
    262   var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
    263 
    264   var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
    265   );
    266   var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
    267   var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
    268   );
    269   var DOCTYPE_NAME = seal(/^html$/i);
    270 
    271   var getGlobal = function getGlobal() {
    272     return typeof window === 'undefined' ? null : window;
    273   };
    274   /**
    275    * Creates a no-op policy for internal use only.
    276    * Don't export this function outside this module!
    277    * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
    278    * @param {Document} document The document object (to determine policy name suffix)
    279    * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
    280    * are not supported).
    281    */
    282 
    283 
    284   var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
    285     if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
    286       return null;
    287     } // Allow the callers to control the unique policy name
    288     // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
    289     // Policy creation with duplicate names throws in Trusted Types.
    290 
    291 
    292     var suffix = null;
    293     var ATTR_NAME = 'data-tt-policy-suffix';
    294 
    295     if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
    296       suffix = document.currentScript.getAttribute(ATTR_NAME);
    297     }
    298 
    299     var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
    300 
    301     try {
    302       return trustedTypes.createPolicy(policyName, {
    303         createHTML: function createHTML(html) {
    304           return html;
    305         },
    306         createScriptURL: function createScriptURL(scriptUrl) {
    307           return scriptUrl;
    308         }
    309       });
    310     } catch (_) {
    311       // Policy creation failed (most likely another DOMPurify script has
    312       // already run). Skip creating the policy, as this will only cause errors
    313       // if TT are enforced.
    314       console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
    315       return null;
    316     }
    317   };
    318 
    319   function createDOMPurify() {
    320     var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
    321 
    322     var DOMPurify = function DOMPurify(root) {
    323       return createDOMPurify(root);
    324     };
    325     /**
    326      * Version label, exposed for easier checks
    327      * if DOMPurify is up to date or not
    328      */
    329 
    330 
    331     DOMPurify.version = '2.4.1';
    332     /**
    333      * Array of elements that DOMPurify removed during sanitation.
    334      * Empty if nothing was removed.
    335      */
    336 
    337     DOMPurify.removed = [];
    338 
    339     if (!window || !window.document || window.document.nodeType !== 9) {
    340       // Not running in a browser, provide a factory function
    341       // so that you can pass your own Window
    342       DOMPurify.isSupported = false;
    343       return DOMPurify;
    344     }
    345 
    346     var originalDocument = window.document;
    347     var document = window.document;
    348     var DocumentFragment = window.DocumentFragment,
    349         HTMLTemplateElement = window.HTMLTemplateElement,
    350         Node = window.Node,
    351         Element = window.Element,
    352         NodeFilter = window.NodeFilter,
    353         _window$NamedNodeMap = window.NamedNodeMap,
    354         NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
    355         HTMLFormElement = window.HTMLFormElement,
    356         DOMParser = window.DOMParser,
    357         trustedTypes = window.trustedTypes;
    358     var ElementPrototype = Element.prototype;
    359     var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
    360     var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
    361     var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
    362     var getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a
    363     // new document created via createHTMLDocument. As per the spec
    364     // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
    365     // a new empty registry is used when creating a template contents owner
    366     // document, so we use that as our parent document to ensure nothing
    367     // is inherited.
    368 
    369     if (typeof HTMLTemplateElement === 'function') {
    370       var template = document.createElement('template');
    371 
    372       if (template.content && template.content.ownerDocument) {
    373         document = template.content.ownerDocument;
    374       }
    375     }
    376 
    377     var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
    378 
    379     var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
    380     var _document = document,
    381         implementation = _document.implementation,
    382         createNodeIterator = _document.createNodeIterator,
    383         createDocumentFragment = _document.createDocumentFragment,
    384         getElementsByTagName = _document.getElementsByTagName;
    385     var importNode = originalDocument.importNode;
    386     var documentMode = {};
    387 
    388     try {
    389       documentMode = clone(document).documentMode ? document.documentMode : {};
    390     } catch (_) {}
    391 
    392     var hooks = {};
    393     /**
    394      * Expose whether this browser supports running the full DOMPurify.
    395      */
    396 
    397     DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
    398     var MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
    399         ERB_EXPR$1 = ERB_EXPR,
    400         TMPLIT_EXPR$1 = TMPLIT_EXPR,
    401         DATA_ATTR$1 = DATA_ATTR,
    402         ARIA_ATTR$1 = ARIA_ATTR,
    403         IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
    404         ATTR_WHITESPACE$1 = ATTR_WHITESPACE;
    405     var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
    406     /**
    407      * We consider the elements and attributes below to be safe. Ideally
    408      * don't add any new ones but feel free to remove unwanted ones.
    409      */
    410 
    411     /* allowed element names */
    412 
    413     var ALLOWED_TAGS = null;
    414     var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
    415     /* Allowed attribute names */
    416 
    417     var ALLOWED_ATTR = null;
    418     var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
    419     /*
    420      * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
    421      * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
    422      * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
    423      * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
    424      */
    425 
    426     var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
    427       tagNameCheck: {
    428         writable: true,
    429         configurable: false,
    430         enumerable: true,
    431         value: null
    432       },
    433       attributeNameCheck: {
    434         writable: true,
    435         configurable: false,
    436         enumerable: true,
    437         value: null
    438       },
    439       allowCustomizedBuiltInElements: {
    440         writable: true,
    441         configurable: false,
    442         enumerable: true,
    443         value: false
    444       }
    445     }));
    446     /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
    447 
    448     var FORBID_TAGS = null;
    449     /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
    450 
    451     var FORBID_ATTR = null;
    452     /* Decide if ARIA attributes are okay */
    453 
    454     var ALLOW_ARIA_ATTR = true;
    455     /* Decide if custom data attributes are okay */
    456 
    457     var ALLOW_DATA_ATTR = true;
    458     /* Decide if unknown protocols are okay */
    459 
    460     var ALLOW_UNKNOWN_PROTOCOLS = false;
    461     /* Output should be safe for common template engines.
    462      * This means, DOMPurify removes data attributes, mustaches and ERB
    463      */
    464 
    465     var SAFE_FOR_TEMPLATES = false;
    466     /* Decide if document with <html>... should be returned */
    467 
    468     var WHOLE_DOCUMENT = false;
    469     /* Track whether config is already set on this instance of DOMPurify. */
    470 
    471     var SET_CONFIG = false;
    472     /* Decide if all elements (e.g. style, script) must be children of
    473      * document.body. By default, browsers might move them to document.head */
    474 
    475     var FORCE_BODY = false;
    476     /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
    477      * string (or a TrustedHTML object if Trusted Types are supported).
    478      * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
    479      */
    480 
    481     var RETURN_DOM = false;
    482     /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
    483      * string  (or a TrustedHTML object if Trusted Types are supported) */
    484 
    485     var RETURN_DOM_FRAGMENT = false;
    486     /* Try to return a Trusted Type object instead of a string, return a string in
    487      * case Trusted Types are not supported  */
    488 
    489     var RETURN_TRUSTED_TYPE = false;
    490     /* Output should be free from DOM clobbering attacks?
    491      * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
    492      */
    493 
    494     var SANITIZE_DOM = true;
    495     /* Achieve full DOM Clobbering protection by isolating the namespace of named
    496      * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
    497      *
    498      * HTML/DOM spec rules that enable DOM Clobbering:
    499      *   - Named Access on Window (§7.3.3)
    500      *   - DOM Tree Accessors (§3.1.5)
    501      *   - Form Element Parent-Child Relations (§4.10.3)
    502      *   - Iframe srcdoc / Nested WindowProxies (§4.8.5)
    503      *   - HTMLCollection (§4.2.10.2)
    504      *
    505      * Namespace isolation is implemented by prefixing `id` and `name` attributes
    506      * with a constant string, i.e., `user-content-`
    507      */
    508 
    509     var SANITIZE_NAMED_PROPS = false;
    510     var SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
    511     /* Keep element content when removing element? */
    512 
    513     var KEEP_CONTENT = true;
    514     /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
    515      * of importing it into a new Document and returning a sanitized copy */
    516 
    517     var IN_PLACE = false;
    518     /* Allow usage of profiles like html, svg and mathMl */
    519 
    520     var USE_PROFILES = {};
    521     /* Tags to ignore content of when KEEP_CONTENT is true */
    522 
    523     var FORBID_CONTENTS = null;
    524     var DEFAULT_FORBID_CONTENTS = addToSet({}, ['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']);
    525     /* Tags that are safe for data: URIs */
    526 
    527     var DATA_URI_TAGS = null;
    528     var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
    529     /* Attributes safe for values like "javascript:" */
    530 
    531     var URI_SAFE_ATTRIBUTES = null;
    532     var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
    533     var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
    534     var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
    535     var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
    536     /* Document namespace */
    537 
    538     var NAMESPACE = HTML_NAMESPACE;
    539     var IS_EMPTY_INPUT = false;
    540     /* Allowed XHTML+XML namespaces */
    541 
    542     var ALLOWED_NAMESPACES = null;
    543     var DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
    544     /* Parsing of strict XHTML documents */
    545 
    546     var PARSER_MEDIA_TYPE;
    547     var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
    548     var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
    549     var transformCaseFunc;
    550     /* Keep a reference to config to pass to hooks */
    551 
    552     var CONFIG = null;
    553     /* Ideally, do not touch anything below this line */
    554 
    555     /* ______________________________________________ */
    556 
    557     var formElement = document.createElement('form');
    558 
    559     var isRegexOrFunction = function isRegexOrFunction(testValue) {
    560       return testValue instanceof RegExp || testValue instanceof Function;
    561     };
    562     /**
    563      * _parseConfig
    564      *
    565      * @param  {Object} cfg optional config literal
    566      */
    567     // eslint-disable-next-line complexity
    568 
    569 
    570     var _parseConfig = function _parseConfig(cfg) {
    571       if (CONFIG && CONFIG === cfg) {
    572         return;
    573       }
    574       /* Shield configuration object from tampering */
    575 
    576 
    577       if (!cfg || _typeof(cfg) !== 'object') {
    578         cfg = {};
    579       }
    580       /* Shield configuration object from prototype pollution */
    581 
    582 
    583       cfg = clone(cfg);
    584       PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
    585       SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
    586 
    587       transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
    588       /* Set configuration parameters */
    589 
    590       ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
    591       ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
    592       ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
    593       URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent
    594       cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent
    595       transformCaseFunc // eslint-disable-line indent
    596       ) // eslint-disable-line indent
    597       : DEFAULT_URI_SAFE_ATTRIBUTES;
    598       DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent
    599       cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent
    600       transformCaseFunc // eslint-disable-line indent
    601       ) // eslint-disable-line indent
    602       : DEFAULT_DATA_URI_TAGS;
    603       FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
    604       FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
    605       FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
    606       USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
    607       ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
    608 
    609       ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
    610 
    611       ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
    612 
    613       SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
    614 
    615       WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
    616 
    617       RETURN_DOM = cfg.RETURN_DOM || false; // Default false
    618 
    619       RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
    620 
    621       RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
    622 
    623       FORCE_BODY = cfg.FORCE_BODY || false; // Default false
    624 
    625       SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
    626 
    627       SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
    628 
    629       KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
    630 
    631       IN_PLACE = cfg.IN_PLACE || false; // Default false
    632 
    633       IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
    634       NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
    635 
    636       if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
    637         CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
    638       }
    639 
    640       if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
    641         CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
    642       }
    643 
    644       if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
    645         CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
    646       }
    647 
    648       if (SAFE_FOR_TEMPLATES) {
    649         ALLOW_DATA_ATTR = false;
    650       }
    651 
    652       if (RETURN_DOM_FRAGMENT) {
    653         RETURN_DOM = true;
    654       }
    655       /* Parse profile info */
    656 
    657 
    658       if (USE_PROFILES) {
    659         ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
    660         ALLOWED_ATTR = [];
    661 
    662         if (USE_PROFILES.html === true) {
    663           addToSet(ALLOWED_TAGS, html$1);
    664           addToSet(ALLOWED_ATTR, html);
    665         }
    666 
    667         if (USE_PROFILES.svg === true) {
    668           addToSet(ALLOWED_TAGS, svg$1);
    669           addToSet(ALLOWED_ATTR, svg);
    670           addToSet(ALLOWED_ATTR, xml);
    671         }
    672 
    673         if (USE_PROFILES.svgFilters === true) {
    674           addToSet(ALLOWED_TAGS, svgFilters);
    675           addToSet(ALLOWED_ATTR, svg);
    676           addToSet(ALLOWED_ATTR, xml);
    677         }
    678 
    679         if (USE_PROFILES.mathMl === true) {
    680           addToSet(ALLOWED_TAGS, mathMl$1);
    681           addToSet(ALLOWED_ATTR, mathMl);
    682           addToSet(ALLOWED_ATTR, xml);
    683         }
    684       }
    685       /* Merge configuration parameters */
    686 
    687 
    688       if (cfg.ADD_TAGS) {
    689         if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
    690           ALLOWED_TAGS = clone(ALLOWED_TAGS);
    691         }
    692 
    693         addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
    694       }
    695 
    696       if (cfg.ADD_ATTR) {
    697         if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
    698           ALLOWED_ATTR = clone(ALLOWED_ATTR);
    699         }
    700 
    701         addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
    702       }
    703 
    704       if (cfg.ADD_URI_SAFE_ATTR) {
    705         addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
    706       }
    707 
    708       if (cfg.FORBID_CONTENTS) {
    709         if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
    710           FORBID_CONTENTS = clone(FORBID_CONTENTS);
    711         }
    712 
    713         addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
    714       }
    715       /* Add #text in case KEEP_CONTENT is set to true */
    716 
    717 
    718       if (KEEP_CONTENT) {
    719         ALLOWED_TAGS['#text'] = true;
    720       }
    721       /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
    722 
    723 
    724       if (WHOLE_DOCUMENT) {
    725         addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
    726       }
    727       /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
    728 
    729 
    730       if (ALLOWED_TAGS.table) {
    731         addToSet(ALLOWED_TAGS, ['tbody']);
    732         delete FORBID_TAGS.tbody;
    733       } // Prevent further manipulation of configuration.
    734       // Not available in IE8, Safari 5, etc.
    735 
    736 
    737       if (freeze) {
    738         freeze(cfg);
    739       }
    740 
    741       CONFIG = cfg;
    742     };
    743 
    744     var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
    745     var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML
    746     // namespace. We need to specify them explicitly
    747     // so that they don't get erroneously deleted from
    748     // HTML namespace.
    749 
    750     var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
    751     /* Keep track of all possible SVG and MathML tags
    752      * so that we can perform the namespace checks
    753      * correctly. */
    754 
    755     var ALL_SVG_TAGS = addToSet({}, svg$1);
    756     addToSet(ALL_SVG_TAGS, svgFilters);
    757     addToSet(ALL_SVG_TAGS, svgDisallowed);
    758     var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
    759     addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
    760     /**
    761      *
    762      *
    763      * @param  {Element} element a DOM element whose namespace is being checked
    764      * @returns {boolean} Return false if the element has a
    765      *  namespace that a spec-compliant parser would never
    766      *  return. Return true otherwise.
    767      */
    768 
    769     var _checkValidNamespace = function _checkValidNamespace(element) {
    770       var parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode
    771       // can be null. We just simulate parent in this case.
    772 
    773       if (!parent || !parent.tagName) {
    774         parent = {
    775           namespaceURI: NAMESPACE,
    776           tagName: 'template'
    777         };
    778       }
    779 
    780       var tagName = stringToLowerCase(element.tagName);
    781       var parentTagName = stringToLowerCase(parent.tagName);
    782 
    783       if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
    784         return false;
    785       }
    786 
    787       if (element.namespaceURI === SVG_NAMESPACE) {
    788         // The only way to switch from HTML namespace to SVG
    789         // is via <svg>. If it happens via any other tag, then
    790         // it should be killed.
    791         if (parent.namespaceURI === HTML_NAMESPACE) {
    792           return tagName === 'svg';
    793         } // The only way to switch from MathML to SVG is via`
    794         // svg if parent is either <annotation-xml> or MathML
    795         // text integration points.
    796 
    797 
    798         if (parent.namespaceURI === MATHML_NAMESPACE) {
    799           return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
    800         } // We only allow elements that are defined in SVG
    801         // spec. All others are disallowed in SVG namespace.
    802 
    803 
    804         return Boolean(ALL_SVG_TAGS[tagName]);
    805       }
    806 
    807       if (element.namespaceURI === MATHML_NAMESPACE) {
    808         // The only way to switch from HTML namespace to MathML
    809         // is via <math>. If it happens via any other tag, then
    810         // it should be killed.
    811         if (parent.namespaceURI === HTML_NAMESPACE) {
    812           return tagName === 'math';
    813         } // The only way to switch from SVG to MathML is via
    814         // <math> and HTML integration points
    815 
    816 
    817         if (parent.namespaceURI === SVG_NAMESPACE) {
    818           return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
    819         } // We only allow elements that are defined in MathML
    820         // spec. All others are disallowed in MathML namespace.
    821 
    822 
    823         return Boolean(ALL_MATHML_TAGS[tagName]);
    824       }
    825 
    826       if (element.namespaceURI === HTML_NAMESPACE) {
    827         // The only way to switch from SVG to HTML is via
    828         // HTML integration points, and from MathML to HTML
    829         // is via MathML text integration points
    830         if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
    831           return false;
    832         }
    833 
    834         if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
    835           return false;
    836         } // We disallow tags that are specific for MathML
    837         // or SVG and should never appear in HTML namespace
    838 
    839 
    840         return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
    841       } // For XHTML and XML documents that support custom namespaces
    842 
    843 
    844       if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
    845         return true;
    846       } // The code should never reach this place (this means
    847       // that the element somehow got namespace that is not
    848       // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
    849       // Return false just in case.
    850 
    851 
    852       return false;
    853     };
    854     /**
    855      * _forceRemove
    856      *
    857      * @param  {Node} node a DOM node
    858      */
    859 
    860 
    861     var _forceRemove = function _forceRemove(node) {
    862       arrayPush(DOMPurify.removed, {
    863         element: node
    864       });
    865 
    866       try {
    867         // eslint-disable-next-line unicorn/prefer-dom-node-remove
    868         node.parentNode.removeChild(node);
    869       } catch (_) {
    870         try {
    871           node.outerHTML = emptyHTML;
    872         } catch (_) {
    873           node.remove();
    874         }
    875       }
    876     };
    877     /**
    878      * _removeAttribute
    879      *
    880      * @param  {String} name an Attribute name
    881      * @param  {Node} node a DOM node
    882      */
    883 
    884 
    885     var _removeAttribute = function _removeAttribute(name, node) {
    886       try {
    887         arrayPush(DOMPurify.removed, {
    888           attribute: node.getAttributeNode(name),
    889           from: node
    890         });
    891       } catch (_) {
    892         arrayPush(DOMPurify.removed, {
    893           attribute: null,
    894           from: node
    895         });
    896       }
    897 
    898       node.removeAttribute(name); // We void attribute values for unremovable "is"" attributes
    899 
    900       if (name === 'is' && !ALLOWED_ATTR[name]) {
    901         if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
    902           try {
    903             _forceRemove(node);
    904           } catch (_) {}
    905         } else {
    906           try {
    907             node.setAttribute(name, '');
    908           } catch (_) {}
    909         }
    910       }
    911     };
    912     /**
    913      * _initDocument
    914      *
    915      * @param  {String} dirty a string of dirty markup
    916      * @return {Document} a DOM, filled with the dirty markup
    917      */
    918 
    919 
    920     var _initDocument = function _initDocument(dirty) {
    921       /* Create a HTML document */
    922       var doc;
    923       var leadingWhitespace;
    924 
    925       if (FORCE_BODY) {
    926         dirty = '<remove></remove>' + dirty;
    927       } else {
    928         /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
    929         var matches = stringMatch(dirty, /^[\r\n\t ]+/);
    930         leadingWhitespace = matches && matches[0];
    931       }
    932 
    933       if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
    934         // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
    935         dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
    936       }
    937 
    938       var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
    939       /*
    940        * Use the DOMParser API by default, fallback later if needs be
    941        * DOMParser not work for svg when has multiple root element.
    942        */
    943 
    944       if (NAMESPACE === HTML_NAMESPACE) {
    945         try {
    946           doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
    947         } catch (_) {}
    948       }
    949       /* Use createHTMLDocument in case DOMParser is not available */
    950 
    951 
    952       if (!doc || !doc.documentElement) {
    953         doc = implementation.createDocument(NAMESPACE, 'template', null);
    954 
    955         try {
    956           doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
    957         } catch (_) {// Syntax error if dirtyPayload is invalid xml
    958         }
    959       }
    960 
    961       var body = doc.body || doc.documentElement;
    962 
    963       if (dirty && leadingWhitespace) {
    964         body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
    965       }
    966       /* Work on whole document or just its body */
    967 
    968 
    969       if (NAMESPACE === HTML_NAMESPACE) {
    970         return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
    971       }
    972 
    973       return WHOLE_DOCUMENT ? doc.documentElement : body;
    974     };
    975     /**
    976      * _createIterator
    977      *
    978      * @param  {Document} root document/fragment to create iterator for
    979      * @return {Iterator} iterator instance
    980      */
    981 
    982 
    983     var _createIterator = function _createIterator(root) {
    984       return createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise
    985       NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
    986     };
    987     /**
    988      * _isClobbered
    989      *
    990      * @param  {Node} elm element to check for clobbering attacks
    991      * @return {Boolean} true if clobbered, false if safe
    992      */
    993 
    994 
    995     var _isClobbered = function _isClobbered(elm) {
    996       return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
    997     };
    998     /**
    999      * _isNode
   1000      *
   1001      * @param  {Node} obj object to check whether it's a DOM node
   1002      * @return {Boolean} true is object is a DOM node
   1003      */
   1004 
   1005 
   1006     var _isNode = function _isNode(object) {
   1007       return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
   1008     };
   1009     /**
   1010      * _executeHook
   1011      * Execute user configurable hooks
   1012      *
   1013      * @param  {String} entryPoint  Name of the hook's entry point
   1014      * @param  {Node} currentNode node to work on with the hook
   1015      * @param  {Object} data additional hook parameters
   1016      */
   1017 
   1018 
   1019     var _executeHook = function _executeHook(entryPoint, currentNode, data) {
   1020       if (!hooks[entryPoint]) {
   1021         return;
   1022       }
   1023 
   1024       arrayForEach(hooks[entryPoint], function (hook) {
   1025         hook.call(DOMPurify, currentNode, data, CONFIG);
   1026       });
   1027     };
   1028     /**
   1029      * _sanitizeElements
   1030      *
   1031      * @protect nodeName
   1032      * @protect textContent
   1033      * @protect removeChild
   1034      *
   1035      * @param   {Node} currentNode to check for permission to exist
   1036      * @return  {Boolean} true if node was killed, false if left alive
   1037      */
   1038 
   1039 
   1040     var _sanitizeElements = function _sanitizeElements(currentNode) {
   1041       var content;
   1042       /* Execute a hook if present */
   1043 
   1044       _executeHook('beforeSanitizeElements', currentNode, null);
   1045       /* Check if element is clobbered or can clobber */
   1046 
   1047 
   1048       if (_isClobbered(currentNode)) {
   1049         _forceRemove(currentNode);
   1050 
   1051         return true;
   1052       }
   1053       /* Check if tagname contains Unicode */
   1054 
   1055 
   1056       if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
   1057         _forceRemove(currentNode);
   1058 
   1059         return true;
   1060       }
   1061       /* Now let's check the element's type and name */
   1062 
   1063 
   1064       var tagName = transformCaseFunc(currentNode.nodeName);
   1065       /* Execute a hook if present */
   1066 
   1067       _executeHook('uponSanitizeElement', currentNode, {
   1068         tagName: tagName,
   1069         allowedTags: ALLOWED_TAGS
   1070       });
   1071       /* Detect mXSS attempts abusing namespace confusion */
   1072 
   1073 
   1074       if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
   1075         _forceRemove(currentNode);
   1076 
   1077         return true;
   1078       }
   1079       /* Mitigate a problem with templates inside select */
   1080 
   1081 
   1082       if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
   1083         _forceRemove(currentNode);
   1084 
   1085         return true;
   1086       }
   1087       /* Remove element if anything forbids its presence */
   1088 
   1089 
   1090       if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
   1091         /* Check if we have a custom element to handle */
   1092         if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
   1093           if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
   1094           if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
   1095         }
   1096         /* Keep content except for bad-listed elements */
   1097 
   1098 
   1099         if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
   1100           var parentNode = getParentNode(currentNode) || currentNode.parentNode;
   1101           var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
   1102 
   1103           if (childNodes && parentNode) {
   1104             var childCount = childNodes.length;
   1105 
   1106             for (var i = childCount - 1; i >= 0; --i) {
   1107               parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
   1108             }
   1109           }
   1110         }
   1111 
   1112         _forceRemove(currentNode);
   1113 
   1114         return true;
   1115       }
   1116       /* Check whether element has a valid namespace */
   1117 
   1118 
   1119       if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
   1120         _forceRemove(currentNode);
   1121 
   1122         return true;
   1123       }
   1124 
   1125       if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
   1126         _forceRemove(currentNode);
   1127 
   1128         return true;
   1129       }
   1130       /* Sanitize element content to be template-safe */
   1131 
   1132 
   1133       if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
   1134         /* Get the element's text content */
   1135         content = currentNode.textContent;
   1136         content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
   1137         content = stringReplace(content, ERB_EXPR$1, ' ');
   1138         content = stringReplace(content, TMPLIT_EXPR$1, ' ');
   1139 
   1140         if (currentNode.textContent !== content) {
   1141           arrayPush(DOMPurify.removed, {
   1142             element: currentNode.cloneNode()
   1143           });
   1144           currentNode.textContent = content;
   1145         }
   1146       }
   1147       /* Execute a hook if present */
   1148 
   1149 
   1150       _executeHook('afterSanitizeElements', currentNode, null);
   1151 
   1152       return false;
   1153     };
   1154     /**
   1155      * _isValidAttribute
   1156      *
   1157      * @param  {string} lcTag Lowercase tag name of containing element.
   1158      * @param  {string} lcName Lowercase attribute name.
   1159      * @param  {string} value Attribute value.
   1160      * @return {Boolean} Returns true if `value` is valid, otherwise false.
   1161      */
   1162     // eslint-disable-next-line complexity
   1163 
   1164 
   1165     var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
   1166       /* Make sure attribute cannot clobber */
   1167       if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
   1168         return false;
   1169       }
   1170       /* Allow valid data-* attributes: At least one character after "-"
   1171           (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
   1172           XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
   1173           We don't need to check the value; it's always URI safe. */
   1174 
   1175 
   1176       if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
   1177         if ( // First condition does a very basic check if a) it's basically a valid custom element tagname AND
   1178         // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
   1179         // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
   1180         _basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || // Alternative, second condition checks if it's an `is`-attribute, AND
   1181         // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
   1182         lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
   1183           return false;
   1184         }
   1185         /* Check value is safe. First, is attr inert? If so, is safe */
   1186 
   1187       } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (!value) ; else {
   1188         return false;
   1189       }
   1190 
   1191       return true;
   1192     };
   1193     /**
   1194      * _basicCustomElementCheck
   1195      * checks if at least one dash is included in tagName, and it's not the first char
   1196      * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
   1197      * @param {string} tagName name of the tag of the node to sanitize
   1198      */
   1199 
   1200 
   1201     var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
   1202       return tagName.indexOf('-') > 0;
   1203     };
   1204     /**
   1205      * _sanitizeAttributes
   1206      *
   1207      * @protect attributes
   1208      * @protect nodeName
   1209      * @protect removeAttribute
   1210      * @protect setAttribute
   1211      *
   1212      * @param  {Node} currentNode to sanitize
   1213      */
   1214 
   1215 
   1216     var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
   1217       var attr;
   1218       var value;
   1219       var lcName;
   1220       var l;
   1221       /* Execute a hook if present */
   1222 
   1223       _executeHook('beforeSanitizeAttributes', currentNode, null);
   1224 
   1225       var attributes = currentNode.attributes;
   1226       /* Check if we have attributes; if not we might have a text node */
   1227 
   1228       if (!attributes) {
   1229         return;
   1230       }
   1231 
   1232       var hookEvent = {
   1233         attrName: '',
   1234         attrValue: '',
   1235         keepAttr: true,
   1236         allowedAttributes: ALLOWED_ATTR
   1237       };
   1238       l = attributes.length;
   1239       /* Go backwards over all attributes; safely remove bad ones */
   1240 
   1241       while (l--) {
   1242         attr = attributes[l];
   1243         var _attr = attr,
   1244             name = _attr.name,
   1245             namespaceURI = _attr.namespaceURI;
   1246         value = name === 'value' ? attr.value : stringTrim(attr.value);
   1247         lcName = transformCaseFunc(name);
   1248         /* Execute a hook if present */
   1249 
   1250         hookEvent.attrName = lcName;
   1251         hookEvent.attrValue = value;
   1252         hookEvent.keepAttr = true;
   1253         hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
   1254 
   1255         _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
   1256 
   1257         value = hookEvent.attrValue;
   1258         /* Did the hooks approve of the attribute? */
   1259 
   1260         if (hookEvent.forceKeepAttr) {
   1261           continue;
   1262         }
   1263         /* Remove attribute */
   1264 
   1265 
   1266         _removeAttribute(name, currentNode);
   1267         /* Did the hooks approve of the attribute? */
   1268 
   1269 
   1270         if (!hookEvent.keepAttr) {
   1271           continue;
   1272         }
   1273         /* Work around a security issue in jQuery 3.0 */
   1274 
   1275 
   1276         if (regExpTest(/\/>/i, value)) {
   1277           _removeAttribute(name, currentNode);
   1278 
   1279           continue;
   1280         }
   1281         /* Sanitize attribute content to be template-safe */
   1282 
   1283 
   1284         if (SAFE_FOR_TEMPLATES) {
   1285           value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
   1286           value = stringReplace(value, ERB_EXPR$1, ' ');
   1287           value = stringReplace(value, TMPLIT_EXPR$1, ' ');
   1288         }
   1289         /* Is `value` valid for this attribute? */
   1290 
   1291 
   1292         var lcTag = transformCaseFunc(currentNode.nodeName);
   1293 
   1294         if (!_isValidAttribute(lcTag, lcName, value)) {
   1295           continue;
   1296         }
   1297         /* Full DOM Clobbering protection via namespace isolation,
   1298          * Prefix id and name attributes with `user-content-`
   1299          */
   1300 
   1301 
   1302         if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
   1303           // Remove the attribute with this value
   1304           _removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
   1305 
   1306 
   1307           value = SANITIZE_NAMED_PROPS_PREFIX + value;
   1308         }
   1309         /* Handle attributes that require Trusted Types */
   1310 
   1311 
   1312         if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
   1313           if (namespaceURI) ; else {
   1314             switch (trustedTypes.getAttributeType(lcTag, lcName)) {
   1315               case 'TrustedHTML':
   1316                 value = trustedTypesPolicy.createHTML(value);
   1317                 break;
   1318 
   1319               case 'TrustedScriptURL':
   1320                 value = trustedTypesPolicy.createScriptURL(value);
   1321                 break;
   1322             }
   1323           }
   1324         }
   1325         /* Handle invalid data-* attribute set by try-catching it */
   1326 
   1327 
   1328         try {
   1329           if (namespaceURI) {
   1330             currentNode.setAttributeNS(namespaceURI, name, value);
   1331           } else {
   1332             /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
   1333             currentNode.setAttribute(name, value);
   1334           }
   1335 
   1336           arrayPop(DOMPurify.removed);
   1337         } catch (_) {}
   1338       }
   1339       /* Execute a hook if present */
   1340 
   1341 
   1342       _executeHook('afterSanitizeAttributes', currentNode, null);
   1343     };
   1344     /**
   1345      * _sanitizeShadowDOM
   1346      *
   1347      * @param  {DocumentFragment} fragment to iterate over recursively
   1348      */
   1349 
   1350 
   1351     var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
   1352       var shadowNode;
   1353 
   1354       var shadowIterator = _createIterator(fragment);
   1355       /* Execute a hook if present */
   1356 
   1357 
   1358       _executeHook('beforeSanitizeShadowDOM', fragment, null);
   1359 
   1360       while (shadowNode = shadowIterator.nextNode()) {
   1361         /* Execute a hook if present */
   1362         _executeHook('uponSanitizeShadowNode', shadowNode, null);
   1363         /* Sanitize tags and elements */
   1364 
   1365 
   1366         if (_sanitizeElements(shadowNode)) {
   1367           continue;
   1368         }
   1369         /* Deep shadow DOM detected */
   1370 
   1371 
   1372         if (shadowNode.content instanceof DocumentFragment) {
   1373           _sanitizeShadowDOM(shadowNode.content);
   1374         }
   1375         /* Check attributes, sanitize if necessary */
   1376 
   1377 
   1378         _sanitizeAttributes(shadowNode);
   1379       }
   1380       /* Execute a hook if present */
   1381 
   1382 
   1383       _executeHook('afterSanitizeShadowDOM', fragment, null);
   1384     };
   1385     /**
   1386      * Sanitize
   1387      * Public method providing core sanitation functionality
   1388      *
   1389      * @param {String|Node} dirty string or DOM node
   1390      * @param {Object} configuration object
   1391      */
   1392     // eslint-disable-next-line complexity
   1393 
   1394 
   1395     DOMPurify.sanitize = function (dirty) {
   1396       var cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
   1397       var body;
   1398       var importedNode;
   1399       var currentNode;
   1400       var oldNode;
   1401       var returnNode;
   1402       /* Make sure we have a string to sanitize.
   1403         DO NOT return early, as this will return the wrong type if
   1404         the user has requested a DOM object rather than a string */
   1405 
   1406       IS_EMPTY_INPUT = !dirty;
   1407 
   1408       if (IS_EMPTY_INPUT) {
   1409         dirty = '<!-->';
   1410       }
   1411       /* Stringify, in case dirty is an object */
   1412 
   1413 
   1414       if (typeof dirty !== 'string' && !_isNode(dirty)) {
   1415         // eslint-disable-next-line no-negated-condition
   1416         if (typeof dirty.toString !== 'function') {
   1417           throw typeErrorCreate('toString is not a function');
   1418         } else {
   1419           dirty = dirty.toString();
   1420 
   1421           if (typeof dirty !== 'string') {
   1422             throw typeErrorCreate('dirty is not a string, aborting');
   1423           }
   1424         }
   1425       }
   1426       /* Check we can run. Otherwise fall back or ignore */
   1427 
   1428 
   1429       if (!DOMPurify.isSupported) {
   1430         if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
   1431           if (typeof dirty === 'string') {
   1432             return window.toStaticHTML(dirty);
   1433           }
   1434 
   1435           if (_isNode(dirty)) {
   1436             return window.toStaticHTML(dirty.outerHTML);
   1437           }
   1438         }
   1439 
   1440         return dirty;
   1441       }
   1442       /* Assign config vars */
   1443 
   1444 
   1445       if (!SET_CONFIG) {
   1446         _parseConfig(cfg);
   1447       }
   1448       /* Clean up removed elements */
   1449 
   1450 
   1451       DOMPurify.removed = [];
   1452       /* Check if dirty is correctly typed for IN_PLACE */
   1453 
   1454       if (typeof dirty === 'string') {
   1455         IN_PLACE = false;
   1456       }
   1457 
   1458       if (IN_PLACE) {
   1459         /* Do some early pre-sanitization to avoid unsafe root nodes */
   1460         if (dirty.nodeName) {
   1461           var tagName = transformCaseFunc(dirty.nodeName);
   1462 
   1463           if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
   1464             throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
   1465           }
   1466         }
   1467       } else if (dirty instanceof Node) {
   1468         /* If dirty is a DOM element, append to an empty document to avoid
   1469            elements being stripped by the parser */
   1470         body = _initDocument('<!---->');
   1471         importedNode = body.ownerDocument.importNode(dirty, true);
   1472 
   1473         if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
   1474           /* Node is already a body, use as is */
   1475           body = importedNode;
   1476         } else if (importedNode.nodeName === 'HTML') {
   1477           body = importedNode;
   1478         } else {
   1479           // eslint-disable-next-line unicorn/prefer-dom-node-append
   1480           body.appendChild(importedNode);
   1481         }
   1482       } else {
   1483         /* Exit directly if we have nothing to do */
   1484         if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes
   1485         dirty.indexOf('<') === -1) {
   1486           return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
   1487         }
   1488         /* Initialize the document to work on */
   1489 
   1490 
   1491         body = _initDocument(dirty);
   1492         /* Check we have a DOM node from the data */
   1493 
   1494         if (!body) {
   1495           return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
   1496         }
   1497       }
   1498       /* Remove first element node (ours) if FORCE_BODY is set */
   1499 
   1500 
   1501       if (body && FORCE_BODY) {
   1502         _forceRemove(body.firstChild);
   1503       }
   1504       /* Get node iterator */
   1505 
   1506 
   1507       var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
   1508       /* Now start iterating over the created document */
   1509 
   1510 
   1511       while (currentNode = nodeIterator.nextNode()) {
   1512         /* Fix IE's strange behavior with manipulated textNodes #89 */
   1513         if (currentNode.nodeType === 3 && currentNode === oldNode) {
   1514           continue;
   1515         }
   1516         /* Sanitize tags and elements */
   1517 
   1518 
   1519         if (_sanitizeElements(currentNode)) {
   1520           continue;
   1521         }
   1522         /* Shadow DOM detected, sanitize it */
   1523 
   1524 
   1525         if (currentNode.content instanceof DocumentFragment) {
   1526           _sanitizeShadowDOM(currentNode.content);
   1527         }
   1528         /* Check attributes, sanitize if necessary */
   1529 
   1530 
   1531         _sanitizeAttributes(currentNode);
   1532 
   1533         oldNode = currentNode;
   1534       }
   1535 
   1536       oldNode = null;
   1537       /* If we sanitized `dirty` in-place, return it. */
   1538 
   1539       if (IN_PLACE) {
   1540         return dirty;
   1541       }
   1542       /* Return sanitized string or DOM */
   1543 
   1544 
   1545       if (RETURN_DOM) {
   1546         if (RETURN_DOM_FRAGMENT) {
   1547           returnNode = createDocumentFragment.call(body.ownerDocument);
   1548 
   1549           while (body.firstChild) {
   1550             // eslint-disable-next-line unicorn/prefer-dom-node-append
   1551             returnNode.appendChild(body.firstChild);
   1552           }
   1553         } else {
   1554           returnNode = body;
   1555         }
   1556 
   1557         if (ALLOWED_ATTR.shadowroot) {
   1558           /*
   1559             AdoptNode() is not used because internal state is not reset
   1560             (e.g. the past names map of a HTMLFormElement), this is safe
   1561             in theory but we would rather not risk another attack vector.
   1562             The state that is cloned by importNode() is explicitly defined
   1563             by the specs.
   1564           */
   1565           returnNode = importNode.call(originalDocument, returnNode, true);
   1566         }
   1567 
   1568         return returnNode;
   1569       }
   1570 
   1571       var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
   1572       /* Serialize doctype if allowed */
   1573 
   1574       if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
   1575         serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
   1576       }
   1577       /* Sanitize final string template-safe */
   1578 
   1579 
   1580       if (SAFE_FOR_TEMPLATES) {
   1581         serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
   1582         serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
   1583         serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR$1, ' ');
   1584       }
   1585 
   1586       return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
   1587     };
   1588     /**
   1589      * Public method to set the configuration once
   1590      * setConfig
   1591      *
   1592      * @param {Object} cfg configuration object
   1593      */
   1594 
   1595 
   1596     DOMPurify.setConfig = function (cfg) {
   1597       _parseConfig(cfg);
   1598 
   1599       SET_CONFIG = true;
   1600     };
   1601     /**
   1602      * Public method to remove the configuration
   1603      * clearConfig
   1604      *
   1605      */
   1606 
   1607 
   1608     DOMPurify.clearConfig = function () {
   1609       CONFIG = null;
   1610       SET_CONFIG = false;
   1611     };
   1612     /**
   1613      * Public method to check if an attribute value is valid.
   1614      * Uses last set config, if any. Otherwise, uses config defaults.
   1615      * isValidAttribute
   1616      *
   1617      * @param  {string} tag Tag name of containing element.
   1618      * @param  {string} attr Attribute name.
   1619      * @param  {string} value Attribute value.
   1620      * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
   1621      */
   1622 
   1623 
   1624     DOMPurify.isValidAttribute = function (tag, attr, value) {
   1625       /* Initialize shared config vars if necessary. */
   1626       if (!CONFIG) {
   1627         _parseConfig({});
   1628       }
   1629 
   1630       var lcTag = transformCaseFunc(tag);
   1631       var lcName = transformCaseFunc(attr);
   1632       return _isValidAttribute(lcTag, lcName, value);
   1633     };
   1634     /**
   1635      * AddHook
   1636      * Public method to add DOMPurify hooks
   1637      *
   1638      * @param {String} entryPoint entry point for the hook to add
   1639      * @param {Function} hookFunction function to execute
   1640      */
   1641 
   1642 
   1643     DOMPurify.addHook = function (entryPoint, hookFunction) {
   1644       if (typeof hookFunction !== 'function') {
   1645         return;
   1646       }
   1647 
   1648       hooks[entryPoint] = hooks[entryPoint] || [];
   1649       arrayPush(hooks[entryPoint], hookFunction);
   1650     };
   1651     /**
   1652      * RemoveHook
   1653      * Public method to remove a DOMPurify hook at a given entryPoint
   1654      * (pops it from the stack of hooks if more are present)
   1655      *
   1656      * @param {String} entryPoint entry point for the hook to remove
   1657      * @return {Function} removed(popped) hook
   1658      */
   1659 
   1660 
   1661     DOMPurify.removeHook = function (entryPoint) {
   1662       if (hooks[entryPoint]) {
   1663         return arrayPop(hooks[entryPoint]);
   1664       }
   1665     };
   1666     /**
   1667      * RemoveHooks
   1668      * Public method to remove all DOMPurify hooks at a given entryPoint
   1669      *
   1670      * @param  {String} entryPoint entry point for the hooks to remove
   1671      */
   1672 
   1673 
   1674     DOMPurify.removeHooks = function (entryPoint) {
   1675       if (hooks[entryPoint]) {
   1676         hooks[entryPoint] = [];
   1677       }
   1678     };
   1679     /**
   1680      * RemoveAllHooks
   1681      * Public method to remove all DOMPurify hooks
   1682      *
   1683      */
   1684 
   1685 
   1686     DOMPurify.removeAllHooks = function () {
   1687       hooks = {};
   1688     };
   1689 
   1690     return DOMPurify;
   1691   }
   1692 
   1693   var purify = createDOMPurify();
   1694 
   1695   return purify;
   1696 
   1697 }));
   1698 //# sourceMappingURL=purify.js.map