@knime/kds-table 10.1.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -745,6 +745,14 @@ var dimension = {
745
745
  variable: "var(--kds-dimension-component-height-0-25x)"
746
746
  }
747
747
  },
748
+ "0.5x": {
749
+ value: 8,
750
+ unit: "px",
751
+ css: {
752
+ value: "8px",
753
+ variable: "var(--kds-dimension-component-height-0-5x)"
754
+ }
755
+ },
748
756
  "0.75x": {
749
757
  value: 12,
750
758
  unit: "px",
@@ -891,6 +899,14 @@ var dimension = {
891
899
  variable: "var(--kds-dimension-component-width-0-25x)"
892
900
  }
893
901
  },
902
+ "0.5x": {
903
+ value: 8,
904
+ unit: "px",
905
+ css: {
906
+ value: "8px",
907
+ variable: "var(--kds-dimension-component-width-0-5x)"
908
+ }
909
+ },
894
910
  "0.75x": {
895
911
  value: 12,
896
912
  unit: "px",
@@ -1646,8 +1662,11 @@ var oe = class extends b {
1646
1662
  }
1647
1663
  };
1648
1664
  //#endregion
1649
- //#region ../../node_modules/.pnpm/dompurify@3.4.13/node_modules/dompurify/dist/purify.es.mjs
1650
- /*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
1665
+ //#region ../../node_modules/.pnpm/dompurify@3.4.16/node_modules/dompurify/dist/purify.es.mjs
1666
+ /*! @license DOMPurify 3.4.16 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.16/LICENSE */
1667
+ function _OverloadYield(e, d) {
1668
+ this.v = e, this.k = d;
1669
+ }
1651
1670
  function _arrayLikeToArray(r, a) {
1652
1671
  (null == a || a > r.length) && (a = r.length);
1653
1672
  for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
@@ -1659,12 +1678,14 @@ function _arrayWithHoles(r) {
1659
1678
  function _iterableToArrayLimit(r, l) {
1660
1679
  var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
1661
1680
  if (null != t) {
1662
- var e, n, i, u, a = [], f = true, o = false;
1681
+ var e, n, i, u, a = [], f = !0, o = !1;
1663
1682
  try {
1664
- if (i = (t = t.call(r)).next, 0 === l);
1665
- else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
1683
+ if (i = (t = t.call(r)).next, 0 === l) {
1684
+ if (Object(t) !== t) return;
1685
+ f = !1;
1686
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
1666
1687
  } catch (r) {
1667
- o = true, n = r;
1688
+ o = !0, n = r;
1668
1689
  } finally {
1669
1690
  try {
1670
1691
  if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
@@ -1678,6 +1699,7 @@ function _iterableToArrayLimit(r, l) {
1678
1699
  function _nonIterableRest() {
1679
1700
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1680
1701
  }
1702
+ /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
1681
1703
  function _slicedToArray(r, e) {
1682
1704
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
1683
1705
  }
@@ -1688,9 +1710,64 @@ function _unsupportedIterableToArray(r, a) {
1688
1710
  return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
1689
1711
  }
1690
1712
  }
1691
- var entries = Object.entries, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1692
- var freeze = Object.freeze, seal = Object.seal, create = Object.create;
1693
- var _ref = typeof Reflect !== "undefined" && Reflect, apply = _ref.apply, construct = _ref.construct;
1713
+ function AsyncGenerator(e) {
1714
+ var t, n;
1715
+ function resume(t, n) {
1716
+ try {
1717
+ var r = e[t](n), o = r.value, u = o instanceof _OverloadYield;
1718
+ Promise.resolve(u ? o.v : o).then(function(n) {
1719
+ if (u) {
1720
+ var i = "return" === t && o.k ? t : "next";
1721
+ if (!o.k || n.done) return resume(i, n);
1722
+ n = e[i](n).value;
1723
+ }
1724
+ settle(!!r.done, n);
1725
+ }, function(e) {
1726
+ resume("throw", e);
1727
+ });
1728
+ } catch (e) {
1729
+ settle(2, e);
1730
+ }
1731
+ }
1732
+ function settle(e, r) {
1733
+ 2 === e ? t.reject(r) : t.resolve({
1734
+ value: r,
1735
+ done: e
1736
+ }), (t = t.next) ? resume(t.key, t.arg) : n = null;
1737
+ }
1738
+ this._invoke = function(e, r) {
1739
+ return new Promise(function(o, u) {
1740
+ var i = {
1741
+ key: e,
1742
+ arg: r,
1743
+ resolve: o,
1744
+ reject: u,
1745
+ next: null
1746
+ };
1747
+ n ? n = n.next = i : (t = n = i, resume(e, r));
1748
+ });
1749
+ }, "function" != typeof e.return && (this.return = void 0);
1750
+ }
1751
+ AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function() {
1752
+ return this;
1753
+ }, AsyncGenerator.prototype.next = function(e) {
1754
+ return this._invoke("next", e);
1755
+ }, AsyncGenerator.prototype.throw = function(e) {
1756
+ return this._invoke("throw", e);
1757
+ }, AsyncGenerator.prototype.return = function(e) {
1758
+ return this._invoke("return", e);
1759
+ };
1760
+ var entries = Object.entries;
1761
+ var setPrototypeOf = Object.setPrototypeOf;
1762
+ var isFrozen = Object.isFrozen;
1763
+ var getPrototypeOf = Object.getPrototypeOf;
1764
+ var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1765
+ var freeze = Object.freeze;
1766
+ var seal = Object.seal;
1767
+ var create = Object.create;
1768
+ var _ref = typeof Reflect !== "undefined" && Reflect;
1769
+ var apply = _ref.apply;
1770
+ var construct = _ref.construct;
1694
1771
  if (!freeze) freeze = function freeze(x) {
1695
1772
  return x;
1696
1773
  };
@@ -1706,9 +1783,11 @@ if (!construct) construct = function construct(Func) {
1706
1783
  return new Func(...args);
1707
1784
  };
1708
1785
  var arrayForEach = unapply(Array.prototype.forEach);
1786
+ Array.prototype.indexOf;
1709
1787
  var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
1710
1788
  var arrayPop = unapply(Array.prototype.pop);
1711
1789
  var arrayPush = unapply(Array.prototype.push);
1790
+ Array.prototype.slice;
1712
1791
  var arraySplice = unapply(Array.prototype.splice);
1713
1792
  var arrayIsArray = Array.isArray;
1714
1793
  var stringToLowerCase = unapply(String.prototype.toLowerCase);
@@ -2368,6 +2447,7 @@ var svg = freeze([
2368
2447
  "patterncontentunits",
2369
2448
  "patterntransform",
2370
2449
  "patternunits",
2450
+ "pointer-events",
2371
2451
  "points",
2372
2452
  "preservealpha",
2373
2453
  "preserveaspectratio",
@@ -2422,6 +2502,7 @@ var svg = freeze([
2422
2502
  "u2",
2423
2503
  "unicode",
2424
2504
  "values",
2505
+ "vector-effect",
2425
2506
  "viewbox",
2426
2507
  "visibility",
2427
2508
  "version",
@@ -2535,6 +2616,24 @@ var NODE_TYPE = {
2535
2616
  documentFragment: 11,
2536
2617
  notation: 12
2537
2618
  };
2619
+ var LITERAL_TEXT_ELEMENT_NAMES = [
2620
+ "style",
2621
+ "script",
2622
+ "xmp",
2623
+ "iframe",
2624
+ "noembed",
2625
+ "noframes",
2626
+ "plaintext",
2627
+ "noscript"
2628
+ ];
2629
+ var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
2630
+ var LITERAL_TEXT_CLOSE = function() {
2631
+ const map = {};
2632
+ arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => {
2633
+ map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i"));
2634
+ });
2635
+ return freeze(map);
2636
+ }();
2538
2637
  var getGlobal = function getGlobal() {
2539
2638
  return typeof window === "undefined" ? null : window;
2540
2639
  };
@@ -2594,10 +2693,25 @@ var _createHooksMap = function _createHooksMap() {
2594
2693
  var _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
2595
2694
  return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
2596
2695
  };
2696
+ /**
2697
+ * Resolve an object-valued configuration option: a prototype-free clone
2698
+ * of cfg[key] when it is an own, truthy object property, else a fresh
2699
+ * fallback built by makeFallback (fresh on every parse, so a previous
2700
+ * parse can never leak state into the next one).
2701
+ *
2702
+ * @param cfg the cloned, prototype-free configuration object
2703
+ * @param key the configuration property to read
2704
+ * @param makeFallback builds the fallback value when the option is absent
2705
+ * @returns the resolved object
2706
+ */
2707
+ var _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback) {
2708
+ const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0;
2709
+ return value && typeof value === "object" ? clone(value) : makeFallback();
2710
+ };
2597
2711
  function createDOMPurify() {
2598
2712
  let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
2599
2713
  const DOMPurify = (root) => createDOMPurify(root);
2600
- DOMPurify.version = "3.4.13";
2714
+ DOMPurify.version = "3.4.16";
2601
2715
  DOMPurify.removed = [];
2602
2716
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
2603
2717
  DOMPurify.isSupported = false;
@@ -2614,6 +2728,7 @@ function createDOMPurify() {
2614
2728
  const ElementPrototype = Element.prototype;
2615
2729
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
2616
2730
  const remove = lookupGetter(ElementPrototype, "remove");
2731
+ const removeAttributeNode = lookupGetter(ElementPrototype, "removeAttributeNode");
2617
2732
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
2618
2733
  const getChildNodes = lookupGetter(ElementPrototype, "childNodes");
2619
2734
  const getParentNode = lookupGetter(ElementPrototype, "parentNode");
@@ -2622,6 +2737,12 @@ function createDOMPurify() {
2622
2737
  const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null;
2623
2738
  const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null;
2624
2739
  const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, "ownerDocument") : null;
2740
+ const _readNodeType = function _readNodeType(node) {
2741
+ return getNodeType ? getNodeType(node) : node.nodeType;
2742
+ };
2743
+ const _readNodeName = function _readNodeName(node) {
2744
+ return getNodeName ? getNodeName(node) : node.nodeName;
2745
+ };
2625
2746
  if (typeof HTMLTemplateElement === "function") {
2626
2747
  const template = document.createElement("template");
2627
2748
  if (template.content && template.content.ownerDocument) document = template.content.ownerDocument;
@@ -2879,9 +3000,9 @@ function createDOMPurify() {
2879
3000
  IN_PLACE = cfg.IN_PLACE || false;
2880
3001
  IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
2881
3002
  NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
2882
- MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
2883
- HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
2884
- const customElementHandling = objectHasOwnProperty(cfg, "CUSTOM_ELEMENT_HANDLING") && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === "object" ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
3003
+ MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(cfg, "MATHML_TEXT_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS));
3004
+ HTML_INTEGRATION_POINTS = _resolveObjectOption(cfg, "HTML_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS));
3005
+ const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null));
2885
3006
  CUSTOM_ELEMENT_HANDLING = create(null);
2886
3007
  if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
2887
3008
  if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck;
@@ -2928,11 +3049,6 @@ function createDOMPurify() {
2928
3049
  addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
2929
3050
  }
2930
3051
  }
2931
- if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
2932
- if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) {
2933
- if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
2934
- addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
2935
- }
2936
3052
  if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
2937
3053
  if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
2938
3054
  addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
@@ -3049,6 +3165,32 @@ function createDOMPurify() {
3049
3165
  }
3050
3166
  };
3051
3167
  /**
3168
+ * _stripAttributeNode
3169
+ *
3170
+ * Remove a single Attr node case/namespace-exactly on an attribute-teardown
3171
+ * path. Name-based removeAttribute() ASCII-lowercases its lookup key for an
3172
+ * HTML element in an HTML document and so silently misses a case-preserved
3173
+ * handler (e.g. `ONERROR` off an XML/XHTML import) - the same defect
3174
+ * _removeAttribute() was fixed for, which a name-based call would reintroduce
3175
+ * on these IN_PLACE teardown paths. Unlike _removeAttribute this does not
3176
+ * record into DOMPurify.removed: the neutralize passes intentionally do not
3177
+ * book-keep. A clobbered/detached node falls back to best-effort name-based
3178
+ * removal.
3179
+ *
3180
+ * @param element the element to strip the attribute from
3181
+ * @param attribute the Attr node to remove
3182
+ * @param name the attribute's name, for the fallback path
3183
+ */
3184
+ const _stripAttributeNode = function _stripAttributeNode(element, attribute, name) {
3185
+ try {
3186
+ removeAttributeNode(element, attribute);
3187
+ } catch (_) {
3188
+ try {
3189
+ element.removeAttribute(name);
3190
+ } catch (_) {}
3191
+ }
3192
+ };
3193
+ /**
3052
3194
  * _neutralizeRoot
3053
3195
  *
3054
3196
  * Fail-closed teardown of an in-place root after the sanitize walk aborts
@@ -3082,30 +3224,45 @@ function createDOMPurify() {
3082
3224
  if (attributes) for (let i = attributes.length - 1; i >= 0; --i) {
3083
3225
  const attribute = attributes[i];
3084
3226
  const name = attribute && attribute.name;
3085
- if (typeof name === "string") try {
3086
- root.removeAttribute(name);
3087
- } catch (_) {}
3227
+ if (typeof name === "string") _stripAttributeNode(root, attribute, name);
3088
3228
  }
3089
3229
  };
3090
3230
  /**
3091
3231
  * _removeAttribute
3092
3232
  *
3233
+ * Name-based getAttributeNode()/removeAttribute() ASCII-lowercase their
3234
+ * lookup key for HTML elements in an HTML document, so they silently miss an
3235
+ * attribute whose stored qualified name still contains uppercase ASCII
3236
+ * letters. That happens when the node came from a case-preserving source
3237
+ * (an XML/XHTML document imported via importNode(), or createAttributeNS()),
3238
+ * where e.g. `ONERROR` survives the walk: the policy check lowercases to
3239
+ * `onerror` and rejects it, but `removeAttribute('ONERROR')` looks up
3240
+ * `onerror` and finds nothing. Remove the exact Attr node instead, which is
3241
+ * case- and namespace-exact, and fall back to name-based removal only when
3242
+ * the caller could not supply the node.
3243
+ *
3093
3244
  * @param name an Attribute name
3094
3245
  * @param element a DOM node
3246
+ * @param attr the exact Attr node to remove, when the caller has it
3095
3247
  */
3096
- const _removeAttribute = function _removeAttribute(name, element) {
3248
+ const _removeAttribute = function _removeAttribute(name, element, attr) {
3249
+ if (!attr) try {
3250
+ attr = element.getAttributeNode(name);
3251
+ } catch (_) {
3252
+ attr = null;
3253
+ }
3254
+ arrayPush(DOMPurify.removed, {
3255
+ attribute: attr || null,
3256
+ from: element
3257
+ });
3097
3258
  try {
3098
- arrayPush(DOMPurify.removed, {
3099
- attribute: element.getAttributeNode(name),
3100
- from: element
3101
- });
3259
+ if (attr) removeAttributeNode(element, attr);
3260
+ else element.removeAttribute(name);
3102
3261
  } catch (_) {
3103
- arrayPush(DOMPurify.removed, {
3104
- attribute: null,
3105
- from: element
3106
- });
3262
+ try {
3263
+ element.removeAttribute(name);
3264
+ } catch (_) {}
3107
3265
  }
3108
- element.removeAttribute(name);
3109
3266
  if (name === "is") if (RETURN_DOM || RETURN_DOM_FRAGMENT) try {
3110
3267
  _forceRemove(element);
3111
3268
  } catch (_) {}
@@ -3130,9 +3287,7 @@ function createDOMPurify() {
3130
3287
  const attribute = attributes[i];
3131
3288
  const name = attribute && attribute.name;
3132
3289
  if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue;
3133
- try {
3134
- element.removeAttribute(name);
3135
- } catch (_) {}
3290
+ _stripAttributeNode(element, attribute, name);
3136
3291
  }
3137
3292
  };
3138
3293
  /**
@@ -3161,7 +3316,7 @@ function createDOMPurify() {
3161
3316
  const stack = [root];
3162
3317
  while (stack.length > 0) {
3163
3318
  const node = stack.pop();
3164
- if ((getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element) _stripDisallowedAttributes(node);
3319
+ if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node);
3165
3320
  const childNodes = getChildNodes(node);
3166
3321
  if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
3167
3322
  }
@@ -3201,12 +3356,28 @@ function createDOMPurify() {
3201
3356
  *
3202
3357
  * @param root the in-place root to sweep
3203
3358
  */
3359
+ /**
3360
+ * Central policy for declarative-partial-updates patch-linkage attributes,
3361
+ * shared by the _neutralizePatchLinkage pre-pass and _isValidAttribute so
3362
+ * the two sites cannot drift: `patchsrc` always links, `for` links
3363
+ * everywhere except on <label>/<output>, and the whole policy is gated on
3364
+ * SAFE_FOR_XML (see the rationale block in _isValidAttribute).
3365
+ *
3366
+ * @param lcName the transformCaseFunc'd attribute name
3367
+ * @param lcTag the transformCaseFunc'd tag name of the carrying element
3368
+ * @return true if the attribute is patch linkage and must be dropped
3369
+ */
3370
+ const _isPatchLinkageAttribute = function _isPatchLinkageAttribute(lcName, lcTag) {
3371
+ if (!SAFE_FOR_XML) return false;
3372
+ if (lcName === "patchsrc") return true;
3373
+ return lcName === "for" && lcTag !== "label" && lcTag !== "output";
3374
+ };
3204
3375
  const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
3205
3376
  if (!SAFE_FOR_XML) return;
3206
3377
  const stack = [root];
3207
3378
  while (stack.length > 0) {
3208
3379
  const node = stack.pop();
3209
- const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
3380
+ const nodeType = _readNodeType(node);
3210
3381
  if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
3211
3382
  try {
3212
3383
  remove(node);
@@ -3215,10 +3386,10 @@ function createDOMPurify() {
3215
3386
  }
3216
3387
  if (nodeType === NODE_TYPE.element) {
3217
3388
  const element = node;
3218
- const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName);
3389
+ const lcTag = transformCaseFunc(_readNodeName(node));
3219
3390
  try {
3220
3391
  if (element.hasAttribute && element.hasAttribute("patchsrc")) element.removeAttribute("patchsrc");
3221
- if (element.hasAttribute && element.hasAttribute("for") && lcTag !== "label" && lcTag !== "output") element.removeAttribute("for");
3392
+ if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) element.removeAttribute("for");
3222
3393
  } catch (_) {}
3223
3394
  }
3224
3395
  const childNodes = getChildNodes(node);
@@ -3329,7 +3500,7 @@ function createDOMPurify() {
3329
3500
  const realTagName = getNodeName ? getNodeName(element) : null;
3330
3501
  if (typeof realTagName !== "string") return false;
3331
3502
  if (transformCaseFunc(realTagName) !== "form") return false;
3332
- return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || element.nodeType !== getNodeType(element) || element.childNodes !== getChildNodes(element);
3503
+ return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.removeAttributeNode !== "function" || typeof element.getAttributeNode !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || element.nodeType !== getNodeType(element) || element.childNodes !== getChildNodes(element);
3333
3504
  };
3334
3505
  /**
3335
3506
  * Checks whether the given value is a DocumentFragment from any realm.
@@ -3387,12 +3558,32 @@ function createDOMPurify() {
3387
3558
  */
3388
3559
  const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
3389
3560
  if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true;
3390
- if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) return true;
3561
+ if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) return true;
3391
3562
  if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true;
3392
3563
  if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true;
3393
3564
  return false;
3394
3565
  };
3395
3566
  /**
3567
+ * Evaluate a CUSTOM_ELEMENT_HANDLING check (a RegExp or a predicate
3568
+ * function, per the validation in _parseConfig) against a name.
3569
+ * Additional arguments are forwarded to predicate functions - the
3570
+ * attributeNameCheck predicate receives the tag name as its second
3571
+ * argument. A null/absent check never matches.
3572
+ *
3573
+ * @param check the configured tagNameCheck / attributeNameCheck value
3574
+ * @param name the name to test
3575
+ * @param args extra arguments forwarded to a predicate function
3576
+ * @return true if the check matches the name
3577
+ */
3578
+ const _matchesNameCheck = function _matchesNameCheck(check, name) {
3579
+ if (check instanceof RegExp) return regExpTest(check, name);
3580
+ if (check instanceof Function) {
3581
+ for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key];
3582
+ return Boolean(check(name, ...args));
3583
+ }
3584
+ return false;
3585
+ };
3586
+ /**
3396
3587
  * Handle a node whose tag is forbidden or not allowlisted: keep
3397
3588
  * allowed custom elements (false return exits _sanitizeElements
3398
3589
  * early - the namespace and fallback-tag removal checks are
@@ -3410,10 +3601,7 @@ function createDOMPurify() {
3410
3601
  * @return true if the node was removed, false if kept
3411
3602
  */
3412
3603
  const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
3413
- if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
3414
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
3415
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
3416
- }
3604
+ if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
3417
3605
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
3418
3606
  const parentNode = getParentNode(currentNode);
3419
3607
  const childNodes = getChildNodes(currentNode);
@@ -3447,6 +3635,42 @@ function createDOMPurify() {
3447
3635
  return set === defaultSet || set === setConfigSet ? clone(set) : set;
3448
3636
  };
3449
3637
  /**
3638
+ * Shared guard for a node that a hook has detached from the walk tree,
3639
+ * used after each element-hook site in _sanitizeElements. Detaching is a
3640
+ * long-standing user pattern (issue #469; draw.io-style foreignObject
3641
+ * filtering). Per the cached, unclobberable parentNode getter the node is
3642
+ * genuinely out of the tree, so it can reach neither the serialized
3643
+ * output nor an IN_PLACE live tree; treat it as removed and stop
3644
+ * processing it. Without this guard, the unsafe-node / namespace checks
3645
+ * would call _forceRemove on a parentless node and hit the REPORT-3
3646
+ * fail-closed throw — which exists for nodes DOMPurify wants gone but
3647
+ * *cannot* detach (clobbered / parentless roots), the opposite of a node
3648
+ * that is already safely gone. The walk root is exempt: a detached
3649
+ * IN_PLACE root is legitimate input and must still be fully sanitized,
3650
+ * and a kill-decision on it must keep hitting the REPORT-3 throw.
3651
+ *
3652
+ * Nodes detached by hooks stay the hook's responsibility for placement:
3653
+ * they are not recorded in DOMPurify.removed, so the post-walk IN_PLACE
3654
+ * pass (which iterates DOMPurify.removed) does not reach them. But a
3655
+ * hook-detached subtree can still hold a queued resource-event handler -
3656
+ * e.g. an <img onload> that began loading when the caller built the live
3657
+ * tree - which fires in page scope after sanitize returns even though the
3658
+ * handler never reached the returned tree. That is the audit-5 F1 hazard,
3659
+ * and the documented node.remove() hook pattern walks straight into it.
3660
+ * So on the IN_PLACE path we neutralize the detached subtree inline,
3661
+ * stripping its non-allow-listed attributes before returning, exactly as
3662
+ * the post-walk pass does for _forceRemove'd subtrees.
3663
+ *
3664
+ * @param currentNode the node a hook may have detached
3665
+ * @param root the current walk root
3666
+ * @return true if the node is detached and now handled, false otherwise
3667
+ */
3668
+ const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) {
3669
+ if (currentNode === root || getParentNode(currentNode) !== null) return false;
3670
+ if (IN_PLACE) _neutralizeSubtree(currentNode);
3671
+ return true;
3672
+ };
3673
+ /**
3450
3674
  * _sanitizeElements
3451
3675
  *
3452
3676
  * @protect nodeName
@@ -3457,34 +3681,31 @@ function createDOMPurify() {
3457
3681
  */
3458
3682
  const _sanitizeElements = function _sanitizeElements(currentNode, root) {
3459
3683
  _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
3460
- if (currentNode !== root && getParentNode(currentNode) === null) {
3461
- if (IN_PLACE) _neutralizeSubtree(currentNode);
3462
- return true;
3463
- }
3684
+ if (_handleHookDetachedNode(currentNode, root)) return true;
3464
3685
  if (_isClobbered(currentNode)) {
3465
3686
  _forceRemove(currentNode);
3466
3687
  return true;
3467
3688
  }
3468
- const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
3689
+ const tagName = transformCaseFunc(_readNodeName(currentNode));
3469
3690
  ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
3470
3691
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
3471
3692
  tagName,
3472
3693
  allowedTags: ALLOWED_TAGS
3473
3694
  });
3474
- if (currentNode !== root && getParentNode(currentNode) === null) {
3475
- if (IN_PLACE) _neutralizeSubtree(currentNode);
3476
- return true;
3477
- }
3695
+ if (_handleHookDetachedNode(currentNode, root)) return true;
3478
3696
  if (_isUnsafeNode(currentNode, tagName)) {
3479
3697
  _forceRemove(currentNode);
3480
3698
  return true;
3481
3699
  }
3482
3700
  if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
3483
3701
  const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
3484
- if (removed === false) _executeHooks(hooks.afterSanitizeElements, currentNode, null);
3702
+ if (removed === false) {
3703
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
3704
+ if (_handleHookDetachedNode(currentNode, root)) return true;
3705
+ }
3485
3706
  return removed;
3486
3707
  }
3487
- if ((getNodeType ? getNodeType(currentNode) : currentNode.nodeType) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
3708
+ if (_readNodeType(currentNode) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
3488
3709
  _forceRemove(currentNode);
3489
3710
  return true;
3490
3711
  }
@@ -3500,7 +3721,7 @@ function createDOMPurify() {
3500
3721
  }
3501
3722
  }
3502
3723
  _executeHooks(hooks.afterSanitizeElements, currentNode, null);
3503
- return false;
3724
+ return _handleHookDetachedNode(currentNode, root);
3504
3725
  };
3505
3726
  /**
3506
3727
  * _isValidAttribute
@@ -3512,20 +3733,17 @@ function createDOMPurify() {
3512
3733
  */
3513
3734
  const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
3514
3735
  if (FORBID_ATTR[lcName]) return false;
3515
- if (SAFE_FOR_XML && lcName === "patchsrc") return false;
3516
- if (SAFE_FOR_XML && lcName === "for" && lcTag !== "label" && lcTag !== "output") return false;
3736
+ if (_isPatchLinkageAttribute(lcName, lcTag)) return false;
3517
3737
  if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false;
3518
3738
  const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
3519
- if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName));
3520
- else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName));
3521
- else if (!nameIsPermitted) if (_isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));
3522
- else return false;
3523
- else if (URI_SAFE_ATTRIBUTES[lcName]);
3524
- else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, "")));
3525
- else if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]);
3526
- else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, "")));
3527
- else if (value) return false;
3528
- return true;
3739
+ if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) return true;
3740
+ if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) return true;
3741
+ if (!nameIsPermitted) return _isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value);
3742
+ if (URI_SAFE_ATTRIBUTES[lcName]) return true;
3743
+ if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
3744
+ if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) return true;
3745
+ if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
3746
+ return !value;
3529
3747
  };
