@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
  2. package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
  3. package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
  4. package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
  5. package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
  6. package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
  7. package/lib/behavior-BwvTUtag.mjs +111 -0
  8. package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
  9. package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
  10. package/lib/cascade-BWjRTD1q.mjs +30265 -0
  11. package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
  12. package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
  13. package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
  14. package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
  15. package/lib/collapse-_nkb2dn7.mjs +1945 -0
  16. package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
  17. package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
  18. package/lib/cursor-BgOuV7Qf.mjs +794 -0
  19. package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
  20. package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
  21. package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
  22. package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
  23. package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
  24. package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
  25. package/lib/factory-droid-ChhmsGWb.mjs +71 -0
  26. package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
  27. package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
  28. package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
  29. package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
  30. package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
  31. package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
  32. package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
  33. package/lib/google-validation-CdvRj4ec.mjs +126 -0
  34. package/lib/id-EJwVLDHE.mjs +2548 -0
  35. package/lib/index.mjs +248 -258
  36. package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
  37. package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
  38. package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
  39. package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
  40. package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
  41. package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
  42. package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
  43. package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
  44. package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
  45. package/lib/pricing-DusBEhwm.mjs +593 -0
  46. package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
  47. package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
  48. package/lib/slugify-ynYWBIA5.mjs +11 -0
  49. package/lib/snowflake-B_jap6lz.mjs +666 -0
  50. package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
  51. package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
  52. package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
  53. package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
  54. package/lib/types/tools/hashline/native/index.d.ts +2 -2
  55. package/lib/types/tools/hashline/native/policy.d.ts +19 -21
  56. package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
  57. package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
  58. package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
  59. package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
  60. package/lib/utils-D2tK38xq.mjs +34006 -0
  61. package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
  62. package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
  63. package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
  64. package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
  65. package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
  66. package/package.json +8 -8
  67. package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
  68. package/lib/anthropic-ClCw0PV_.mjs +0 -3624
  69. package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
  70. package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
  71. package/lib/bundled-references-DY3EJxZV.mjs +0 -56
  72. package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
  73. package/lib/collapse-CkMNRNr7.mjs +0 -2304
  74. package/lib/cursor-C6jaIJDg.mjs +0 -283
  75. package/lib/cursor-D-XZYDf_.mjs +0 -4544
  76. package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
  77. package/lib/devin-ExGIghmx.mjs +0 -69
  78. package/lib/devin-u0ljw5P6.mjs +0 -628
  79. package/lib/effort-BdtQMN-_.mjs +0 -23
  80. package/lib/event-stream-BKEtb45Y.mjs +0 -167
  81. package/lib/gemini-headers-Co9cVvex.mjs +0 -54
  82. package/lib/google-auth-qAN-6DMW.mjs +0 -232
  83. package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
  84. package/lib/google-lTxuq28n.mjs +0 -38
  85. package/lib/google-shared-Y01j9xOr.mjs +0 -856
  86. package/lib/google-validation-BEkNs-Bx.mjs +0 -18
  87. package/lib/google-vertex-DcM-FRC5.mjs +0 -99
  88. package/lib/hosts-00rjRzUD.mjs +0 -203
  89. package/lib/id-AL5obQzR.mjs +0 -71
  90. package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
  91. package/lib/ollama-6R0oXZks.mjs +0 -574
  92. package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
  93. package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
  94. package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
  95. package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
  96. package/lib/openai-responses-CjpafAEr.mjs +0 -861
  97. package/lib/protobuf-BMgDYu_U.mjs +0 -717
  98. package/lib/provider-response-SqKSkkUc.mjs +0 -22
  99. package/lib/proxy-DxvCQOCA.mjs +0 -230
  100. package/lib/request-debug-BwPOqN_j.mjs +0 -183
  101. package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
  102. package/lib/sse-debug-B-tkLCPW.mjs +0 -11
  103. package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
  104. package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
  105. package/lib/taxonomy-DSIM99rS.mjs +0 -15392
  106. package/lib/thinking-ngMwf_1Y.mjs +0 -336
  107. package/lib/type-guards-CttAANEx.mjs +0 -11
  108. package/lib/utils-CE3DSebh.mjs +0 -11763
  109. package/lib/vision-guard-BCpXWUj3.mjs +0 -77
@@ -1,10 +1,17 @@
1
1
  import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
2
  __installBunShim();
