@knime/kds-table 11.5.0 → 12.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
@@ -1667,8 +1667,8 @@ var oe = class extends b {
1667
1667
  }
1668
1668
  };
1669
1669
  //#endregion
1670
- //#region ../../node_modules/.pnpm/dompurify@3.4.16/node_modules/dompurify/dist/purify.es.mjs
1671
- /*! @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 */
1670
+ //#region ../../node_modules/.pnpm/dompurify@3.4.17/node_modules/dompurify/dist/purify.es.mjs
1671
+ /*! @license DOMPurify 3.4.17 | (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.17/LICENSE */
1672
1672
  function _OverloadYield(e, d) {
1673
1673
  this.v = e, this.k = d;
1674
1674
  }
@@ -1792,9 +1792,12 @@ Array.prototype.indexOf;
1792
1792
  var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
1793
1793
  var arrayPop = unapply(Array.prototype.pop);
1794
1794
  var arrayPush = unapply(Array.prototype.push);
1795
- Array.prototype.slice;
1795
+ var arraySlice = unapply(Array.prototype.slice);
1796
1796
  var arraySplice = unapply(Array.prototype.splice);
1797
1797
  var arrayIsArray = Array.isArray;
1798
+ var setCreate = unconstruct(Set);
1799
+ var setAdd = unapply(Set.prototype.add);
1800
+ var setHas = unapply(Set.prototype.has);
1798
1801
  var stringToLowerCase = unapply(String.prototype.toLowerCase);
1799
1802
  var stringToString = unapply(String.prototype.toString);
1800
1803
  var stringMatch = unapply(String.prototype.match);
@@ -1937,6 +1940,25 @@ function lookupGetter(object, prop) {
1937
1940
  }
1938
1941
  return fallbackValue;
1939
1942
  }
1943
+ /**
1944
+ * Like lookupGetter, but for accessor properties only, and returns null
1945
+ * instead of a null-returning fallback when no getter exists on the chain.
1946
+ * Lets a caller fall back to a direct property read in environments that
1947
+ * lack the getter, where a fallback returning null would be indistinguishable
1948
+ * from a legitimate null value (e.g. namespaceURI of a no-namespace element).
1949
+ *
1950
+ * @param object - The object (usually a prototype) to start the lookup at.
1951
+ * @param prop - The accessor property name.
1952
+ * @returns The unapplied getter, or null if none was found.
1953
+ */
1954
+ function lookupAccessor(object, prop) {
1955
+ while (object !== null) {
1956
+ const desc = getOwnPropertyDescriptor(object, prop);
1957
+ if (desc) return desc.get ? unapply(desc.get) : null;
1958
+ object = getPrototypeOf(object);
1959
+ }
1960
+ return null;
1961
+ }
1940
1962
  function isRegex(value) {
1941
1963
  try {
1942
1964
  regExpTest(value, "");
@@ -2621,7 +2643,7 @@ var NODE_TYPE = {
2621
2643
  documentFragment: 11,
2622
2644
  notation: 12
2623
2645
  };
2624
- var LITERAL_TEXT_ELEMENT_NAMES = [
2646
+ var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, [
2625
2647
  "style",
2626
2648
  "script",
2627
2649
  "xmp",
@@ -2630,15 +2652,7 @@ var LITERAL_TEXT_ELEMENT_NAMES = [
2630
2652
  "noframes",
2631
2653
  "plaintext",
2632
2654
  "noscript"
2633
- ];
2634
- var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
2635
- var LITERAL_TEXT_CLOSE = function() {
2636
- const map = {};
2637
- arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => {
2638
- map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i"));
2639
- });
2640
- return freeze(map);
2641
- }();
2655
+ ]));
2642
2656
  var getGlobal = function getGlobal() {
2643
2657
  return typeof window === "undefined" ? null : window;
2644
2658
  };