3530
3748
  const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [
3531
3749
  "annotation-xml",
@@ -3570,24 +3788,38 @@ function createDOMPurify() {
3570
3788
  /**
3571
3789
  * Write a modified attribute value back onto the element. On
3572
3790
  * success, re-probe for clobbering introduced by the new value and
3573
- * remove the element when found; otherwise pop the removal entry
3574
- * recorded by the earlier _removeAttribute (long-standing pairing
3575
- * with the SANITIZE_NAMED_PROPS path - do not "fix" casually). On
3791
+ * remove the element when found; otherwise, when this writeback is the
3792
+ * recreate half of the SANITIZE_NAMED_PROPS remove-and-recreate, pop the
3793
+ * removal entry that path recorded so it does not show as removed. On
3576
3794
  * failure, remove the attribute instead.
3577
3795
  *
3796
+ * Returns true only on a clean write (the value was set and the new value
3797
+ * introduced no clobbering). The caller uses that, together with its own
3798
+ * knowledge of whether this attribute pushed a DOMPurify.removed record, to
3799
+ * decide whether to pop that record. The pop must happen ONLY for the
3800
+ * named-prop remove-and-recreate; popping on any other value change (trim,
3801
+ * template scrubbing, Trusted Types) would consume an unrelated _forceRemove
3802
+ * subtree-cleanup record and let that detached subtree keep a live event
3803
+ * handler through the IN_PLACE neutralization pass (SO-001).
3804
+ *
3578
3805
  * @param currentNode the element carrying the attribute
3579
3806
  * @param name the attribute name as present on the element
3580
3807
  * @param namespaceURI the attribute's namespace, if any
3581
3808
  * @param value the new attribute value
3809
+ * @return true if the value was written without introducing clobbering
3582
3810
  */
3583
3811
  const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) {
3584
3812
  try {
3585
3813
  if (namespaceURI) currentNode.setAttributeNS(namespaceURI, name, value);
3586
3814
  else currentNode.setAttribute(name, value);
3587
- if (_isClobbered(currentNode)) _forceRemove(currentNode);
3588
- else arrayPop(DOMPurify.removed);
3815
+ if (_isClobbered(currentNode)) {
3816
+ _forceRemove(currentNode);
3817
+ return false;
3818
+ }
3819
+ return true;
3589
3820
  } catch (_) {
3590
3821
  _removeAttribute(name, currentNode);
3822
+ return false;
3591
3823
  }
3592
3824
  };
3593
3825
  /**
@@ -3599,9 +3831,11 @@ function createDOMPurify() {
3599
3831
  * @protect setAttribute
3600
3832
  *
3601
3833
  * @param currentNode to sanitize
3834
+ * @param root the current walk root
3602
3835
  */
3603
- const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
3836
+ const _sanitizeAttributes = function _sanitizeAttributes(currentNode, root) {
3604
3837
  _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
3838
+ if (_handleHookDetachedNode(currentNode, root)) return;
3605
3839
  const attributes = currentNode.attributes;
3606
3840
  if (!attributes || _isClobbered(currentNode)) return;
3607
3841
  ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
@@ -3620,6 +3854,7 @@ function createDOMPurify() {
3620
3854
  const lcName = transformCaseFunc(name);
3621
3855
  const initValue = attrValue;
3622
3856
  let value = name === "value" ? initValue : stringTrim(initValue);
3857
+ let recreatedNamedProp = false;
3623
3858
  hookEvent.attrName = lcName;
3624
3859
  hookEvent.attrValue = value;
3625
3860
  hookEvent.keepAttr = true;
@@ -3627,35 +3862,39 @@ function createDOMPurify() {
3627
3862
  _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
3628
3863
  value = hookEvent.attrValue;
3629
3864
  if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
3630
- _removeAttribute(name, currentNode);
3865
+ _removeAttribute(name, currentNode, attr);
3631
3866
  value = SANITIZE_NAMED_PROPS_PREFIX + value;
3867
+ recreatedNamedProp = true;
3632
3868
  }
3633
3869
  if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
3634
- _removeAttribute(name, currentNode);
3870
+ _removeAttribute(name, currentNode, attr);
3635
3871
  continue;
3636
3872
  }
3637
3873
  if (lcName === "attributename" && stringMatch(value, "href")) {
3638
- _removeAttribute(name, currentNode);
3874
+ _removeAttribute(name, currentNode, attr);
3639
3875
  continue;
3640
3876
  }
3641
3877
  if (hookEvent.forceKeepAttr) continue;
3642
3878
  if (!hookEvent.keepAttr) {
3643
- _removeAttribute(name, currentNode);
3879
+ _removeAttribute(name, currentNode, attr);
3644
3880
  continue;
3645
3881
  }
3646
3882
  if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
3647
- _removeAttribute(name, currentNode);
3883
+ _removeAttribute(name, currentNode, attr);
3648
3884
  continue;
3649
3885
  }
3650
3886
  if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value);
