@aicayzer/inkkit 0.3.4 → 0.3.5

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.
@@ -7133,7 +7133,7 @@ function initializeFlow(effects) {
7133
7133
  */
7134
7134
  var resolver = { resolveAll: createResolver() };
7135
7135
  var string$1 = initializeFactory("string");
7136
- var text$5 = initializeFactory("text");
7136
+ var text$4 = initializeFactory("text");
7137
7137
  /**
7138
7138
  * @param {'string' | 'text'} field
7139
7139
  * Field.
@@ -7309,7 +7309,7 @@ var constructs_exports = /* @__PURE__ */ __exportAll({
7309
7309
  flowInitial: () => flowInitial,
7310
7310
  insideSpan: () => insideSpan,
7311
7311
  string: () => string,
7312
- text: () => text$4
7312
+ text: () => text$3
7313
7313
  });
7314
7314
  /** @satisfies {Extension['document']} */
7315
7315
  var document$1 = {
@@ -7353,7 +7353,7 @@ var string = {
7353
7353
  [92]: characterEscape
7354
7354
  };
7355
7355
  /** @satisfies {Extension['text']} */
7356
- var text$4 = {
7356
+ var text$3 = {
7357
7357
  [-5]: lineEnding$1,
7358
7358
  [-4]: lineEnding$1,
7359
7359
  [-3]: lineEnding$1,
@@ -7867,7 +7867,7 @@ function parse(options) {
7867
7867
  flow: create(flow$1),
7868
7868
  lazy: {},
7869
7869
  string: create(string$1),
7870
- text: create(text$5)
7870
+ text: create(text$4)
7871
7871
  };
7872
7872
  return parser;
7873
7873
  /**
@@ -10612,7 +10612,7 @@ function heading(node, _, state, info) {
10612
10612
  /**
10613
10613
  * @import {Html} from 'mdast'
10614
10614
  */
10615
- html$2.peek = htmlPeek;
10615
+ html.peek = htmlPeek;
10616
10616
  /**
10617
10617
  * Serialize an HTML node.
10618
10618
  *
@@ -10621,7 +10621,7 @@ html$2.peek = htmlPeek;
10621
10621
  * @returns {string}
10622
10622
  * Serialized markdown.
10623
10623
  */
10624
- function html$2(node) {
10624
+ function html(node) {
10625
10625
  return node.value || "";
10626
10626
  }
10627
10627
  /**
@@ -11347,7 +11347,7 @@ function peek(_, _1, state) {
11347
11347
  * @returns {string}
11348
11348
  * Serialized markdown.
11349
11349
  */
11350
- function text$3(node, parent, state, info) {
11350
+ function text$2(node, parent, state, info) {
11351
11351
  /* c8 ignore next -- parent always passed */
11352
11352
  const siblings = parent ? parent.children : [];
11353
11353
  const index = siblings.indexOf(node);
@@ -11410,7 +11410,7 @@ var handle = {
11410
11410
  emphasis,
11411
11411
  hardBreak,
11412
11412
  heading,
11413
- html: html$2,
11413
+ html,
11414
11414
  image,
11415
11415
  imageReference,
11416
11416
  inlineCode,
@@ -11421,7 +11421,7 @@ var handle = {
11421
11421
  paragraph,
11422
11422
  root: root$1,
11423
11423
  strong,
11424
- text: text$3,
11424
+ text: text$2,
11425
11425
  thematicBreak
11426
11426
  };
11427
11427
  //#endregion
@@ -24647,7 +24647,7 @@ function moveSelectionBlock(state, dir) {
24647
24647
  let $start = !$side.parent.inlineContent ? $side : $side.depth ? state.doc.resolve(dir > 0 ? $side.after() : $side.before()) : null;
24648
24648
  return $start && Selection.findFrom($start, dir);
24649
24649
  }
24650
- function apply$1(view, sel) {
24650
+ function apply(view, sel) {
24651
24651
  view.dispatch(view.state.tr.setSelection(sel).scrollIntoView());
24652
24652
  return true;
24653
24653
  }
@@ -24658,24 +24658,24 @@ function selectHorizontally(view, dir, mods) {
24658
24658
  let { $head } = sel, node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter;
24659
24659
  if (!node || node.isText || !node.isLeaf) return false;
24660
24660
  let $newHead = view.state.doc.resolve($head.pos + node.nodeSize * (dir < 0 ? -1 : 1));
24661
- return apply$1(view, new TextSelection(sel.$anchor, $newHead));
24661
+ return apply(view, new TextSelection(sel.$anchor, $newHead));
24662
24662
  } else if (!sel.empty) return false;
24663
24663
  else if (view.endOfTextblock(dir > 0 ? "forward" : "backward")) {
24664
24664
  let next = moveSelectionBlock(view.state, dir);
24665
- if (next && next instanceof NodeSelection) return apply$1(view, next);
24665
+ if (next && next instanceof NodeSelection) return apply(view, next);
24666
24666
  return false;
24667
24667
  } else if (!(mac$1 && mods.indexOf("m") > -1)) {
24668
24668
  let $head = sel.$head, node = $head.textOffset ? null : dir < 0 ? $head.nodeBefore : $head.nodeAfter, desc;
24669
24669
  if (!node || node.isText) return false;
24670
24670
  let nodePos = dir < 0 ? $head.pos - node.nodeSize : $head.pos;
24671
24671
  if (!(node.isAtom || (desc = view.docView.descAt(nodePos)) && !desc.contentDOM)) return false;
24672
- if (NodeSelection.isSelectable(node)) return apply$1(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
24673
- else return apply$1(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
24672
+ if (NodeSelection.isSelectable(node)) return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
24673
+ else return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
24674
24674
  }
24675
- } else if (sel instanceof NodeSelection && sel.node.isInline) return apply$1(view, new TextSelection(dir > 0 ? sel.$to : sel.$from));
24675
+ } else if (sel instanceof NodeSelection && sel.node.isInline) return apply(view, new TextSelection(dir > 0 ? sel.$to : sel.$from));
24676
24676
  else {
24677
24677
  let next = moveSelectionBlock(view.state, dir);
24678
- if (next) return apply$1(view, next);
24678
+ if (next) return apply(view, next);
24679
24679
  return false;
24680
24680
  }
24681
24681
  }
@@ -24835,12 +24835,12 @@ function selectVertically(view, dir, mods) {
24835
24835
  let { $from, $to } = sel;
24836
24836
  if (!$from.parent.inlineContent || view.endOfTextblock(dir < 0 ? "up" : "down")) {
24837
24837
  let next = moveSelectionBlock(view.state, dir);
24838
- if (next && next instanceof NodeSelection) return apply$1(view, next);
24838
+ if (next && next instanceof NodeSelection) return apply(view, next);
24839
24839
  }
24840
24840
  if (!$from.parent.inlineContent) {
24841
24841
  let side = dir < 0 ? $from : $to;
24842
24842
  let beyond = sel instanceof AllSelection ? Selection.near(side, dir) : Selection.findFrom(side, dir);
24843
- return beyond ? apply$1(view, beyond) : false;
24843
+ return beyond ? apply(view, beyond) : false;
24844
24844
  }
24845
24845
  return false;
24846
24846
  }
@@ -28404,2545 +28404,6 @@ function editorLabels(ctx) {
28404
28404
  return ctx.isInjected(labelsCtx.key) ? ctx.get(labelsCtx.key) : defaultLabels;
28405
28405
  }
28406
28406
  //#endregion
28407
- //#region node_modules/.pnpm/dompurify@3.4.17/node_modules/dompurify/dist/purify.es.mjs
28408
- /*! @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 */
28409
- function _OverloadYield(e, d) {
28410
- this.v = e, this.k = d;
28411
- }
28412
- function _arrayLikeToArray(r, a) {
28413
- (null == a || a > r.length) && (a = r.length);
28414
- for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
28415
- return n;
28416
- }
28417
- function _arrayWithHoles(r) {
28418
- if (Array.isArray(r)) return r;
28419
- }
28420
- function _iterableToArrayLimit(r, l) {
28421
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
28422
- if (null != t) {
28423
- var e, n, i, u, a = [], f = !0, o = !1;
28424
- try {
28425
- if (i = (t = t.call(r)).next, 0 === l) {
28426
- if (Object(t) !== t) return;
28427
- f = !1;
28428
- } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
28429
- } catch (r) {
28430
- o = !0, n = r;
28431
- } finally {
28432
- try {
28433
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
28434
- } finally {
28435
- if (o) throw n;
28436
- }
28437
- }
28438
- return a;
28439
- }
28440
- }
28441
- function _nonIterableRest() {
28442
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
28443
- }
28444
- /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
28445
- function _slicedToArray(r, e) {
28446
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
28447
- }
28448
- function _unsupportedIterableToArray(r, a) {
28449
- if (r) {
28450
- if ("string" == typeof r) return _arrayLikeToArray(r, a);
28451
- var t = {}.toString.call(r).slice(8, -1);
28452
- 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;
28453
- }
28454
- }
28455
- function AsyncGenerator(e) {
28456
- var t, n;
28457
- function resume(t, n) {
28458
- try {
28459
- var r = e[t](n), o = r.value, u = o instanceof _OverloadYield;
28460
- Promise.resolve(u ? o.v : o).then(function(n) {
28461
- if (u) {
28462
- var i = "return" === t && o.k ? t : "next";
28463
- if (!o.k || n.done) return resume(i, n);
28464
- n = e[i](n).value;
28465
- }
28466
- settle(!!r.done, n);
28467
- }, function(e) {
28468
- resume("throw", e);
28469
- });
28470
- } catch (e) {
28471
- settle(2, e);
28472
- }
28473
- }
28474
- function settle(e, r) {
28475
- 2 === e ? t.reject(r) : t.resolve({
28476
- value: r,
28477
- done: e
28478
- }), (t = t.next) ? resume(t.key, t.arg) : n = null;
28479
- }
28480
- this._invoke = function(e, r) {
28481
- return new Promise(function(o, u) {
28482
- var i = {
28483
- key: e,
28484
- arg: r,
28485
- resolve: o,
28486
- reject: u,
28487
- next: null
28488
- };
28489
- n ? n = n.next = i : (t = n = i, resume(e, r));
28490
- });
28491
- }, "function" != typeof e.return && (this.return = void 0);
28492
- }
28493
- AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function() {
28494
- return this;
28495
- }, AsyncGenerator.prototype.next = function(e) {
28496
- return this._invoke("next", e);
28497
- }, AsyncGenerator.prototype.throw = function(e) {
28498
- return this._invoke("throw", e);
28499
- }, AsyncGenerator.prototype.return = function(e) {
28500
- return this._invoke("return", e);
28501
- };
28502
- var entries$1 = Object.entries;
28503
- var setPrototypeOf = Object.setPrototypeOf;
28504
- var isFrozen = Object.isFrozen;
28505
- var getPrototypeOf = Object.getPrototypeOf;
28506
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
28507
- var freeze = Object.freeze;
28508
- var seal = Object.seal;
28509
- var create = Object.create;
28510
- var _ref = typeof Reflect !== "undefined" && Reflect;
28511
- var apply = _ref.apply;
28512
- var construct = _ref.construct;
28513
- if (!freeze) freeze = function freeze(x) {
28514
- return x;
28515
- };
28516
- if (!seal) seal = function seal(x) {
28517
- return x;
28518
- };
28519
- if (!apply) apply = function apply(func, thisArg) {
28520
- for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key];
28521
- return func.apply(thisArg, args);
28522
- };
28523
- if (!construct) construct = function construct(Func) {
28524
- for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) args[_key2 - 1] = arguments[_key2];
28525
- return new Func(...args);
28526
- };
28527
- var arrayForEach = unapply(Array.prototype.forEach);
28528
- Array.prototype.indexOf;
28529
- var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
28530
- var arrayPop = unapply(Array.prototype.pop);
28531
- var arrayPush = unapply(Array.prototype.push);
28532
- var arraySlice = unapply(Array.prototype.slice);
28533
- var arraySplice = unapply(Array.prototype.splice);
28534
- var arrayIsArray = Array.isArray;
28535
- var setCreate = unconstruct(Set);
28536
- var setAdd = unapply(Set.prototype.add);
28537
- var setHas = unapply(Set.prototype.has);
28538
- var stringToLowerCase = unapply(String.prototype.toLowerCase);
28539
- var stringToString = unapply(String.prototype.toString);
28540
- var stringMatch = unapply(String.prototype.match);
28541
- var stringReplace = unapply(String.prototype.replace);
28542
- var stringIndexOf = unapply(String.prototype.indexOf);
28543
- var stringTrim = unapply(String.prototype.trim);
28544
- var numberToString = unapply(Number.prototype.toString);
28545
- var booleanToString = unapply(Boolean.prototype.toString);
28546
- var bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString);
28547
- var symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString);
28548
- var objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
28549
- var objectToString = unapply(Object.prototype.toString);
28550
- var regExpTest = unapply(RegExp.prototype.test);
28551
- var typeErrorCreate = unconstruct(TypeError);
28552
- /**
28553
- * Creates a new function that calls the given function with a specified thisArg and arguments.
28554
- *
28555
- * @param func - The function to be wrapped and called.
28556
- * @returns A new function that calls the given function with a specified thisArg and arguments.
28557
- */
28558
- function unapply(func) {
28559
- return function(thisArg) {
28560
- if (thisArg instanceof RegExp) thisArg.lastIndex = 0;
28561
- for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) args[_key3 - 1] = arguments[_key3];
28562
- return apply(func, thisArg, args);
28563
- };
28564
- }
28565
- /**
28566
- * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
28567
- *
28568
- * @param func - The constructor function to be wrapped and called.
28569
- * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
28570
- */
28571
- function unconstruct(Func) {
28572
- return function() {
28573
- for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) args[_key4] = arguments[_key4];
28574
- return construct(Func, args);
28575
- };
28576
- }
28577
- /**
28578
- * Add properties to a lookup table
28579
- *
28580
- * @param set - The set to which elements will be added.
28581
- * @param array - The array containing elements to be added to the set.
28582
- * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
28583
- * @returns The modified set with added elements.
28584
- */
28585
- function addToSet(set, array) {
28586
- let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase;
28587
- if (setPrototypeOf) setPrototypeOf(set, null);
28588
- if (!arrayIsArray(array)) return set;
28589
- let l = array.length;
28590
- while (l--) {
28591
- let element = array[l];
28592
- if (typeof element === "string") {
28593
- const lcElement = transformCaseFunc(element);
28594
- if (lcElement !== element) {
28595
- if (!isFrozen(array)) array[l] = lcElement;
28596
- element = lcElement;
28597
- }
28598
- }
28599
- set[element] = true;
28600
- }
28601
- return set;
28602
- }
28603
- /**
28604
- * Clean up an array to harden against CSPP
28605
- *
28606
- * @param array - The array to be cleaned.
28607
- * @returns The cleaned version of the array
28608
- */
28609
- function cleanArray(array) {
28610
- for (let index = 0; index < array.length; index++) if (!objectHasOwnProperty(array, index)) array[index] = null;
28611
- return array;
28612
- }
28613
- /**
28614
- * Shallow clone an object
28615
- *
28616
- * @param object - The object to be cloned.
28617
- * @returns A new object that copies the original.
28618
- */
28619
- function clone(object) {
28620
- const newObject = create(null);
28621
- for (const _ref2 of entries$1(object)) {
28622
- var _ref3 = _slicedToArray(_ref2, 2);
28623
- const property = _ref3[0];
28624
- const value = _ref3[1];
28625
- if (objectHasOwnProperty(object, property)) {
28626
- if (arrayIsArray(value)) newObject[property] = cleanArray(value);
28627
- else if (value && typeof value === "object" && value.constructor === Object) newObject[property] = clone(value);
28628
- else newObject[property] = value;
28629
- }
28630
- }
28631
- return newObject;
28632
- }
28633
- /**
28634
- * Convert non-node values into strings without depending on direct property access.
28635
- *
28636
- * @param value - The value to stringify.
28637
- * @returns A string representation of the provided value.
28638
- */
28639
- function stringifyValue(value) {
28640
- switch (typeof value) {
28641
- case "string": return value;
28642
- case "number": return numberToString(value);
28643
- case "boolean": return booleanToString(value);
28644
- case "bigint": return bigintToString ? bigintToString(value) : "0";
28645
- case "symbol": return symbolToString ? symbolToString(value) : "Symbol()";
28646
- case "undefined": return objectToString(value);
28647
- case "function":
28648
- case "object": {
28649
- if (value === null) return objectToString(value);
28650
- const valueAsRecord = value;
28651
- const valueToString = lookupGetter(valueAsRecord, "toString");
28652
- if (typeof valueToString === "function") {
28653
- const stringified = valueToString(valueAsRecord);
28654
- return typeof stringified === "string" ? stringified : objectToString(stringified);
28655
- }
28656
- return objectToString(value);
28657
- }
28658
- default: return objectToString(value);
28659
- }
28660
- }
28661
- /**
28662
- * This method automatically checks if the prop is function or getter and behaves accordingly.
28663
- *
28664
- * @param object - The object to look up the getter function in its prototype chain.
28665
- * @param prop - The property name for which to find the getter function.
28666
- * @returns The getter function found in the prototype chain or a fallback function.
28667
- */
28668
- function lookupGetter(object, prop) {
28669
- while (object !== null) {
28670
- const desc = getOwnPropertyDescriptor(object, prop);
28671
- if (desc) {
28672
- if (desc.get) return unapply(desc.get);
28673
- if (typeof desc.value === "function") return unapply(desc.value);
28674
- }
28675
- object = getPrototypeOf(object);
28676
- }
28677
- function fallbackValue() {
28678
- return null;
28679
- }
28680
- return fallbackValue;
28681
- }
28682
- /**
28683
- * Like lookupGetter, but for accessor properties only, and returns null
28684
- * instead of a null-returning fallback when no getter exists on the chain.
28685
- * Lets a caller fall back to a direct property read in environments that
28686
- * lack the getter, where a fallback returning null would be indistinguishable
28687
- * from a legitimate null value (e.g. namespaceURI of a no-namespace element).
28688
- *
28689
- * @param object - The object (usually a prototype) to start the lookup at.
28690
- * @param prop - The accessor property name.
28691
- * @returns The unapplied getter, or null if none was found.
28692
- */
28693
- function lookupAccessor(object, prop) {
28694
- while (object !== null) {
28695
- const desc = getOwnPropertyDescriptor(object, prop);
28696
- if (desc) return desc.get ? unapply(desc.get) : null;
28697
- object = getPrototypeOf(object);
28698
- }
28699
- return null;
28700
- }
28701
- function isRegex(value) {
28702
- try {
28703
- regExpTest(value, "");
28704
- return true;
28705
- } catch (_unused) {
28706
- return false;
28707
- }
28708
- }
28709
- var html$1 = freeze([
28710
- "a",
28711
- "abbr",
28712
- "acronym",
28713
- "address",
28714
- "area",
28715
- "article",
28716
- "aside",
28717
- "audio",
28718
- "b",
28719
- "bdi",
28720
- "bdo",
28721
- "big",
28722
- "blink",
28723
- "blockquote",
28724
- "body",
28725
- "br",
28726
- "button",
28727
- "canvas",
28728
- "caption",
28729
- "center",
28730
- "cite",
28731
- "code",
28732
- "col",
28733
- "colgroup",
28734
- "content",
28735
- "data",
28736
- "datalist",
28737
- "dd",
28738
- "decorator",
28739
- "del",
28740
- "details",
28741
- "dfn",
28742
- "dialog",
28743
- "dir",
28744
- "div",
28745
- "dl",
28746
- "dt",
28747
- "element",
28748
- "em",
28749
- "fieldset",
28750
- "figcaption",
28751
- "figure",
28752
- "font",
28753
- "footer",
28754
- "form",
28755
- "h1",
28756
- "h2",
28757
- "h3",
28758
- "h4",
28759
- "h5",
28760
- "h6",
28761
- "head",
28762
- "header",
28763
- "hgroup",
28764
- "hr",
28765
- "html",
28766
- "i",
28767
- "img",
28768
- "input",
28769
- "ins",
28770
- "kbd",
28771
- "label",
28772
- "legend",
28773
- "li",
28774
- "main",
28775
- "map",
28776
- "mark",
28777
- "marquee",
28778
- "menu",
28779
- "menuitem",
28780
- "meter",
28781
- "nav",
28782
- "nobr",
28783
- "ol",
28784
- "optgroup",
28785
- "option",
28786
- "output",
28787
- "p",
28788
- "picture",
28789
- "pre",
28790
- "progress",
28791
- "q",
28792
- "rp",
28793
- "rt",
28794
- "ruby",
28795
- "s",
28796
- "samp",
28797
- "search",
28798
- "section",
28799
- "select",
28800
- "shadow",
28801
- "slot",
28802
- "small",
28803
- "source",
28804
- "spacer",
28805
- "span",
28806
- "strike",
28807
- "strong",
28808
- "style",
28809
- "sub",
28810
- "summary",
28811
- "sup",
28812
- "table",
28813
- "tbody",
28814
- "td",
28815
- "template",
28816
- "textarea",
28817
- "tfoot",
28818
- "th",
28819
- "thead",
28820
- "time",
28821
- "tr",
28822
- "track",
28823
- "tt",
28824
- "u",
28825
- "ul",
28826
- "var",
28827
- "video",
28828
- "wbr"
28829
- ]);
28830
- var svg$1$1 = freeze([
28831
- "svg",
28832
- "a",
28833
- "altglyph",
28834
- "altglyphdef",
28835
- "altglyphitem",
28836
- "animatecolor",
28837
- "animatemotion",
28838
- "animatetransform",
28839
- "circle",
28840
- "clippath",
28841
- "defs",
28842
- "desc",
28843
- "ellipse",
28844
- "enterkeyhint",
28845
- "exportparts",
28846
- "filter",
28847
- "font",
28848
- "g",
28849
- "glyph",
28850
- "glyphref",
28851
- "hkern",
28852
- "image",
28853
- "inputmode",
28854
- "line",
28855
- "lineargradient",
28856
- "marker",
28857
- "mask",
28858
- "metadata",
28859
- "mpath",
28860
- "part",
28861
- "path",
28862
- "pattern",
28863
- "polygon",
28864
- "polyline",
28865
- "radialgradient",
28866
- "rect",
28867
- "stop",
28868
- "style",
28869
- "switch",
28870
- "symbol",
28871
- "text",
28872
- "textpath",
28873
- "title",
28874
- "tref",
28875
- "tspan",
28876
- "view",
28877
- "vkern"
28878
- ]);
28879
- var svgFilters = freeze([
28880
- "feBlend",
28881
- "feColorMatrix",
28882
- "feComponentTransfer",
28883
- "feComposite",
28884
- "feConvolveMatrix",
28885
- "feDiffuseLighting",
28886
- "feDisplacementMap",
28887
- "feDistantLight",
28888
- "feDropShadow",
28889
- "feFlood",
28890
- "feFuncA",
28891
- "feFuncB",
28892
- "feFuncG",
28893
- "feFuncR",
28894
- "feGaussianBlur",
28895
- "feImage",
28896
- "feMerge",
28897
- "feMergeNode",
28898
- "feMorphology",
28899
- "feOffset",
28900
- "fePointLight",
28901
- "feSpecularLighting",
28902
- "feSpotLight",
28903
- "feTile",
28904
- "feTurbulence"
28905
- ]);
28906
- var svgDisallowed = freeze([
28907
- "animate",
28908
- "color-profile",
28909
- "cursor",
28910
- "discard",
28911
- "font-face",
28912
- "font-face-format",
28913
- "font-face-name",
28914
- "font-face-src",
28915
- "font-face-uri",
28916
- "foreignobject",
28917
- "hatch",
28918
- "hatchpath",
28919
- "mesh",
28920
- "meshgradient",
28921
- "meshpatch",
28922
- "meshrow",
28923
- "missing-glyph",
28924
- "script",
28925
- "set",
28926
- "solidcolor",
28927
- "unknown",
28928
- "use"
28929
- ]);
28930
- var mathMl$1 = freeze([
28931
- "math",
28932
- "menclose",
28933
- "merror",
28934
- "mfenced",
28935
- "mfrac",
28936
- "mglyph",
28937
- "mi",
28938
- "mlabeledtr",
28939
- "mmultiscripts",
28940
- "mn",
28941
- "mo",
28942
- "mover",
28943
- "mpadded",
28944
- "mphantom",
28945
- "mroot",
28946
- "mrow",
28947
- "ms",
28948
- "mspace",
28949
- "msqrt",
28950
- "mstyle",
28951
- "msub",
28952
- "msup",
28953
- "msubsup",
28954
- "mtable",
28955
- "mtd",
28956
- "mtext",
28957
- "mtr",
28958
- "munder",
28959
- "munderover",
28960
- "mprescripts"
28961
- ]);
28962
- var mathMlDisallowed = freeze([
28963
- "maction",
28964
- "maligngroup",
28965
- "malignmark",
28966
- "mlongdiv",
28967
- "mscarries",
28968
- "mscarry",
28969
- "msgroup",
28970
- "mstack",
28971
- "msline",
28972
- "msrow",
28973
- "semantics",
28974
- "annotation",
28975
- "annotation-xml",
28976
- "mprescripts",
28977
- "none"
28978
- ]);
28979
- var text$2 = freeze(["#text"]);
28980
- var html = freeze([
28981
- "accept",
28982
- "action",
28983
- "align",
28984
- "alt",
28985
- "autocapitalize",
28986
- "autocomplete",
28987
- "autopictureinpicture",
28988
- "autoplay",
28989
- "background",
28990
- "bgcolor",
28991
- "border",
28992
- "capture",
28993
- "cellpadding",
28994
- "cellspacing",
28995
- "checked",
28996
- "cite",
28997
- "class",
28998
- "clear",
28999
- "color",
29000
- "cols",
29001
- "colspan",
29002
- "command",
29003
- "commandfor",
29004
- "controls",
29005
- "controlslist",
29006
- "coords",
29007
- "crossorigin",
29008
- "datetime",
29009
- "decoding",
29010
- "default",
29011
- "dir",
29012
- "disabled",
29013
- "disablepictureinpicture",
29014
- "disableremoteplayback",
29015
- "download",
29016
- "draggable",
29017
- "enctype",
29018
- "enterkeyhint",
29019
- "exportparts",
29020
- "face",
29021
- "for",
29022
- "headers",
29023
- "height",
29024
- "hidden",
29025
- "high",
29026
- "href",
29027
- "hreflang",
29028
- "id",
29029
- "inert",
29030
- "inputmode",
29031
- "integrity",
29032
- "ismap",
29033
- "kind",
29034
- "label",
29035
- "lang",
29036
- "list",
29037
- "loading",
29038
- "loop",
29039
- "low",
29040
- "max",
29041
- "maxlength",
29042
- "media",
29043
- "method",
29044
- "min",
29045
- "minlength",
29046
- "multiple",
29047
- "muted",
29048
- "name",
29049
- "nonce",
29050
- "noshade",
29051
- "novalidate",
29052
- "nowrap",
29053
- "open",
29054
- "optimum",
29055
- "part",
29056
- "pattern",
29057
- "placeholder",
29058
- "playsinline",
29059
- "popover",
29060
- "popovertarget",
29061
- "popovertargetaction",
29062
- "poster",
29063
- "preload",
29064
- "pubdate",
29065
- "radiogroup",
29066
- "readonly",
29067
- "rel",
29068
- "required",
29069
- "rev",
29070
- "reversed",
29071
- "role",
29072
- "rows",
29073
- "rowspan",
29074
- "spellcheck",
29075
- "scope",
29076
- "selected",
29077
- "shape",
29078
- "size",
29079
- "sizes",
29080
- "slot",
29081
- "span",
29082
- "srclang",
29083
- "start",
29084
- "src",
29085
- "srcset",
29086
- "step",
29087
- "style",
29088
- "summary",
29089
- "tabindex",
29090
- "title",
29091
- "translate",
29092
- "type",
29093
- "usemap",
29094
- "valign",
29095
- "value",
29096
- "width",
29097
- "wrap",
29098
- "xmlns"
29099
- ]);
29100
- var svg$2 = freeze([
29101
- "accent-height",
29102
- "accumulate",
29103
- "additive",
29104
- "alignment-baseline",
29105
- "amplitude",
29106
- "ascent",
29107
- "attributename",
29108
- "attributetype",
29109
- "azimuth",
29110
- "basefrequency",
29111
- "baseline-shift",
29112
- "begin",
29113
- "bias",
29114
- "by",
29115
- "class",
29116
- "clip",
29117
- "clippathunits",
29118
- "clip-path",
29119
- "clip-rule",
29120
- "color",
29121
- "color-interpolation",
29122
- "color-interpolation-filters",
29123
- "color-profile",
29124
- "color-rendering",
29125
- "cx",
29126
- "cy",
29127
- "d",
29128
- "dx",
29129
- "dy",
29130
- "diffuseconstant",
29131
- "direction",
29132
- "display",
29133
- "divisor",
29134
- "dominant-baseline",
29135
- "dur",
29136
- "edgemode",
29137
- "elevation",
29138
- "end",
29139
- "exponent",
29140
- "fill",
29141
- "fill-opacity",
29142
- "fill-rule",
29143
- "filter",
29144
- "filterunits",
29145
- "flood-color",
29146
- "flood-opacity",
29147
- "font-family",
29148
- "font-size",
29149
- "font-size-adjust",
29150
- "font-stretch",
29151
- "font-style",
29152
- "font-variant",
29153
- "font-weight",
29154
- "fx",
29155
- "fy",
29156
- "g1",
29157
- "g2",
29158
- "glyph-name",
29159
- "glyphref",
29160
- "gradientunits",
29161
- "gradienttransform",
29162
- "height",
29163
- "href",
29164
- "id",
29165
- "image-rendering",
29166
- "in",
29167
- "in2",
29168
- "intercept",
29169
- "k",
29170
- "k1",
29171
- "k2",
29172
- "k3",
29173
- "k4",
29174
- "kerning",
29175
- "keypoints",
29176
- "keysplines",
29177
- "keytimes",
29178
- "lang",
29179
- "lengthadjust",
29180
- "letter-spacing",
29181
- "kernelmatrix",
29182
- "kernelunitlength",
29183
- "lighting-color",
29184
- "local",
29185
- "marker-end",
29186
- "marker-mid",
29187
- "marker-start",
29188
- "markerheight",
29189
- "markerunits",
29190
- "markerwidth",
29191
- "maskcontentunits",
29192
- "maskunits",
29193
- "max",
29194
- "mask",
29195
- "mask-type",
29196
- "media",
29197
- "method",
29198
- "mode",
29199
- "min",
29200
- "name",
29201
- "numoctaves",
29202
- "offset",
29203
- "operator",
29204
- "opacity",
29205
- "order",
29206
- "orient",
29207
- "orientation",
29208
- "origin",
29209
- "overflow",
29210
- "paint-order",
29211
- "path",
29212
- "pathlength",
29213
- "patterncontentunits",
29214
- "patterntransform",
29215
- "patternunits",
29216
- "pointer-events",
29217
- "points",
29218
- "preservealpha",
29219
- "preserveaspectratio",
29220
- "primitiveunits",
29221
- "r",
29222
- "rx",
29223
- "ry",
29224
- "radius",
29225
- "refx",
29226
- "refy",
29227
- "repeatcount",
29228
- "repeatdur",
29229
- "restart",
29230
- "result",
29231
- "rotate",
29232
- "scale",
29233
- "seed",
29234
- "shape-rendering",
29235
- "slope",
29236
- "specularconstant",
29237
- "specularexponent",
29238
- "spreadmethod",
29239
- "startoffset",
29240
- "stddeviation",
29241
- "stitchtiles",
29242
- "stop-color",
29243
- "stop-opacity",
29244
- "stroke-dasharray",
29245
- "stroke-dashoffset",
29246
- "stroke-linecap",
29247
- "stroke-linejoin",
29248
- "stroke-miterlimit",
29249
- "stroke-opacity",
29250
- "stroke",
29251
- "stroke-width",
29252
- "style",
29253
- "surfacescale",
29254
- "systemlanguage",
29255
- "tabindex",
29256
- "tablevalues",
29257
- "targetx",
29258
- "targety",
29259
- "transform",
29260
- "transform-origin",
29261
- "text-anchor",
29262
- "text-decoration",
29263
- "text-orientation",
29264
- "text-rendering",
29265
- "textlength",
29266
- "type",
29267
- "u1",
29268
- "u2",
29269
- "unicode",
29270
- "values",
29271
- "vector-effect",
29272
- "viewbox",
29273
- "visibility",
29274
- "version",
29275
- "vert-adv-y",
29276
- "vert-origin-x",
29277
- "vert-origin-y",
29278
- "width",
29279
- "word-spacing",
29280
- "wrap",
29281
- "writing-mode",
29282
- "xchannelselector",
29283
- "ychannelselector",
29284
- "x",
29285
- "x1",
29286
- "x2",
29287
- "xmlns",
29288
- "y",
29289
- "y1",
29290
- "y2",
29291
- "z",
29292
- "zoomandpan"
29293
- ]);
29294
- var mathMl = freeze([
29295
- "accent",
29296
- "accentunder",
29297
- "align",
29298
- "bevelled",
29299
- "close",
29300
- "columnalign",
29301
- "columnlines",
29302
- "columnspacing",
29303
- "columnspan",
29304
- "denomalign",
29305
- "depth",
29306
- "dir",
29307
- "display",
29308
- "displaystyle",
29309
- "encoding",
29310
- "fence",
29311
- "frame",
29312
- "height",
29313
- "href",
29314
- "id",
29315
- "largeop",
29316
- "length",
29317
- "linethickness",
29318
- "lquote",
29319
- "lspace",
29320
- "mathbackground",
29321
- "mathcolor",
29322
- "mathsize",
29323
- "mathvariant",
29324
- "maxsize",
29325
- "minsize",
29326
- "movablelimits",
29327
- "notation",
29328
- "numalign",
29329
- "open",
29330
- "rowalign",
29331
- "rowlines",
29332
- "rowspacing",
29333
- "rowspan",
29334
- "rspace",
29335
- "rquote",
29336
- "scriptlevel",
29337
- "scriptminsize",
29338
- "scriptsizemultiplier",
29339
- "selection",
29340
- "separator",
29341
- "separators",
29342
- "stretchy",
29343
- "subscriptshift",
29344
- "supscriptshift",
29345
- "symmetric",
29346
- "voffset",
29347
- "width",
29348
- "xmlns"
29349
- ]);
29350
- var xml = freeze([
29351
- "xlink:href",
29352
- "xml:id",
29353
- "xlink:title",
29354
- "xml:space",
29355
- "xmlns:xlink"
29356
- ]);
29357
- var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
29358
- var ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
29359
- var TMPLIT_EXPR = seal(/\${[\w\W]*/g);
29360
- var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/);
29361
- var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
29362
- var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
29363
- var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
29364
- var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
29365
- var DOCTYPE_NAME = seal(/^html$/i);
29366
- var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
29367
- var ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g);
29368
- var COMMENT_MARKUP_PROBE = seal(/<[/\w]/g);
29369
- var FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i);
29370
- var SELF_CLOSING_TAG = seal(/\/>/i);
29371
- var NODE_TYPE = {
29372
- element: 1,
29373
- attribute: 2,
29374
- text: 3,
29375
- cdataSection: 4,
29376
- entityReference: 5,
29377
- entityNode: 6,
29378
- processingInstruction: 7,
29379
- comment: 8,
29380
- document: 9,
29381
- documentType: 10,
29382
- documentFragment: 11,
29383
- notation: 12
29384
- };
29385
- var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, [
29386
- "style",
29387
- "script",
29388
- "xmp",
29389
- "iframe",
29390
- "noembed",
29391
- "noframes",
29392
- "plaintext",
29393
- "noscript"
29394
- ]));
29395
- var getGlobal = function getGlobal() {
29396
- return typeof window === "undefined" ? null : window;
29397
- };
29398
- /**
29399
- * Creates a no-op policy for internal use only.
29400
- * Don't export this function outside this module!
29401
- * @param trustedTypes The policy factory.
29402
- * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
29403
- * @return The policy created (or null, if Trusted Types
29404
- * are not supported or creating the policy failed).
29405
- */
29406
- var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
29407
- if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") return null;
29408
- let suffix = null;
29409
- const ATTR_NAME = "data-tt-policy-suffix";
29410
- if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) suffix = purifyHostElement.getAttribute(ATTR_NAME);
29411
- const policyName = "dompurify" + (suffix ? "#" + suffix : "");
29412
- try {
29413
- return trustedTypes.createPolicy(policyName, {
29414
- createHTML(html) {
29415
- return html;
29416
- },
29417
- createScriptURL(scriptUrl) {
29418
- return scriptUrl;
29419
- }
29420
- });
29421
- } catch (_) {
29422
- console.warn("TrustedTypes policy " + policyName + " could not be created.");
29423
- return null;
29424
- }
29425
- };
29426
- var _createHooksMap = function _createHooksMap() {
29427
- return {
29428
- afterSanitizeAttributes: [],
29429
- afterSanitizeElements: [],
29430
- afterSanitizeShadowDOM: [],
29431
- beforeSanitizeAttributes: [],
29432
- beforeSanitizeElements: [],
29433
- beforeSanitizeShadowDOM: [],
29434
- uponSanitizeAttribute: [],
29435
- uponSanitizeElement: [],
29436
- uponSanitizeShadowNode: []
29437
- };
29438
- };
29439
- /**
29440
- * Resolve a set-valued configuration option: a fresh set built from
29441
- * cfg[key] when it is an own array property (seeded with a clone of
29442
- * options.base when given, case-normalized via options.transform),
29443
- * the fallback set otherwise.
29444
- *
29445
- * @param cfg the cloned, prototype-free configuration object
29446
- * @param key the configuration property to read
29447
- * @param fallback the set to use when the option is absent or not an array
29448
- * @param options transform and optional base set to merge into
29449
- * @returns the resolved set
29450
- */
29451
- var _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
29452
- return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
29453
- };
29454
- /**
29455
- * Resolve an object-valued configuration option: a prototype-free clone
29456
- * of cfg[key] when it is an own, truthy object property, else a fresh
29457
- * fallback built by makeFallback (fresh on every parse, so a previous
29458
- * parse can never leak state into the next one).
29459
- *
29460
- * @param cfg the cloned, prototype-free configuration object
29461
- * @param key the configuration property to read
29462
- * @param makeFallback builds the fallback value when the option is absent
29463
- * @returns the resolved object
29464
- */
29465
- var _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback) {
29466
- const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0;
29467
- return value && typeof value === "object" ? clone(value) : makeFallback();
29468
- };
29469
- function createDOMPurify() {
29470
- let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
29471
- const DOMPurify = (root) => createDOMPurify(root);
29472
- DOMPurify.version = "3.4.17";
29473
- DOMPurify.removed = [];
29474
- if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
29475
- DOMPurify.isSupported = false;
29476
- return DOMPurify;
29477
- }
29478
- let document = window.document;
29479
- const originalDocument = document;
29480
- const currentScript = originalDocument.currentScript;
29481
- window.DocumentFragment;
29482
- const HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter;
29483
- window.NamedNodeMap === void 0 && (window.NamedNodeMap || window.MozNamedAttrMap);
29484
- window.HTMLFormElement;
29485
- const DOMParser = window.DOMParser, trustedTypes = window.trustedTypes;
29486
- const ElementPrototype = Element.prototype;
29487
- const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
29488
- const remove = lookupGetter(ElementPrototype, "remove");
29489
- const removeAttributeNode = lookupGetter(ElementPrototype, "removeAttributeNode");
29490
- const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
29491
- const getChildNodes = lookupGetter(ElementPrototype, "childNodes");
29492
- const getParentNode = lookupGetter(ElementPrototype, "parentNode");
29493
- const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot");
29494
- const getAttributes = lookupGetter(ElementPrototype, "attributes");
29495
- const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null;
29496
- const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null;
29497
- const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, "ownerDocument") : null;
29498
- const _readNodeType = function _readNodeType(node) {
29499
- return getNodeType ? getNodeType(node) : node.nodeType;
29500
- };
29501
- const _readNodeName = function _readNodeName(node) {
29502
- return getNodeName ? getNodeName(node) : node.nodeName;
29503
- };
29504
- const getNamespaceURI = lookupAccessor(ElementPrototype, "namespaceURI");
29505
- const _readNamespaceURI = function _readNamespaceURI(element) {
29506
- return getNamespaceURI ? getNamespaceURI(element) : element.namespaceURI;
29507
- };
29508
- if (typeof HTMLTemplateElement === "function") {
29509
- const template = document.createElement("template");
29510
- if (template.content && template.content.ownerDocument) document = template.content.ownerDocument;
29511
- }
29512
- let trustedTypesPolicy;
29513
- let emptyHTML = "";
29514
- let defaultTrustedTypesPolicy;
29515
- let defaultTrustedTypesPolicyResolved = false;
29516
- let IN_TRUSTED_TYPES_POLICY = 0;
29517
- const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy() {
29518
- if (IN_TRUSTED_TYPES_POLICY > 0) throw typeErrorCreate("A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted Types\" section of the README.");
29519
- };
29520
- const _createTrustedHTML = function _createTrustedHTML(html) {
29521
- _assertNotInTrustedTypesPolicy();
29522
- IN_TRUSTED_TYPES_POLICY++;
29523
- try {
29524
- return trustedTypesPolicy.createHTML(html);
29525
- } finally {
29526
- IN_TRUSTED_TYPES_POLICY--;
29527
- }
29528
- };
29529
- const _createTrustedScriptURL = function _createTrustedScriptURL(scriptUrl) {
29530
- _assertNotInTrustedTypesPolicy();
29531
- IN_TRUSTED_TYPES_POLICY++;
29532
- try {
29533
- return trustedTypesPolicy.createScriptURL(scriptUrl);
29534
- } finally {
29535
- IN_TRUSTED_TYPES_POLICY--;
29536
- }
29537
- };
29538
- const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy() {
29539
- if (!defaultTrustedTypesPolicyResolved) {
29540
- defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
29541
- defaultTrustedTypesPolicyResolved = true;
29542
- }
29543
- return defaultTrustedTypesPolicy;
29544
- };
29545
- const _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
29546
- const importNode = originalDocument.importNode;
29547
- let hooks = _createHooksMap();
29548
- /**
29549
- * Expose whether this browser supports running the full DOMPurify.
29550
- */
29551
- DOMPurify.isSupported = typeof entries$1 === "function" && typeof getParentNode === "function" && implementation && implementation.createHTMLDocument !== void 0;
29552
- const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
29553
- let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
29554
- /**
29555
- * We consider the elements and attributes below to be safe. Ideally
29556
- * don't add any new ones but feel free to remove unwanted ones.
29557
- */
29558
- let ALLOWED_TAGS = null;
29559
- const DEFAULT_ALLOWED_TAGS = addToSet({}, [
29560
- ...html$1,
29561
- ...svg$1$1,
29562
- ...svgFilters,
29563
- ...mathMl$1,
29564
- ...text$2
29565
- ]);
29566
- let ALLOWED_ATTR = null;
29567
- const DEFAULT_ALLOWED_ATTR = addToSet({}, [
29568
- ...html,
29569
- ...svg$2,
29570
- ...mathMl,
29571
- ...xml
29572
- ]);
29573
- let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
29574
- tagNameCheck: {
29575
- writable: true,
29576
- configurable: false,
29577
- enumerable: true,
29578
- value: null
29579
- },
29580
- attributeNameCheck: {
29581
- writable: true,
29582
- configurable: false,
29583
- enumerable: true,
29584
- value: null
29585
- },
29586
- allowCustomizedBuiltInElements: {
29587
- writable: true,
29588
- configurable: false,
29589
- enumerable: true,
29590
- value: false
29591
- }
29592
- }));
29593
- let FORBID_TAGS = null;
29594
- let FORBID_ATTR = null;
29595
- const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
29596
- tagCheck: {
29597
- writable: true,
29598
- configurable: false,
29599
- enumerable: true,
29600
- value: null
29601
- },
29602
- attributeCheck: {
29603
- writable: true,
29604
- configurable: false,
29605
- enumerable: true,
29606
- value: null
29607
- }
29608
- }));
29609
- let ALLOW_ARIA_ATTR = true;
29610
- let ALLOW_DATA_ATTR = true;
29611
- let ALLOW_UNKNOWN_PROTOCOLS = false;
29612
- let ALLOW_SELF_CLOSE_IN_ATTR = true;
29613
- let SAFE_FOR_TEMPLATES = false;
29614
- let SAFE_FOR_XML = true;
29615
- let WHOLE_DOCUMENT = false;
29616
- let SET_CONFIG = false;
29617
- let SET_CONFIG_ALLOWED_TAGS = null;
29618
- let SET_CONFIG_ALLOWED_ATTR = null;
29619
- let FORCE_BODY = false;
29620
- let RETURN_DOM = false;
29621
- let RETURN_DOM_FRAGMENT = false;
29622
- let RETURN_TRUSTED_TYPE = false;
29623
- let SANITIZE_DOM = true;
29624
- let SANITIZE_NAMED_PROPS = false;
29625
- const SANITIZE_NAMED_PROPS_PREFIX = "user-content-";
29626
- let KEEP_CONTENT = true;
29627
- let IN_PLACE = false;
29628
- let IN_PLACE_VISITED = null;
29629
- let USE_PROFILES = {};
29630
- let FORBID_CONTENTS = null;
29631
- const DEFAULT_FORBID_CONTENTS = addToSet({}, [
29632
- "annotation-xml",
29633
- "audio",
29634
- "colgroup",
29635
- "desc",
29636
- "foreignobject",
29637
- "head",
29638
- "iframe",
29639
- "math",
29640
- "mi",
29641
- "mn",
29642
- "mo",
29643
- "ms",
29644
- "mtext",
29645
- "noembed",
29646
- "noframes",
29647
- "noscript",
29648
- "plaintext",
29649
- "script",
29650
- "selectedcontent",
29651
- "style",
29652
- "svg",
29653
- "template",
29654
- "thead",
29655
- "title",
29656
- "video",
29657
- "xmp"
29658
- ]);
29659
- let DATA_URI_TAGS = null;
29660
- const DEFAULT_DATA_URI_TAGS = addToSet({}, [
29661
- "audio",
29662
- "video",
29663
- "img",
29664
- "source",
29665
- "image",
29666
- "track"
29667
- ]);
29668
- let URI_SAFE_ATTRIBUTES = null;
29669
- const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
29670
- "alt",
29671
- "class",
29672
- "for",
29673
- "id",
29674
- "label",
29675
- "name",
29676
- "pattern",
29677
- "placeholder",
29678
- "role",
29679
- "summary",
29680
- "title",
29681
- "value",
29682
- "style",
29683
- "xmlns"
29684
- ]);
29685
- const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
29686
- const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
29687
- const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
29688
- let NAMESPACE = HTML_NAMESPACE;
29689
- let IS_EMPTY_INPUT = false;
29690
- let ALLOWED_NAMESPACES = null;
29691
- const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
29692
- MATHML_NAMESPACE,
29693
- SVG_NAMESPACE,
29694
- HTML_NAMESPACE
29695
- ], stringToString);
29696
- const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze([
29697
- "mi",
29698
- "mo",
29699
- "mn",
29700
- "ms",
29701
- "mtext"
29702
- ]);
29703
- let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS);
29704
- const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]);
29705
- let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS);
29706
- const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
29707
- "title",
29708
- "style",
29709
- "font",
29710
- "a",
29711
- "script"
29712
- ]);
29713
- let PARSER_MEDIA_TYPE = null;
29714
- const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"];
29715
- const DEFAULT_PARSER_MEDIA_TYPE = "text/html";
29716
- let transformCaseFunc = null;
29717
- let CONFIG = null;
29718
- const formElement = document.createElement("form");
29719
- const isRegexOrFunction = function isRegexOrFunction(testValue) {
29720
- return testValue instanceof RegExp || testValue instanceof Function;
29721
- };
29722
- /**
29723
- * _parseConfig
29724
- *
29725
- * @param cfg optional config literal
29726
- */
29727
- const _parseConfig = function _parseConfig() {
29728
- let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
29729
- if (CONFIG && CONFIG === cfg) return;
29730
- if (!cfg || typeof cfg !== "object") cfg = {};
29731
- cfg = clone(cfg);
29732
- PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
29733
- transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase;
29734
- ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, { transform: transformCaseFunc });
29735
- ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, { transform: transformCaseFunc });
29736
- ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, { transform: stringToString });
29737
- URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, {
29738
- transform: transformCaseFunc,
29739
- base: DEFAULT_URI_SAFE_ATTRIBUTES
29740
- });
29741
- DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, {
29742
- transform: transformCaseFunc,
29743
- base: DEFAULT_DATA_URI_TAGS
29744
- });
29745
- FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, { transform: transformCaseFunc });
29746
- FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), { transform: transformCaseFunc });
29747
- FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), { transform: transformCaseFunc });
29748
- USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
29749
- ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
29750
- ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
29751
- ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
29752
- ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false;
29753
- SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
29754
- SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false;
29755
- WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
29756
- RETURN_DOM = cfg.RETURN_DOM || false;
29757
- RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
29758
- RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
29759
- FORCE_BODY = cfg.FORCE_BODY || false;
29760
- SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
29761
- SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false;
29762
- KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
29763
- IN_PLACE = cfg.IN_PLACE || false;
29764
- IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
29765
- NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
29766
- MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(cfg, "MATHML_TEXT_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS));
29767
- HTML_INTEGRATION_POINTS = _resolveObjectOption(cfg, "HTML_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS));
29768
- const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null));
29769
- CUSTOM_ELEMENT_HANDLING = create(null);
29770
- if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
29771
- if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck;
29772
- if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements;
29773
- seal(CUSTOM_ELEMENT_HANDLING);
29774
- if (SAFE_FOR_TEMPLATES) ALLOW_DATA_ATTR = false;
29775
- if (RETURN_DOM_FRAGMENT) RETURN_DOM = true;
29776
- if (USE_PROFILES) {
29777
- ALLOWED_TAGS = addToSet({}, text$2);
29778
- ALLOWED_ATTR = create(null);
29779
- if (USE_PROFILES.html === true) {
29780
- addToSet(ALLOWED_TAGS, html$1);
29781
- addToSet(ALLOWED_ATTR, html);
29782
- }
29783
- if (USE_PROFILES.svg === true) {
29784
- addToSet(ALLOWED_TAGS, svg$1$1);
29785
- addToSet(ALLOWED_ATTR, svg$2);
29786
- addToSet(ALLOWED_ATTR, xml);
29787
- }
29788
- if (USE_PROFILES.svgFilters === true) {
29789
- addToSet(ALLOWED_TAGS, svgFilters);
29790
- addToSet(ALLOWED_ATTR, svg$2);
29791
- addToSet(ALLOWED_ATTR, xml);
29792
- }
29793
- if (USE_PROFILES.mathMl === true) {
29794
- addToSet(ALLOWED_TAGS, mathMl$1);
29795
- addToSet(ALLOWED_ATTR, mathMl);
29796
- addToSet(ALLOWED_ATTR, xml);
29797
- }
29798
- }
29799
- EXTRA_ELEMENT_HANDLING.tagCheck = null;
29800
- EXTRA_ELEMENT_HANDLING.attributeCheck = null;
29801
- if (objectHasOwnProperty(cfg, "ADD_TAGS")) {
29802
- if (typeof cfg.ADD_TAGS === "function") EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
29803
- else if (arrayIsArray(cfg.ADD_TAGS)) {
29804
- if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) ALLOWED_TAGS = clone(ALLOWED_TAGS);
29805
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
29806
- }
29807
- }
29808
- if (objectHasOwnProperty(cfg, "ADD_ATTR")) {
29809
- if (typeof cfg.ADD_ATTR === "function") EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
29810
- else if (arrayIsArray(cfg.ADD_ATTR)) {
29811
- if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) ALLOWED_ATTR = clone(ALLOWED_ATTR);
29812
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
29813
- }
29814
- }
29815
- if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
29816
- if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
29817
- addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
29818
- }
29819
- if (KEEP_CONTENT) ALLOWED_TAGS["#text"] = true;
29820
- if (WHOLE_DOCUMENT) addToSet(ALLOWED_TAGS, [
29821
- "html",
29822
- "head",
29823
- "body"
29824
- ]);
29825
- if (ALLOWED_TAGS.table) {
29826
- addToSet(ALLOWED_TAGS, ["tbody"]);
29827
- delete FORBID_TAGS.tbody;
29828
- }
29829
- if (cfg.TRUSTED_TYPES_POLICY) {
29830
- if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.");
29831
- if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") throw typeErrorCreate("TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.");
29832
- const previousTrustedTypesPolicy = trustedTypesPolicy;
29833
- trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
29834
- try {
29835
- emptyHTML = _createTrustedHTML("");
29836
- } catch (error) {
29837
- trustedTypesPolicy = previousTrustedTypesPolicy;
29838
- throw error;
29839
- }
29840
- } else if (cfg.TRUSTED_TYPES_POLICY === null) {
29841
- trustedTypesPolicy = void 0;
29842
- emptyHTML = "";
29843
- } else {
29844
- if (trustedTypesPolicy === void 0) trustedTypesPolicy = _getDefaultTrustedTypesPolicy();
29845
- if (trustedTypesPolicy && typeof emptyHTML === "string") emptyHTML = _createTrustedHTML("");
29846
- }
29847
- if (freeze) freeze(cfg);
29848
- CONFIG = cfg;
29849
- };
29850
- const ALL_SVG_TAGS = addToSet({}, [
29851
- ...svg$1$1,
29852
- ...svgFilters,
29853
- ...svgDisallowed
29854
- ]);
29855
- const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
29856
- /**
29857
- * Namespace rules for an element in the SVG namespace.
29858
- *
29859
- * @param tagName the element's lowercase tag name
29860
- * @param parent the (possibly simulated) parent node
29861
- * @param parentTagName the parent's lowercase tag name
29862
- * @returns true if a spec-compliant parser could produce this element
29863
- */
29864
- const _checkSvgNamespace = function _checkSvgNamespace(tagName, parent, parentTagName) {
29865
- if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "svg";
29866
- if (parent.namespaceURI === MATHML_NAMESPACE) return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
29867
- return Boolean(ALL_SVG_TAGS[tagName]);
29868
- };
29869
- /**
29870
- * Namespace rules for an element in the MathML namespace.
29871
- *
29872
- * @param tagName the element's lowercase tag name
29873
- * @param parent the (possibly simulated) parent node
29874
- * @param parentTagName the parent's lowercase tag name
29875
- * @returns true if a spec-compliant parser could produce this element
29876
- */
29877
- const _checkMathMlNamespace = function _checkMathMlNamespace(tagName, parent, parentTagName) {
29878
- if (parent.namespaceURI === HTML_NAMESPACE) return tagName === "math";
29879
- if (parent.namespaceURI === SVG_NAMESPACE) return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName];
29880
- return Boolean(ALL_MATHML_TAGS[tagName]);
29881
- };
29882
- /**
29883
- * Namespace rules for an element in the HTML namespace.
29884
- *
29885
- * @param tagName the element's lowercase tag name
29886
- * @param parent the (possibly simulated) parent node
29887
- * @param parentTagName the parent's lowercase tag name
29888
- * @returns true if a spec-compliant parser could produce this element
29889
- */
29890
- const _checkHtmlNamespace = function _checkHtmlNamespace(tagName, parent, parentTagName) {
29891
- if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) return false;
29892
- if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) return false;
29893
- return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
29894
- };
29895
- /**
29896
- * @param element a DOM element whose namespace is being checked
29897
- * @returns Return false if the element has a
29898
- * namespace that a spec-compliant parser would never
29899
- * return. Return true otherwise.
29900
- */
29901
- const _checkValidNamespace = function _checkValidNamespace(element) {
29902
- const elementNamespace = _readNamespaceURI(element);
29903
- const tagName = stringToLowerCase(_readNodeName(element));
29904
- const parentNode = getParentNode(element);
29905
- let parent;
29906
- let parentTagName;
29907
- if (parentNode && _readNodeType(parentNode) === NODE_TYPE.element) {
29908
- parent = { namespaceURI: _readNamespaceURI(parentNode) };
29909
- parentTagName = stringToLowerCase(_readNodeName(parentNode));
29910
- } else {
29911
- parent = { namespaceURI: NAMESPACE };
29912
- parentTagName = "template";
29913
- }
29914
- if (!ALLOWED_NAMESPACES[elementNamespace]) return false;
29915
- if (elementNamespace === SVG_NAMESPACE) return _checkSvgNamespace(tagName, parent, parentTagName);
29916
- if (elementNamespace === MATHML_NAMESPACE) return _checkMathMlNamespace(tagName, parent, parentTagName);
29917
- if (elementNamespace === HTML_NAMESPACE) return _checkHtmlNamespace(tagName, parent, parentTagName);
29918
- if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[elementNamespace]) return true;
29919
- return false;
29920
- };
29921
- /**
29922
- * _forceRemove
29923
- *
29924
- * @param node a DOM node
29925
- */
29926
- const _forceRemove = function _forceRemove(node) {
29927
- arrayPush(DOMPurify.removed, { element: node });
29928
- try {
29929
- getParentNode(node).removeChild(node);
29930
- } catch (_) {
29931
- remove(node);
29932
- if (!getParentNode(node)) throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place");
29933
- }
29934
- };
29935
- /**
29936
- * _stripAttributeNode
29937
- *
29938
- * Remove a single Attr node case/namespace-exactly on an attribute-teardown
29939
- * path. Name-based removeAttribute() ASCII-lowercases its lookup key for an
29940
- * HTML element in an HTML document and so silently misses a case-preserved
29941
- * handler (e.g. `ONERROR` off an XML/XHTML import) - the same defect
29942
- * _removeAttribute() was fixed for, which a name-based call would reintroduce
29943
- * on these IN_PLACE teardown paths. Unlike _removeAttribute this does not
29944
- * record into DOMPurify.removed: the neutralize passes intentionally do not
29945
- * book-keep. A clobbered/detached node falls back to best-effort name-based
29946
- * removal.
29947
- *
29948
- * @param element the element to strip the attribute from
29949
- * @param attribute the Attr node to remove
29950
- * @param name the attribute's name, for the fallback path
29951
- */
29952
- const _stripAttributeNode = function _stripAttributeNode(element, attribute, name) {
29953
- try {
29954
- removeAttributeNode(element, attribute);
29955
- } catch (_) {
29956
- try {
29957
- element.removeAttribute(name);
29958
- } catch (_) {}
29959
- }
29960
- };
29961
- /**
29962
- * Fail-closed teardown of an in-place root: strip every disallowed attribute
29963
- * in the subtree first, so nothing armed is left behind, then remove all
29964
- * children and the root's own attributes.
29965
- *
29966
- * @param root the in-place root to empty
29967
- */
29968
- const _neutralizeRoot = function _neutralizeRoot(root) {
29969
- _neutralizeSubtree(root);
29970
- const childNodes = getChildNodes(root);
29971
- if (childNodes) arrayForEach(arraySlice(childNodes), (child) => {
29972
- try {
29973
- remove(child);
29974
- } catch (_) {}
29975
- });
29976
- const attributes = _readNodeType(root) === NODE_TYPE.element ? getAttributes(root) : null;
29977
- if (attributes) for (let i = attributes.length - 1; i >= 0; --i) {
29978
- const attribute = attributes[i];
29979
- const name = attribute && attribute.name;
29980
- if (typeof name === "string") _stripAttributeNode(root, attribute, name);
29981
- }
29982
- };
29983
- /**
29984
- * Removes an attribute, preferably as its exact Attr node: name-based
29985
- * removal lowercases the name in HTML documents and misses case-preserved
29986
- * names, e.g. from imported XHTML.
29987
- *
29988
- * @param name an Attribute name
29989
- * @param element a DOM node
29990
- * @param attr the exact Attr node to remove, when the caller has it
29991
- */
29992
- const _removeAttribute = function _removeAttribute(name, element, attr) {
29993
- if (!attr) try {
29994
- attr = element.getAttributeNode(name);
29995
- } catch (_) {
29996
- attr = null;
29997
- }
29998
- arrayPush(DOMPurify.removed, {
29999
- attribute: attr || null,
30000
- from: element
30001
- });
30002
- try {
30003
- if (attr) removeAttributeNode(element, attr);
30004
- else element.removeAttribute(name);
30005
- } catch (_) {
30006
- try {
30007
- element.removeAttribute(name);
30008
- } catch (_) {}
30009
- }
30010
- if (name === "is") {
30011
- if (RETURN_DOM || RETURN_DOM_FRAGMENT) try {
30012
- _forceRemove(element);
30013
- } catch (_) {}
30014
- else try {
30015
- element.setAttribute(name, "");
30016
- } catch (_) {}
30017
- }
30018
- };
30019
- /**
30020
- * Removes every attribute the configuration does not allow. Used to
30021
- * neutralize nodes discarded from an in-place tree.
30022
- *
30023
- * @param element the element to strip
30024
- */
30025
- const _stripDisallowedAttributes = function _stripDisallowedAttributes(element) {
30026
- const attributes = getAttributes(element);
30027
- if (!attributes) return;
30028
- for (let i = attributes.length - 1; i >= 0; --i) {
30029
- const attribute = attributes[i];
30030
- const name = attribute && attribute.name;
30031
- if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue;
30032
- _stripAttributeNode(element, attribute, name);
30033
- }
30034
- };
30035
- /**
30036
- * Iterative depth-first walk, so deep trees cannot overflow the call stack,
30037
- * reading through the cached getters, so clobbering cannot hide children.
30038
- * When `visit` returns false, the node's children are skipped. With
30039
- * `intoShadow`, open shadow roots are walked after their host's children.
30040
- *
30041
- * @param root where to start
30042
- * @param visit called for every node
30043
- * @param intoShadow whether to enter open shadow roots
30044
- */
30045
- const _walkTree = function _walkTree(root, visit) {
30046
- let intoShadow = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : false;
30047
- const stack = [root];
30048
- while (stack.length > 0) {
30049
- const node = stack.pop();
30050
- if (visit(node) === false) continue;
30051
- if (intoShadow && _readNodeType(node) === NODE_TYPE.element) {
30052
- const shadowRoot = getShadowRoot(node);
30053
- if (_isDocumentFragment(shadowRoot)) stack.push(shadowRoot);
30054
- }
30055
- const childNodes = getChildNodes(node);
30056
- if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
30057
- }
30058
- };
30059
- /**
30060
- * Strips disallowed attributes from every element of a discarded subtree,
30061
- * so a handler that is already queued (a loading image) cannot fire.
30062
- *
30063
- * @param root the root of a removed subtree
30064
- */
30065
- const _neutralizeSubtree = function _neutralizeSubtree(root) {
30066
- _walkTree(root, (node) => {
30067
- if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node);
30068
- });
30069
- };
30070
- /**
30071
- * All nodes under `root`, root first, including open shadow roots. Template
30072
- * content is not entered, it is inert.
30073
- *
30074
- * @param root the in-place root
30075
- * @return the nodes
30076
- */
30077
- const _collectLiveNodes = function _collectLiveNodes(root) {
30078
- const nodes = [];
30079
- _walkTree(root, (node) => {
30080
- nodes.push(node);
30081
- }, true);
30082
- return nodes;
30083
- };
30084
- /**
30085
- * Strips disallowed attributes from every element that was under the
30086
- * in-place root when the call started and no longer is, whatever removed
30087
- * or moved it.
30088
- *
30089
- * @param root the in-place root
30090
- * @param before the root's nodes, collected before the walk
30091
- */
30092
- const _neutralizeEscapedElements = function _neutralizeEscapedElements(root, before) {
30093
- const reachable = setCreate();
30094
- arrayForEach(_collectLiveNodes(root), (node) => {
30095
- if (_readNodeType(node) === NODE_TYPE.element) setAdd(reachable, node);
30096
- });
30097
- arrayForEach(before, (node) => {
30098
- if (_readNodeType(node) === NODE_TYPE.element && !setHas(reachable, node)) _stripDisallowedAttributes(node);
30099
- });
30100
- };
30101
- /**
30102
- * Neutralizes everything that left the in-place tree during the call: what
30103
- * DOMPurify removed, and what hooks or custom elements removed or moved out.
30104
- *
30105
- * @param root the in-place root
30106
- * @param before the root's nodes, collected before the walk
30107
- * @return true if the root itself was removed
30108
- */
30109
- const _neutralizeDiscarded = function _neutralizeDiscarded(root, before) {
30110
- let rootRemoved = false;
30111
- arrayForEach(DOMPurify.removed, (entry) => {
30112
- if (entry.element) {
30113
- rootRemoved = rootRemoved || entry.element === root;
30114
- _neutralizeSubtree(entry.element);
30115
- }
30116
- });
30117
- _neutralizeEscapedElements(root, before);
30118
- return rootRemoved;
30119
- };
30120
- const MAX_UNVISITED_ROUNDS = 8;
30121
- /**
30122
- * The walk only moves forward, so a node moved to a position it already
30123
- * passed is never visited. Give every original node that is still in the
30124
- * tree but unvisited the normal treatment, hooks included. Nodes created
30125
- * during the call are left alone. Fails closed if the tree keeps changing.
30126
- *
30127
- * @param root the in-place root
30128
- * @param before the root's nodes, collected before the walk
30129
- */
30130
- const _sanitizeUnvisitedNodes = function _sanitizeUnvisitedNodes(root, before) {
30131
- const visited = IN_PLACE_VISITED;
30132
- let original = null;
30133
- const getOriginal = () => {
30134
- if (!original) {
30135
- original = setCreate();
30136
- arrayForEach(before, (beforeNode) => {
30137
- setAdd(original, beforeNode);
30138
- });
30139
- }
30140
- return original;
30141
- };
30142
- for (let round = 0;; round++) {
30143
- const live = _collectLiveNodes(root);
30144
- const containers = [root];
30145
- let pending = false;
30146
- arrayForEach(live, (node) => {
30147
- if (_readNodeType(node) === NODE_TYPE.documentFragment) arrayPush(containers, node);
30148
- else if (!pending && !setHas(visited, node)) pending = setHas(getOriginal(), node);
30149
- });
30150
- if (!pending) return;
30151
- if (round >= MAX_UNVISITED_ROUNDS) throw typeErrorCreate("the tree kept changing during in-place sanitization; refusing to return it");
30152
- arrayForEach(containers, (container, index) => {
30153
- _sanitizeUnvisitedIn(container, index > 0, root, getOriginal());
30154
- });
30155
- }
30156
- };
30157
- /**
30158
- * One _sanitizeUnvisitedNodes pass over the root or an open shadow root.
30159
- *
30160
- * @param container the root or an open shadow root
30161
- * @param inShadow whether container is a shadow root
30162
- * @param root the in-place root
30163
- * @param original the root's nodes collected before the walk, as a set
30164
- */
30165
- const _sanitizeUnvisitedIn = function _sanitizeUnvisitedIn(container, inShadow, root, original) {
30166
- const iterator = _createNodeIterator(container);
30167
- let node;
30168
- while (node = iterator.nextNode()) {
30169
- if (!setHas(original, node) || setHas(IN_PLACE_VISITED, node)) continue;
30170
- if (inShadow) _executeHooks(hooks.uponSanitizeShadowNode, node, null);
30171
- _sanitizeElements(node, root);
30172
- _sanitizeAttributes(node, root);
30173
- if (_isDocumentFragment(node.content)) _sanitizeShadowDOM2(node.content);
30174
- }
30175
- };
30176
- /**
30177
- * Records that _sanitizeElements processed `node`. No-op outside IN_PLACE.
30178
- *
30179
- * @param node the node being processed
30180
- */
30181
- const _markVisited = function _markVisited(node) {
30182
- if (IN_PLACE_VISITED) setAdd(IN_PLACE_VISITED, node);
30183
- };
30184
- /**
30185
- * Patch-linkage attributes (declarative partial updates): `patchsrc`
30186
- * always, `for` everywhere except on <label> and <output>. Gated on
30187
- * SAFE_FOR_XML. Shared by the IN_PLACE pre-pass and _isValidAttribute.
30188
- *
30189
- * @param lcName the transformCaseFunc'd attribute name
30190
- * @param lcTag the transformCaseFunc'd tag name of the carrying element
30191
- * @return true if the attribute is patch linkage and must be dropped
30192
- */
30193
- const _isPatchLinkageAttribute = function _isPatchLinkageAttribute(lcName, lcTag) {
30194
- if (!SAFE_FOR_XML) return false;
30195
- if (lcName === "patchsrc") return true;
30196
- return lcName === "for" && lcTag !== "label" && lcTag !== "output";
30197
- };
30198
- /**
30199
- * IN_PLACE pre-pass: sever all patch linkage before the walk, so no patch
30200
- * can fire mid-walk into a part of the tree the walker already passed.
30201
- * Removes range markers (processing instructions, comments with markup)
30202
- * and strips linkage attributes. It cannot undo a patch that already fired.
30203
- *
30204
- * TODO: if the shipped feature can patch through `for` on <label>/<output>,
30205
- * drop that pair here too (see test/declarative-patch-probe.html).
30206
- *
30207
- * @param root the in-place root to sweep
30208
- */
30209
- const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
30210
- if (!SAFE_FOR_XML) return;
30211
- _walkTree(root, (node) => {
30212
- const nodeType = _readNodeType(node);
30213
- if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
30214
- try {
30215
- remove(node);
30216
- } catch (_) {}
30217
- return false;
30218
- }
30219
- if (nodeType === NODE_TYPE.element) {
30220
- const element = node;
30221
- const lcTag = transformCaseFunc(_readNodeName(node));
30222
- try {
30223
- if (element.hasAttribute && element.hasAttribute("patchsrc")) element.removeAttribute("patchsrc");
30224
- if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) element.removeAttribute("for");
30225
- } catch (_) {}
30226
- }
30227
- return true;
30228
- });
30229
- };
30230
- /**
30231
- * _initDocument
30232
- *
30233
- * @param dirty - a string of dirty markup
30234
- * @return a DOM, filled with the dirty markup
30235
- */
30236
- const _initDocument = function _initDocument(dirty) {
30237
- let doc = null;
30238
- let leadingWhitespace = null;
30239
- if (FORCE_BODY) dirty = "<remove></remove>" + dirty;
30240
- else {
30241
- const matches = stringMatch(dirty, /^[\r\n\t ]+/);
30242
- leadingWhitespace = matches && matches[0];
30243
- }
30244
- if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) dirty = "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>" + dirty + "</body></html>";
30245
- const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
30246
- if (NAMESPACE === HTML_NAMESPACE) try {
30247
- doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
30248
- } catch (_) {}
30249
- if (!doc || !doc.documentElement) {
30250
- doc = implementation.createDocument(NAMESPACE, "template", null);
30251
- try {
30252
- doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
30253
- } catch (_) {}
30254
- }
30255
- const body = doc.body || doc.documentElement;
30256
- if (dirty && leadingWhitespace) body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
30257
- if (NAMESPACE === HTML_NAMESPACE) return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0];
30258
- return WHOLE_DOCUMENT ? doc.documentElement : body;
30259
- };
30260
- /**
30261
- * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
30262
- *
30263
- * @param root The root element or node to start traversing on.
30264
- * @return The created NodeIterator
30265
- */
30266
- const _createNodeIterator = function _createNodeIterator(root) {
30267
- const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
30268
- return createNodeIterator.call(doc || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
30269
- };
30270
- /**
30271
- * Replace template expression syntax (mustache, ERB, template
30272
- * literal) with a space; shared by all SAFE_FOR_TEMPLATES scrub
30273
- * sites. Order matters: mustache, then ERB, then template literal.
30274
- *
30275
- * @param value the string to scrub
30276
- * @returns the scrubbed string
30277
- */
30278
- const _stripTemplateExpressions = function _stripTemplateExpressions(value) {
30279
- value = stringReplace(value, MUSTACHE_EXPR$1, " ");
30280
- value = stringReplace(value, ERB_EXPR$1, " ");
30281
- value = stringReplace(value, TMPLIT_EXPR$1, " ");
30282
- return value;
30283
- };
30284
- /**
30285
- * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
30286
- * character data of an element subtree. Used as the final safety net for
30287
- * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
30288
- * which only form after text-node normalization (e.g. fragments split across
30289
- * stripped elements) cannot survive into a template-evaluating framework.
30290
- *
30291
- * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
30292
- * in place rather than round-tripping through innerHTML. This preserves
30293
- * descendant node references (important for IN_PLACE callers), avoids a
30294
- * serialize/reparse cycle, and reads literal character data — which means
30295
- * `<%...%>` in text content matches the ERB regex against its real bytes
30296
- * instead of the HTML-entity-escaped form innerHTML would produce.
30297
- *
30298
- * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
30299
- * attributes is performed during the per-node `_sanitizeAttributes` pass.
30300
- *
30301
- * @param node The root element whose character data should be scrubbed.
30302
- */
30303
- const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
30304
- var _node$querySelectorAl;
30305
- _scrubOwnCharacterData(node);
30306
- const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template");
30307
- if (templates) arrayForEach(templates, (tmpl) => {
30308
- if (_isDocumentFragment(tmpl.content)) _scrubTemplateExpressions2(tmpl.content);
30309
- });
30310
- };
30311
- /**
30312
- * _scrubOwnCharacterData
30313
- *
30314
- * Non-recursive core of _scrubTemplateExpressions: normalize `node` and
30315
- * strip template expressions from its own character data only. Does not
30316
- * enter <template>.content or attached shadow roots (NodeIterator never
30317
- * does). Used by _sanitizeShadowDOM, where every nested template content
30318
- * and shadow root is already walked - and therefore scrubbed - by its own
30319
- * recursive _sanitizeShadowDOM call; recursing here as well would rescrub
30320
- * each nested fragment once per ancestor, which is quadratic in nesting
30321
- * depth.
30322
- *
30323
- * @param node The root whose own character data should be scrubbed.
30324
- */
30325
- const _scrubOwnCharacterData = function _scrubOwnCharacterData(node) {
30326
- node.normalize();
30327
- const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
30328
- const walker = createNodeIterator.call(doc || node, node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
30329
- let currentNode = walker.nextNode();
30330
- while (currentNode) {
30331
- currentNode.data = _stripTemplateExpressions(currentNode.data);
30332
- currentNode = walker.nextNode();
30333
- }
30334
- };
30335
- /**
30336
- * _isClobbered
30337
- *
30338
- * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
30339
- * interface with [LegacyOverrideBuiltIns]; a descendant element with a
30340
- * `name` attribute matching a prototype property shadows that property
30341
- * on direct reads. We use this check at the IN_PLACE entry-point and
30342
- * during attribute sanitization to refuse clobbered forms.
30343
- *
30344
- * @param element element to check for clobbering attacks
30345
- * @return true if clobbered, false if safe
30346
- */
30347
- const _isClobbered = function _isClobbered(element) {
30348
- const realTagName = getNodeName ? getNodeName(element) : null;
30349
- if (typeof realTagName !== "string") return false;
30350
- if (transformCaseFunc(realTagName) !== "form") return false;
30351
- 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);
30352
- };
30353
- /**
30354
- * Checks whether the given value is a DocumentFragment from any realm.
30355
- *
30356
- * The realm-independent replacement reads `nodeType` through the cached
30357
- * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
30358
- * constant (11). nodeType is a numeric value resolved from the node's
30359
- * internal slot, identical across realms for the same kind of node.
30360
- *
30361
- * @param value object to check
30362
- * @return true if value is a DocumentFragment-shaped node from any realm
30363
- */
30364
- const _isDocumentFragment = function _isDocumentFragment(value) {
30365
- if (!getNodeType || typeof value !== "object" || value === null) return false;
30366
- try {
30367
- return getNodeType(value) === NODE_TYPE.documentFragment;
30368
- } catch (_) {
30369
- return false;
30370
- }
30371
- };
30372
- /**
30373
- * Checks whether the given object is a DOM node, including nodes that
30374
- * originate from a different window/realm (e.g. an iframe's
30375
- * contentDocument). The previous `value instanceof Node` check was
30376
- * realm-bound: nodes from a different window failed it, causing
30377
- * sanitize() to silently stringify them and reset IN_PLACE to false,
30378
- * returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
30379
- *
30380
- * @param value object to check whether it's a DOM node
30381
- * @return true if value is a DOM node from any realm
30382
- */
30383
- const _isNode = function _isNode(value) {
30384
- if (!getNodeType || typeof value !== "object" || value === null) return false;
30385
- try {
30386
- return typeof getNodeType(value) === "number";
30387
- } catch (_) {
30388
- return false;
30389
- }
30390
- };
30391
- function _executeHooks(hooks, currentNode, data) {
30392
- if (hooks.length === 0) return;
30393
- arrayForEach(hooks, (hook) => {
30394
- hook.call(DOMPurify, currentNode, data, CONFIG);
30395
- });
30396
- }
30397
- /**
30398
- * Structural-threat checks that condemn a node regardless of the
30399
- * allowlists: mXSS via namespace confusion, risky CSS construction,
30400
- * processing instructions, markup-bearing comments. Pure predicate;
30401
- * the caller removes. Check order is load-bearing.
30402
- *
30403
- * @param currentNode the node to inspect
30404
- * @param tagName the node's transformCaseFunc'd tag name
30405
- * @return true if the node must be removed
30406
- */
30407
- const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
30408
- if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true;
30409
- 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;
30410
- if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true;
30411
- if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true;
30412
- return false;
30413
- };
30414
- /**
30415
- * Evaluate a CUSTOM_ELEMENT_HANDLING check (a RegExp or a predicate
30416
- * function, per the validation in _parseConfig) against a name.
30417
- * Additional arguments are forwarded to predicate functions - the
30418
- * attributeNameCheck predicate receives the tag name as its second
30419
- * argument. A null/absent check never matches.
30420
- *
30421
- * @param check the configured tagNameCheck / attributeNameCheck value
30422
- * @param name the name to test
30423
- * @param args extra arguments forwarded to a predicate function
30424
- * @return true if the check matches the name
30425
- */
30426
- const _matchesNameCheck = function _matchesNameCheck(check, name) {
30427
- if (check instanceof RegExp) return regExpTest(check, name);
30428
- if (check instanceof Function) {
30429
- for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key];
30430
- return Boolean(check(name, ...args));
30431
- }
30432
- return false;
30433
- };
30434
- /**
30435
- * Handle a node whose tag is forbidden or not allowlisted: keep
30436
- * allowed custom elements (false return exits _sanitizeElements
30437
- * early - the namespace and fallback-tag removal checks are
30438
- * intentionally skipped for kept custom elements), else hoist
30439
- * content per KEEP_CONTENT and remove.
30440
- *
30441
- * A kept custom element is the ONLY case in which this function
30442
- * returns false, so the caller uses that return value to run the
30443
- * afterSanitizeElements hook on the kept element and keep the
30444
- * element-hook lifecycle consistent with normal allowlisted
30445
- * elements (GHSA-c2j3-45gr-mqc4).
30446
- *
30447
- * @param currentNode the disallowed node
30448
- * @param tagName the node's transformCaseFunc'd tag name
30449
- * @return true if the node was removed, false if kept
30450
- */
30451
- const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
30452
- if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
30453
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && !FORBID_CONTENTS[stringToLowerCase(tagName)]) {
30454
- const parentNode = getParentNode(currentNode);
30455
- const childNodes = getChildNodes(currentNode);
30456
- if (childNodes && parentNode) {
30457
- const childCount = childNodes.length;
30458
- for (let i = childCount - 1; i >= 0; --i) {
30459
- const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i];
30460
- parentNode.insertBefore(hoisted, getNextSibling(currentNode));
30461
- }
30462
- }
30463
- }
30464
- _forceRemove(currentNode);
30465
- return true;
30466
- };
30467
- /**
30468
- * Fork a hook-mutable allowlist off its shared binding the first time a
30469
- * (possibly lazily-installed) uponSanitize* hook is about to see it, so the
30470
- * hook cannot widen the per-instance default or the setConfig binding by
30471
- * reference and leak past the call. Returns the set unchanged once it is
30472
- * already call-local, so repeated calls across elements are idempotent.
30473
- *
30474
- * @param hookList the uponSanitize* hook array for this event
30475
- * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding
30476
- * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant
30477
- * @param setConfigSet the captured setConfig() binding, or null
30478
- * @return a call-local clone if a hook is present and set is still shared,
30479
- * else set unchanged
30480
- */
30481
- const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) {
30482
- if (hookList.length === 0) return set;
30483
- return set === defaultSet || set === setConfigSet ? clone(set) : set;
30484
- };
30485
- /**
30486
- * A hook may have detached the node it was called for. If so, treat it as
30487
- * removed and stop processing it; the walk root is exempt. On the IN_PLACE
30488
- * path the detached subtree is neutralized right away.
30489
- *
30490
- * @param currentNode the node a hook may have detached
30491
- * @param root the current walk root
30492
- * @return true if the node was detached
30493
- */
30494
- const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) {
30495
- if (currentNode === root || getParentNode(currentNode) !== null) return false;
30496
- if (IN_PLACE) _neutralizeSubtree(currentNode);
30497
- return true;
30498
- };
30499
- /**
30500
- * _sanitizeElements
30501
- *
30502
- * @protect nodeName
30503
- * @protect textContent
30504
- * @protect removeChild
30505
- * @param currentNode to check for permission to exist
30506
- * @return true if node was killed, false if left alive
30507
- */
30508
- const _sanitizeElements = function _sanitizeElements(currentNode, root) {
30509
- _markVisited(currentNode);
30510
- _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
30511
- if (_handleHookDetachedNode(currentNode, root)) return true;
30512
- if (_isClobbered(currentNode)) {
30513
- _forceRemove(currentNode);
30514
- return true;
30515
- }
30516
- const tagName = transformCaseFunc(_readNodeName(currentNode));
30517
- ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
30518
- _executeHooks(hooks.uponSanitizeElement, currentNode, {
30519
- tagName,
30520
- allowedTags: ALLOWED_TAGS
30521
- });
30522
- if (_handleHookDetachedNode(currentNode, root)) return true;
30523
- if (_isUnsafeNode(currentNode, tagName)) {
30524
- _forceRemove(currentNode);
30525
- return true;
30526
- }
30527
- if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
30528
- const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
30529
- if (removed === false) {
30530
- _executeHooks(hooks.afterSanitizeElements, currentNode, null);
30531
- if (_handleHookDetachedNode(currentNode, root)) return true;
30532
- }
30533
- return removed;
30534
- }
30535
- if (_readNodeType(currentNode) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
30536
- _forceRemove(currentNode);
30537
- return true;
30538
- }
30539
- if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) {
30540
- _forceRemove(currentNode);
30541
- return true;
30542
- }
30543
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
30544
- const content = _stripTemplateExpressions(currentNode.textContent);
30545
- if (currentNode.textContent !== content) {
30546
- arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
30547
- currentNode.textContent = content;
30548
- }
30549
- }
30550
- _executeHooks(hooks.afterSanitizeElements, currentNode, null);
30551
- return _handleHookDetachedNode(currentNode, root);
30552
- };
30553
- /**
30554
- * _isValidAttribute
30555
- *
30556
- * @param lcTag Lowercase tag name of containing element.
30557
- * @param lcName Lowercase attribute name.
30558
- * @param value Attribute value.
30559
- * @return Returns true if `value` is valid, otherwise false.
30560
- */
30561
- const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
30562
- if (FORBID_ATTR[lcName]) return false;
30563
- if (_isPatchLinkageAttribute(lcName, lcTag)) return false;
30564
- if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false;
30565
- const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
30566
- if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) return true;
30567
- if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) return true;
30568
- 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);
30569
- if (URI_SAFE_ATTRIBUTES[lcName]) return true;
30570
- if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
30571
- if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) return true;
30572
- if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
30573
- return !value;
30574
- };
30575
- const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [
30576
- "annotation-xml",
30577
- "color-profile",
30578
- "font-face",
30579
- "font-face-format",
30580
- "font-face-name",
30581
- "font-face-src",
30582
- "font-face-uri",
30583
- "missing-glyph"
30584
- ]);
30585
- /**
30586
- * _isBasicCustomElement
30587
- * checks if at least one dash is included in tagName, and it's not the first char
30588
- * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
30589
- *
30590
- * @param tagName name of the tag of the node to sanitize
30591
- * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
30592
- */
30593
- const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
30594
- return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
30595
- };
30596
- /**
30597
- * Wrap an attribute value in the matching Trusted Types object when
30598
- * the active policy requires it. Namespaced attributes pass through
30599
- * unchanged (no TT support yet, see
30600
- * https://bugs.chromium.org/p/chromium/issues/detail?id=1305293).
30601
- *
30602
- * @param lcTag lowercase tag name of the containing element
30603
- * @param lcName lowercase attribute name
30604
- * @param namespaceURI the attribute's namespace, if any
30605
- * @param value the attribute value to wrap
30606
- * @return the value, wrapped when Trusted Types demand it
30607
- */
30608
- const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value) {
30609
- if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) switch (trustedTypes.getAttributeType(lcTag, lcName)) {
30610
- case "TrustedHTML": return _createTrustedHTML(value);
30611
- case "TrustedScriptURL": return _createTrustedScriptURL(value);
30612
- }
30613
- return value;
30614
- };
30615
- /**
30616
- * Write a modified attribute value back onto the element. On
30617
- * success, re-probe for clobbering introduced by the new value and
30618
- * remove the element when found; otherwise, when this writeback is the
30619
- * recreate half of the SANITIZE_NAMED_PROPS remove-and-recreate, pop the
30620
- * removal entry that path recorded so it does not show as removed. On
30621
- * failure, remove the attribute instead.
30622
- *
30623
- * Returns true only on a clean write (the value was set and the new value
30624
- * introduced no clobbering). The caller uses that, together with its own
30625
- * knowledge of whether this attribute pushed a DOMPurify.removed record, to
30626
- * decide whether to pop that record. The pop must happen ONLY for the
30627
- * named-prop remove-and-recreate; popping on any other value change (trim,
30628
- * template scrubbing, Trusted Types) would consume an unrelated _forceRemove
30629
- * subtree-cleanup record and let that detached subtree keep a live event
30630
- * handler through the IN_PLACE neutralization pass (SO-001).
30631
- *
30632
- * @param currentNode the element carrying the attribute
30633
- * @param name the attribute name as present on the element
30634
- * @param namespaceURI the attribute's namespace, if any
30635
- * @param value the new attribute value
30636
- * @return true if the value was written without introducing clobbering
30637
- */
30638
- const _setAttributeValue = function _setAttributeValue(currentNode, name, namespaceURI, value) {
30639
- try {
30640
- if (namespaceURI) currentNode.setAttributeNS(namespaceURI, name, value);
30641
- else currentNode.setAttribute(name, value);
30642
- if (_isClobbered(currentNode)) {
30643
- _forceRemove(currentNode);
30644
- return false;
30645
- }
30646
- return true;
30647
- } catch (_) {
30648
- _removeAttribute(name, currentNode);
30649
- return false;
30650
- }
30651
- };
30652
- /**
30653
- * _isUnsafeAttributeValue
30654
- *
30655
- * Value-based attribute checks that the attribute walk applies before any
30656
- * hook can force-keep an attribute, shared with the public
30657
- * isValidAttribute() so that it never approves a value sanitize() would
30658
- * strip.
30659
- *
30660
- * @param name the attribute name as found on the node (case preserved)
30661
- * @param value the attribute value
30662
- * @returns true if the attribute must be removed because of its value
30663
- */
30664
- const _isUnsafeAttributeValue = function _isUnsafeAttributeValue(name, value) {
30665
- if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) return true;
30666
- return stringToLowerCase(name) === "attributename" && stringMatch(value, "href") !== null;
30667
- };
30668
- /**
30669
- * _sanitizeAttributes
30670
- *
30671
- * @protect attributes
30672
- * @protect nodeName
30673
- * @protect removeAttribute
30674
- * @protect setAttribute
30675
- *
30676
- * @param currentNode to sanitize
30677
- * @param root the current walk root
30678
- */
30679
- const _sanitizeAttributes = function _sanitizeAttributes(currentNode, root) {
30680
- _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
30681
- if (_handleHookDetachedNode(currentNode, root)) return;
30682
- const attributes = currentNode.attributes;
30683
- if (!attributes || _isClobbered(currentNode)) return;
30684
- ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
30685
- const hookEvent = {
30686
- attrName: "",
30687
- attrValue: "",
30688
- keepAttr: true,
30689
- allowedAttributes: ALLOWED_ATTR,
30690
- forceKeepAttr: void 0
30691
- };
30692
- let l = attributes.length;
30693
- const lcTag = transformCaseFunc(currentNode.nodeName);
30694
- while (l--) {
30695
- const attr = attributes[l];
30696
- const name = attr.name, namespaceURI = attr.namespaceURI, attrValue = attr.value;
30697
- const lcName = transformCaseFunc(name);
30698
- const initValue = attrValue;
30699
- let value = name === "value" ? initValue : stringTrim(initValue);
30700
- let recreatedNamedProp = false;
30701
- hookEvent.attrName = lcName;
30702
- hookEvent.attrValue = value;
30703
- hookEvent.keepAttr = true;
30704
- hookEvent.forceKeepAttr = void 0;
30705
- _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
30706
- value = hookEvent.attrValue;
30707
- if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
30708
- _removeAttribute(name, currentNode, attr);
30709
- value = SANITIZE_NAMED_PROPS_PREFIX + value;
30710
- recreatedNamedProp = true;
30711
- }
30712
- if (_isUnsafeAttributeValue(name, value)) {
30713
- _removeAttribute(name, currentNode, attr);
30714
- continue;
30715
- }
30716
- if (hookEvent.forceKeepAttr) continue;
30717
- if (!hookEvent.keepAttr) {
30718
- _removeAttribute(name, currentNode, attr);
30719
- continue;
30720
- }
30721
- if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
30722
- _removeAttribute(name, currentNode, attr);
30723
- continue;
30724
- }
30725
- if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value);
30726
- if (!_isValidAttribute(lcTag, lcName, value)) {
30727
- _removeAttribute(name, currentNode, attr);
30728
- continue;
30729
- }
30730
- value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
30731
- if (value !== initValue) {
30732
- if (_setAttributeValue(currentNode, name, namespaceURI, value) && recreatedNamedProp) arrayPop(DOMPurify.removed);
30733
- }
30734
- }
30735
- _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
30736
- _handleHookDetachedNode(currentNode, root);
30737
- };
30738
- /**
30739
- * _sanitizeShadowDOM
30740
- *
30741
- * @param fragment to iterate over recursively
30742
- */
30743
- const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
30744
- let shadowNode = null;
30745
- const shadowIterator = _createNodeIterator(fragment);
30746
- _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
30747
- while (shadowNode = shadowIterator.nextNode()) {
30748
- _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
30749
- _sanitizeElements(shadowNode, fragment);
30750
- _sanitizeAttributes(shadowNode, fragment);
30751
- if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content);
30752
- if (_readNodeType(shadowNode) === NODE_TYPE.element) {
30753
- const innerSr = getShadowRoot(shadowNode);
30754
- if (_isDocumentFragment(innerSr)) {
30755
- _sanitizeAttachedShadowRoots(innerSr);
30756
- _sanitizeShadowDOM2(innerSr);
30757
- }
30758
- }
30759
- }
30760
- if (SAFE_FOR_TEMPLATES) _scrubOwnCharacterData(fragment);
30761
- _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
30762
- };
30763
- /**
30764
- * Sanitizes every attached shadow root under `root`, since the node
30765
- * iterator does not enter shadow trees. Needed for IN_PLACE input and for
30766
- * DOM input whose clonable shadow roots were copied by importNode().
30767
- *
30768
- * @param root the subtree root to walk for attached shadow roots
30769
- */
30770
- const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots(root) {
30771
- const stack = [{
30772
- node: root,
30773
- shadow: null
30774
- }];
30775
- while (stack.length > 0) {
30776
- const item = stack.pop();
30777
- if (item.shadow) {
30778
- _sanitizeShadowDOM2(item.shadow);
30779
- continue;
30780
- }
30781
- const node = item.node;
30782
- const isElement = _readNodeType(node) === NODE_TYPE.element;
30783
- const childNodes = getChildNodes(node);
30784
- if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({
30785
- node: childNodes[i],
30786
- shadow: null
30787
- });
30788
- if (isElement) {
30789
- const rootName = getNodeName ? getNodeName(node) : null;
30790
- if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") {
30791
- const content = node.content;
30792
- if (_isDocumentFragment(content)) stack.push({
30793
- node: content,
30794
- shadow: null
30795
- });
30796
- }
30797
- }
30798
- if (isElement) {
30799
- const sr = getShadowRoot(node);
30800
- if (_isDocumentFragment(sr)) stack.push({
30801
- node: null,
30802
- shadow: sr
30803
- }, {
30804
- node: sr,
30805
- shadow: null
30806
- });
30807
- }
30808
- }
30809
- };
30810
- DOMPurify.sanitize = function(dirty) {
30811
- let cfg = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
30812
- let body = null;
30813
- let importedNode = null;
30814
- let currentNode = null;
30815
- let returnNode = null;
30816
- IS_EMPTY_INPUT = !dirty;
30817
- if (IS_EMPTY_INPUT) dirty = "<!-->";
30818
- if (typeof dirty !== "string" && !_isNode(dirty)) {
30819
- dirty = stringifyValue(dirty);
30820
- if (typeof dirty !== "string") throw typeErrorCreate("dirty is not a string, aborting");
30821
- }
30822
- if (!DOMPurify.isSupported) return dirty;
30823
- if (SET_CONFIG) {
30824
- ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS;
30825
- ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR;
30826
- } else _parseConfig(cfg);
30827
- if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) ALLOWED_TAGS = clone(ALLOWED_TAGS);
30828
- if (hooks.uponSanitizeAttribute.length > 0) ALLOWED_ATTR = clone(ALLOWED_ATTR);
30829
- DOMPurify.removed = [];
30830
- const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
30831
- let inPlaceNodes = [];
30832
- const outerVisited = IN_PLACE_VISITED;
30833
- if (inPlace) {
30834
- _neutralizePatchLinkage(dirty);
30835
- const nn = _readNodeName(dirty);
30836
- if (typeof nn === "string") {
30837
- const tagName = transformCaseFunc(nn);
30838
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
30839
- _neutralizeRoot(dirty);
30840
- throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place");
30841
- }
30842
- }
30843
- if (_isClobbered(dirty)) {
30844
- _neutralizeRoot(dirty);
30845
- throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place");
30846
- }
30847
- inPlaceNodes = _collectLiveNodes(dirty);
30848
- IN_PLACE_VISITED = setCreate();
30849
- } else if (_isNode(dirty)) {
30850
- body = _initDocument("<!---->");
30851
- importedNode = body.ownerDocument.importNode(dirty, true);
30852
- if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") body = importedNode;
30853
- else if (importedNode.nodeName === "HTML") body = importedNode;
30854
- else body.appendChild(importedNode);
30855
- _sanitizeAttachedShadowRoots(body);
30856
- } else {
30857
- if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
30858
- body = _initDocument(dirty);
30859
- if (!body) return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : "";
30860
- }
30861
- if (body && FORCE_BODY) _forceRemove(body.firstChild);
30862
- const walkRoot = inPlace ? dirty : body;
30863
- try {
30864
- if (inPlace) _sanitizeAttachedShadowRoots(dirty);
30865
- const nodeIterator = _createNodeIterator(walkRoot);
30866
- while (currentNode = nodeIterator.nextNode()) {
30867
- _sanitizeElements(currentNode, walkRoot);
30868
- _sanitizeAttributes(currentNode, walkRoot);
30869
- if (_isDocumentFragment(currentNode.content)) _sanitizeShadowDOM2(currentNode.content);
30870
- }
30871
- if (inPlace) _sanitizeUnvisitedNodes(dirty, inPlaceNodes);
30872
- } catch (error) {
30873
- if (inPlace) {
30874
- _neutralizeRoot(dirty);
30875
- _neutralizeDiscarded(dirty, inPlaceNodes);
30876
- }
30877
- throw error;
30878
- } finally {
30879
- IN_PLACE_VISITED = outerVisited;
30880
- }
30881
- if (inPlace) {
30882
- if (_neutralizeDiscarded(dirty, inPlaceNodes)) throw typeErrorCreate("a node selected for removal could not be safely returned; refusing to sanitize in place");
30883
- if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(dirty);
30884
- return dirty;
30885
- }
30886
- if (RETURN_DOM) {
30887
- if (SAFE_FOR_TEMPLATES) _scrubTemplateExpressions2(body);
30888
- if (RETURN_DOM_FRAGMENT) {
30889
- returnNode = createDocumentFragment.call(body.ownerDocument);
30890
- while (body.firstChild) returnNode.appendChild(body.firstChild);
30891
- } else returnNode = body;
30892
- if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) returnNode = importNode.call(originalDocument, returnNode, true);
30893
- return returnNode;
30894
- }
30895
- let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
30896
- if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML;
30897
- if (SAFE_FOR_TEMPLATES) serializedHTML = _stripTemplateExpressions(serializedHTML);
30898
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
30899
- };
30900
- DOMPurify.setConfig = function() {
30901
- let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
30902
- _parseConfig(cfg);
30903
- SET_CONFIG = true;
30904
- SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS;
30905
- SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR;
30906
- };
30907
- DOMPurify.clearConfig = function() {
30908
- CONFIG = null;
30909
- SET_CONFIG = false;
30910
- SET_CONFIG_ALLOWED_TAGS = null;
30911
- SET_CONFIG_ALLOWED_ATTR = null;
30912
- trustedTypesPolicy = defaultTrustedTypesPolicy;
30913
- emptyHTML = "";
30914
- };
30915
- DOMPurify.isValidAttribute = function(tag, attr, value) {
30916
- if (!CONFIG) _parseConfig({});
30917
- const lcTag = transformCaseFunc(tag);
30918
- const lcName = transformCaseFunc(attr);
30919
- if (typeof value === "string" && (_isUnsafeAttributeValue(attr, value) || !ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value))) return false;
30920
- return _isValidAttribute(lcTag, lcName, value);
30921
- };
30922
- DOMPurify.addHook = function(entryPoint, hookFunction) {
30923
- if (typeof hookFunction !== "function") return;
30924
- if (!objectHasOwnProperty(hooks, entryPoint)) return;
30925
- arrayPush(hooks[entryPoint], hookFunction);
30926
- };
30927
- DOMPurify.removeHook = function(entryPoint, hookFunction) {
30928
- if (!objectHasOwnProperty(hooks, entryPoint)) return;
30929
- if (hookFunction !== void 0) {
30930
- const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
30931
- return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0];
30932
- }
30933
- return arrayPop(hooks[entryPoint]);
30934
- };
30935
- DOMPurify.removeHooks = function(entryPoint) {
30936
- if (!objectHasOwnProperty(hooks, entryPoint)) return;
30937
- hooks[entryPoint] = [];
30938
- };
30939
- DOMPurify.removeAllHooks = function() {
30940
- hooks = _createHooksMap();
30941
- };
30942
- return DOMPurify;
30943
- }
30944
- var purify_default = createDOMPurify();
30945
- //#endregion
30946
28407
  //#region src/types.ts