@@ -2716,7 +2730,7 @@ var _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback)
2716
2730
  function createDOMPurify() {
2717
2731
  let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
2718
2732
  const DOMPurify = (root) => createDOMPurify(root);
2719
- DOMPurify.version = "3.4.16";
2733
+ DOMPurify.version = "3.4.17";
2720
2734
  DOMPurify.removed = [];
2721
2735
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
2722
2736
  DOMPurify.isSupported = false;
@@ -2748,6 +2762,10 @@ function createDOMPurify() {
2748
2762
  const _readNodeName = function _readNodeName(node) {
2749
2763
  return getNodeName ? getNodeName(node) : node.nodeName;
2750
2764
  };
2765
+ const getNamespaceURI = lookupAccessor(ElementPrototype, "namespaceURI");
2766
+ const _readNamespaceURI = function _readNamespaceURI(element) {
2767
+ return getNamespaceURI ? getNamespaceURI(element) : element.namespaceURI;
2768
+ };
2751
2769
  if (typeof HTMLTemplateElement === "function") {
2752
2770
  const template = document.createElement("template");
2753
2771
  if (template.content && template.content.ownerDocument) document = template.content.ownerDocument;
@@ -2868,6 +2886,7 @@ function createDOMPurify() {
2868
2886
  const SANITIZE_NAMED_PROPS_PREFIX = "user-content-";
2869
2887
  let KEEP_CONTENT = true;
2870
2888
  let IN_PLACE = false;
2889
+ let IN_PLACE_VISITED = null;
2871
2890
  let USE_PROFILES = {};
2872
2891
  let FORBID_CONTENTS = null;
2873
2892
  const DEFAULT_FORBID_CONTENTS = addToSet({}, [
@@ -3141,18 +3160,23 @@ function createDOMPurify() {
3141
3160
  * return. Return true otherwise.
3142
3161
  */
3143
3162
  const _checkValidNamespace = function _checkValidNamespace(element) {
3144
- let parent = getParentNode(element);
3145
- if (!parent || !parent.tagName) parent = {
3146
- namespaceURI: NAMESPACE,
3147
- tagName: "template"
3148
- };
3149
- const tagName = stringToLowerCase(element.tagName);
3150
- const parentTagName = stringToLowerCase(parent.tagName);
3151
- if (!ALLOWED_NAMESPACES[element.namespaceURI]) return false;
3152
- if (element.namespaceURI === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName);
3153
- if (element.namespaceURI === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName);
3154
- if (element.namespaceURI === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName);
3155
- if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) return true;
3163
+ const elementNamespace = _readNamespaceURI(element);
3164
+ const tagName = stringToLowerCase(_readNodeName(element));
3165
+ const parentNode = getParentNode(element);
3166
+ let parent;
3167
+ let parentTagName;
3168
+ if (parentNode && _readNodeType(parentNode) === NODE_TYPE.element) {
3169
+ parent = { namespaceURI: _readNamespaceURI(parentNode) };
3170
+ parentTagName = stringToLowerCase(_readNodeName(parentNode));
3171
+ } else {
3172
+ parent = { namespaceURI: NAMESPACE };
3173
+ parentTagName = "template";
3174
+ }
3175
+ if (!ALLOWED_NAMESPACES[elementNamespace]) return false;
3176
+ if (elementNamespace === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName);
3177
+ if (elementNamespace === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName);
3178
+ if (elementNamespace === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName);
3179
+ if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[elementNamespace]) return true;
3156
3180
  return false;
3157
3181
  };
3158
3182
  /**
@@ -3196,36 +3220,21 @@ function createDOMPurify() {
3196
3220
  }
3197
3221
  };
3198
3222
  /**
3199
- * _neutralizeRoot
3200
- *
3201
- * Fail-closed teardown of an in-place root after the sanitize walk aborts
3202
- * (campaign-3 F2). An internal throw mid-walk — e.g. a page-registered
3203
- * custom element's reaction detaches a node so `_forceRemove`'s deliberate
3204
- * parentless guard throws, or any other re-entrant engine mutation — would
3205
- * otherwise leave the caller's *live* tree half-sanitized, with everything
3206
- * after the abort point still carrying its handlers. There is no safe way
3207
- * to resume the walk (the tree mutated under us), so we strip the root bare:
3208
- * remove every child and every attribute, then let the caller's catch see
3209
- * the original error. Clobber-safe (cached `remove`/`childNodes`/`attributes`
3210
- * getters; the root was already clobber-pre-flighted at the IN_PLACE entry).
3223
+ * Fail-closed teardown of an in-place root: strip every disallowed attribute
3224
+ * in the subtree first, so nothing armed is left behind, then remove all
3225
+ * children and the root's own attributes.
3211
3226
  *
3212
3227
  * @param root the in-place root to empty
3213
3228
  */
3214
3229
  const _neutralizeRoot = function _neutralizeRoot(root) {
3215
3230
  _neutralizeSubtree(root);
3216
3231
  const childNodes = getChildNodes(root);
3217
- if (childNodes) {
3218
- const snapshot = [];
3219
- arrayForEach(childNodes, (child) => {
3220
- arrayPush(snapshot, child);
3221
- });
3222
- arrayForEach(snapshot, (child) => {
3223
- try {
3224
- remove(child);
3225
- } catch (_) {}
3226
- });
3227
- }
3228
- const attributes = getAttributes(root);
3232
+ if (childNodes) arrayForEach(arraySlice(childNodes), (child) => {
3233
+ try {
3234
+ remove(child);
3235
+ } catch (_) {}
3236
+ });
3237
+ const attributes = _readNodeType(root) === NODE_TYPE.element ? getAttributes(root) : null;
3229
3238
  if (attributes) for (let i = attributes.length - 1; i >= 0; --i) {
3230
3239
  const attribute = attributes[i];
3231
3240
  const name = attribute && attribute.name;
@@ -3233,18 +3242,9 @@ function createDOMPurify() {
3233
3242
  }
3234
3243
  };
3235
3244
  /**
3236
- * _removeAttribute
3237
- *
3238
- * Name-based getAttributeNode()/removeAttribute() ASCII-lowercase their
3239
- * lookup key for HTML elements in an HTML document, so they silently miss an
3240
- * attribute whose stored qualified name still contains uppercase ASCII
3241
- * letters. That happens when the node came from a case-preserving source
3242
- * (an XML/XHTML document imported via importNode(), or createAttributeNS()),
3243
- * where e.g. `ONERROR` survives the walk: the policy check lowercases to
3244
- * `onerror` and rejects it, but `removeAttribute('ONERROR')` looks up
3245
- * `onerror` and finds nothing. Remove the exact Attr node instead, which is
3246
- * case- and namespace-exact, and fall back to name-based removal only when
3247
- * the caller could not supply the node.
3245
+ * Removes an attribute, preferably as its exact Attr node: name-based
3246
+ * removal lowercases the name in HTML documents and misses case-preserved
3247
+ * names, e.g. from imported XHTML.
3248
3248
  *
3249
3249
  * @param name an Attribute name
3250
3250
  * @param element a DOM node
@@ -3276,12 +3276,8 @@ function createDOMPurify() {
3276
3276
  } catch (_) {}
3277
3277
  };
3278
3278
  /**
3279
- * _stripDisallowedAttributes
3280
- *
3281
- * Removes every attribute the active configuration does not allow from a
3282
- * single element, using the same allowlist as the main attribute pass (so
3283
- * `on*` handlers go, but no `/^on/` blocklist is introduced). Used only to
3284
- * neutralise nodes that are being discarded from an in-place tree.
3279
+ * Removes every attribute the configuration does not allow. Used to
3280
+ * neutralize nodes discarded from an in-place tree.
3285
3281
  *
3286
3282
  * @param element the element to strip
3287
3283
  */
@@ -3296,77 +3292,158 @@ function createDOMPurify() {
3296
3292
  }
3297
3293
  };
3298
3294
  /**
3299
- * _neutralizeSubtree
3295
+ * Iterative depth-first walk, so deep trees cannot overflow the call stack,
3296
+ * reading through the cached getters, so clobbering cannot hide children.
3297
+ * When `visit` returns false, the node's children are skipped. With
3298
+ * `intoShadow`, open shadow roots are walked after their host's children.
3300
3299
  *
3301
- * Completes the audit-5 F1 fix across every removal path. The KEEP_CONTENT
3302
- * move-hoist neutralises only disallowed-tag removals; clobber, mXSS-canary,
3303
- * namespace, comment, processing-instruction and KEEP_CONTENT:false removals
3304
- * all drop their subtree wholesale via `_forceRemove`. On the IN_PLACE path
3305
- * those dropped nodes are detached from the caller's LIVE tree but a
3306
- * handler-bearing original among them (an `<img onerror>`/`<video>` that was
3307
- * loading) keeps its queued resource event, which fires in page scope after
3308
- * sanitize returns. This walks a removed subtree and strips every attribute
3309
- * the active configuration does not allow — so `on*` handlers are cancelled
3310
- * through the SAME allowlist that governs kept nodes, not a separate `/^on/`
3311
- * blocklist. Run synchronously before sanitize returns, i.e. before any
3312
- * queued event can fire. Hook-free by design: these nodes leave the output,
3313
- * so firing attribute hooks for them would be surprising. Clobber-safe reads;
3314
- * a doomed clobbered node may shadow `removeAttribute` (its own attributes are
3315
- * irrelevant — it is discarded — while its non-clobbered descendants, e.g.
3316
- * the `<img>`, are reached and scrubbed).
3317
- *
3318
- * @param root the root of a removed subtree to neutralise
3300
+ * @param root where to start
3301
+ * @param visit called for every node
3302
+ * @param intoShadow whether to enter open shadow roots
3319
3303
  */
3320
- const _neutralizeSubtree = function _neutralizeSubtree(root) {
3304
+ const _walkTree = function _walkTree(root, visit) {
3305
+ let intoShadow = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : false;
3321
3306
  const stack = [root];
3322
3307
  while (stack.length > 0) {
3323
3308
  const node = stack.pop();
3324
- if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node);
3309
+ if (visit(node) === false) continue;
3310
+ if (intoShadow && _readNodeType(node) === NODE_TYPE.element) {
3311
+ const shadowRoot = getShadowRoot(node);
3312
+ if (_isDocumentFragment(shadowRoot)) stack.push(shadowRoot);
3313
+ }
3325
3314
  const childNodes = getChildNodes(node);
3326
3315
  if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
3327
3316
  }
3328
3317
  };
3329
3318
  /**
3330
- * _neutralizePatchLinkage
3319
+ * Strips disallowed attributes from every element of a discarded subtree,
3320
+ * so a handler that is already queued (a loading image) cannot fire.
3331
3321
  *
3332
- * IN_PLACE entry pre-pass (declarative-partial-updates / streaming
3333
- * hardening, https://github.com/WICG/declarative-partial-updates).
3322
+ * @param root the root of a removed subtree
3323
+ */
3324
+ const _neutralizeSubtree = function _neutralizeSubtree(root) {
3325
+ _walkTree(root, (node) => {
3326
+ if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node);
3327
+ });
3328
+ };
3329
+ /**
3330
+ * All nodes under `root`, root first, including open shadow roots. Template
3331
+ * content is not entered, it is inert.
3334
3332
  *
3335
- * The main walk strips patch linkage (`for`/`patchsrc`) and removes range
3336
- * markers (PIs / markup comments) node-by-node, in document order, AS it
3337
- * reaches each node. On a live in-place root that leaves a window: from the
3338
- * moment the root is connected until the walk arrives at a given node, that
3339
- * node's linkage is live. A patch applied on connection/stream can fire as
3340
- * a microtask during the walk and inject or teleport an unsanitized DOM
3341
- * range into a region the iterator has already passed and will not revisit,
3342
- * so the post-return "tree is sanitized" contract is violated. Sweep the
3343
- * whole tree once up front and sever every linkage before the walk begins,
3344
- * closing that window.
3333
+ * @param root the in-place root
3334
+ * @return the nodes
3335
+ */
3336
+ const _collectLiveNodes = function _collectLiveNodes(root) {
3337
+ const nodes = [];
3338
+ _walkTree(root, (node) => {
3339
+ nodes.push(node);
3340
+ }, true);
3341
+ return nodes;
3342
+ };
3343
+ /**
3344
+ * Strips disallowed attributes from every element that was under the
3345
+ * in-place root when the call started and no longer is, whatever removed
3346
+ * or moved it.
3345
3347
  *
3346
- * This CANNOT undo a patch that already fired before sanitize ran — that is
3347
- * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat —
3348
- * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML
3349
- * to group with the rest of the declarative-partial-updates handling and
3350
- * stay overridable, consistent with the codebase.
3348
+ * @param root the in-place root
3349
+ * @param before the root's nodes, collected before the walk
3350
+ */
3351
+ const _neutralizeEscapedElements = function _neutralizeEscapedElements(root, before) {
3352
+ const reachable = setCreate();
3353
+ arrayForEach(_collectLiveNodes(root), (node) => {
3354
+ if (_readNodeType(node) === NODE_TYPE.element) setAdd(reachable, node);
3355
+ });
3356
+ arrayForEach(before, (node) => {
3357
+ if (_readNodeType(node) === NODE_TYPE.element && !setHas(reachable, node)) _stripDisallowedAttributes(node);
3358
+ });
3359
+ };
3360
+ /**
3361
+ * Neutralizes everything that left the in-place tree during the call: what
3362
+ * DOMPurify removed, and what hooks or custom elements removed or moved out.
3351
3363
  *
3352
- * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a
3353
- * clobbered root cannot defeat the sweep of its non-clobbered descendants.
3364
+ * @param root the in-place root
3365
+ * @param before the root's nodes, collected before the walk
3366
+ * @return true if the root itself was removed
3367
+ */
3368
+ const _neutralizeDiscarded = function _neutralizeDiscarded(root, before) {
3369
+ let rootRemoved = false;
3370
+ arrayForEach(DOMPurify.removed, (entry) => {
3371
+ if (entry.element) {
3372
+ rootRemoved = rootRemoved || entry.element === root;
3373
+ _neutralizeSubtree(entry.element);
3374
+ }
3375
+ });
3376
+ _neutralizeEscapedElements(root, before);
3377
+ return rootRemoved;
3378
+ };
3379
+ const MAX_UNVISITED_ROUNDS = 8;
3380
+ /**
3381
+ * The walk only moves forward, so a node moved to a position it already
3382
+ * passed is never visited. Give every original node that is still in the
3383
+ * tree but unvisited the normal treatment, hooks included. Nodes created
3384
+ * during the call are left alone. Fails closed if the tree keeps changing.
3354
3385
  *
3355
- * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe
3356
- * .html Q1): this mirrors the existing policy of keeping `for` on
3357
- * <label>/<output>. If the shipping feature can drive a patch through a
3358
- * surviving `for`-on-label/output + `id` pair, this pre-pass and the
3359
- * attribute check at _isBasicCustomElement's caller must additionally drop
3360
- * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified.
3386
+ * @param root the in-place root
3387
+ * @param before the root's nodes, collected before the walk
3388
+ */
3389
+ const _sanitizeUnvisitedNodes = function _sanitizeUnvisitedNodes(root, before) {
3390
+ const visited = IN_PLACE_VISITED;
3391
+ let original = null;
3392
+ const getOriginal = () => {
3393
+ if (!original) {
3394
+ original = setCreate();
3395
+ arrayForEach(before, (beforeNode) => {
3396
+ setAdd(original, beforeNode);
3397
+ });
3398
+ }
3399
+ return original;
3400
+ };
3401
+ for (let round = 0;; round++) {
3402
+ const live = _collectLiveNodes(root);
3403
+ const containers = [root];
3404
+ let pending = false;
3405
+ arrayForEach(live, (node) => {
3406
+ if (_readNodeType(node) === NODE_TYPE.documentFragment) arrayPush(containers, node);
3407
+ else if (!pending && !setHas(visited, node)) pending = setHas(getOriginal(), node);
3408
+ });
3409
+ if (!pending) return;
3410
+ if (round >= MAX_UNVISITED_ROUNDS) throw typeErrorCreate("the tree kept changing during in-place sanitization; refusing to return it");
3411
+ arrayForEach(containers, (container, index) => {
3412
+ _sanitizeUnvisitedIn(container, index > 0, root, getOriginal());
3413
+ });
3414
+ }
3415
+ };
3416
+ /**
3417
+ * One _sanitizeUnvisitedNodes pass over the root or an open shadow root.
3361
3418
  *
3362
- * @param root the in-place root to sweep
3419
+ * @param container the root or an open shadow root
3420
+ * @param inShadow whether container is a shadow root
3421
+ * @param root the in-place root
3422
+ * @param original the root's nodes collected before the walk, as a set
3423
+ */
3424
+ const _sanitizeUnvisitedIn = function _sanitizeUnvisitedIn(container, inShadow, root, original) {
3425
+ const iterator = _createNodeIterator(container);
3426
+ let node;
3427
+ while (node = iterator.nextNode()) {
3428
+ if (!setHas(original, node) || setHas(IN_PLACE_VISITED, node)) continue;
3429
+ if (inShadow) _executeHooks(hooks.uponSanitizeShadowNode, node, null);
3430
+ _sanitizeElements(node, root);
3431
+ _sanitizeAttributes(node, root);
3432
+ if (_isDocumentFragment(node.content)) _sanitizeShadowDOM2(node.content);
3433
+ }
3434
+ };
3435
+ /**
3436
+ * Records that _sanitizeElements processed `node`. No-op outside IN_PLACE.
3437
+ *
3438
+ * @param node the node being processed
3363
3439
  */
3440
+ const _markVisited = function _markVisited(node) {
3441
+ if (IN_PLACE_VISITED) setAdd(IN_PLACE_VISITED, node);
3442
+ };
3364
3443
  /**
3365
- * Central policy for declarative-partial-updates patch-linkage attributes,
3366
- * shared by the _neutralizePatchLinkage pre-pass and _isValidAttribute so
3367
- * the two sites cannot drift: `patchsrc` always links, `for` links
3368
- * everywhere except on <label>/<output>, and the whole policy is gated on
3369
- * SAFE_FOR_XML (see the rationale block in _isValidAttribute).
3444
+ * Patch-linkage attributes (declarative partial updates): `patchsrc`
3445
+ * always, `for` everywhere except on <label> and <output>. Gated on
3446
+ * SAFE_FOR_XML. Shared by the IN_PLACE pre-pass and _isValidAttribute.
3370
3447
  *
3371
3448
  * @param lcName the transformCaseFunc'd attribute name
3372
3449
  * @param lcTag the transformCaseFunc'd tag name of the carrying element
@@ -3377,17 +3454,26 @@ function createDOMPurify() {
3377
3454
  if (lcName === "patchsrc") return true;
3378
3455
  return lcName === "for" && lcTag !== "label" && lcTag !== "output";
3379
3456
  };
3457
+ /**
3458
+ * IN_PLACE pre-pass: sever all patch linkage before the walk, so no patch
3459
+ * can fire mid-walk into a part of the tree the walker already passed.
3460
+ * Removes range markers (processing instructions, comments with markup)
3461
+ * and strips linkage attributes. It cannot undo a patch that already fired.
3462
+ *
3463
+ * TODO: if the shipped feature can patch through `for` on <label>/<output>,
3464
+ * drop that pair here too (see test/declarative-patch-probe.html).
3465
+ *
3466
+ * @param root the in-place root to sweep
3467
+ */
3380
3468
  const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
3381
3469
  if (!SAFE_FOR_XML) return;
3382
- const stack = [root];
3383
- while (stack.length > 0) {
3384
- const node = stack.pop();
3470
+ _walkTree(root, (node) => {
3385
3471
  const nodeType = _readNodeType(node);
3386
3472
  if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
3387
3473
  try {
3388
3474
  remove(node);
3389
3475
  } catch (_) {}
3390
- continue;
3476
+ return false;
3391
3477
  }
3392
3478
  if (nodeType === NODE_TYPE.element) {
3393
3479
  const element = node;
@@ -3397,9 +3483,8 @@ function createDOMPurify() {
3397
3483
  if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) element.removeAttribute("for");
3398
3484
  } catch (_) {}
3399
3485
  }
3400
- const childNodes = getChildNodes(node);
3401
- if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
3402
- }
3486
+ return true;
3487
+ });
3403
3488
  };
3404
3489
  /**
3405
3490
  * _initDocument
@@ -3476,6 +3561,27 @@ function createDOMPurify() {
3476
3561
  */
3477
3562
  const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
3478
3563
  var _node$querySelectorAl;
3564
+ _scrubOwnCharacterData(node);
3565
+ const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template");
3566
+ if (templates) arrayForEach(templates, (tmpl) => {
3567
+ if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content);
3568
+ });
3569
+ };
3570
+ /**
3571
+ * _scrubOwnCharacterData
3572
+ *
3573
+ * Non-recursive core of _scrubTemplateExpressions: normalize `node` and
3574
+ * strip template expressions from its own character data only. Does not
3575
+ * enter <template>.content or attached shadow roots (NodeIterator never
3576
+ * does). Used by _sanitizeShadowDOM, where every nested template content
3577
+ * and shadow root is already walked - and therefore scrubbed - by its own
3578
+ * recursive _sanitizeShadowDOM call; recursing here as well would rescrub
3579
+ * each nested fragment once per ancestor, which is quadratic in nesting
3580
+ * depth.
3581
+ *
3582
+ * @param node The root whose own character data should be scrubbed.
3583
+ */
3584
+ const _scrubOwnCharacterData = function _scrubOwnCharacterData(node) {
3479
3585
  node.normalize();
3480
3586
  const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
3481
3587
  const walker = createNodeIterator.call(doc || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
@@ -3484,10 +3590,6 @@ function createDOMPurify() {
3484
3590
  currentNode.data = _stripTemplateExpressions(currentNode.data);
3485
3591
  currentNode = walker.nextNode();
3486
3592
  }
3487
- const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template");
3488
- if (templates) arrayForEach(templates, (tmpl) => {
3489
- if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content);
3490
- });
3491
3593
  };