3
- //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.1.17/node_modules/@oh-my-pi/pi-utils/src/dom/parser.ts
4
- const RAW_TEXT_ELEMENTS = {
5
- script: true,
6
- style: true
3
+ //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/dom/parser.ts
4
+ /** Closing-tag patterns for raw-text elements, reused across parses (callers reset `lastIndex`). */
5
+ const RAW_TEXT_CLOSE = {
6
+ script: /<\/script\s*>/gi,
7
+ style: /<\/style\s*>/gi
7
8
  };
9
+ const DOCTYPE_PATTERN = /<!doctype\b/iy;
10
+ const TAG_NAME_PATTERN = /[^\s/>]+/y;
11
+ const ATTRIBUTE_NAME_PATTERN = /[^\s=/>]+/y;
12
+ const UNQUOTED_VALUE_PATTERN = /[^\s>]+/y;
13
+ const SVG_NAMESPACE$1 = "http://www.w3.org/2000/svg";
14
+ const HTML_NAMESPACE$1 = "http://www.w3.org/1999/xhtml";
8
15
  const VOID_ELEMENTS$1 = {
9
16
  area: true,
10
17
  base: true,
@@ -186,9 +193,11 @@ const NAMED_ENTITIES = {
186
193
  yuml: "ÿ",
187
194
  yen: "¥"
188
195
  };
196
+ const ENTITY_PATTERN = /&(#(?:x[0-9a-f]+|\d+)|[a-z][a-z0-9]+);/gi;
189
197
  /** Decode common named entities and all valid numeric character references. */
190
198
  function decodeEntities(value) {
191
- return value.replace(/&(#(?:x[0-9a-f]+|\d+)|[a-z][a-z0-9]+);/gi, (whole, entity) => {
199
+ if (!value.includes("&")) return value;
200
+ return value.replace(ENTITY_PATTERN, (whole, entity) => {
192
201
  if (entity[0] !== "#") return NAMED_ENTITIES[entity] ?? NAMED_ENTITIES[entity.toLowerCase()] ?? whole;
193
202
  const hexadecimal = entity[1]?.toLowerCase() === "x";
194
203
  const codePoint = Number.parseInt(entity.slice(hexadecimal ? 2 : 1), hexadecimal ? 16 : 10);
@@ -210,7 +219,8 @@ function findTagEnd(html, start) {
210
219
  function parseStartTag(source) {
211
220
  let index = 0;
212
221
  while (/\s/.test(source[index] ?? "")) index++;
213
- const nameMatch = /^[^\s/>]+/.exec(source.slice(index));
222
+ TAG_NAME_PATTERN.lastIndex = index;
223
+ const nameMatch = TAG_NAME_PATTERN.exec(source);
214
224
  if (!nameMatch) return null;
215
225
  const name = nameMatch[0].toLowerCase();
216
226
  index += nameMatch[0].length;
@@ -222,7 +232,8 @@ function parseStartTag(source) {
222
232
  selfClosing = true;
223
233
  break;
224
234
  }
225
- const attributeMatch = /^[^\s=/>]+/.exec(source.slice(index));
235
+ ATTRIBUTE_NAME_PATTERN.lastIndex = index;
236
+ const attributeMatch = ATTRIBUTE_NAME_PATTERN.exec(source);
226
237
  if (!attributeMatch) break;
227
238
  const attributeName = attributeMatch[0];
228
239
  index += attributeMatch[0].length;
@@ -243,7 +254,8 @@ function parseStartTag(source) {
243
254
  index = end + 1;
244
255
  }
245
256
  } else {
246
- value = /^[^\s>]+/.exec(source.slice(index))?.[0] ?? "";
257
+ UNQUOTED_VALUE_PATTERN.lastIndex = index;
258
+ value = UNQUOTED_VALUE_PATTERN.exec(source)?.[0] ?? "";
247
259
  index += value.length;
248
260
  }
249
261
  }
@@ -264,7 +276,8 @@ function closeOptionalElements(stack, incoming) {
264
276
  }
265
277
  if (CLOSE_ON_OPEN[incoming]?.includes(current.localName)) stack.pop();
266
278
  }
267
- function parseInto(html, document, root, contextTag) {
279
+ /** Parse markup, appending the resulting nodes to `root` (a document, fragment, or element). */
280
+ function parseInto(html, document, root) {
268
281
  const stack = [];
269
282
  const xmlLike = root instanceof Document && /^\s*(?:<\?xml[\s\S]*?\?>\s*)?<(?:feed|rss)\b/i.test(html);
270
283
  let parent = root;
@@ -284,7 +297,7 @@ function parseInto(html, document, root, contextTag) {
284
297
  index = end;
285
298
  continue;
286
299
  }
287
- if (/^<!doctype\b/i.test(html.slice(index))) {
300
+ if (html[index + 1] === "!" && isDoctypeAt(html, index)) {
288
301
  const end = html.indexOf(">", index + 2);
289
302
  index = end < 0 ? html.length : end + 1;
290
303
  continue;
@@ -319,7 +332,7 @@ function parseInto(html, document, root, contextTag) {
319
332
  }
320
333
  closeOptionalElements(stack, parsed.name);
321
334
  parent = stack[stack.length - 1] ?? root;
322
- const namespace = parent instanceof Element && parent.namespaceURI === "http://www.w3.org/2000/svg" ? "http://www.w3.org/2000/svg" : parsed.name === "svg" ? "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml";
335
+ const namespace = parent !== root && parent instanceof Element && parent.namespaceURI === SVG_NAMESPACE$1 || parsed.name === "svg" ? SVG_NAMESPACE$1 : HTML_NAMESPACE$1;
323
336
  const element = document.createElementNS(namespace, parsed.name);
324
337
  for (let attributeIndex = parsed.attributes.length - 1; attributeIndex >= 0; attributeIndex--) {
325
338
  const [name, value] = parsed.attributes[attributeIndex];
@@ -327,8 +340,8 @@ function parseInto(html, document, root, contextTag) {
327
340
  }
328
341
  parent.appendChild(element);
329
342
  index = end + 1;
330
- if (RAW_TEXT_ELEMENTS[parsed.name] && !parsed.selfClosing) {
331
- const closePattern = new RegExp(`</${parsed.name}\\s*>`, "ig");
343
+ if (RAW_TEXT_CLOSE[parsed.name] && !parsed.selfClosing) {
344
+ const closePattern = Object.hasOwn(RAW_TEXT_CLOSE, parsed.name) ? RAW_TEXT_CLOSE[parsed.name] : new RegExp(`</${parsed.name}\\s*>`, "ig");
332
345
  closePattern.lastIndex = index;
333
346
  const match = closePattern.exec(html);
334
347
  const rawEnd = match?.index ?? html.length;
@@ -336,16 +349,20 @@ function parseInto(html, document, root, contextTag) {
336
349
  index = match ? closePattern.lastIndex : html.length;
337
350
  continue;
338
351
  }
339
- if (!VOID_ELEMENTS$1[parsed.name] && !(namespace === "http://www.w3.org/2000/svg" && parsed.selfClosing)) {
352
+ if (!(xmlLike ? parsed.selfClosing : VOID_ELEMENTS$1[parsed.name] || namespace === SVG_NAMESPACE$1 && parsed.selfClosing)) {
340
353
  stack.push(element);
341
354
  parent = element;
342
355
  }
343
356
  }
344
357
  }
345
- /** Parse markup into a document fragment. */
346
- function parseFragment(html, document, contextTag) {
358
+ function isDoctypeAt(html, index) {
359
+ DOCTYPE_PATTERN.lastIndex = index;
360
+ return DOCTYPE_PATTERN.test(html);
361
+ }
362
+ /** Parse markup into a document fragment. `_contextTag` is accepted for compatibility and ignored. */
363
+ function parseFragment(html, document, _contextTag) {
347
364
  const fragment = document.createDocumentFragment();
348
- parseInto(html, document, fragment, contextTag);
365
+ parseInto(html, document, fragment);
349
366
  return fragment;
350
367
  }
351
368
  /** Parse markup directly into a document. */
@@ -355,7 +372,24 @@ function parseDocument(html) {
355
372
  return document;
356
373
  }
357
374
  //#endregion
358
- //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.1.17/node_modules/@oh-my-pi/pi-utils/src/dom/selector.ts
375
+ //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/dom/selector.ts
376
+ const SUPPORTED_PSEUDOS = {
377
+ not: true,
378
+ is: true,
379
+ where: true,
380
+ "first-child": true,
381
+ "last-child": true,
382
+ "only-child": true,
383
+ empty: true,
384
+ root: true,
385
+ "nth-child": true,
386
+ "first-of-type": true,
387
+ "last-of-type": true
388
+ };
389
+ const ATTRIBUTE_PATTERN = /^\s*([^\s~|^$*!=]+)\s*(?:(\^=|\$=|\*=|~=|\|=|=)\s*(?:(["'])(.*?)\3|([^\s]+))\s*([isIS])?)?\s*$/;
390
+ const IDENTIFIER_CHARACTER = /[a-zA-Z0-9_-]/;
391
+ const MAX_CACHED_SELECTORS = 512;
392
+ const compiledSelectors = /* @__PURE__ */ new Map();
359
393
  function splitTopLevel(value, delimiter) {
360
394
  const parts = [];
361
395
  let start = 0;
@@ -381,7 +415,7 @@ function splitTopLevel(value, delimiter) {
381
415
  parts.push(value.slice(start).trim());
382
416
  return parts.filter(Boolean);
383
417
  }
384
- function parseComplex(selector) {
418
+ function splitComplex(selector) {
385
419
  const simples = [];
386
420
  const combinators = [];
387
421
  let current = "";
@@ -444,7 +478,7 @@ function readIdentifier(source, start) {
444
478
  index += 2;
445
479
  continue;
446
480
  }
447
- if (!/[a-zA-Z0-9_-]/.test(character)) break;
481
+ if (!IDENTIFIER_CHARACTER.test(character)) break;
448
482
  value += character;
449
483
  index++;
450
484
  }
@@ -466,81 +500,89 @@ function findClosing(source, start, opener, closer) {
466
500
  }
467
501
  return source.length - 1;
468
502
  }
469
- function matchAttribute(element, expression) {
470
- const match = /^\s*([^\s~|^$*!=]+)\s*(?:(\^=|\$=|\*=|~=|\|=|=)\s*(?:(["'])(.*?)\3|([^\s]+))\s*([isIS])?)?\s*$/.exec(expression);
471
- if (!match) return false;
503
+ function compileAttribute(expression) {
504
+ const match = ATTRIBUTE_PATTERN.exec(expression);
505
+ if (!match) return null;
472
506
  const [, name, operator, , quotedValue, bareValue, flag] = match;
473
- const actual = element.getAttribute(name);
474
- if (!operator) return actual !== null;
475
- if (actual === null) return false;
476
- let left = actual;
477
- let right = (quotedValue ?? bareValue ?? "").replace(/\\(.)/g, "$1");
478
- if (flag?.toLowerCase() === "i") {
479
- left = left.toLowerCase();
480
- right = right.toLowerCase();
481
- }
482
- switch (operator) {
483
- case "=": return left === right;
484
- case "^=": return left.startsWith(right);
485
- case "$=": return left.endsWith(right);
486
- case "*=": return left.includes(right);
487
- case "~=": return left.split(/\s+/).includes(right);
488
- case "|=": return left === right || left.startsWith(`${right}-`);
489
- default: return false;
490
- }
507
+ const ignoreCase = flag?.toLowerCase() === "i";
508
+ const value = (quotedValue ?? bareValue ?? "").replace(/\\(.)/g, "$1");
509
+ return {
510
+ name,
511
+ operator,
512
+ value: ignoreCase ? value.toLowerCase() : value,
513
+ ignoreCase
514
+ };
491
515
  }
492
- function matchNth(element, expression) {
493
- const index = (element.parentElement?.children ?? []).indexOf(element) + 1;
516
+ function compileNth(expression) {
494
517
  const normalized = expression.trim().toLowerCase().replace(/\s+/g, "");
495
- if (normalized === "odd") return index % 2 === 1;
496
- if (normalized === "even") return index % 2 === 0;
497
- if (/^[+-]?\d+$/.test(normalized)) return index === Number(normalized);
518
+ if (normalized === "odd" || normalized === "even") return { kind: normalized };
519
+ if (/^[+-]?\d+$/.test(normalized)) return {
520
+ kind: "index",
521
+ index: Number(normalized)
522
+ };
498
523
  const match = /^([+-]?\d*)n([+-]\d+)?$/.exec(normalized);
499
- if (!match) return false;
500
- const coefficient = match[1] === "" || match[1] === "+" ? 1 : match[1] === "-" ? -1 : Number(match[1]);
501
- const offset = Number(match[2] ?? 0);
502
- return coefficient === 0 ? index === offset : (index - offset) / coefficient >= 0 && Number.isInteger((index - offset) / coefficient);
524
+ if (!match) return { kind: "invalid" };
525
+ return {
526
+ kind: "formula",
527
+ coefficient: match[1] === "" || match[1] === "+" ? 1 : match[1] === "-" ? -1 : Number(match[1]),
528
+ offset: Number(match[2] ?? 0)
529
+ };
503
530
  }
504
- function matchPseudo(element, name, argument) {
505
- switch (name) {
506
- case "not": return argument !== void 0 && !matchesSelector(element, argument);
507
- case "is":
508
- case "where": return argument !== void 0 && matchesSelector(element, argument);
509
- case "first-child": return element.parentElement?.firstElementChild === element;
510
- case "last-child": return element.parentElement?.lastElementChild === element;
511
- case "only-child": return element.parentElement?.children.length === 1;
512
- case "empty": return element.childNodes.every((child) => child.nodeType === Node.COMMENT_NODE || child.textContent === "");
513
- case "root": return element.ownerDocument?.documentElement === element;
514
- case "nth-child": return argument !== void 0 && matchNth(element, argument);
515
- case "first-of-type":
516
- for (let sibling = element.previousElementSibling; sibling; sibling = sibling.previousElementSibling) if (sibling.tagName === element.tagName) return false;
517
- return true;
518
- case "last-of-type":
519
- for (let sibling = element.nextElementSibling; sibling; sibling = sibling.nextElementSibling) if (sibling.tagName === element.tagName) return false;
520
- return true;
521
- default: return false;
522
- }
531
+ function compilePseudo(name, argument) {
532
+ if (!SUPPORTED_PSEUDOS[name]) return null;
533
+ if (name === "not" || name === "is" || name === "where") return argument === void 0 ? null : {
534
+ name,
535
+ list: compileSelector(argument),
536
+ nth: null
537
+ };
538
+ if (name === "nth-child") return argument === void 0 ? null : {
539
+ name,
540
+ list: null,
541
+ nth: compileNth(argument)
542
+ };
543
+ return {
544
+ name,
545
+ list: null,
546
+ nth: null
547
+ };
523
548
  }
524
- function matchSimple(element, selector) {
549
+ function compileCompound(selector) {
550
+ const compound = {
551
+ tag: null,
552
+ ids: [],
553
+ classes: [],
554
+ attributes: [],
555
+ pseudos: [],
556
+ invalid: false,
557
+ bare: false
558
+ };
525
559
  let index = 0;
526
560
  if (selector[index] === "*") index++;
527
561
  else if (/[a-zA-Z_]/.test(selector[index] ?? "")) {
528
562
  const tag = readIdentifier(selector, index);
529
- if (element.localName !== tag.value.toLowerCase()) return false;
563
+ compound.tag = tag.value.toLowerCase();
530
564
  index = tag.end;
531
565
  }
532
566
  while (index < selector.length) {
533
567
  const marker = selector[index];
534
568
  if (marker === "#" || marker === ".") {
535
569
  const identifier = readIdentifier(selector, index + 1);
536
- if (!identifier.value) return false;
537
- if (marker === "#" ? element.id !== identifier.value : !element.classList.contains(identifier.value)) return false;
570
+ if (!identifier.value) {
571
+ compound.invalid = true;
572
+ break;
573
+ }
574
+ (marker === "#" ? compound.ids : compound.classes).push(identifier.value);
538
575
  index = identifier.end;
539
576
  continue;
540
577
  }
541
578
  if (marker === "[") {
542
579
  const end = findClosing(selector, index, "[", "]");
543
- if (!matchAttribute(element, selector.slice(index + 1, end))) return false;
580
+ const attribute = compileAttribute(selector.slice(index + 1, end));
581
+ if (!attribute) {
582
+ compound.invalid = true;
583
+ break;
584
+ }
585
+ compound.attributes.push(attribute);
544
586
  index = end + 1;
545
587
  continue;
546
588
  }
@@ -553,19 +595,151 @@ function matchSimple(element, selector) {
553
595
  argument = selector.slice(index + 1, end);
554
596
  index = end + 1;
555
597
  }
556
- if (!matchPseudo(element, identifier.value.toLowerCase(), argument)) return false;
598
+ const pseudo = compilePseudo(identifier.value.toLowerCase(), argument);
599
+ if (!pseudo) {
600
+ compound.invalid = true;
601
+ break;
602
+ }
603
+ compound.pseudos.push(pseudo);
557
604
  continue;
558
605
  }
559
- return false;
606
+ compound.invalid = true;
607
+ break;
608
+ }
609
+ compound.bare = !compound.invalid && compound.ids.length === 0 && compound.classes.length === 0 && compound.attributes.length === 0 && compound.pseudos.length === 0;
610
+ return compound;
611
+ }
612
+ function compileSelector(selector) {
613
+ const cached = compiledSelectors.get(selector);
614
+ if (cached) return cached;
615
+ const list = {
616
+ universal: false,
617
+ tags: null,
618
+ complexes: []
619
+ };
620
+ for (const part of splitTopLevel(selector, ",")) {
621
+ const { simples, combinators } = splitComplex(part);
622
+ if (!simples.length) continue;
623
+ const compounds = simples.map(compileCompound);
624
+ const only = compounds[0];
625
+ if (compounds.length === 1 && only.bare) {
626
+ if (only.tag === null) list.universal = true;
627
+ else (list.tags ??= /* @__PURE__ */ new Set()).add(only.tag);
628
+ continue;
629
+ }
630
+ list.complexes.push({
631
+ compounds,
632
+ combinators
633
+ });
560
634
  }
635
+ if (compiledSelectors.size >= MAX_CACHED_SELECTORS) compiledSelectors.clear();
636
+ compiledSelectors.set(selector, list);
637
+ return list;
638
+ }
639
+ function isWhitespace(code) {
640
+ return code === 32 || code >= 9 && code <= 13 || code === 160 || code === 5760 || code >= 8192 && code <= 8202 || code === 8232 || code === 8233 || code === 8239 || code === 8287 || code === 12288 || code === 65279;
641
+ }
642
+ /** Whether a whitespace-separated class string contains a token, without splitting it. */
643
+ function hasClassToken(className, token) {
644
+ if (!token) return false;
645
+ for (let index = 0; index < token.length; index++) if (isWhitespace(token.charCodeAt(index))) return false;
646
+ let from = 0;
647
+ while (true) {
648
+ const found = className.indexOf(token, from);
649
+ if (found < 0) return false;
650
+ const end = found + token.length;
651
+ if ((found === 0 || isWhitespace(className.charCodeAt(found - 1))) && (end === className.length || isWhitespace(className.charCodeAt(end)))) return true;
652
+ from = found + 1;
653
+ }
654
+ }
655
+ function matchAttribute(element, test) {
656
+ const actual = element.getAttribute(test.name);
657
+ if (!test.operator) return actual !== null;
658
+ if (actual === null) return false;
659
+ const left = test.ignoreCase ? actual.toLowerCase() : actual;
660
+ const right = test.value;
661
+ switch (test.operator) {
662
+ case "=": return left === right;
663
+ case "^=": return left.startsWith(right);
664
+ case "$=": return left.endsWith(right);
665
+ case "*=": return left.includes(right);
666
+ case "~=": return left.split(/\s+/).includes(right);
667
+ case "|=": return left === right || left.startsWith(`${right}-`);
668
+ default: return false;
669
+ }
670
+ }
671
+ /** One-based position among element siblings, or 0 without a parent element. */
672
+ function elementIndex(element) {
673
+ const parent = element.parentElement;
674
+ if (!parent) return 0;
675
+ let index = 0;
676
+ for (const sibling of parent.childNodes) {
677
+ if (!(sibling instanceof Element)) continue;
678
+ index++;
679
+ if (sibling === element) return index;
680
+ }
681
+ return 0;
682
+ }
683
+ function matchNth(element, test) {
684
+ if (test.kind === "invalid") return false;
685
+ const index = elementIndex(element);
686
+ switch (test.kind) {
687
+ case "odd": return index % 2 === 1;
688
+ case "even": return index % 2 === 0;
689
+ case "index": return index === test.index;
690
+ case "formula": return test.coefficient === 0 ? index === test.offset : (index - test.offset) / test.coefficient >= 0 && Number.isInteger((index - test.offset) / test.coefficient);
691
+ }
692
+ }
693
+ function hasSingleElementChild(parent) {
694
+ let count = 0;
695
+ for (const child of parent.childNodes) if (child instanceof Element && ++count > 1) return false;
696
+ return count === 1;
697
+ }
698
+ function matchPseudo(element, pseudo) {
699
+ switch (pseudo.name) {
700
+ case "not": return !matchesList(element, pseudo.list);
701
+ case "is":
702
+ case "where": return matchesList(element, pseudo.list);
703
+ case "first-child": return element.parentElement?.firstElementChild === element;
704
+ case "last-child": return element.parentElement?.lastElementChild === element;
705
+ case "only-child": {
706
+ const parent = element.parentElement;
707
+ return parent !== null && hasSingleElementChild(parent);
708
+ }
709
+ case "empty": return !element.hasChildNodes() || element.childNodes.every((child) => child.nodeType === Node.COMMENT_NODE || child.textContent === "");
710
+ case "root": return element.ownerDocument?.documentElement === element;
711
+ case "nth-child": return matchNth(element, pseudo.nth);
712
+ case "first-of-type":
713
+ for (let sibling = element.previousElementSibling; sibling; sibling = sibling.previousElementSibling) if (sibling.tagName === element.tagName) return false;
714
+ return true;
715
+ case "last-of-type":
716
+ for (let sibling = element.nextElementSibling; sibling; sibling = sibling.nextElementSibling) if (sibling.tagName === element.tagName) return false;
717
+ return true;
718
+ default: return false;
719
+ }
720
+ }
721
+ function matchCompound(element, compound) {
722
+ if (compound.invalid) return false;
723
+ if (compound.tag !== null && element.localName !== compound.tag) return false;
724
+ if (compound.bare) return true;
725
+ for (const id of compound.ids) if (element.id !== id) return false;
726
+ if (compound.classes.length) {
727
+ const className = element.className;
728
+ for (const token of compound.classes) if (!hasClassToken(className, token)) return false;
729
+ }
730
+ for (const attribute of compound.attributes) if (!matchAttribute(element, attribute)) return false;
731
+ for (const pseudo of compound.pseudos) if (!matchPseudo(element, pseudo)) return false;
561
732
  return true;
562
733
  }
563
734
  function matchComplexAt(element, complex, index) {
564
- if (!matchSimple(element, complex.simples[index])) return false;
735
+ if (!matchCompound(element, complex.compounds[index])) return false;
565
736
  if (index === 0) return true;
566
737
  const combinator = complex.combinators[index - 1] ?? " ";
567
738
  if (combinator === ">") return element.parentElement !== null && matchComplexAt(element.parentElement, complex, index - 1);
568
- if (combinator === "+") return element.previousElementSibling !== null && matchComplexAt(element.previousElementSibling, complex, index - 1);
739
+ if (combinator === "+") {
740
+ const previous = element.previousElementSibling;
741
+ return previous !== null && matchComplexAt(previous, complex, index - 1);
742
+ }
569
743
  if (combinator === "~") {
570
744
  for (let sibling = element.previousElementSibling; sibling; sibling = sibling.previousElementSibling) if (matchComplexAt(sibling, complex, index - 1)) return true;
571
745
  return false;
@@ -573,27 +747,52 @@ function matchComplexAt(element, complex, index) {
573
747
  for (let ancestor = element.parentElement; ancestor; ancestor = ancestor.parentElement) if (matchComplexAt(ancestor, complex, index - 1)) return true;
574
748
  return false;
575
749
  }
750
+ function matchesList(element, list) {
751
+ if (list.universal) return true;
752
+ if (list.tags?.has(element.localName)) return true;
753
+ for (const complex of list.complexes) if (matchComplexAt(element, complex, complex.compounds.length - 1)) return true;
754
+ return false;
755
+ }
756
+ function collectMatches(nodes, list, result) {
757
+ for (let index = 0; index < nodes.length; index++) {
758
+ const node = nodes[index];
759
+ if (node instanceof Element && matchesList(node, list)) result.push(node);
760
+ if (node.hasChildNodes()) collectMatches(node.childNodes, list, result);
761
+ }
762
+ }
763
+ function findMatch(nodes, list) {
764
+ for (let index = 0; index < nodes.length; index++) {
765
+ const node = nodes[index];
766
+ if (node instanceof Element && matchesList(node, list)) return node;
767
+ if (node.hasChildNodes()) {
768
+ const found = findMatch(node.childNodes, list);
769
+ if (found) return found;
770
+ }
771
+ }
772
+ return null;
773
+ }
576
774
  /** Whether an element matches a CSS selector list. */
577
775
  function matchesSelector(element, selector) {
578
- for (const part of splitTopLevel(selector, ",")) {
579
- const complex = parseComplex(part);
580
- if (complex.simples.length && matchComplexAt(element, complex, complex.simples.length - 1)) return true;
581
- }
582
- return false;
776
+ return matchesList(element, compileSelector(selector));
777
+ }
778
+ /** Nearest inclusive ancestor of an element matching a CSS selector list. */
779
+ function closestMatching(element, selector) {
780
+ const list = compileSelector(selector);
781
+ for (let current = element; current; current = current.parentElement) if (matchesList(current, list)) return current;
782
+ return null;
583
783
  }
584
784
  /** Query descendants of a node in document order. */
585
- function querySelectorAllFrom(root, selector, includeRoot) {
785
+ function querySelectorAllFrom(root, selector, _includeRoot) {
586
786
  const result = [];
587
- const visit = (node) => {
588
- if (node instanceof Element && matchesSelector(node, selector)) result.push(node);
589
- for (const child of node.childNodes) visit(child);
590
- };
591
- if (includeRoot) for (const child of root.childNodes) visit(child);
592
- else for (const child of root.childNodes) visit(child);
787
+ if (root.hasChildNodes()) collectMatches(root.childNodes, compileSelector(selector), result);
593
788
  return result;
594
789
  }
790
+ /** First descendant of a node in document order matching a selector, stopping at the first match. */
791
+ function querySelectorFrom(root, selector) {
792
+ return root.hasChildNodes() ? findMatch(root.childNodes, compileSelector(selector)) : null;
793
+ }
595
794
  //#endregion
596
- //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.1.17/node_modules/@oh-my-pi/pi-utils/src/dom/core.ts
795
+ //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/dom/core.ts
597
796
  /** Behavior-compatible reimplementation of linkedom's used surface. */
598
797
  /** DOM node type constants. */
599
798
  let NodeType = /* @__PURE__ */ function(NodeType) {
@@ -649,26 +848,29 @@ var CustomEvent = class extends Event {
649
848
  };
650
849
  /** Minimal event-target implementation used by DOM nodes and window. */
651
850
  var EventTarget = class {
652
- #listeners = /* @__PURE__ */ new Map();
851
+ /** Allocated on the first `addEventListener`; most nodes never get listeners. */
852
+ #listeners;
653
853
  /** Register an event listener. */
654
854
  addEventListener(type, listener) {
655
855
  if (!listener) return;
656
- let listeners = this.#listeners.get(type);
856
+ const listenerMap = this.#listeners ??= /* @__PURE__ */ new Map();
857
+ let listeners = listenerMap.get(type);
657
858
  if (!listeners) {
658
859
  listeners = /* @__PURE__ */ new Set();
659
- this.#listeners.set(type, listeners);
860
+ listenerMap.set(type, listeners);
660
861
  }
661
862
  listeners.add(listener);
662
863
  }
663
864
  /** Remove an event listener. */
664
865
  removeEventListener(type, listener) {
665
- if (listener) this.#listeners.get(type)?.delete(listener);
866
+ if (listener) this.#listeners?.get(type)?.delete(listener);
666
867
  }
667
868
  /** Dispatch an event to listeners and optionally through node ancestors. */
668
869
  dispatchEvent(event) {
669
870
  if (!event.target) event.target = this;
670
871
  event.currentTarget = this;
671
- for (const listener of Array.from(this.#listeners.get(event.type) ?? [])) {
872
+ const listeners = this.#listeners?.get(event.type);
873
+ for (const listener of listeners ? Array.from(listeners) : []) {
672
874
  if (typeof listener === "function") listener.call(this, event);
673
875
  else listener.handleEvent(event);
674
876
  if (event.propagationStopped) break;
@@ -677,6 +879,8 @@ var EventTarget = class {
677
879
  return !event.defaultPrevented;
678
880
  }
679
881
  };
882
+ /** Index of a node in its parent's `childNodes`, or -1; bound to Node's private index hint. */
883
+ let indexInParent;
680
884
  /** Base class for the implemented DOM tree. */
681
885
  var Node = class Node extends EventTarget {
682
886
  static ELEMENT_NODE = 1;
@@ -689,32 +893,108 @@ var Node = class Node extends EventTarget {
689
893
  nodeName;
690
894
  parentNode = null;
691
895
  ownerDocument;
692
- childNodes = [];
896
+ /** Allocated on first access or insertion, so leaf nodes (text, comments, attributes) usually never allocate. */
897
+ #childNodes;
898
+ /** Last known index in the parent's `childNodes`; always verified before use, so a stale value only costs a rescan. */
899
+ #index = 0;
900
+ static {
901
+ indexInParent = (node) => {
902
+ const siblings = node.#siblings();
903
+ return siblings ? node.#indexIn(siblings) : -1;
904
+ };
905
+ }
693
906
  constructor(nodeType, nodeName, ownerDocument = null) {
694
907
  super();
695
908
  this.nodeType = nodeType;
696
909
  this.nodeName = nodeName;
697
910
  this.ownerDocument = ownerDocument;
698
911
  }
912
+ /** Child nodes in tree order. */
913
+ get childNodes() {
914
+ this.#childNodes ??= [];
915
+ return this.#childNodes;
916
+ }
917
+ set childNodes(value) {
918
+ this.#childNodes = value;
919
+ }
920
+ /** Whether this node has any children (without allocating a child list). */
921
+ hasChildNodes() {
922
+ return this.#childNodes !== void 0 && this.#childNodes.length > 0;
923
+ }
699
924
  /** First child node, if present. */
700
925
  get firstChild() {
701
- return this.childNodes[0] ?? null;
926
+ return this.#childNodes?.[0] ?? null;
702
927
  }
703
928
  /** Last child node, if present. */
704
929
  get lastChild() {
705
- return this.childNodes[this.childNodes.length - 1] ?? null;
930
+ const children = this.#childNodes;
931
+ return children ? children[children.length - 1] ?? null : null;
706
932
  }
707
933
  /** Previous node with the same parent. */
708
934
  get previousSibling() {
709
- if (!this.parentNode) return null;
710
- const index = this.parentNode.childNodes.indexOf(this);
711
- return index > 0 ? this.parentNode.childNodes[index - 1] : null;
935
+ const siblings = this.#siblings();
936
+ if (!siblings) return null;
937
+ const index = this.#indexIn(siblings);
938
+ return index > 0 ? siblings[index - 1] : null;
712
939
  }
713
940
  /** Next node with the same parent. */
714
941
  get nextSibling() {
715
- if (!this.parentNode) return null;
716
- const index = this.parentNode.childNodes.indexOf(this);
717
- return index >= 0 ? this.parentNode.childNodes[index + 1] ?? null : null;
942
+ const siblings = this.#siblings();
943
+ if (!siblings) return null;
944
+ const index = this.#indexIn(siblings);
945
+ return index >= 0 ? siblings[index + 1] ?? null : null;
946
+ }
947
+ /** The parent's child list, without allocating one. */
948
+ #siblings() {
949
+ const parent = this.parentNode;
950
+ return parent ? parent.#childNodes : void 0;
951
+ }
952
+ /** Locate this node in `siblings` via the index hint, re-indexing all siblings on a miss. */
953
+ #indexIn(siblings) {
954
+ const hint = this.#index;
955
+ if (siblings[hint] === this) return hint;
956
+ if (siblings[hint + 1] === this) return ++this.#index;
957
+ if (hint > 0 && siblings[hint - 1] === this) return --this.#index;
958
+ let found = -1;
959
+ for (let index = 0; index < siblings.length; index++) {
960
+ const sibling = siblings[index];
961
+ sibling.#index = index;
962
+ if (found < 0 && sibling === this) found = index;
963
+ }
964
+ if (found >= 0) this.#index = found;
965
+ return found;
966
+ }
967
+ /** Index of a child in this node's `childNodes`, or -1. */
968
+ #childIndex(child) {
969
+ const children = this.#childNodes;
970
+ if (!children) return -1;
971
+ return child?.parentNode === this ? child.#indexIn(children) : children.indexOf(child);
972
+ }
973
+ /** Move every child of a fragment into this node at `index` (append for null). */
974
+ #adoptChildren(fragment, index) {
975
+ const moved = fragment.#childNodes;
976
+ if (!moved?.length) return;
977
+ if (moved.some((nested) => nested.parentNode !== fragment || nested instanceof DocumentFragment)) {
978
+ const reference = index === null ? null : this.#childNodes?.[index] ?? null;
979
+ for (const nested of Array.from(moved)) if (reference === null) this.appendChild(nested);
980
+ else this.insertBefore(nested, reference);
981
+ return;
982
+ }
983
+ const document = this.documentForCreation();
984
+ const nodes = moved.slice();
985
+ moved.length = 0;
986
+ const children = this.#childNodes ??= [];
987
+ const tail = index === null ? [] : children.splice(index);
988
+ for (const node of nodes) {
989
+ node.parentNode = this;
990
+ node.setOwnerDocument(document);
991
+ node.#index = children.length;
992
+ children.push(node);
993
+ }
994
+ for (const node of tail) {
995
+ node.#index = children.length;
996
+ children.push(node);
997
+ }
718
998
  }
719
999
  /** Connectedness to a document. */
720
1000
  get isConnected() {
@@ -729,7 +1009,11 @@ var Node = class Node extends EventTarget {
729
1009
  set nodeValue(_value) {}
730
1010
  /** Text contained by this node. */
731
1011
  get textContent() {
732
- return this.childNodes.map((child) => child.textContent ?? "").join("");
1012
+ const children = this.#childNodes;
1013
+ if (!children?.length) return "";
1014
+ const only = children[0];
1015
+ if (children.length === 1 && only instanceof Text) return only.data;
1016
+ return collectText(children);
733
1017
  }
734
1018
  set textContent(value) {
735
1019
  this.replaceChildren();
@@ -744,41 +1028,45 @@ var Node = class Node extends EventTarget {
744
1028
  const node = child;
745
1029
  if (node === this || node.contains(this)) throw new Error("The new child is an ancestor of this node");
746
1030
  if (child instanceof DocumentFragment) {
747
- for (const nested of Array.from(child.childNodes)) this.appendChild(nested);
1031
+ this.#adoptChildren(child, null);
748
1032
  return child;
749
1033
  }
750
1034
  child.parentNode?.removeChild(child);
751
1035
  child.parentNode = this;
752
1036
  child.setOwnerDocument(this.documentForCreation());
753
- this.childNodes.push(child);
1037
+ const children = this.#childNodes ??= [];
1038
+ node.#index = children.length;
1039
+ children.push(child);
754
1040
  return child;
755
1041
  }
756
1042
  /** Insert a node before a current child, or append for null. */
757
1043
  insertBefore(child, reference) {
758
1044
  if (reference === null) return this.appendChild(child);
759
- const index = this.childNodes.indexOf(reference);
1045
+ const index = this.#childIndex(reference);
760
1046
  if (index < 0) throw new Error("The reference node is not a child of this node");
761
1047
  if (child instanceof DocumentFragment) {
762
- for (const nested of Array.from(child.childNodes)) this.insertBefore(nested, reference);
1048
+ this.#adoptChildren(child, index);
763
1049
  return child;
764
1050
  }
765
1051
  child.parentNode?.removeChild(child);
766
1052
  child.parentNode = this;
767
1053
  child.setOwnerDocument(this.documentForCreation());
1054
+ const node = child;
1055
+ node.#index = index;
768
1056
  this.childNodes.splice(index, 0, child);
769
1057
  return child;
770
1058
  }
771
1059
  /** Replace a current child with another node. */
772
1060
  replaceChild(child, previous) {
773
- const index = this.childNodes.indexOf(previous);
1061
+ const index = this.#childIndex(previous);
774
1062
  if (index < 0) throw new Error("The node to replace is not a child of this node");
775
1063
  this.removeChild(previous);
776
- this.insertBefore(child, this.childNodes[index] ?? null);
1064
+ this.insertBefore(child, this.#childNodes?.[index] ?? null);
777
1065
  return previous;
778
1066
  }
779
1067
  /** Remove a current child. */
780
1068
  removeChild(child) {
781
- const index = this.childNodes.indexOf(child);
1069
+ const index = this.#childIndex(child);
782
1070
  if (index < 0) throw new Error("The node to remove is not a child of this node");
783
1071
  this.childNodes.splice(index, 1);
784
1072
  child.parentNode = null;
@@ -786,8 +1074,9 @@ var Node = class Node extends EventTarget {
786
1074
  }
787
1075
  /** Replace all children with nodes or strings. */
788
1076
  replaceChildren(...children) {
789
- for (const child of this.childNodes) child.parentNode = null;
790
- this.childNodes = [];
1077
+ const previous = this.#childNodes;
1078
+ if (previous) for (const child of previous) child.parentNode = null;
1079
+ this.#childNodes = void 0;
791
1080
  this.append(...children);
792
1081
  }
793
1082
  /** Append nodes or strings. */
@@ -818,7 +1107,7 @@ var Node = class Node extends EventTarget {
818
1107
  /** Clone this node, optionally including descendants. */
819
1108
  cloneNode(deep = false) {
820
1109
  const clone = new Node(this.nodeType, this.nodeName, this.ownerDocument);
821
- if (deep) for (const child of this.childNodes) clone.appendChild(child.cloneNode(true));
1110
+ if (deep && this.#childNodes) for (const child of this.#childNodes) clone.appendChild(child.cloneNode(true));
822
1111
  return clone;
823
1112
  }
824
1113
  /** Compare tree position sufficiently for document-order consumers. */
@@ -830,14 +1119,15 @@ var Node = class Node extends EventTarget {
830
1119
  const nodes = [];
831
1120
  const visit = (node) => {
832
1121
  nodes.push(node);
833
- for (const child of node.childNodes) visit(child);
1122
+ for (const child of node.#childNodes ?? []) visit(child);
834
1123
  };
835
1124
  visit(root);
836
1125
  return nodes.indexOf(this) < nodes.indexOf(other) ? 4 : 2;
837
1126
  }
838
1127
  setOwnerDocument(document) {
839
1128
  if (this.nodeType !== 9) this.ownerDocument = document;
840
- for (const child of this.childNodes) child.setOwnerDocument(document);
1129
+ const children = this.#childNodes;
1130
+ if (children) for (const child of children) child.setOwnerDocument(document);
841
1131
  }
842
1132
  documentForCreation() {
843
1133
  if (this instanceof Document) return this;
@@ -924,7 +1214,11 @@ var NamedNodeMap = class extends Array {
924
1214
  /** Find an attribute case-insensitively. */
925
1215
  getNamedItem(name) {
926
1216
  const normalized = name.toLowerCase();
927
- return this.find((attr) => attr.name.toLowerCase() === normalized) ?? null;
1217
+ for (let index = 0; index < this.length; index++) {
1218
+ const attr = this[index];
1219
+ if (attr.name === normalized || attr.name.toLowerCase() === normalized) return attr;
1220
+ }
1221
+ return null;
928
1222
  }
929
1223
  /** Set an attribute object and return the prior one. */
930
1224
  setNamedItem(attr) {
@@ -975,7 +1269,7 @@ var DOMTokenList = class {
975
1269
  }
976
1270
  /** Whether a class token exists. */
977
1271
  contains(token) {
978
- return this.#tokens().includes(token);
1272
+ return hasClassToken(this.#element.className, token);
979
1273
  }
980
1274
  /** Toggle a class token. */
981
1275
  toggle(token, force) {
@@ -1007,13 +1301,18 @@ var DOMTokenList = class {
1007
1301
  };
1008
1302
  /** Mutable inline style declaration. */
1009
1303
  var CSSStyleDeclaration = class {
1010
- #values = /* @__PURE__ */ new Map();
1304
+ /** Allocated on the first non-empty declaration. */
1305
+ #values;
1306
+ /** Serialized declarations; `undefined` after a change until the next read. */
1307
+ #cssText = "";
1011
1308
  /** Serialized declarations. */
1012
1309
  get cssText() {
1013
- return [...this.#values].map(([name, value]) => `${name}: ${value};`).join(" ");
1310
+ this.#cssText ??= this.#values ? [...this.#values].map(([name, value]) => `${name}: ${value};`).join(" ") : "";
1311
+ return this.#cssText;
1014
1312
  }
1015
1313
  set cssText(value) {
1016
- this.#values.clear();
1314
+ this.#values?.clear();
1315
+ this.#cssText = void 0;
1017
1316
  for (const declaration of value.split(";")) {
1018
1317
  const colon = declaration.indexOf(":");
1019
1318
  if (colon > 0) this.setProperty(declaration.slice(0, colon).trim(), declaration.slice(colon + 1).trim());
@@ -1021,31 +1320,42 @@ var CSSStyleDeclaration = class {
1021
1320
  }
1022
1321
  /** Read a CSS property. */
1023
1322
  getPropertyValue(name) {
1024
- return this.#values.get(name) ?? "";
1323
+ return this.#values?.get(name) ?? "";
1025
1324
  }
1026
1325
  /** Set a CSS property. */
1027
1326
  setProperty(name, value, _priority) {
1028
- if (value === null || value === "") this.#values.delete(name);
1029
- else this.#values.set(name, String(value));
1327
+ if (value === null || value === "") {
1328
+ if (this.#values?.delete(name)) this.#cssText = void 0;
1329
+ return;
1330
+ }
1331
+ this.#values ??= /* @__PURE__ */ new Map();
1332
+ this.#values.set(name, String(value));
1333
+ this.#cssText = void 0;
1030
1334
  }
1031
1335
  /** Remove and return a CSS property. */
1032
1336
  removeProperty(name) {
1033
1337
  const value = this.getPropertyValue(name);
1034
- this.#values.delete(name);
1338
+ if (this.#values?.delete(name)) this.#cssText = void 0;
1035
1339
  return value;
1036
1340
  }
1037
1341
  };
1038
1342
  const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
1039
1343
  const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
1344
+ /** An element's inline style when one has been created; bound to Element's private field. */
1345
+ let inlineStyleOf;
1040
1346
  /** DOM element with attributes, selectors, and HTML serialization. */
1041
1347
  var Element = class Element extends Node {
1042
1348
  localName;
1043
1349
  tagName;
1044
1350
  namespaceURI;
1045
1351
  qualifiedName;
1046
- attributes = new NamedNodeMap();
1047
- classList;
1048
- style = new CSSStyleDeclaration();
1352
+ /** Attribute, class-list and style objects are created on first use. */
1353
+ #attributes;
1354
+ #classList;
1355
+ #style;
1356
+ static {
1357
+ inlineStyleOf = (element) => element.#style;
1358
+ }
1049
1359
  constructor(tagName, ownerDocument = null, namespaceURI = HTML_NAMESPACE) {
1050
1360
  const localName = tagName.toLowerCase();
1051
1361
  const qualified = namespaceURI === HTML_NAMESPACE ? localName.toUpperCase() : tagName;
@@ -1054,29 +1364,58 @@ var Element = class Element extends Node {
1054
1364
  this.tagName = qualified;
1055
1365
  this.qualifiedName = tagName;
1056
1366
  this.namespaceURI = namespaceURI;
1057
- this.classList = new DOMTokenList(this);
1367
+ }
1368
+ /** Attribute collection. */
1369
+ get attributes() {
1370
+ this.#attributes ??= new NamedNodeMap();
1371
+ return this.#attributes;
1372
+ }
1373
+ /** Class token list over the `class` attribute. */
1374
+ get classList() {
1375
+ this.#classList ??= new DOMTokenList(this);
1376
+ return this.#classList;
1377
+ }
1378
+ /** Inline style declaration. */
1379
+ get style() {
1380
+ this.#style ??= new CSSStyleDeclaration();
1381
+ return this.#style;
1382
+ }
1383
+ /** Whether the element has any attribute objects (without allocating the collection). */
1384
+ hasAttributes() {
1385
+ return this.#attributes !== void 0 && this.#attributes.length > 0;
1058
1386
  }
1059
1387
  /** Element children. */
1060
1388
  get children() {
1061
- return this.childNodes.filter((child) => child instanceof Element);
1389
+ return childElements(this);
1062
1390
  }
1063
1391
  /** First element child. */
1064
1392
  get firstElementChild() {
1065
- return this.children[0] ?? null;
1393
+ return firstElementIn(this);
1066
1394
  }
1067
1395
  /** Last element child. */
1068
1396
  get lastElementChild() {
1069
- const children = this.children;
1070
- return children[children.length - 1] ?? null;
1397
+ return lastElementIn(this);
1071
1398
  }
1072
1399
  /** Previous sibling that is an element. */
1073
1400
  get previousElementSibling() {
1074
- for (let node = this.previousSibling; node; node = node.previousSibling) if (node instanceof Element) return node;
1401
+ const index = indexInParent(this);
1402
+ if (index < 0) return null;
1403
+ const siblings = this.parentNode.childNodes;
1404
+ for (let position = index - 1; position >= 0; position--) {
1405
+ const sibling = siblings[position];
1406
+ if (sibling instanceof Element) return sibling;
1407
+ }
1075
1408
  return null;
1076
1409
  }
1077
1410
  /** Next sibling that is an element. */
1078
1411
  get nextElementSibling() {
1079
- for (let node = this.nextSibling; node; node = node.nextSibling) if (node instanceof Element) return node;
1412
+ const index = indexInParent(this);
1413
+ if (index < 0) return null;
1414
+ const siblings = this.parentNode.childNodes;
1415
+ for (let position = index + 1; position < siblings.length; position++) {
1416
+ const sibling = siblings[position];
1417
+ if (sibling instanceof Element) return sibling;
1418
+ }
1080
1419
  return null;
1081
1420
  }
1082
1421
  /** Attribute-backed element id. */
@@ -1120,11 +1459,11 @@ var Element = class Element extends Node {
1120
1459
  get text() {}
1121
1460
  /** HTML contained inside this element. */
1122
1461
  get innerHTML() {
1123
- return this.childNodes.map(serializeNode).join("");
1462
+ return serializeChildren(this);
1124
1463
  }
1125
1464
  set innerHTML(value) {
1126
1465
  this.replaceChildren();
1127
- for (const child of parseFragment(value, this.documentForCreation(), this.localName).childNodes.slice()) this.appendChild(child);
1466
+ parseInto(value, this.documentForCreation(), this);
1128
1467
  }
1129
1468
  /** Serialized element and descendants. */
1130
1469
  get outerHTML() {
@@ -1133,30 +1472,34 @@ var Element = class Element extends Node {
1133
1472
  set outerHTML(value) {
1134
1473
  const parent = this.parentNode;
1135
1474
  if (!parent) return;
1136
- const fragment = parseFragment(value, this.documentForCreation(), this.parentElement?.localName);
1137
- for (const child of Array.from(fragment.childNodes)) parent.insertBefore(child, this);
1475
+ parent.insertBefore(parseFragment(value, this.documentForCreation()), this);
1138
1476
  parent.removeChild(this);
1139
1477
  }
1140
1478
  /** Read an attribute. */
1141
1479
  getAttribute(name) {
1142
- if (name.toLowerCase() === "style" && this.style.cssText) return this.style.cssText;
1143
- return this.attributes.getNamedItem(name)?.value ?? null;
1480
+ const style = this.#style;
1481
+ if (style && name.toLowerCase() === "style") {
1482
+ const cssText = style.cssText;
1483
+ if (cssText) return cssText;
1484
+ }
1485
+ return this.#attributes?.getNamedItem(name)?.value ?? null;
1144
1486
  }
1145
1487
  /** Read an attribute object. */
1146
1488
  getAttributeNode(name) {
1147
- return this.attributes.getNamedItem(name);
1489
+ return this.#attributes?.getNamedItem(name) ?? null;
1148
1490
  }
1149
1491
  /** Whether an attribute exists. */
1150
1492
  hasAttribute(name) {
1151
- return this.attributes.getNamedItem(name) !== null || name.toLowerCase() === "style" && Boolean(this.style.cssText);
1493
+ return (this.#attributes?.getNamedItem(name) ?? null) !== null || this.#style !== void 0 && name.toLowerCase() === "style" && Boolean(this.#style.cssText);
1152
1494
  }
1153
1495
  /** Set an attribute. */
1154
1496
  setAttribute(name, value) {
1155
1497
  const normalized = name.toLowerCase();
1156
1498
  if (normalized === "style") this.style.cssText = String(value);
1157
- const existing = this.attributes.getNamedItem(normalized);
1499
+ const attributes = this.attributes;
1500
+ const existing = attributes.getNamedItem(normalized);
1158
1501
  if (existing) existing.value = String(value);
1159
- else this.attributes.unshift(new Attr(name, String(value), this.ownerDocument));
1502
+ else attributes.unshift(new Attr(name, String(value), this.ownerDocument));
1160
1503
  }
1161
1504
  /** Set a namespaced attribute. */
1162
1505
  setAttributeNS(_namespace, name, value) {
@@ -1164,13 +1507,14 @@ var Element = class Element extends Node {
1164
1507
  }
1165
1508
  /** Remove an attribute. */
1166
1509
  removeAttribute(name) {
1167
- const existing = this.attributes.getNamedItem(name);
1168
- if (existing) this.attributes.splice(this.attributes.indexOf(existing), 1);
1169
- if (name.toLowerCase() === "style") this.style.cssText = "";
1510
+ const attributes = this.#attributes;
1511
+ const existing = attributes?.getNamedItem(name);
1512
+ if (attributes && existing) attributes.splice(attributes.indexOf(existing), 1);
1513
+ if (this.#style && name.toLowerCase() === "style") this.#style.cssText = "";
1170
1514
  }
1171
1515
  /** Find the first descendant matching a selector. */
1172
1516
  querySelector(selector) {
1173
- return querySelectorAllFrom(this, selector, false)[0] ?? null;
1517
+ return querySelectorFrom(this, selector);
1174
1518
  }
1175
1519
  /** Find all descendants matching a selector. */
1176
1520
  querySelectorAll(selector) {
@@ -1182,8 +1526,7 @@ var Element = class Element extends Node {
1182
1526
  }
1183
1527
  /** Find the nearest matching ancestor including this element. */
1184
1528
  closest(selector) {
1185
- for (let element = this; element; element = element.parentElement) if (element.matches(selector)) return element;
1186
- return null;
1529
+ return closestMatching(this, selector);
1187
1530
  }
1188
1531
  /** Descendant elements with a tag name. */
1189
1532
  getElementsByTagName(tagName) {
@@ -1192,7 +1535,10 @@ var Element = class Element extends Node {
1192
1535
  /** Descendant elements containing all requested class tokens. */
1193
1536
  getElementsByClassName(classNames) {
1194
1537
  const tokens = classNames.trim().split(/\s+/).filter(Boolean);
1195
- return querySelectorAllFrom(this, "*", false).filter((element) => tokens.every((token) => element.classList.contains(token)));
1538
+ return querySelectorAllFrom(this, "*", false).filter((element) => {
1539
+ const className = element.className;
1540
+ return tokens.every((token) => hasClassToken(className, token));
1541
+ });
1196
1542
  }
1197
1543
  /**
1198
1544
  * Return a zero-sized rectangle because this parser DOM has no layout.
@@ -1229,11 +1575,12 @@ var Element = class Element extends Node {
1229
1575
  }
1230
1576
  cloneNode(deep = false) {
1231
1577
  const clone = this.ownerDocument?.createElementNS(this.namespaceURI, this.qualifiedName) ?? new Element(this.qualifiedName, null, this.namespaceURI);
1232
- for (let index = this.attributes.length - 1; index >= 0; index--) {
1233
- const attr = this.attributes[index];
1578
+ const attributes = this.#attributes;
1579
+ if (attributes) for (let index = attributes.length - 1; index >= 0; index--) {
1580
+ const attr = attributes[index];
1234
1581
  clone.setAttribute(attr.name, attr.value);
1235
1582
  }
1236
- if (deep) for (const child of this.childNodes) clone.appendChild(child.cloneNode(true));
1583
+ if (deep && this.hasChildNodes()) for (const child of this.childNodes) clone.appendChild(child.cloneNode(true));
1237
1584
  return clone;
1238
1585
  }
1239
1586
  };
@@ -1301,20 +1648,19 @@ var DocumentFragment = class DocumentFragment extends Node {
1301
1648
  }
1302
1649
  /** Element children. */
1303
1650
  get children() {
1304
- return this.childNodes.filter((child) => child instanceof Element);
1651
+ return childElements(this);
1305
1652
  }
1306
1653
  /** First element child. */
1307
1654
  get firstElementChild() {
1308
- return this.children[0] ?? null;
1655
+ return firstElementIn(this);
1309
1656
  }
1310
1657
  /** Last element child. */
1311
1658
  get lastElementChild() {
1312
- const children = this.children;
1313
- return children[children.length - 1] ?? null;
1659
+ return lastElementIn(this);
1314
1660
  }
1315
1661
  /** First matching descendant. */
1316
1662
  querySelector(selector) {
1317
- return querySelectorAllFrom(this, selector, false)[0] ?? null;
1663
+ return querySelectorFrom(this, selector);
1318
1664
  }
1319
1665
  /** All matching descendants. */
1320
1666
  querySelectorAll(selector) {
@@ -1334,11 +1680,11 @@ var HTMLTemplateElement = class HTMLTemplateElement extends HTMLElement {
1334
1680
  this.content = new DocumentFragment(ownerDocument);
1335
1681
  }
1336
1682
  get innerHTML() {
1337
- return this.content.childNodes.map(serializeNode).join("");
1683
+ return serializeChildren(this.content);
1338
1684
  }
1339
1685
  set innerHTML(value) {
1340
1686
  this.content.replaceChildren();
1341
- for (const child of parseFragment(value, this.documentForCreation(), "template").childNodes.slice()) this.content.appendChild(child);
1687
+ parseInto(value, this.documentForCreation(), this.content);
1342
1688
  }
1343
1689
  get textContent() {
1344
1690
  return this.content.textContent ?? "";
@@ -1379,28 +1725,28 @@ var Document = class Document extends Node {
1379
1725
  }
1380
1726
  /** Root element of the document. */
1381
1727
  get documentElement() {
1382
- return this.children[0] ?? null;
1728
+ return firstElementIn(this);
1383
1729
  }
1384
1730
  /** Element children. */
1385
1731
  get children() {
1386
- return this.childNodes.filter((child) => child instanceof Element);
1732
+ return childElements(this);
1387
1733
  }
1388
1734
  /** HTML body, or a detached empty body when absent like linkedom. */
1389
1735
  get body() {
1390
- const body = this.querySelector("body");
1736
+ const body = querySelectorFrom(this, "body");
1391
1737
  return body instanceof HTMLElement ? body : this.createElement("body");
1392
1738
  }
1393
1739
  /** HTML head, or a detached empty head when absent. */
1394
1740
  get head() {
1395
- const head = this.querySelector("head");
1741
+ const head = querySelectorFrom(this, "head");
1396
1742
  return head instanceof HTMLElement ? head : this.createElement("head");
1397
1743
  }
1398
1744
  /** Document title text. */
1399
1745
  get title() {
1400
- return this.querySelector("title")?.textContent ?? "";
1746
+ return querySelectorFrom(this, "title")?.textContent ?? "";
1401
1747
  }
1402
1748
  set title(value) {
1403
- let title = this.querySelector("title");
1749
+ let title = querySelectorFrom(this, "title");
1404
1750
  if (!title) {
1405
1751
  title = this.createElement("title");
1406
1752
  this.head.appendChild(title);
@@ -1444,12 +1790,12 @@ var Document = class Document extends Node {
1444
1790
  }
1445
1791
  /** Find the first element by id. */
1446
1792
  getElementById(id) {
1447
- const element = this.querySelector(`#${cssEscapeIdentifier(id)}`);
1793
+ const element = SELECTOR_SAFE_ID.test(id) ? findElementById(this, id) : querySelectorFrom(this, `#${cssEscapeIdentifier(id)}`);
1448
1794
  return element instanceof HTMLElement ? element : null;
1449
1795
  }
1450
1796
  /** Find the first matching descendant. */
1451
1797
  querySelector(selector) {
1452
- return querySelectorAllFrom(this, selector, true)[0] ?? null;
1798
+ return querySelectorFrom(this, selector);
1453
1799
  }
1454
1800
  /** Find all matching descendants. */
1455
1801
  querySelectorAll(selector) {
@@ -1462,7 +1808,10 @@ var Document = class Document extends Node {
1462
1808
  /** Descendant elements containing all class tokens. */
1463
1809
  getElementsByClassName(classNames) {
1464
1810
  const tokens = classNames.trim().split(/\s+/).filter(Boolean);
1465
- return this.querySelectorAll("*").filter((element) => tokens.every((token) => element.classList.contains(token)));
1811
+ return this.querySelectorAll("*").filter((element) => {
1812
+ const className = element.className;
1813
+ return tokens.every((token) => hasClassToken(className, token));
1814
+ });
1466
1815
  }
1467
1816
  /** Adopt a node into this document. */
1468
1817
  adoptNode(node) {
@@ -1581,31 +1930,98 @@ const BOOLEAN_ATTRIBUTES = {
1581
1930
  reversed: true,
1582
1931
  selected: true
1583
1932
  };
1933
+ const TEXT_ESCAPE_PATTERN = /[&\u00a0<>]/;
1934
+ /** Ids whose escaped `#id` selector parses as one plain id compound (no combinators, lists, quotes or groups). */
1935
+ const SELECTOR_SAFE_ID = /^[^\s,>+~"'[\]()\\]+$/;
1584
1936
  function escapeText(value) {
1585
- return value.replace(/&/g, "&amp;").replace(/ /g, "&#160;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1937
+ if (!TEXT_ESCAPE_PATTERN.test(value)) return value;
1938
+ return value.replace(/&/g, "&amp;").replace(/\u00a0/g, "&#160;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1586
1939
  }
1587
1940
  function escapeAttribute(value) {
1588
- return value.replace(/"/g, "&quot;");
1941
+ return value.includes("\"") ? value.replace(/"/g, "&quot;") : value;
1942
+ }
1943
+ /** Serialize a node's children; `raw` emits text data unescaped (script/style content). */
1944
+ function serializeChildren(parent, raw = false) {
1945
+ if (!parent.hasChildNodes()) return "";
1946
+ let html = "";
1947
+ for (const child of parent.childNodes) html += raw && child instanceof Text ? child.data : serializeNode(child);
1948
+ return html;
1589
1949
  }
1590
1950
  /** Serialize a DOM node as HTML. */
1591
1951
  function serializeNode(node) {
1592
1952
  if (node instanceof Comment) return `<!--${node.data}-->`;
1593
1953
  if (node instanceof Text) return node.serializeRaw ? node.data : escapeText(node.data);
1594
- if (node instanceof Document || node instanceof DocumentFragment) return node.childNodes.map(serializeNode).join("");
1954
+ if (node instanceof Document || node instanceof DocumentFragment) return serializeChildren(node);
1595
1955
  if (!(node instanceof Element)) return "";
1596
- const attributes = node.attributes.map((attr) => attr.value === "" && BOOLEAN_ATTRIBUTES[attr.name.toLowerCase()] ? ` ${attr.name}` : ` ${attr.name}="${escapeAttribute(attr.value)}"`).join("");
1597
- const style = node.style.cssText && !node.attributes.getNamedItem("style") ? ` style="${escapeAttribute(node.style.cssText)}"` : "";
1598
- const opening = `<${node.qualifiedName}${attributes}${style}>`;
1956
+ let opening = `<${node.qualifiedName}`;
1957
+ const hasAttributes = node.hasAttributes();
1958
+ if (hasAttributes) for (const attr of node.attributes) opening += attr.value === "" && BOOLEAN_ATTRIBUTES[attr.name.toLowerCase()] ? ` ${attr.name}` : ` ${attr.name}="${escapeAttribute(attr.value)}"`;
1959
+ const cssText = inlineStyleOf(node)?.cssText;
1960
+ if (cssText && !(hasAttributes && node.attributes.getNamedItem("style"))) opening += ` style="${escapeAttribute(cssText)}"`;
1961
+ opening += ">";
1599
1962
  if (VOID_ELEMENTS[node.localName]) return opening;
1600
1963
  const raw = node.localName === "script" || node.localName === "style";
1601
- const childNodes = node instanceof HTMLTemplateElement ? node.content.childNodes : node.childNodes;
1602
- return `${opening}${raw ? childNodes.map((child) => child instanceof Text ? child.data : serializeNode(child)).join("") : childNodes.map(serializeNode).join("")}</${node.qualifiedName}>`;
1964
+ const content = serializeChildren(node instanceof HTMLTemplateElement ? node.content : node, raw);
1965
+ return `${opening}${content}</${node.qualifiedName}>`;
1966
+ }
1967
+ function childElements(parent) {
1968
+ return parent.hasChildNodes() ? parent.childNodes.filter((child) => child instanceof Element) : [];
1969
+ }
1970
+ function firstElementIn(parent) {
1971
+ if (!parent.hasChildNodes()) return null;
1972
+ for (const child of parent.childNodes) if (child instanceof Element) return child;
1973
+ return null;
1974
+ }
1975
+ function lastElementIn(parent) {
1976
+ if (!parent.hasChildNodes()) return null;
1977
+ const children = parent.childNodes;
1978
+ for (let index = children.length - 1; index >= 0; index--) {
1979
+ const child = children[index];
1980
+ if (child instanceof Element) return child;
1981
+ }
1982
+ return null;
1983
+ }
1984
+ /** First descendant element in document order whose `id` equals `id`. */
1985
+ function findElementById(parent, id) {
1986
+ if (!parent.hasChildNodes()) return null;
1987
+ for (const child of parent.childNodes) {
1988
+ if (child instanceof Element && child.id === id) return child;
1989
+ const found = findElementById(child, id);
1990
+ if (found) return found;
1991
+ }
1992
+ return null;
1993
+ }
1994
+ /**
1995
+ * Concatenate descendant text iteratively, mirroring each node type's `textContent`: character data and
1996
+ * attributes contribute their value, documents nothing, templates their content fragment.
1997
+ */
1998
+ function collectText(children) {
1999
+ let text = "";
2000
+ const pending = [];
2001
+ for (let index = children.length - 1; index >= 0; index--) pending.push(children[index]);
2002
+ while (pending.length > 0) {
2003
+ const node = pending.pop();
2004
+ if (node instanceof Text) {
2005
+ text += node.data;
2006
+ continue;
2007
+ }
2008
+ if (node instanceof Attr) {
2009
+ text += node.value;
2010
+ continue;
2011
+ }
2012
+ if (node instanceof Document) continue;
2013
+ const owner = node instanceof HTMLTemplateElement ? node.content : node;
2014
+ if (!owner.hasChildNodes()) continue;
2015
+ const nested = owner.childNodes;
2016
+ for (let index = nested.length - 1; index >= 0; index--) pending.push(nested[index]);
2017
+ }
2018
+ return text;
1603
2019
  }
1604
2020
  function cssEscapeIdentifier(value) {
1605
2021
  return value.replace(/([^a-zA-Z0-9_-])/g, "\\$1");
1606
2022
  }
1607
2023
  //#endregion
1608
- //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.1.17/node_modules/@oh-my-pi/pi-utils/src/dom.ts
2024
+ //#region node_modules/.pnpm/@oh-my-pi+pi-utils@18.12.6/node_modules/@oh-my-pi/pi-utils/src/dom.ts
1609
2025
  /** Behavior-compatible reimplementation of linkedom's used surface. */
1610
2026
  /** Parse HTML or XML-like markup into a lightweight window and document. */
1611
2027
  function parseHTML(html) {