3651
3887
  if (!_isValidAttribute(lcTag, lcName, value)) {
3652
- _removeAttribute(name, currentNode);
3888
+ _removeAttribute(name, currentNode, attr);
3653
3889
  continue;
3654
3890
  }
3655
3891
  value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
3656
- if (value !== initValue) _setAttributeValue(currentNode, name, namespaceURI, value);
3892
+ if (value !== initValue) {
3893
+ if (_setAttributeValue(currentNode, name, namespaceURI, value) && recreatedNamedProp) arrayPop(DOMPurify.removed);
3894
+ }
3657
3895
  }
3658
3896
  _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
3897
+ _handleHookDetachedNode(currentNode, root);
3659
3898
  };
3660
3899
  /**
3661
3900
  * _sanitizeShadowDOM
@@ -3669,9 +3908,9 @@ function createDOMPurify() {
3669
3908
  while (shadowNode = shadowIterator.nextNode()) {
3670
3909
  _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
3671
3910
  _sanitizeElements(shadowNode, fragment);
3672
- _sanitizeAttributes(shadowNode);
3911
+ _sanitizeAttributes(shadowNode, fragment);
3673
3912
  if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content);
3674
- if ((getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType) === NODE_TYPE.element) {
3913
+ if (_readNodeType(shadowNode) === NODE_TYPE.element) {
3675
3914
  const innerSr = getShadowRoot(shadowNode);
3676
3915
  if (_isDocumentFragment(innerSr)) {
3677
3916
  _sanitizeAttachedShadowRoots(innerSr);
@@ -3712,7 +3951,7 @@ function createDOMPurify() {
3712
3951
  continue;
3713
3952
  }
3714
3953
  const node = item.node;
3715
- const isElement = (getNodeType ? getNodeType(node) : node.nodeType) === NODE_TYPE.element;
3954
+ const isElement = _readNodeType(node) === NODE_TYPE.element;
3716
3955
  const childNodes = getChildNodes(node);
3717
3956
  if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({
3718
3957
  node: childNodes[i],
@@ -3763,7 +4002,7 @@ function createDOMPurify() {
3763
4002
  const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
3764
4003
  if (inPlace) {
3765
4004
  _neutralizePatchLinkage(dirty);
3766
- const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
4005
+ const nn = _readNodeName(dirty);
3767
4006
  if (typeof nn === "string") {
3768
4007
  const tagName = transformCaseFunc(nn);
3769
4008
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
@@ -3787,7 +4026,7 @@ function createDOMPurify() {
3787
4026
  if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") body = importedNode;
3788
4027
  else if (importedNode.nodeName === "HTML") body = importedNode;
3789
4028
  else body.appendChild(importedNode);
3790
- _sanitizeAttachedShadowRoots(importedNode);
4029
+ _sanitizeAttachedShadowRoots(body);
3791
4030
  } else {
3792
4031
  if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
3793
4032
  body = _initDocument(dirty);
@@ -3799,7 +4038,7 @@ function createDOMPurify() {
3799
4038
  const nodeIterator = _createNodeIterator(walkRoot);
3800
4039
  while (currentNode = nodeIterator.nextNode()) {
3801
4040
  _sanitizeElements(currentNode, walkRoot);
3802
- _sanitizeAttributes(currentNode);
4041
+ _sanitizeAttributes(currentNode, walkRoot);
3803
4042
  if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content);
3804
4043
  }
3805
4044
  } catch (error) {
@@ -3812,9 +4051,14 @@ function createDOMPurify() {
3812
4051
  throw error;
3813
4052
  }
3814
4053
  if (inPlace) {
4054
+ let rootWasRemoved = false;
3815
4055
  arrayForEach(DOMPurify.removed, (entry) => {
3816
- if (entry.element) _neutralizeSubtree(entry.element);
4056
+ if (entry.element) {
4057
+ if (entry.element === dirty) rootWasRemoved = true;
4058
+ _neutralizeSubtree(entry.element);
4059
+ }
3817
4060
  });
4061
+ if (rootWasRemoved) throw typeErrorCreate("a node selected for removal could not be safely returned; refusing to sanitize in place");
3818
4062
  if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty);
3819
4063
  return dirty;
3820
4064
  }