3492
3594
  /**
3493
3595
  * _isClobbered
@@ -3563,7 +3665,7 @@ function createDOMPurify() {
3563
3665
  */
3564
3666
  const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
3565
3667
  if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true;
3566
- 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;
3668
+ if (SAFE_FOR_XML && LITERAL_TEXT_ELEMENTS[tagName] && _readNodeType(currentNode) === NODE_TYPE.element && _readNamespaceURI(currentNode) === HTML_NAMESPACE && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent))) return true;
3567
3669
  if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true;
3568
3670
  if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true;
3569
3671
  return false;
@@ -3607,7 +3709,7 @@ function createDOMPurify() {
3607
3709
  */
3608
3710
  const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
3609
3711
  if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
3610
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
3712
+ if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && !FORBID_CONTENTS[stringToLowerCase(tagName)]) {
3611
3713
  const parentNode = getParentNode(currentNode);
3612
3714
  const childNodes = getChildNodes(currentNode);
3613
3715
  if (childNodes && parentNode) {
@@ -3640,35 +3742,13 @@ function createDOMPurify() {
3640
3742
  return set === defaultSet || set === setConfigSet ? clone(set) : set;
3641
3743
  };
3642
3744
  /**
3643
- * Shared guard for a node that a hook has detached from the walk tree,
3644
- * used after each element-hook site in _sanitizeElements. Detaching is a
3645
- * long-standing user pattern (issue #469; draw.io-style foreignObject
3646
- * filtering). Per the cached, unclobberable parentNode getter the node is
3647
- * genuinely out of the tree, so it can reach neither the serialized
3648
- * output nor an IN_PLACE live tree; treat it as removed and stop
3649
- * processing it. Without this guard, the unsafe-node / namespace checks
3650
- * would call _forceRemove on a parentless node and hit the REPORT-3
3651
- * fail-closed throw — which exists for nodes DOMPurify wants gone but
3652
- * *cannot* detach (clobbered / parentless roots), the opposite of a node
3653
- * that is already safely gone. The walk root is exempt: a detached
3654
- * IN_PLACE root is legitimate input and must still be fully sanitized,
3655
- * and a kill-decision on it must keep hitting the REPORT-3 throw.
3656
- *
3657
- * Nodes detached by hooks stay the hook's responsibility for placement:
3658
- * they are not recorded in DOMPurify.removed, so the post-walk IN_PLACE
3659
- * pass (which iterates DOMPurify.removed) does not reach them. But a
3660
- * hook-detached subtree can still hold a queued resource-event handler -
3661
- * e.g. an <img onload> that began loading when the caller built the live
3662
- * tree - which fires in page scope after sanitize returns even though the
3663
- * handler never reached the returned tree. That is the audit-5 F1 hazard,
3664
- * and the documented node.remove() hook pattern walks straight into it.
3665
- * So on the IN_PLACE path we neutralize the detached subtree inline,
3666
- * stripping its non-allow-listed attributes before returning, exactly as
3667
- * the post-walk pass does for _forceRemove'd subtrees.
3745
+ * A hook may have detached the node it was called for. If so, treat it as
3746
+ * removed and stop processing it; the walk root is exempt. On the IN_PLACE
3747
+ * path the detached subtree is neutralized right away.
3668
3748
  *
3669
3749
  * @param currentNode the node a hook may have detached
3670
3750
  * @param root the current walk root
3671
- * @return true if the node is detached and now handled, false otherwise
3751
+ * @return true if the node was detached
3672
3752
  */
3673
3753
  const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) {
3674
3754
  if (currentNode === root || getParentNode(currentNode) !== null) return false;
@@ -3685,6 +3765,7 @@ function createDOMPurify() {
3685
3765
  * @return true if node was killed, false if left alive
3686
3766
  */
3687
3767
  const _sanitizeElements = function _sanitizeElements(currentNode, root) {
3768
+ _markVisited(currentNode);
3688
3769
  _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
3689
3770
  if (_handleHookDetachedNode(currentNode, root)) return true;
3690
3771
  if (_isClobbered(currentNode)) {
@@ -3828,6 +3909,22 @@ function createDOMPurify() {
3828
3909
  }
3829
3910
  };
3830
3911
  /**
3912
+ * _isUnsafeAttributeValue
3913
+ *
3914
+ * Value-based attribute checks that the attribute walk applies before any
3915
+ * hook can force-keep an attribute, shared with the public
3916
+ * isValidAttribute() so that it never approves a value sanitize() would
3917
+ * strip.
3918
+ *
3919
+ * @param name the attribute name as found on the node (case preserved)
3920
+ * @param value the attribute value
3921
+ * @returns true if the attribute must be removed because of its value
3922
+ */
3923
+ const _isUnsafeAttributeValue = function _isUnsafeAttributeValue(name, value) {
3924
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) return true;
3925
+ return stringToLowerCase(name) === "attributename" && stringMatch(value, "href") !== null;
3926
+ };
3927
+ /**
3831
3928
  * _sanitizeAttributes
3832
3929
  *
3833
3930
  * @protect attributes
@@ -3871,11 +3968,7 @@ function createDOMPurify() {
3871
3968
  value = SANITIZE_NAMED_PROPS_PREFIX + value;
3872
3969
  recreatedNamedProp = true;
3873
3970
  }
3874
- if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
3875
- _removeAttribute(name, currentNode, attr);
3876
- continue;
3877
- }
3878
- if (lcName === "attributename" && stringMatch(value, "href")) {
3971
+ if (_isUnsafeAttributeValue(name, value)) {
3879
3972
  _removeAttribute(name, currentNode, attr);
3880
3973
  continue;
3881
3974
  }
@@ -3923,24 +4016,13 @@ function createDOMPurify() {
3923
4016
  }
3924
4017
  }
3925
4018
  }
4019
+ if (SAFE_FOR_TEMPLATES) _scrubOwnCharacterData(fragment);
3926
4020
  _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
3927
4021
  };
3928
4022
  /**
3929
- * _sanitizeAttachedShadowRoots
3930
- *
3931
- * Walks `root` and feeds every attached shadow root we encounter into
3932
- * the existing _sanitizeShadowDOM pipeline. The default node iterator
3933
- * does not descend into shadow trees, so nodes inside an attached
3934
- * shadow root would otherwise be skipped entirely.
3935
- *
3936
- * Two real input paths put attached shadow roots in front of us:
3937
- * 1. IN_PLACE on a DOM node that already has shadow roots attached.
3938
- * 2. DOM-node input where importNode(dirty, true) deep-clones the
3939
- * shadow root because it was created with `clonable: true`.
3940
- *
3941
- * This pass runs once, up front, so the main iteration loop (and the
3942
- * existing _sanitizeShadowDOM template-content recursion) stay
3943
- * untouched — string-input paths are not affected.
4023
+ * Sanitizes every attached shadow root under `root`, since the node
4024
+ * iterator does not enter shadow trees. Needed for IN_PLACE input and for
4025
+ * DOM input whose clonable shadow roots were copied by importNode().
3944
4026
  *
3945
4027
  * @param root the subtree root to walk for attached shadow roots
3946
4028
  */
@@ -4005,6 +4087,8 @@ function createDOMPurify() {
4005
4087
  if (hooks.uponSanitizeAttribute.length > 0) ALLOWED_ATTR = clone(ALLOWED_ATTR);
4006
4088
  DOMPurify.removed = [];
4007
4089
  const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
4090
+ let inPlaceNodes = [];
4091
+ const outerVisited = IN_PLACE_VISITED;
4008
4092
  if (inPlace) {
4009
4093
  _neutralizePatchLinkage(dirty);
4010
4094
  const nn = _readNodeName(dirty);
@@ -4019,12 +4103,8 @@ function createDOMPurify() {
4019
4103
  _neutralizeRoot(dirty);
4020
4104
  throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place");
4021
4105
  }
4022
- try {
4023
- _sanitizeAttachedShadowRoots(dirty);
4024
- } catch (error) {
4025
- _neutralizeRoot(dirty);
4026
- throw error;
4027
- }
4106
+ inPlaceNodes = _collectLiveNodes(dirty);
4107
+ IN_PLACE_VISITED = setCreate();
4028
4108
  } else if (_isNode(dirty)) {
4029
4109
  body = _initDocument("<!---->");
4030
4110
  importedNode = body.ownerDocument.importNode(dirty, true);
@@ -4040,30 +4120,25 @@ function createDOMPurify() {
4040
4120
  if (body && FORCE_BODY) _forceRemove(body.firstChild);
4041
4121
  const walkRoot = inPlace ? dirty : body;
4042
4122
  try {
4123
+ if (inPlace) _sanitizeAttachedShadowRoots(dirty);
4043
4124
  const nodeIterator = _createNodeIterator(walkRoot);
4044
4125
  while (currentNode = nodeIterator.nextNode()) {
4045
4126
  _sanitizeElements(currentNode, walkRoot);
4046
4127
  _sanitizeAttributes(currentNode, walkRoot);
4047
4128
  if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content);
4048
4129
  }
4130
+ if (inPlace) _sanitizeUnvisitedNodes(dirty, inPlaceNodes);
4049
4131
  } catch (error) {
4050
4132
  if (inPlace) {
4051
4133
  _neutralizeRoot(dirty);
4052
- arrayForEach(DOMPurify.removed, (entry) => {
4053
- if (entry.element) _neutralizeSubtree(entry.element);
4054
- });
4134
+ _neutralizeDiscarded(dirty, inPlaceNodes);
4055
4135
  }
4056
4136
  throw error;
4137
+ } finally {
4138
+ IN_PLACE_VISITED = outerVisited;
4057
4139
  }
4058
4140
  if (inPlace) {
4059
- let rootWasRemoved = false;
4060
- arrayForEach(DOMPurify.removed, (entry) => {
4061
- if (entry.element) {
4062
- if (entry.element === dirty) rootWasRemoved = true;
4063
- _neutralizeSubtree(entry.element);
4064
- }
4065
- });
4066
- if (rootWasRemoved) throw typeErrorCreate("a node selected for removal could not be safely returned; refusing to sanitize in place");
4141
+ if (_neutralizeDiscarded(dirty, inPlaceNodes)) throw typeErrorCreate("a node selected for removal could not be safely returned; refusing to sanitize in place");
4067
4142
  if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty);
4068
4143
  return dirty;
4069
4144
  }
@@ -4100,6 +4175,7 @@ function createDOMPurify() {
4100
4175
  if (!CONFIG) _parseConfig({});
4101
4176
  const lcTag = transformCaseFunc(tag);
4102
4177
  const lcName = transformCaseFunc(attr);
4178
+ if (typeof value === "string" && (_isUnsafeAttributeValue(attr, value) || !ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value))) return false;
4103
4179
  return _isValidAttribute(lcTag, lcName, value);
4104
4180
  };
4105
4181
  DOMPurify.addHook = function(entryPoint, hookFunction) {
@@ -5443,6 +5519,7 @@ var SortControl_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
5443
5519
  const props = __props;
5444
5520
  const emit = __emit;
5445
5521
  const sortPopoverRef = useTemplateRef("sortPopoverRef");
5522
+ const sortButtonEl = useTemplateRef("sortButton");
5446
5523
  const selectedColumn = ref(props.colSortValues?.[0]?.id?.toString() ?? NONE_COLUMN_VALUE);
5447
5524
  watch(() => props.colSortValues?.[0]?.id, (val) => {
5448
5525
  if (val === void 0 && selectedColumn.value !== void 0) return;
@@ -5469,25 +5546,25 @@ var SortControl_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
5469
5546
  };
5470
5547
  return (_ctx, _cache) => {
5471
5548
  return openBlock(), createElementBlock(Fragment, null, [createVNode(unref(KdsToggleButton), {
5549
+ ref: "sortButton",
5472
5550
  "model-value": unref(buttonIsActive),
5473
5551
  label: "Sorting",
5474
5552
  size: "small",
5475
5553
  variant: "transparent",
5476
5554
  "leading-icon": "sort-ascending",
5477
- style: normalizeStyle(sortPopoverRef.value?.anchorStyle),
5478
5555
  "aria-controls": sortPopoverRef.value?.popoverId,
5479
5556
  "aria-expanded": unref(showPopover),
5480
5557
  "aria-haspopup": "dialog",
5481
5558
  "onUpdate:modelValue": unref(onButtonClick)
5482
5559
  }, null, 8, [
5483
5560
  "model-value",
5484
- "style",
5485
5561
  "aria-controls",
5486
5562
  "aria-expanded",
5487
5563
  "onUpdate:modelValue"
5488
5564
  ]), createVNode(unref(KdsPopover), {
5489
5565
  ref_key: "sortPopoverRef",
5490
5566
  ref: sortPopoverRef,
5567
+ anchor: sortButtonEl.value?.$el,
5491
5568
  "model-value": unref(showPopover),
5492
5569
  "aria-label": "Sort",
5493
5570
  "popover-type": "auto",
@@ -5523,13 +5600,14 @@ var SortControl_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
5523
5600
  })]),
5524
5601
  _: 1
5525
5602
  }, 8, [
5603
+ "anchor",
5526
5604
  "model-value",
5527
5605
  "max-inline-size",
5528
5606
  "onUpdate:modelValue"
5529
5607
  ])], 64);
5530
5608
  };
5531
5609
  }