30947
28408
  /** Every failure InkKit reports. Hosts branch on `code`; `message` is for logs. When the failure
30948
28409
  * started elsewhere, such as in an adapter, the host clipboard or the renderer, `cause` holds the
@@ -30956,226 +28417,209 @@ var InkKitError = class extends Error {
30956
28417
  }
30957
28418
  };
30958
28419
  //#endregion
28420
+ //#region src/diagram-theme.ts
28421
+ var namespace = "--_inkkit-diagram-";
28422
+ var font = "Arial, sans-serif";
28423
+ var placement = 0;
28424
+ var colors$1 = {
28425
+ bg: "#ffffff",
28426
+ fg: "#1c1c1e",
28427
+ muted: "#636366",
28428
+ line: "#48484a",
28429
+ surface: "#f2f2f7",
28430
+ "surface-alt": "#e5e5ea",
28431
+ border: "#8e8e93",
28432
+ accent: "#a6d5ff"
28433
+ };
28434
+ var series = [
28435
+ "#0088ff",
28436
+ "#34c759",
28437
+ "#6155f5",
28438
+ "#ff8d28",
28439
+ "#ff383c",
28440
+ "#00c8b3",
28441
+ "#ffcc00",
28442
+ "#00c0e8"
28443
+ ];
28444
+ function captureDiagramTheme(root) {
28445
+ const doc = root?.ownerDocument ?? document;
28446
+ const card = doc.createElement("div");
28447
+ card.className = "inkkit-mermaid-preview";
28448
+ card.style.cssText = "position:fixed;left:0;top:0;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none;contain:strict;color-scheme:light";
28449
+ card.style.setProperty(namespace + "bg", "#ffffff");
28450
+ card.style.setProperty(namespace + "fg", "#1c1c1e");
28451
+ const fallback = { ...colors$1 };
28452
+ for (const [index, color] of series.entries()) fallback[`series-${index + 1}`] = `color-mix(in srgb, ${color} 35%, #ffffff)`;
28453
+ const probes = Object.entries(fallback).map(([key, value]) => {
28454
+ const probe = doc.createElement("span");
28455
+ probe.style.color = `var(${namespace}${key}, ${value})`;
28456
+ card.append(probe);
28457
+ return [key, probe];
28458
+ });
28459
+ (root ?? doc.body).append(card);
28460
+ try {
28461
+ const view = doc.defaultView;
28462
+ const theme = {
28463
+ [namespace + "font"]: font,
28464
+ [namespace + "font-mono"]: "monospace"
28465
+ };
28466
+ for (const [key, probe] of probes) theme[namespace + key] = view.getComputedStyle(probe).color;
28467
+ return theme;
28468
+ } finally {
28469
+ card.remove();
28470
+ }
28471
+ }
28472
+ function privateVariables(value) {
28473
+ return value.replace(/--pele-([a-z0-9-]+)/g, (_match, name) => {
28474
+ const index = /^series-(\d+)$/.exec(name);
28475
+ return namespace + (index ? `series-${(Number(index[1]) - 1) % 8 + 1}` : name);
28476
+ });
28477
+ }
28478
+ function resolveVariables(value, variables, depth = 0) {
28479
+ if (depth > 20) throw new Error("The diagram theme contains a variable cycle.");
28480
+ let result = "";
28481
+ let cursor = 0;
28482
+ for (;;) {
28483
+ const start = value.indexOf("var(", cursor);
28484
+ if (start === -1) return result + value.slice(cursor);
28485
+ result += value.slice(cursor, start);
28486
+ let level = 1;
28487
+ let end = start + 4;
28488
+ let comma = -1;
28489
+ for (; end < value.length && level; end++) {
28490
+ if (value[end] === "(") level++;
28491
+ if (value[end] === ")") level--;
28492
+ if (value[end] === "," && level === 1 && comma === -1) comma = end;
28493
+ }
28494
+ if (level) throw new Error("The diagram theme contains an incomplete variable.");
28495
+ const name = value.slice(start + 4, comma < 0 ? end - 1 : comma).trim();
28496
+ const fallback = comma < 0 ? "" : value.slice(comma + 1, end - 1).trim();
28497
+ result += resolveVariables(variables[name] || fallback, variables, depth + 1);
28498
+ cursor = end;
28499
+ }
28500
+ }
28501
+ function rebaseIDs(svg) {
28502
+ const prefix = `inkkit-diagram-placement-${++placement}-`;
28503
+ const ids = /* @__PURE__ */ new Map();
28504
+ for (const element of [svg, ...svg.querySelectorAll("[id]")]) {
28505
+ const id = element.getAttribute("id");
28506
+ if (!id) continue;
28507
+ const replacement = prefix + ids.size;
28508
+ ids.set(id, replacement);
28509
+ element.setAttribute("id", replacement);
28510
+ }
28511
+ const references = (value) => value.replace(/url\(\s*(['"]?)#([^\s)'";]+)\1\s*\)/g, (original, _quote, id) => ids.has(id) ? `url(#${ids.get(id)})` : original);
28512
+ for (const element of [svg, ...svg.querySelectorAll("*")]) {
28513
+ for (const attribute of [...element.attributes]) {
28514
+ if (attribute.name === "id") continue;
28515
+ let value = references(attribute.value);
28516
+ if (/^(?:href|xlink:href)$/.test(attribute.name) && value.startsWith("#")) value = "#" + (ids.get(value.slice(1)) ?? value.slice(1));
28517
+ if (/^aria-(?:labelledby|describedby)$/.test(attribute.name)) value = value.split(/\s+/).map((id) => ids.get(id) ?? id).join(" ");
28518
+ element.setAttribute(attribute.name, value);
28519
+ }
28520
+ if (element.tagName.toLowerCase() === "style") {
28521
+ let text = references(element.textContent ?? "");
28522
+ for (const [id, replacement] of ids) {
28523
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28524
+ text = text.replace(new RegExp(`#${escaped}(?![\\w-])`, "g"), "#" + replacement);
28525
+ }
28526
+ element.textContent = text;
28527
+ }
28528
+ }
28529
+ }
28530
+ /** Apply presentation to cached geometry without running the layout again. */
28531
+ function themedDiagram(source, root, portable = false, capturedTheme) {
28532
+ const template = (root?.ownerDocument ?? document).createElement("template");
28533
+ template.innerHTML = source;
28534
+ const svg = template.content.querySelector("svg");
28535
+ if (!svg) throw new Error("The renderer did not produce a diagram.");
28536
+ rebaseIDs(svg);
28537
+ for (const element of [svg, ...svg.querySelectorAll("*")]) {
28538
+ for (const attribute of [...element.attributes]) element.setAttribute(attribute.name, privateVariables(attribute.value));
28539
+ if (element.tagName.toLowerCase() === "style") element.textContent = privateVariables(element.textContent ?? "");
28540
+ }
28541
+ for (const label of svg.querySelectorAll(".pele-slice-labels text")) {
28542
+ label.setAttribute("fill", `var(${namespace}fg, #1c1c1e)`);
28543
+ label.setAttribute("stroke", `var(${namespace}bg, #ffffff)`);
28544
+ label.setAttribute("stroke-width", "3");
28545
+ label.setAttribute("stroke-linejoin", "round");
28546
+ label.setAttribute("paint-order", "stroke");
28547
+ }
28548
+ if (portable) {
28549
+ const variables = { ...capturedTheme ?? captureDiagramTheme(root) };
28550
+ for (const name of Array.from(svg.style)) if (name.startsWith("--")) variables[name] = svg.style.getPropertyValue(name);
28551
+ for (const element of [svg, ...svg.querySelectorAll("*")]) {
28552
+ for (const attribute of [...element.attributes]) element.setAttribute(attribute.name, resolveVariables(attribute.value, variables));
28553
+ if (element.tagName.toLowerCase() === "style") element.textContent = resolveVariables(element.textContent ?? "", variables);
28554
+ if ("style" in element) {
28555
+ const style = element.style;
28556
+ for (const name of Array.from(style)) if (name.startsWith("--")) style.removeProperty(name);
28557
+ }
28558
+ }
28559
+ svg.style.fontFamily = font;
28560
+ svg.style.background = "#ffffff";
28561
+ }
28562
+ return svg.outerHTML;
28563
+ }
28564
+ //#endregion
30959
28565
  //#region src/mermaid.ts
30960
28566
  function isMermaid(node) {
30961
28567
  return node.type.name === "code_block" && node.attrs.language === "mermaid";
30962
28568
  }
30963
- var refusal = "HTML, styles, actions, resources and diagram configuration are disabled. The source is retained.";
30964
- var cssResource = /url\s*\(\s*[^#\s]|(?:image-set|cross-fade|image|element|src)\s*\(/i;
30965
- var annotationName = String.raw`\w(?:[\w -]*\w)?`;
30966
- var classAnnotation = new RegExp(String.raw`(?<=^[ \t]*(?:class[ \t]+[^\s<>"]+(?:\["[^"\n<>]*"\])?[ \t]+)?)<<(${annotationName})>>(?=[ \t{]|$)`, "gm");
30967
- var stateAnnotation = /(?<=^[ \t]*state[ \t]+[^\s<>"]+[ \t]+)<<(fork|join|choice)>>(?=[ \t]*$)/gim;
30968
- var stateBrackets = /^[ \t]*state[ \t].*\[\[(fork|join|choice)\]\]/gim;
30969
- function annotations(source) {
30970
- const header = /^\s*(?:%%[^\n]*\n\s*)*(classDiagram|stateDiagram)/.exec(source)?.[1];
30971
- const pattern = header === "classDiagram" ? classAnnotation : header === "stateDiagram" ? stateAnnotation : void 0;
30972
- if (!pattern) return {
30973
- names: [],
30974
- rest: source
30975
- };
30976
- const names = [];
30977
- const rest = source.replace(pattern, (_, name) => {
30978
- names.push(header === "stateDiagram" ? name.toLowerCase() : name);
30979
- return "";
30980
- });
30981
- if (header === "classDiagram" && /<<\s*%%/.test(rest)) throw new Error(refusal);
30982
- return {
30983
- names,
30984
- rest
30985
- };
28569
+ var renderer;
28570
+ function registerDiagram(render) {
28571
+ renderer = render;
30986
28572
  }
30987
- function validateDiagram(source) {
30988
- if (source.length > 3e4) throw new Error("The diagram exceeds the 30,000 character rendering limit.");
30989
- if (!/^\s*(?:%%[^\n]*\n\s*)*(?:flowchart|graph|sequenceDiagram|classDiagram|stateDiagram(?:-v2)?|erDiagram|pie)\b/.test(source)) throw new Error("This diagram type is not supported. The source is retained.");
30990
- const found = annotations(source);
30991
- if (/%%\{|^[^\S\n\r\u2028\u2029]*---|<\s*[a-z!/?]|&(?:#\w+|[a-z]+);|@\{|\$\$|(?:https?|data|file|javascript|vbscript|blob):|\/\/|url\s*\(|image-set\s*\(|cross-fade\s*\(|@import|\\/im.test(found.rest)) throw new Error(refusal);
30992
- return found;
28573
+ var diagramsAvailable = () => renderer !== void 0;
28574
+ async function renderDiagram(source) {
28575
+ if (!renderer) throw new Error("Diagram rendering is not included in this build. The source is retained.");
28576
+ return renderer(source);
30993
28577
  }
30994
- var entries = (value) => value instanceof Map ? [...value.values()] : Array.isArray(value) ? value : [];
30995
- var filled = (value) => value instanceof Map ? value.size > 0 : Array.isArray(value) ? value.length > 0 : typeof value === "object" && value !== null ? Object.keys(value).length > 0 : Boolean(value);
30996
- var clickable = (classes) => (Array.isArray(classes) ? classes : String(classes ?? "").split(/\s+/)).map(String).includes("clickable");
30997
- var unchecked = () => /* @__PURE__ */ new Error("The diagram could not be checked. The source is retained.");
30998
- function walk(node, visit, seen = /* @__PURE__ */ new Set()) {
30999
- if (typeof node !== "object" || node === null || seen.has(node)) return false;
31000
- seen.add(node);
31001
- if (visit(node)) return true;
31002
- return Object.values(node).some((value) => walk(value, visit, seen));
31003
- }
31004
- var statementIn = (node, kinds) => walk(node, (entry) => kinds.includes(String(entry.stmt)));
31005
- function refuseDirectives({ type, db }) {
31006
- const store = db;
31007
- const field = (name) => {
31008
- if (!(name in store)) throw unchecked();
31009
- return store[name];
31010
- };
31011
- const read = (name) => {
31012
- const accessor = field(name);
31013
- if (typeof accessor !== "function") throw unchecked();
31014
- return accessor.call(db);
31015
- };
31016
- let found;
31017
- switch (type) {
31018
- case "flowchart-v2": {
31019
- const edges = read("getEdges");
31020
- found = filled(read("getClasses")) || filled(field("tooltips")) || filled(edges.defaultStyle) || edges.defaultInterpolate !== void 0 || entries(read("getVertices")).some((vertex) => filled(vertex.styles) || Boolean(vertex.link || vertex.haveCallback || vertex.icon || vertex.img) || clickable(vertex.classes)) || entries(edges).some((edge) => filled(edge.style) || edge.interpolate !== void 0 || clickable(edge.classes)) || entries(read("getSubGraphs")).some((graph) => clickable(graph.classes));
31021
- break;
31022
- }
31023
- case "stateDiagram":
31024
- found = statementIn(field("rootDoc"), [
31025
- "style",
31026
- "classDef",
31027
- "click"
31028
- ]) || filled(read("getClasses")) || filled(read("getLinks")) || entries(read("getStates")).some((state) => filled(state.styles) || filled(state.textStyles));
31029
- break;
31030
- case "classDiagram":
31031
- found = filled(field("styleClasses")) || entries(read("getClasses")).some((node) => filled(node.styles) || Boolean(node.link || node.haveCallback || node.tooltip) || clickable(node.cssClasses));
31032
- break;
31033
- case "er":
31034
- found = filled(read("getClasses")) || entries(read("getEntities")).some((entity) => filled(entity.cssStyles)) || entries(read("getSubGraphs")).some((graph) => filled(graph.cssStyles));
31035
- break;
31036
- case "sequence":
31037
- found = entries(read("getActors")).some((actor) => filled(actor.links) || filled(actor.properties));
31038
- break;
31039
- case "pie":
31040
- found = false;
31041
- break;
31042
- default: throw new Error("This diagram type is not supported. The source is retained.");
31043
- }
31044
- if (found) throw new Error(refusal);
31045
- }
31046
- function refuseStrayAnnotations({ type, db }, source, names) {
31047
- if (names.length === 0) return;
31048
- const store = db;
31049
- const expected = [...names];
31050
- const parsed = [];
31051
- if (type === "classDiagram") {
31052
- if (typeof store.getClasses !== "function") throw unchecked();
31053
- for (const node of entries(store.getClasses.call(db))) {
31054
- if (!Array.isArray(node.annotations)) throw unchecked();
31055
- parsed.push(...node.annotations.map(String));
31056
- }
31057
- } else if (type === "stateDiagram") {
31058
- if (!("rootDoc" in store)) throw unchecked();
31059
- walk(store.rootDoc, ({ stmt, type }) => {
31060
- if (stmt === "state" && /^(?:fork|join|choice)$/.test(String(type))) parsed.push(String(type));
28578
+ /** Geometry belongs to one document, independently of its visible previews. */
28579
+ var DiagramStore = class {
28580
+ entries = /* @__PURE__ */ new Map();
28581
+ generation = 0;
28582
+ destroyed = false;
28583
+ get epoch() {
28584
+ return this.generation;
28585
+ }
28586
+ render(source) {
28587
+ if (this.destroyed) return Promise.reject(/* @__PURE__ */ new Error("The diagram document was destroyed."));
28588
+ const key = source.replace(/\r\n?/g, "\n");
28589
+ const previous = this.entries.get(key);
28590
+ if (previous) return previous;
28591
+ const generation = this.generation;
28592
+ const pending = Promise.resolve().then(() => {
28593
+ if (this.destroyed || generation !== this.generation || this.entries.get(key) !== pending) throw new Error("The diagram is no longer current.");
28594
+ return renderDiagram(key);
28595
+ }).then((svg) => {
28596
+ if (this.destroyed || generation !== this.generation || this.entries.get(key) !== pending) throw new Error("The diagram is no longer current.");
28597
+ return svg;
31061
28598
  });
31062
- for (const [, name] of source.matchAll(stateBrackets)) expected.push(name.toLowerCase());
31063
- } else throw new Error(refusal);
31064
- if (parsed.sort().join("\n") !== expected.sort().join("\n")) throw new Error(refusal);
31065
- }
31066
- var loadMermaid;
31067
- function registerMermaid(load) {
31068
- loadMermaid = load;
31069
- }
31070
- var diagramsAvailable = () => loadMermaid !== void 0;
31071
- var sequence$1 = 0;
31072
- var queue = Promise.resolve();
31073
- var cache = /* @__PURE__ */ new Map();
31074
- function safeDiagramSVG(svg) {
31075
- const clean = purify_default.sanitize(svg, {
31076
- USE_PROFILES: {
31077
- svg: true,
31078
- svgFilters: true
31079
- },
31080
- FORBID_TAGS: [
31081
- "foreignObject",
31082
- "image",
31083
- "a",
31084
- "script",
31085
- "animate",
31086
- "set"
31087
- ],
31088
- FORBID_ATTR: ["href", "xlink:href"]
31089
- });
31090
- const template = document.createElement("template");
31091
- template.innerHTML = clean;
31092
- const root = template.content.querySelector("svg");
31093
- if (!root) throw new Error("The renderer did not produce a diagram.");
31094
- for (const element of [root, ...root.querySelectorAll("*")]) {
31095
- for (const attribute of [...element.attributes]) if (/^on/i.test(attribute.name) || /(?:https?|data|file|javascript|blob):|@import|\\/i.test(attribute.value) || cssResource.test(attribute.value)) element.removeAttribute(attribute.name);
31096
- if (element.tagName.toLowerCase() === "style" && (/@import|(?:https?|data|file):|\\/i.test(element.textContent ?? "") || cssResource.test(element.textContent ?? ""))) element.remove();
31097
- }
31098
- root.setAttribute("xmlns", "http://www.w3.org/2000/svg");
31099
- return root.outerHTML;
31100
- }
31101
- function renderDiagram(source) {
31102
- const load = loadMermaid;
31103
- if (!load) return Promise.reject(/* @__PURE__ */ new Error("Diagram rendering is not included in this build. The source is retained."));
31104
- let names;
31105
- try {
31106
- names = validateDiagram(source).names;
31107
- } catch (error) {
31108
- return Promise.reject(error);
31109
- }
31110
- const previous = cache.get(source);
31111
- if (previous) return previous;
31112
- const rendered = queue.then(async () => {
31113
- const mermaid = await load();
31114
- mermaid.initialize({
31115
- startOnLoad: false,
31116
- securityLevel: "strict",
31117
- htmlLabels: false,
31118
- suppressErrorRendering: true,
31119
- fontFamily: "Arial, sans-serif",
31120
- altFontFamily: "Arial, sans-serif",
31121
- layout: "dagre",
31122
- look: "classic",
31123
- theme: "default",
31124
- maxTextSize: 3e4,
31125
- maxEdges: 500,
31126
- flowchart: { htmlLabels: false },
31127
- sequence: {
31128
- actorFontFamily: "Arial, sans-serif",
31129
- noteFontFamily: "Arial, sans-serif",
31130
- messageFontFamily: "Arial, sans-serif"
31131
- },
31132
- secure: [
31133
- "securityLevel",
31134
- "htmlLabels",
31135
- "theme",
31136
- "themeCSS",
31137
- "themeVariables",
31138
- "fontFamily",
31139
- "dompurifyConfig",
31140
- "flowchart",
31141
- "startOnLoad",
31142
- "maxTextSize",
31143
- "maxEdges",
31144
- "secure",
31145
- "altFontFamily",
31146
- "layout",
31147
- "look",
31148
- "sequence",
31149
- "class",
31150
- "state",
31151
- "er",
31152
- "pie",
31153
- "suppressErrorRendering"
31154
- ]
28599
+ this.entries.set(key, pending);
28600
+ pending.catch(() => {
28601
+ if (this.entries.get(key) === pending) this.entries.delete(key);
31155
28602
  });
31156
- const parsed = await mermaid.mermaidAPI.getDiagramFromText(source);
31157
- refuseDirectives(parsed);
31158
- refuseStrayAnnotations(parsed, source, names);
31159
- const holder = document.createElement("div");
31160
- holder.style.cssText = "position:fixed;left:-100000px;top:0;width:1200px;pointer-events:none";
31161
- holder.setAttribute("aria-hidden", "true");
31162
- document.body.append(holder);
31163
- try {
31164
- return safeDiagramSVG((await mermaid.render(`inkkitDiagram${++sequence$1}`, source, holder)).svg);
31165
- } finally {
31166
- holder.remove();
31167
- }
31168
- });
31169
- queue = rendered.catch(() => void 0);
31170
- cache.set(source, rendered);
31171
- rendered.catch(() => {
31172
- if (cache.get(source) === rendered) cache.delete(source);
31173
- });
31174
- if (cache.size > 64) cache.delete(cache.keys().next().value);
31175
- return rendered;
31176
- }
31177
- async function diagramImage(source) {
31178
- const svg = await renderDiagram(source);
28603
+ return pending;
28604
+ }
28605
+ reconcile(doc) {
28606
+ const sources = /* @__PURE__ */ new Set();
28607
+ doc.descendants((node) => {
28608
+ if (isMermaid(node)) sources.add(node.textContent.replace(/\r\n?/g, "\n"));
28609
+ });
28610
+ for (const key of this.entries.keys()) if (!sources.has(key)) this.entries.delete(key);
28611
+ }
28612
+ clear() {
28613
+ this.generation++;
28614
+ this.entries.clear();
28615
+ }
28616
+ destroy() {
28617
+ this.destroyed = true;
28618
+ this.clear();
28619
+ }
28620
+ };
28621
+ async function diagramImage(source, store, root, theme) {
28622
+ const svg = themedDiagram(await (store ? store.render(source) : renderDiagram(source)), root, true, theme);
31179
28623
  const parsed = new DOMParser().parseFromString(svg, "image/svg+xml").documentElement;
31180
28624
  const bounds = (parsed.getAttribute("viewBox") ?? "").split(/[\s,]+/).map(Number);
31181
28625
  const width = bounds[2] || Number.parseFloat(parsed.getAttribute("width") ?? "");
@@ -31211,49 +28655,111 @@ async function diagramImage(source) {
31211
28655
  URL.revokeObjectURL(url);
31212
28656
  }
31213
28657
  }
31214
- function mermaidPreview(onError) {
31215
- return $prose((ctx) => new Plugin({
31216
- key: new PluginKey("mermaidPreview"),
31217
- props: { decorations(state) {
31218
- const widgets = [];
31219
- state.doc.descendants((node, pos) => {
31220
- if (!isMermaid(node)) return true;
31221
- const source = node.textContent;
31222
- widgets.push(Decoration.widget(pos + node.nodeSize, () => {
31223
- const preview = document.createElement("div");
31224
- preview.className = "inkkit-mermaid-preview";
31225
- preview.contentEditable = "false";
31226
- preview.textContent = editorLabels(ctx).diagramRendering;
31227
- preview.setAttribute("role", "status");
31228
- preview.setAttribute("aria-live", "polite");
31229
- let active = true;
31230
- preview.cancel = () => {
31231
- active = false;
31232
- };
31233
- renderDiagram(source).then((svg) => {
31234
- if (active) {
31235
- preview.innerHTML = svg;
31236
- preview.dataset.state = "ready";
31237
- }
31238
- }, (error) => {
31239
- if (!active) return;
31240
- const message = error instanceof Error ? error.message : "The diagram could not be rendered.";
31241
- preview.textContent = `${editorLabels(ctx).diagramUnavailable} ${message}`;
31242
- preview.dataset.state = "error";
31243
- onError(new InkKitError("diagram-unavailable", message, { cause: error }));
31244
- });
31245
- return preview;
31246
- }, {
31247
- key: `mermaid:${source}`,
31248
- side: -1,
31249
- ignoreSelection: true,
31250
- destroy: (node) => node.cancel?.()
31251
- }));
31252
- return false;
28658
+ function mermaidPreview(store, onError) {
28659
+ return $prose((ctx) => {
28660
+ const jobs = /* @__PURE__ */ new Set();
28661
+ let timer;
28662
+ let stopped = false;
28663
+ let viewGeneration = 0;
28664
+ const schedule = () => {
28665
+ if (!stopped && timer === void 0) timer = setTimeout(run, 0);
28666
+ };
28667
+ const run = () => {
28668
+ timer = void 0;
28669
+ if (stopped || document.visibilityState === "hidden") return;
28670
+ const job = [...jobs].find((item) => item.active && item.visible && !item.running && item.element.isConnected);
28671
+ if (!job) return;
28672
+ job.running = true;
28673
+ store.render(job.source).then((svg) => {
28674
+ if (!job.active || stopped) return;
28675
+ job.element.innerHTML = themedDiagram(svg);
28676
+ job.element.dataset.state = "ready";
28677
+ }, (error) => {
28678
+ if (!job.active || stopped) return;
28679
+ const message = error instanceof Error ? error.message : "The diagram could not be rendered.";
28680
+ job.element.textContent = `${editorLabels(ctx).diagramUnavailable} ${message}`;
28681
+ job.element.dataset.state = "error";
28682
+ onError(new InkKitError("diagram-unavailable", message, { cause: error }));
28683
+ }).finally(() => {
28684
+ jobs.delete(job);
28685
+ observer?.unobserve(job.element);
28686
+ schedule();
31253
28687
  });
31254
- return DecorationSet.create(state.doc, widgets);
31255
- } }
31256
- }));
28688
+ };
28689
+ const observer = typeof IntersectionObserver === "undefined" ? void 0 : new IntersectionObserver((entries) => {
28690
+ for (const entry of entries) {
28691
+ const job = [...jobs].find((item) => item.element === entry.target);
28692
+ if (job) job.visible = entry.isIntersecting;
28693
+ }
28694
+ schedule();
28695
+ });
28696
+ return new Plugin({
28697
+ key: new PluginKey("mermaidPreview"),
28698
+ view: (view) => {
28699
+ const generation = ++viewGeneration;
28700
+ stopped = false;
28701
+ document.addEventListener("visibilitychange", schedule);
28702
+ store.reconcile(view.state.doc);
28703
+ schedule();
28704
+ return {
28705
+ update(view, previous) {
28706
+ if (view.state.doc !== previous.doc) store.reconcile(view.state.doc);
28707
+ schedule();
28708
+ },
28709
+ destroy() {
28710
+ stopped = true;
28711
+ if (timer !== void 0) clearTimeout(timer);
28712
+ timer = void 0;
28713
+ document.removeEventListener("visibilitychange", schedule);
28714
+ queueMicrotask(() => {
28715
+ if (generation !== viewGeneration || !stopped) return;
28716
+ observer?.disconnect();
28717
+ for (const job of jobs) job.active = false;
28718
+ jobs.clear();
28719
+ });
28720
+ }
28721
+ };
28722
+ },
28723
+ props: { decorations(state) {
28724
+ const widgets = [];
28725
+ state.doc.descendants((node, pos) => {
28726
+ if (!isMermaid(node)) return true;
28727
+ const source = node.textContent;
28728
+ widgets.push(Decoration.widget(pos + node.nodeSize, () => {
28729
+ const preview = document.createElement("div");
28730
+ preview.className = "inkkit-mermaid-preview";
28731
+ preview.contentEditable = "false";
28732
+ preview.textContent = editorLabels(ctx).diagramRendering;
28733
+ preview.setAttribute("role", "status");
28734
+ preview.setAttribute("aria-live", "polite");
28735
+ const job = {
28736
+ element: preview,
28737
+ source,
28738
+ active: true,
28739
+ visible: !observer,
28740
+ running: false
28741
+ };
28742
+ jobs.add(job);
28743
+ preview.cancel = () => {
28744
+ job.active = false;
28745
+ jobs.delete(job);
28746
+ observer?.unobserve(preview);
28747
+ };
28748
+ observer?.observe(preview);
28749
+ schedule();
28750
+ return preview;
28751
+ }, {
28752
+ key: `mermaid:${store.epoch}:${source}`,
28753
+ side: -1,
28754
+ ignoreSelection: true,
28755
+ destroy: (node) => node.cancel?.()
28756
+ }));
28757
+ return false;
28758
+ });
28759
+ return DecorationSet.create(state.doc, widgets);
28760
+ } }
28761
+ });
28762
+ });
31257
28763
  }
31258
28764
  //#endregion
31259
28765
  //#region src/bom.ts
@@ -49232,7 +46738,7 @@ var visibleClipboard = $prose((ctx) => new Plugin({
49232
46738
  }
49233
46739
  }));
49234
46740
  /** Export a frozen document fragment; presentation URLs never enter the clipboard. */
49235
- async function portableClipboard(content, schema, markdown, adapter, context, completeDiagrams, files, signal = new AbortController().signal, linkSchemes) {
46741
+ async function portableClipboard(content, schema, markdown, adapter, context, completeDiagrams, files, signal = new AbortController().signal, linkSchemes, diagramStore, diagramRoot) {
49236
46742
  signal.throwIfAborted();
49237
46743
  content = shareableFragment(content);
49238
46744
  const base = clipboardContent(content, schema, linkSchemes);
@@ -49304,6 +46810,7 @@ async function portableClipboard(content, schema, markdown, adapter, context, co
49304
46810
  };
49305
46811
  }
49306
46812
  }));
46813
+ const diagramTheme = captureDiagramTheme(diagramRoot);
49307
46814
  const diagrams = [];
49308
46815
  for (const code of container.querySelectorAll("pre[data-language=\"mermaid\"] > code")) {
49309
46816
  const source = code.textContent ?? "";
@@ -49311,7 +46818,7 @@ async function portableClipboard(content, schema, markdown, adapter, context, co
49311
46818
  const result = { source };
49312
46819
  diagrams.push(result);
49313
46820
  try {
49314
- const image = await withFileSignal(diagramImage(source), signal);
46821
+ const image = await withFileSignal(diagramImage(source, diagramStore, diagramRoot, diagramTheme), signal);
49315
46822
  const figure = document.createElement("figure");
49316
46823
  figure.setAttribute("data-inkkit-mermaid", source);
49317
46824
  const fence = code.parentElement.getAttribute("data-inkkit-fence");
@@ -51936,8 +49443,9 @@ function cleanSemantics(container, localIDs) {
51936
49443
  while (walker.nextNode()) comments.push(walker.currentNode);
51937
49444
  for (const comment of comments) comment.parentNode?.removeChild(comment);
51938
49445
  }
51939
- async function printableMarkdown(content, schema, adapter, context, files, signal = new AbortController().signal) {
49446
+ async function printableMarkdown(content, schema, adapter, context, files, signal = new AbortController().signal, diagrams, diagramRoot) {
51940
49447
  signal.throwIfAborted();
49448
+ const diagramTheme = captureDiagramTheme(diagramRoot);
51941
49449
  content = shareableFragment(content);
51942
49450
  const container = document.createElement("div");
51943
49451
  container.innerHTML = clipboardContent(content, schema).html;
@@ -52006,7 +49514,7 @@ async function printableMarkdown(content, schema, adapter, context, files, signa
52006
49514
  for (const code of container.querySelectorAll("pre[data-language=\"mermaid\"] > code")) {
52007
49515
  const source = code.textContent ?? "";
52008
49516
  try {
52009
- await withFileSignal(renderDiagram(source), signal);
49517
+ await withFileSignal(diagrams ? diagrams.render(source) : renderDiagram(source), signal);
52010
49518
  } catch (error) {
52011
49519
  signal.throwIfAborted();
52012
49520
  const message = `${error instanceof Error ? error.message : "This diagram could not be rendered."} The source is printed below.`;
@@ -52020,7 +49528,7 @@ async function printableMarkdown(content, schema, adapter, context, files, signa
52020
49528
  continue;
52021
49529
  }
52022
49530
  try {
52023
- const image = await validatedImage(await withFileSignal(diagramImage(source), signal), signal);
49531
+ const image = await validatedImage(await withFileSignal(diagramImage(source, diagrams, diagramRoot, diagramTheme), signal), signal);
52024
49532
  const figure = document.createElement("figure");
52025
49533
  figure.className = "inkkit-print-diagram";
52026
49534
  const element = document.createElement("img");
@@ -52066,9 +49574,10 @@ var EditorOutput = class {
52066
49574
  async printable(snapshot, captured) {
52067
49575
  const state = this.runtime.ctx().get(editorViewCtx).state;
52068
49576
  const doc = this.runtime.exportDocument(snapshot.text);
49577
+ this.runtime.diagrams().reconcile(doc);
52069
49578
  const output = await this.exportContent(captured, async (signal) => {
52070
49579
  if (snapshot.format === "md" && !this.runtime.images() && !this.runtime.files() && hasAuthoredImagesInLiterals(doc.content, (source) => this.runtime.ctx().get(remarkCtx).parse(source))) throw new InkKitError("image-unavailable", "No image adapter is configured for the authored images.");
52071
- return snapshot.format === "txt" ? printableText(snapshot.text) : printableMarkdown(doc.content, state.schema, this.runtime.images(), this.runtime.context(), this.runtime.files(), signal);
49580
+ return snapshot.format === "txt" ? printableText(snapshot.text) : printableMarkdown(doc.content, state.schema, this.runtime.images(), this.runtime.context(), this.runtime.files(), signal, this.runtime.diagrams(), this.runtime.root());
52072
49581
  });
52073
49582
  return Object.freeze({
52074
49583
  documentId: snapshot.documentId,
@@ -52106,6 +49615,7 @@ var EditorOutput = class {
52106
49615
  }
52107
49616
  const { schema, selection } = this.runtime.ctx().get(editorViewCtx).state;
52108
49617
  const doc = all || !this.runtime.sourceMode() ? this.runtime.exportDocument(snapshot.text) : this.runtime.ctx().get(editorViewCtx).state.doc;
49618
+ if (all || !this.runtime.sourceMode()) this.runtime.diagrams().reconcile(doc);
52109
49619
  const selectedSource = !all && this.runtime.sourceMode() ? sourceSelection(snapshot.text, this.runtime.element().selectionStart, this.runtime.element().selectionEnd) : void 0;
52110
49620
  const selectedDoc = selectedSource ? this.runtime.ctx().get(parserCtx)(selectedSource.shareable) : void 0;
52111
49621
  const completeDiagrams = /* @__PURE__ */ new Set();
@@ -52120,7 +49630,7 @@ var EditorOutput = class {
52120
49630
  } catch (error) {
52121
49631
  throw coded(error, "preservation");
52122
49632
  }
52123
- const result = await this.exportContent(captured, (signal) => portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.runtime.images(), this.runtime.context(), completeDiagrams, this.runtime.files(), signal, this.runtime.linkSchemes()));
49633
+ const result = await this.exportContent(captured, (signal) => portableClipboard(all || selectedDoc ? content : selectionContent(doc, content), schema, markdown, this.runtime.images(), this.runtime.context(), completeDiagrams, this.runtime.files(), signal, this.runtime.linkSchemes(), this.runtime.diagrams(), this.runtime.root()));
52124
49634
  const metadata = referenceMetadata(this.runtime.ctx(), selectedDoc ?? doc, content);
52125
49635
  if (metadata != null) result.html = withReferenceMetadata(result.html, metadata);
52126
49636
  this.runtime.assertCaptured(captured);
@@ -57608,7 +55118,7 @@ async function createMilkdownEditor(root, options, runtime) {
57608
55118
  return true;
57609
55119
  }
57610
55120
  }));
57611
- }).use(labelsCtx).use(linkSchemesCtx).use(runtime.plugins.paste).use(visibleClipboard).use(runtime.plugins.suggestions).use(runtime.plugins.keymap).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => runtime.visibleRect())).use(tablePlugins).use(tableBlock).use(runtime.plugins.change).use(runtime.plugins.historyInput).use(history).use(clipboard).use(cursor).use(taskListPlugin((operation) => runtime.mutate(operation))).use(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(runtime.copy ? codeCopyPlugin((text) => runtime.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-C4gIww13.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview((error) => runtime.report(error))).use(selectionPlugin).use($prose(() => search())).use(runtime.plugins.policy).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
55121
+ }).use(labelsCtx).use(linkSchemesCtx).use(runtime.plugins.paste).use(visibleClipboard).use(runtime.plugins.suggestions).use(runtime.plugins.keymap).use(createDialect(Boolean(options.images || options.files), Boolean(options.wikiLinks), Boolean(options.files))).use(codeControlCtx).use(codeControlsPlugin(() => runtime.visibleRect())).use(tablePlugins).use(tableBlock).use(runtime.plugins.change).use(runtime.plugins.historyInput).use(history).use(clipboard).use(cursor).use(taskListPlugin((operation) => runtime.mutate(operation))).use(undoTypedRule).use(quoteBackspace).use(calloutEnter).use(literalEnter).use(literalReread).use(listItemBackspace).use(nestedItemEnter).use(rejoinLists).use(movedListItems).use(textInputPolicy).use(runtime.copy ? codeCopyPlugin((text) => runtime.copy?.(text)) : []).use(placeholderPlugin).use(options.rendering?.codeHighlighting === false ? [] : (await import("./highlight-Caqd0kqu.js")).highlightPlugin).use(options.rendering?.diagramPreview === false || !diagramsAvailable() ? [] : mermaidPreview(runtime.diagrams, (error) => runtime.report(error))).use(selectionPlugin).use($prose(() => search())).use(runtime.plugins.policy).use(options.wikiLinks ? wikiLinkView(options.wikiLinks, {
57612
55122
  capture: () => runtime.capture(),
57613
55123
  active: () => runtime.active(),
57614
55124
  labels: {
@@ -59780,9 +57290,12 @@ var InkKitEditor = class InkKitEditor {
59780
57290
  revealLiteral: () => this.revealLiteralSelection(),
59781
57291
  revealCurrent: () => this.revealCurrentSelection()
59782
57292
  });
57293
+ diagrams = new DiagramStore();
59783
57294
  output = new EditorOutput({
59784
57295
  ctx: () => this.editor.ctx,
59785
57296
  exportDocument: (text) => this.document.exportDocument(text),
57297
+ diagrams: () => this.diagrams,
57298
+ root: () => this.root,
59786
57299
  sourceMode: () => this.mode === "source",
59787
57300
  element: () => this.source.element,
59788
57301
  images: () => this.options.images,
@@ -60336,6 +57849,7 @@ var InkKitEditor = class InkKitEditor {
60336
57849
  this.activation.destroy();
60337
57850
  this.clipboard.destroy();
60338
57851
  this.source.destroy();
57852
+ this.diagrams.destroy();
60339
57853
  await this.editor.destroy();
60340
57854
  if (this.ownsRootClass) this.root.classList.remove("inkkit-root");
60341
57855
  }
@@ -60413,6 +57927,7 @@ var InkKitEditor = class InkKitEditor {
60413
57927
  report: (error) => instance.report(error)
60414
57928
  });
60415
57929
  instance.editor = await createMilkdownEditor(root, options, {
57930
+ diagrams: instance.diagrams,
60416
57931
  plugins: {
60417
57932
  indent: instance.indentPlugin,
60418
57933
  paste: instance.pasteController.plugin,
@@ -60501,6 +58016,7 @@ var InkKitEditor = class InkKitEditor {
60501
58016
  this.output.cancel();
60502
58017
  this.mediaPolicy();
60503
58018
  this.pasteController.cancelPending();
58019
+ this.diagrams.clear();
60504
58020
  this.session.load(input.documentId, input.generation);
60505
58021
  this.document.resetCaches();
60506
58022
  this.history.reset();
@@ -61048,4 +58564,4 @@ var InkKitEditor = class InkKitEditor {
61048
58564
  }
61049
58565
  };
61050
58566
  //#endregion
61051
- export { Decoration as a, PluginKey as c, __toESM as d, $prose as i, ok$1 as l, registerMermaid as n, DecorationSet as o, InkKitError as r, Plugin as s, InkKitEditor as t, __commonJSMin as u };
58567
+ export { Decoration as a, PluginKey as c, __toESM as d, $prose as i, ok$1 as l, registerDiagram as n, DecorationSet as o, InkKitError as r, Plugin as s, InkKitEditor as t, __commonJSMin as u };