5532
- }), [["__scopeId", "data-v-97a272c8"]]);
5610
+ }), [["__scopeId", "data-v-9c79ff18"]]);
5533
5611
  //#endregion
5534
5612
  //#region src/components/control/TableActionBar.vue?vue&type=script&setup=true&lang.ts
5535
5613
  var _hoisted_1$5 = { class: "left" };
@@ -8719,7 +8797,10 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
8719
8797
  }, createSlots({ _: 2 }, [renderList($options.forwardedSlotEntries, ([slotName]) => {
8720
8798
  return {
8721
8799
  name: slotName,
8722
- fn: withCtx((slotProps) => [renderSlot(_ctx.$slots, slotName, normalizeProps(guardReactiveProps(slotProps ?? {})), void 0, true)])
8800
+ fn: withCtx((slotProps) => [renderSlot(_ctx.$slots, slotName, normalizeProps(guardReactiveProps({
8801
+ ...slotProps ?? {},
8802
+ usedForAutoSizeCalculation: true
8803
+ })), void 0, true)])
8723
8804
  };
8724
8805
  })]), 1032, [
8725
8806
  "data",
@@ -8730,7 +8811,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
8730
8811
  "onVnodeMounted"
8731
8812
  ])) : createCommentVNode("", true)], 64);
8732
8813
  }
8733
- var TableUIWithAutoSizeCalculation_default = /*#__PURE__*/ _plugin_vue_export_helper_default(TableUIWithAutoSizeCalculation_vue_vue_type_script_lang_default, [["render", _sfc_render], ["__scopeId", "data-v-8ae322ef"]]);
8814
+ var TableUIWithAutoSizeCalculation_default = /*#__PURE__*/ _plugin_vue_export_helper_default(TableUIWithAutoSizeCalculation_vue_vue_type_script_lang_default, [["render", _sfc_render], ["__scopeId", "data-v-2d3b1862"]]);
8734
8815
  //#endregion
8735
8816
  export { PopoverContainer_default as PopoverContainer, TableActionBar_default as TableActionBar, TableUI_default as TableUI, TableUIWithAutoSizeCalculation_default as TableUIWithAutoSizeCalculation, columnSortText, columnTypes, constants_default as constants, defaultPageSize, getMissingValueMessage, isMissingValue, unpackObjectRepresentation, useButtonPopoverInteraction, useColumnSizes };
8736
8817