@ai-react-markdown/engine 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.dev.js CHANGED
@@ -172,8 +172,51 @@ var defaultUrlTransform = (value) => {
172
172
  return "";
173
173
  };
174
174
 
175
- // src/components/incrementalParse/computeFreezeBoundary.ts
176
- import { htmlBlockNames } from "micromark-util-html-tag-name";
175
+ // src/components/incrementalParse/freezeScanState.ts
176
+ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
177
+ return {
178
+ defListEnabled,
179
+ mathFlow,
180
+ referenceTaint,
181
+ confirmedOffset: 0,
182
+ candidates: [],
183
+ defs: /* @__PURE__ */ new Map(),
184
+ footnoteDefs: /* @__PURE__ */ new Map(),
185
+ unresolvedRefs: [],
186
+ tagBalance: /* @__PURE__ */ new Map(),
187
+ openTotal: 0,
188
+ p5Tok: { kind: "data" },
189
+ formPointerMaybeSet: false,
190
+ openStack: [],
191
+ mdBlock: { kind: "none" },
192
+ blankRun: 0,
193
+ lastBlankStart: -1,
194
+ hazardVerdict: false,
195
+ prevLineBlank: true,
196
+ // doc start counts as a block start
197
+ prevLineWasText: false,
198
+ prevLineWasValidDef: false,
199
+ prevLineOpenContent: false,
200
+ tableMaybeOpen: false,
201
+ containerMaybeOpen: false,
202
+ paragraphHasUnpairedRun: false,
203
+ openBracket: null,
204
+ p5SealPending: false,
205
+ defBlockMaybeOpen: false,
206
+ fnDefResumable: false,
207
+ phasePoisonedAt: Infinity,
208
+ pendingTruncatedTags: [],
209
+ pendingTruncatedCloses: [],
210
+ pendingTag: null
211
+ };
212
+ }
213
+ function pendingFenceCloser(checkpoint) {
214
+ const cp = checkpoint;
215
+ if (cp.phasePoisonedAt !== Infinity) return "";
216
+ if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
217
+ if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
218
+ return "";
219
+ }
177
220
 
178
221
  // src/components/incrementalParse/mdLineText.ts
179
222
  var MD_BLANK_RE = /^[ \t\r]*$/;
@@ -181,6 +224,9 @@ var isMdBlank = (text) => MD_BLANK_RE.test(text);
181
224
  var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
182
225
  var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
183
226
 
227
+ // src/components/incrementalParse/freezeLineSyntax.ts
228
+ import { htmlBlockNames } from "micromark-util-html-tag-name";
229
+
184
230
  // src/components/incrementalParse/referenceTaint.ts
185
231
  import { normalizeIdentifier } from "micromark-util-normalize-identifier";
186
232
  var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
@@ -366,7 +412,7 @@ function settleRefsAndEarliestUnresolved(cp) {
366
412
  return earliestUnresolved;
367
413
  }
368
414
 
369
- // src/components/incrementalParse/computeFreezeBoundary.ts
415
+ // src/components/incrementalParse/freezeLineSyntax.ts
370
416
  var TYPE6_NAMES = new Set(htmlBlockNames);
371
417
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
372
418
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
@@ -618,43 +664,6 @@ function maskIntraLineCodeSpans(text, carryOpen) {
618
664
  out += text.slice(cursor);
619
665
  return { masked: out, unpaired: false };
620
666
  }
621
- function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
622
- return {
623
- defListEnabled,
624
- mathFlow,
625
- referenceTaint,
626
- confirmedOffset: 0,
627
- candidates: [],
628
- defs: /* @__PURE__ */ new Map(),
629
- footnoteDefs: /* @__PURE__ */ new Map(),
630
- unresolvedRefs: [],
631
- tagBalance: /* @__PURE__ */ new Map(),
632
- openTotal: 0,
633
- p5Tok: { kind: "data" },
634
- formPointerMaybeSet: false,
635
- openStack: [],
636
- mdBlock: { kind: "none" },
637
- blankRun: 0,
638
- lastBlankStart: -1,
639
- hazardVerdict: false,
640
- prevLineBlank: true,
641
- // doc start counts as a block start
642
- prevLineWasText: false,
643
- prevLineWasValidDef: false,
644
- prevLineOpenContent: false,
645
- tableMaybeOpen: false,
646
- containerMaybeOpen: false,
647
- paragraphHasUnpairedRun: false,
648
- openBracket: null,
649
- p5SealPending: false,
650
- defBlockMaybeOpen: false,
651
- fnDefResumable: false,
652
- phasePoisonedAt: Infinity,
653
- pendingTruncatedTags: [],
654
- pendingTruncatedCloses: [],
655
- pendingTag: null
656
- };
657
- }
658
667
  function classifyBlockStart(text, indent, defListEnabled) {
659
668
  if (indent >= 4) return true;
660
669
  if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;
@@ -662,71 +671,23 @@ function classifyBlockStart(text, indent, defListEnabled) {
662
671
  if (indent === 0) return false;
663
672
  return null;
664
673
  }
665
- function computeFreezeBoundary(text, options, resume) {
666
- const mathFlow = options.mathFlow ?? true;
667
- const referenceTaint = options.referenceTaint ?? true;
668
- const prev = resume;
669
- const cp = prev && prev.defListEnabled === options.defListEnabled && prev.mathFlow === mathFlow && prev.referenceTaint === referenceTaint && prev.confirmedOffset <= text.length ? prev : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
670
- let start = cp.confirmedOffset;
671
- let tailLine = null;
672
- while (start < text.length) {
673
- let end = text.length;
674
- let textEnd = text.length;
675
- {
676
- const nl = text.indexOf("\n", start);
677
- const cr = text.indexOf("\r", start);
678
- if (cr !== -1 && (nl === -1 || cr < nl)) {
679
- textEnd = cr;
680
- end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;
681
- } else if (nl !== -1) {
682
- textEnd = nl;
683
- end = nl;
684
- }
685
- }
686
- const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);
687
- const lineText = text.slice(start, textEnd);
688
- const ln = {
689
- start,
690
- end,
691
- text: lineText,
692
- blank: confirmed && isMdBlank(lineText),
693
- indent: computeIndent(lineText)
694
- };
695
- if (!confirmed) {
696
- tailLine = ln;
697
- break;
698
- }
699
- processConfirmedLine(cp, ln, text);
700
- cp.confirmedOffset = end + 1;
701
- start = end + 1;
702
- }
703
- const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
704
- const defListSettled = (c) => {
705
- if (!options.defListEnabled || c.blankRun >= 2) return true;
706
- if (c.defListSettled !== null) return c.defListSettled;
707
- if (tailLine) return !canBecomeDdLine(tailLine.text, false);
708
- return false;
709
- };
710
- const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);
711
- let boundary = 0;
712
- for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {
713
- const c = cp.candidates[i];
714
- if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;
715
- if (c.offset > cp.phasePoisonedAt) continue;
716
- if (c.offset > earliestUnresolved) continue;
717
- if (!defListSettled(c)) continue;
718
- boundary = c.offset;
719
- break;
720
- }
721
- return { boundary, checkpoint: cp };
722
- }
723
- function pendingFenceCloser(checkpoint) {
724
- const cp = checkpoint;
725
- if (cp.phasePoisonedAt !== Infinity) return "";
726
- if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
727
- if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
728
- return "";
729
- }
674
+ var SCANNER_NAME_LISTS = [
675
+ ["type1", TYPE1_NAMES],
676
+ ["rawText", RAW_TEXT_ELEMENTS],
677
+ ["type6", TYPE6_NAMES],
678
+ ["void", VOID_TAGS],
679
+ ["documentStructure", DOCUMENT_STRUCTURE_NAMES],
680
+ // Added with F28, and it is the list that would have made F28 visible: the
681
+ // derived census alphabet partitions names by their membership across THIS
682
+ // table, so before it existed `frame` shared one 39-name class with `div`
683
+ // and could never be sampled apart from it.
684
+ ["noElement", NO_ELEMENT_NAMES],
685
+ ["tablePart", TABLE_PART_NAMES],
686
+ ["scopeBarrier", SCOPE_BARRIER_NAMES],
687
+ ["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
688
+ ];
689
+
690
+ // src/components/incrementalParse/freezeLineTransition.ts
730
691
  function floatingResidue(text, commentOpenAtStart) {
731
692
  let out = "";
732
693
  let open = commentOpenAtStart;
@@ -1376,24 +1337,66 @@ function processConfirmedLine(cp, ln, text) {
1376
1337
  }
1377
1338
  }
1378
1339
  }
1379
- var SCANNER_NAME_LISTS = [
1380
- ["type1", TYPE1_NAMES],
1381
- ["rawText", RAW_TEXT_ELEMENTS],
1382
- ["type6", TYPE6_NAMES],
1383
- ["void", VOID_TAGS],
1384
- ["documentStructure", DOCUMENT_STRUCTURE_NAMES],
1385
- // Added with F28, and it is the list that would have made F28 visible: the
1386
- // derived census alphabet partitions names by their membership across THIS
1387
- // table, so before it existed `frame` shared one 39-name class with `div`
1388
- // and could never be sampled apart from it.
1389
- ["noElement", NO_ELEMENT_NAMES],
1390
- ["tablePart", TABLE_PART_NAMES],
1391
- ["scopeBarrier", SCOPE_BARRIER_NAMES],
1392
- ["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
1393
- ];
1394
1340
 
1395
- // src/components/incrementalParse/spliceParse.ts
1396
- import { normalizeIdentifier as normalizeIdentifier2 } from "micromark-util-normalize-identifier";
1341
+ // src/components/incrementalParse/computeFreezeBoundary.ts
1342
+ function computeFreezeBoundary(text, options, resume) {
1343
+ const mathFlow = options.mathFlow ?? true;
1344
+ const referenceTaint = options.referenceTaint ?? true;
1345
+ const prev = resume;
1346
+ const cp = prev && prev.defListEnabled === options.defListEnabled && prev.mathFlow === mathFlow && prev.referenceTaint === referenceTaint && prev.confirmedOffset <= text.length ? prev : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
1347
+ let start = cp.confirmedOffset;
1348
+ let tailLine = null;
1349
+ while (start < text.length) {
1350
+ let end = text.length;
1351
+ let textEnd = text.length;
1352
+ {
1353
+ const nl = text.indexOf("\n", start);
1354
+ const cr = text.indexOf("\r", start);
1355
+ if (cr !== -1 && (nl === -1 || cr < nl)) {
1356
+ textEnd = cr;
1357
+ end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;
1358
+ } else if (nl !== -1) {
1359
+ textEnd = nl;
1360
+ end = nl;
1361
+ }
1362
+ }
1363
+ const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);
1364
+ const lineText = text.slice(start, textEnd);
1365
+ const ln = {
1366
+ start,
1367
+ end,
1368
+ text: lineText,
1369
+ blank: confirmed && isMdBlank(lineText),
1370
+ indent: computeIndent(lineText)
1371
+ };
1372
+ if (!confirmed) {
1373
+ tailLine = ln;
1374
+ break;
1375
+ }
1376
+ processConfirmedLine(cp, ln, text);
1377
+ cp.confirmedOffset = end + 1;
1378
+ start = end + 1;
1379
+ }
1380
+ const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
1381
+ const defListSettled = (c) => {
1382
+ if (!options.defListEnabled || c.blankRun >= 2) return true;
1383
+ if (c.defListSettled !== null) return c.defListSettled;
1384
+ if (tailLine) return !canBecomeDdLine(tailLine.text, false);
1385
+ return false;
1386
+ };
1387
+ const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);
1388
+ let boundary = 0;
1389
+ for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {
1390
+ const c = cp.candidates[i];
1391
+ if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;
1392
+ if (c.offset > cp.phasePoisonedAt) continue;
1393
+ if (c.offset > earliestUnresolved) continue;
1394
+ if (!defListSettled(c)) continue;
1395
+ boundary = c.offset;
1396
+ break;
1397
+ }
1398
+ return { boundary, checkpoint: cp };
1399
+ }
1397
1400
 
1398
1401
  // src/components/hastPredicates.ts
1399
1402
  function isFootnoteSection(node) {
@@ -1441,121 +1444,7 @@ function attributeHastChildren(mdast, hast, stopAt = Infinity) {
1441
1444
  }
1442
1445
  }
1443
1446
 
1444
- // src/components/incrementalParse/spliceParse.ts
1445
- function collectPrefixInjection(mdast, content, boundary, resume) {
1446
- const resumeValid = resume != null && resume.boundary <= boundary;
1447
- if (resumeValid && resume.uninjectable) return { events: resume.events, uninjectable: true };
1448
- const resumeAt = resumeValid ? resume.boundary : 0;
1449
- const events = resumeAt > 0 ? cloneEventsForAppend(resume.events) : [];
1450
- let uninjectable = false;
1451
- let cacheable = true;
1452
- const pushRef = (token) => {
1453
- const last = events[events.length - 1];
1454
- if (last && last.kind === "refs") last.tokens.push(token);
1455
- else events.push({ kind: "refs", tokens: [token] });
1456
- };
1457
- const visit7 = (node, nested) => {
1458
- const type = node.type;
1459
- if (type === "definition") {
1460
- const start = node.position?.start?.offset;
1461
- const end = node.position?.end?.offset;
1462
- if (start !== void 0 && end !== void 0 && start < boundary) {
1463
- const slice = content.slice(start, end);
1464
- if (nested && slice.includes("\n")) uninjectable = true;
1465
- else events.push({ kind: "def", source: slice });
1466
- }
1467
- return;
1468
- }
1469
- if (type === "footnoteDefinition") {
1470
- const start = node.position?.start;
1471
- const end = node.position?.end?.offset;
1472
- if (start?.offset === void 0 || end === void 0 || start.offset >= boundary) return;
1473
- if (nested) {
1474
- uninjectable = true;
1475
- return;
1476
- }
1477
- const lineStart = start.offset - (start.column - 1);
1478
- events.push({
1479
- kind: "footnoteDef",
1480
- source: content.slice(lineStart, end),
1481
- origStart: lineStart,
1482
- origLine: start.line
1483
- });
1484
- return;
1485
- }
1486
- if (type === "footnoteReference") {
1487
- const start = node.position?.start?.offset;
1488
- const end = node.position?.end?.offset;
1489
- if (start === void 0 || end === void 0) {
1490
- uninjectable = true;
1491
- return;
1492
- }
1493
- pushRef(content.slice(start, end));
1494
- return;
1495
- }
1496
- const children = node.children;
1497
- if (children) {
1498
- for (const child of children) visit7(child, true);
1499
- }
1500
- };
1501
- let lastStart = -1;
1502
- for (const child of mdast.children) {
1503
- const start = child.position?.start?.offset;
1504
- if (start !== void 0) {
1505
- if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };
1506
- lastStart = start;
1507
- }
1508
- if (start === void 0) {
1509
- if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);
1510
- cacheable = false;
1511
- visit7(child, false);
1512
- continue;
1513
- }
1514
- if (start >= boundary || start < resumeAt) continue;
1515
- visit7(child, false);
1516
- }
1517
- return { events, uninjectable, cacheable };
1518
- }
1519
- function cloneEventsForAppend(events) {
1520
- const out = events.slice();
1521
- const last = out[out.length - 1];
1522
- if (last && last.kind === "refs") out[out.length - 1] = { kind: "refs", tokens: last.tokens.slice() };
1523
- return out;
1524
- }
1525
- var TERMINATOR_LABEL = "__aimd_injection_terminator__";
1526
- var INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;
1527
- function tailMentionsTerminator(tailSource) {
1528
- return normalizeIdentifier2(tailSource).replace(/\[ /g, "[").includes(`[${normalizeIdentifier2(TERMINATOR_LABEL)}`);
1529
- }
1530
- function buildInjectionPrefix(events) {
1531
- if (events.length === 0) return { text: "", segments: [] };
1532
- let text = "";
1533
- let line = 1;
1534
- const segments = [];
1535
- for (const event of events) {
1536
- if (text.length > 0) {
1537
- text += "\n\n";
1538
- line += 2;
1539
- }
1540
- const injStart = text.length;
1541
- const source = event.kind === "refs" ? event.tokens.join(" ") : event.source;
1542
- if (event.kind === "footnoteDef") {
1543
- segments.push({
1544
- injStart,
1545
- injEnd: injStart + source.length,
1546
- offsetDelta: event.origStart - injStart,
1547
- lineDelta: event.origLine - line
1548
- });
1549
- }
1550
- text += source;
1551
- line += countNewlines(source);
1552
- }
1553
- return { text: `${text}
1554
-
1555
- ${INJECTION_TERMINATOR}
1556
-
1557
- `, segments };
1558
- }
1447
+ // src/components/incrementalParse/spliceCoordinates.ts
1559
1448
  function rebaseTree(node, offsetDelta, lineDelta) {
1560
1449
  rebaseTreeDual(node, EMPTY_SEGMENTS, offsetDelta, lineDelta);
1561
1450
  }
@@ -1584,6 +1473,23 @@ function rebaseDualWalk(node, segments, maxEnd, offsetDelta, lineDelta) {
1584
1473
  for (const child of children) rebaseDualWalk(child, segments, maxEnd, offsetDelta, lineDelta);
1585
1474
  }
1586
1475
  }
1476
+ function rebasePoint(point, offsetDelta, lineDelta) {
1477
+ return {
1478
+ line: point.line + lineDelta,
1479
+ column: point.column,
1480
+ offset: point.offset !== void 0 ? point.offset + offsetDelta : void 0
1481
+ };
1482
+ }
1483
+ function countNewlines(text, end = text.length) {
1484
+ let count = 0;
1485
+ for (let i = text.indexOf("\n"); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count += 1;
1486
+ for (let i = text.indexOf("\r"); i !== -1 && i < end; i = text.indexOf("\r", i + 1)) {
1487
+ if (text.charCodeAt(i + 1) !== 10) count += 1;
1488
+ }
1489
+ return count;
1490
+ }
1491
+
1492
+ // src/components/incrementalParse/spliceHtmlGuards.ts
1587
1493
  var TABLE_PART_TAG_RE = /<(?:td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\b/i;
1588
1494
  var TABLE_TOKEN_RE = /<(\/?)(table|td|th|tr|tbody|thead|tfoot|caption|col|colgroup)\b/gi;
1589
1495
  function hasStrayTablePart(values) {
@@ -1665,127 +1571,26 @@ function rawTextRegionCrossesOut(values) {
1665
1571
  }
1666
1572
  return false;
1667
1573
  }
1668
- function spliceTrees(input) {
1669
- const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;
1670
- const injectedLen = injectionPrefix.length;
1671
- const injectedLines = countNewlines(injectionPrefix);
1672
- const prefixLines = countNewlines(content, boundary);
1673
- const offsetDelta = boundary - injectedLen;
1674
- const lineDelta = prefixLines - injectedLines;
1675
- const prefixMdast = [];
1676
- for (const child of prevMdast.children) {
1677
- const start = child.position?.start?.offset;
1678
- if (start !== void 0 && start < boundary) prefixMdast.push(child);
1679
- }
1680
- const attrs = attributeHastChildren(prevMdast, prevHast, boundary);
1681
- const cutRegion = [];
1682
- for (let i = 0; i < prevHast.children.length; i++) {
1683
- if (attrs[i] < boundary) {
1684
- const node2 = prevHast.children[i];
1685
- const end = node2.position?.end?.offset;
1686
- if (end !== void 0 && end > boundary) return null;
1687
- if (isTrailingLiteralText(node2)) {
1688
- const prev = i > 0 ? prevHast.children[i - 1] : void 0;
1689
- if (!prev || prev.type !== "element" || prev.position === void 0) return null;
1690
- if (!ownsTrailingLiteral(prev, node2, prefixMdast))
1691
- return null;
1692
- }
1693
- cutRegion.push(node2);
1694
- continue;
1695
- }
1696
- const node = prevHast.children[i];
1697
- if (i > 0 && attrs[i - 1] < boundary && prevHast.children[i - 1].type === "element" && isTrailingLiteralText(node) && // …and only when that element really IS an html block's output: a
1698
- // raw literal can only trail an `html` mdast node. A position-less
1699
- // text after a `<p>` is the NEXT block's remnant — a stray end tag
1700
- // (`</t>\na`) parse5 dropped, whose text merged with the wrap
1701
- // separator — owned by the tail, which re-parses it; freezing it
1702
- // here duplicated it (v2.4.0 review P3). Falls through to the
1703
- // remnant look-ahead below, which bails to a full parse. And the
1704
- // literal must really be THAT block's trailing text: the block's raw
1705
- // source ends with it. A dropped-tag block right after a frozen html
1706
- // element (`</details>\n\n</t>\ntext`) puts its remnant in the same
1707
- // position, and freezing it duplicated it (release soak of the fix).
1708
- ownsTrailingLiteral(prevHast.children[i - 1], node, prefixMdast)) {
1709
- cutRegion.push(node);
1710
- break;
1711
- }
1712
- for (let j = i; j < prevHast.children.length; j++) {
1713
- const look = prevHast.children[j];
1714
- if (look.type === "element" || look.position !== void 0) break;
1715
- if (isTrailingLiteralText(look)) return null;
1716
- }
1717
- break;
1718
- }
1719
- const tailMdastChildren = tailMdast.children.filter((child) => {
1720
- const start = child.position?.start?.offset;
1721
- return !(start !== void 0 && start < injectedLen);
1722
- });
1723
- const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));
1724
- const prefixHtmlValues = prefixMdast.flatMap((c) => c.type === "html" ? [c.value] : []);
1725
- if (hasStrayTablePart(prefixHtmlValues)) return null;
1726
- if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;
1727
- const leadingHtml = [];
1728
- for (const child of tailMdastChildren) {
1729
- if (isWrapInvisible(child)) continue;
1730
- if (child.type !== "html") break;
1731
- if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;
1732
- leadingHtml.push(child.value);
1574
+ function isSanitizeStrippedConstruct(value) {
1575
+ const v = value.trim();
1576
+ return v.startsWith("<!--") && v.endsWith("-->") || v.startsWith("<?") && v.endsWith("?>") || v.startsWith("<![CDATA[") && v.endsWith("]]>") || /^<![A-Za-z]/.test(v) && !/^<!doctype/i.test(v) && v.endsWith(">");
1577
+ }
1578
+ function isExactSanitizeStrippedConstruct(value) {
1579
+ if (value.startsWith("<!--")) {
1580
+ if (value.length < 7 || !value.endsWith("-->")) return false;
1581
+ const close = value.indexOf("-->", 4);
1582
+ const bangClose = value.indexOf("--!>", 4);
1583
+ if (close !== value.length - 3) return false;
1584
+ return bangClose === -1 || bangClose > close;
1733
1585
  }
1734
- if (headRoutedCaptureUnclosed(leadingHtml)) return null;
1735
- const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);
1736
- if (aligned === null) return null;
1737
- const hastChildren = aligned.children;
1738
- const interiorFinalLiteral = aligned.interiorFinalLiteral;
1739
- const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);
1740
- if (stripResult === null) return null;
1741
- const strippedTailHast = stripResult.rest;
1742
- for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);
1743
- for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);
1744
- const mdastChildren = prefixMdast.concat(tailMdastChildren);
1745
- const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);
1746
- if (seamMergeVerdict === null) return null;
1747
- const seamMergeAllowed = seamMergeVerdict;
1748
- let firstTailChild = true;
1749
- for (const child of strippedTailHast) {
1750
- const tailEnd = hastChildren[hastChildren.length - 1];
1751
- if (firstTailChild && child.type === "text" && child.position !== void 0) {
1752
- return null;
1753
- }
1754
- if (firstTailChild && tailEnd && tailEnd.type === "text" && child.type === "text" && child.position === void 0) {
1755
- if (interiorFinalLiteral && tailEnd.value.trim() !== "") {
1756
- if (seamMergeAllowed) return null;
1757
- firstTailChild = false;
1758
- hastChildren.push(child);
1759
- continue;
1760
- }
1761
- const literalSeam = tailEnd.value.trim() !== "" && !tailWrapVisible;
1762
- if (seamMergeAllowed || literalSeam) {
1763
- hastChildren[hastChildren.length - 1] = { type: "text", value: tailEnd.value + child.value };
1764
- firstTailChild = false;
1765
- continue;
1766
- }
1767
- }
1768
- firstTailChild = false;
1769
- hastChildren.push(child);
1586
+ if (/^<!doctype/i.test(value)) return false;
1587
+ if (value.startsWith("<?") || /^<!(?:[A-Za-z]|\[CDATA\[)/.test(value)) {
1588
+ return value.indexOf(">") === value.length - 1;
1770
1589
  }
1771
- if (!hastChildren.some((child) => child.position !== void 0)) return null;
1772
- const docStart = { line: 1, column: 1, offset: 0 };
1773
- const mdastRootPosition = tailMdast.position ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) } : prevMdast.position;
1774
- const hastRootPosition = mdastRootPosition;
1775
- const mdast = { type: "root", children: mdastChildren };
1776
- if (mdastRootPosition) mdast.position = mdastRootPosition;
1777
- const hast = { type: "root", children: hastChildren };
1778
- if (hastRootPosition) hast.position = hastRootPosition;
1779
- if (prevHast.data !== void 0) hast.data = prevHast.data;
1780
- return { mdast, hast };
1781
- }
1782
- function rebasePoint(point, offsetDelta, lineDelta) {
1783
- return {
1784
- line: point.line + lineDelta,
1785
- column: point.column,
1786
- offset: point.offset !== void 0 ? point.offset + offsetDelta : void 0
1787
- };
1590
+ return false;
1788
1591
  }
1592
+
1593
+ // src/components/incrementalParse/prefixAlignment.ts
1789
1594
  function isWrapInvisible(node) {
1790
1595
  return node.type === "definition" || node.type === "footnoteDefinition";
1791
1596
  }
@@ -1927,96 +1732,303 @@ function stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible) {
1927
1732
  idx += 1;
1928
1733
  continue;
1929
1734
  }
1930
- const start = node.position?.start?.offset;
1931
- if (start === void 0 || start >= injectedLen) return null;
1932
- consumed += 1;
1933
- idx += 1;
1735
+ const start = node.position?.start?.offset;
1736
+ if (start === void 0 || start >= injectedLen) return null;
1737
+ consumed += 1;
1738
+ idx += 1;
1739
+ }
1740
+ if (consumed < injectedVisibleCount) return null;
1741
+ let remnant = "";
1742
+ let remnantMerged = null;
1743
+ if (tailWrapVisible) {
1744
+ const gap = children[idx];
1745
+ if (!gap || !isSeparatorText(gap)) return null;
1746
+ remnant = gap.value.slice(1);
1747
+ remnantMerged = remnant !== "";
1748
+ idx += 1;
1749
+ }
1750
+ const rest = children.slice(idx);
1751
+ if (remnant !== "") rest.unshift({ type: "text", value: remnant });
1752
+ return { rest, remnantMerged };
1753
+ }
1754
+ function tailLeadingTextIsHoist(tailMdastChildren, tailHastChildren) {
1755
+ const firstText = tailHastChildren[0];
1756
+ const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));
1757
+ if (firstVisible?.type === "html" && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;
1758
+ if (!firstText) return false;
1759
+ if (!isSeparatorText(firstText)) {
1760
+ if (firstText.type === "text" && firstText.position === void 0 && firstVisible?.type === "html") {
1761
+ if (/^\s*<\/[A-Za-z][A-Za-z0-9-]*\s*>/.test(firstVisible.value)) return true;
1762
+ if (isSanitizeStrippedConstruct(firstVisible.value)) return false;
1763
+ return null;
1764
+ }
1765
+ return false;
1766
+ }
1767
+ if (!firstVisible) return false;
1768
+ const firstContent = tailHastChildren.find((c) => !isSeparatorText(c));
1769
+ if (firstContent) {
1770
+ const start = firstContent.position?.start?.offset;
1771
+ const vStart = firstVisible.position?.start?.offset;
1772
+ const vEnd = firstVisible.position?.end?.offset;
1773
+ if (start !== void 0 && vStart !== void 0 && vEnd !== void 0) {
1774
+ if (start >= vStart && start < vEnd) return true;
1775
+ }
1776
+ }
1777
+ if (firstVisible.type === "math") return false;
1778
+ if (firstVisible.type === "html" && isSanitizeStrippedConstruct(firstVisible.value)) return false;
1779
+ return null;
1780
+ }
1781
+ function isSeparatorText(node) {
1782
+ return node.type === "text" && node.position === void 0 && node.value.trim() === "";
1783
+ }
1784
+ function ownsTrailingLiteral(el, literal, prefixMdast) {
1785
+ const start = el.position?.start?.offset;
1786
+ if (start === void 0) return false;
1787
+ const owner = prefixMdast.find((c) => c.type === "html" && c.position?.start?.offset === start);
1788
+ if (!owner || owner.type !== "html") return false;
1789
+ const text = literal.value.trim();
1790
+ return text !== "" && owner.value.trimEnd().endsWith(text);
1791
+ }
1792
+ function isTrailingLiteralText(node) {
1793
+ return node.type === "text" && node.position === void 0 && node.value.trim() !== "";
1794
+ }
1795
+ function countTrailingNewlines(value) {
1796
+ let n = 0;
1797
+ for (let i = value.length - 1; i >= 0 && value[i] === "\n"; i--) n += 1;
1798
+ return n;
1799
+ }
1800
+
1801
+ // src/components/incrementalParse/prefixInjection.ts
1802
+ import { normalizeIdentifier as normalizeIdentifier2 } from "micromark-util-normalize-identifier";
1803
+ function collectPrefixInjection(mdast, content, boundary, resume) {
1804
+ const resumeValid = resume != null && resume.boundary <= boundary;
1805
+ if (resumeValid && resume.uninjectable) return { events: resume.events, uninjectable: true };
1806
+ const resumeAt = resumeValid ? resume.boundary : 0;
1807
+ const events = resumeAt > 0 ? cloneEventsForAppend(resume.events) : [];
1808
+ let uninjectable = false;
1809
+ let cacheable = true;
1810
+ const pushRef = (token) => {
1811
+ const last = events[events.length - 1];
1812
+ if (last && last.kind === "refs") last.tokens.push(token);
1813
+ else events.push({ kind: "refs", tokens: [token] });
1814
+ };
1815
+ const visit7 = (node, nested) => {
1816
+ const type = node.type;
1817
+ if (type === "definition") {
1818
+ const start = node.position?.start?.offset;
1819
+ const end = node.position?.end?.offset;
1820
+ if (start !== void 0 && end !== void 0 && start < boundary) {
1821
+ const slice = content.slice(start, end);
1822
+ if (nested && slice.includes("\n")) uninjectable = true;
1823
+ else events.push({ kind: "def", source: slice });
1824
+ }
1825
+ return;
1826
+ }
1827
+ if (type === "footnoteDefinition") {
1828
+ const start = node.position?.start;
1829
+ const end = node.position?.end?.offset;
1830
+ if (start?.offset === void 0 || end === void 0 || start.offset >= boundary) return;
1831
+ if (nested) {
1832
+ uninjectable = true;
1833
+ return;
1834
+ }
1835
+ const lineStart = start.offset - (start.column - 1);
1836
+ events.push({
1837
+ kind: "footnoteDef",
1838
+ source: content.slice(lineStart, end),
1839
+ origStart: lineStart,
1840
+ origLine: start.line
1841
+ });
1842
+ return;
1843
+ }
1844
+ if (type === "footnoteReference") {
1845
+ const start = node.position?.start?.offset;
1846
+ const end = node.position?.end?.offset;
1847
+ if (start === void 0 || end === void 0) {
1848
+ uninjectable = true;
1849
+ return;
1850
+ }
1851
+ pushRef(content.slice(start, end));
1852
+ return;
1853
+ }
1854
+ const children = node.children;
1855
+ if (children) {
1856
+ for (const child of children) visit7(child, true);
1857
+ }
1858
+ };
1859
+ let lastStart = -1;
1860
+ for (const child of mdast.children) {
1861
+ const start = child.position?.start?.offset;
1862
+ if (start !== void 0) {
1863
+ if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };
1864
+ lastStart = start;
1865
+ }
1866
+ if (start === void 0) {
1867
+ if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);
1868
+ cacheable = false;
1869
+ visit7(child, false);
1870
+ continue;
1871
+ }
1872
+ if (start >= boundary || start < resumeAt) continue;
1873
+ visit7(child, false);
1874
+ }
1875
+ return { events, uninjectable, cacheable };
1876
+ }
1877
+ function cloneEventsForAppend(events) {
1878
+ const out = events.slice();
1879
+ const last = out[out.length - 1];
1880
+ if (last && last.kind === "refs") out[out.length - 1] = { kind: "refs", tokens: last.tokens.slice() };
1881
+ return out;
1882
+ }
1883
+ var TERMINATOR_LABEL = "__aimd_injection_terminator__";
1884
+ var INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;
1885
+ function tailMentionsTerminator(tailSource) {
1886
+ return normalizeIdentifier2(tailSource).replace(/\[ /g, "[").includes(`[${normalizeIdentifier2(TERMINATOR_LABEL)}`);
1887
+ }
1888
+ function buildInjectionPrefix(events) {
1889
+ if (events.length === 0) return { text: "", segments: [] };
1890
+ let text = "";
1891
+ let line = 1;
1892
+ const segments = [];
1893
+ for (const event of events) {
1894
+ if (text.length > 0) {
1895
+ text += "\n\n";
1896
+ line += 2;
1897
+ }
1898
+ const injStart = text.length;
1899
+ const source = event.kind === "refs" ? event.tokens.join(" ") : event.source;
1900
+ if (event.kind === "footnoteDef") {
1901
+ segments.push({
1902
+ injStart,
1903
+ injEnd: injStart + source.length,
1904
+ offsetDelta: event.origStart - injStart,
1905
+ lineDelta: event.origLine - line
1906
+ });
1907
+ }
1908
+ text += source;
1909
+ line += countNewlines(source);
1910
+ }
1911
+ return { text: `${text}
1912
+
1913
+ ${INJECTION_TERMINATOR}
1914
+
1915
+ `, segments };
1916
+ }
1917
+
1918
+ // src/components/incrementalParse/spliceParse.ts
1919
+ function spliceTrees(input) {
1920
+ const { prevMdast, prevHast, tailMdast, tailHast, content, boundary, injectionPrefix, injectedSegments } = input;
1921
+ const injectedLen = injectionPrefix.length;
1922
+ const injectedLines = countNewlines(injectionPrefix);
1923
+ const prefixLines = countNewlines(content, boundary);
1924
+ const offsetDelta = boundary - injectedLen;
1925
+ const lineDelta = prefixLines - injectedLines;
1926
+ const prefixMdast = [];
1927
+ for (const child of prevMdast.children) {
1928
+ const start = child.position?.start?.offset;
1929
+ if (start !== void 0 && start < boundary) prefixMdast.push(child);
1930
+ }
1931
+ const attrs = attributeHastChildren(prevMdast, prevHast, boundary);
1932
+ const cutRegion = [];
1933
+ for (let i = 0; i < prevHast.children.length; i++) {
1934
+ if (attrs[i] < boundary) {
1935
+ const node2 = prevHast.children[i];
1936
+ const end = node2.position?.end?.offset;
1937
+ if (end !== void 0 && end > boundary) return null;
1938
+ if (isTrailingLiteralText(node2)) {
1939
+ const prev = i > 0 ? prevHast.children[i - 1] : void 0;
1940
+ if (!prev || prev.type !== "element" || prev.position === void 0) return null;
1941
+ if (!ownsTrailingLiteral(prev, node2, prefixMdast))
1942
+ return null;
1943
+ }
1944
+ cutRegion.push(node2);
1945
+ continue;
1946
+ }
1947
+ const node = prevHast.children[i];
1948
+ if (i > 0 && attrs[i - 1] < boundary && prevHast.children[i - 1].type === "element" && isTrailingLiteralText(node) && // …and only when that element really IS an html block's output: a
1949
+ // raw literal can only trail an `html` mdast node. A position-less
1950
+ // text after a `<p>` is the NEXT block's remnant — a stray end tag
1951
+ // (`</t>\na`) parse5 dropped, whose text merged with the wrap
1952
+ // separator — owned by the tail, which re-parses it; freezing it
1953
+ // here duplicated it (v2.4.0 review P3). Falls through to the
1954
+ // remnant look-ahead below, which bails to a full parse. And the
1955
+ // literal must really be THAT block's trailing text: the block's raw
1956
+ // source ends with it. A dropped-tag block right after a frozen html
1957
+ // element (`</details>\n\n</t>\ntext`) puts its remnant in the same
1958
+ // position, and freezing it duplicated it (release soak of the fix).
1959
+ ownsTrailingLiteral(prevHast.children[i - 1], node, prefixMdast)) {
1960
+ cutRegion.push(node);
1961
+ break;
1962
+ }
1963
+ for (let j = i; j < prevHast.children.length; j++) {
1964
+ const look = prevHast.children[j];
1965
+ if (look.type === "element" || look.position !== void 0) break;
1966
+ if (isTrailingLiteralText(look)) return null;
1967
+ }
1968
+ break;
1934
1969
  }
1935
- if (consumed < injectedVisibleCount) return null;
1936
- let remnant = "";
1937
- let remnantMerged = null;
1938
- if (tailWrapVisible) {
1939
- const gap = children[idx];
1940
- if (!gap || !isSeparatorText(gap)) return null;
1941
- remnant = gap.value.slice(1);
1942
- remnantMerged = remnant !== "";
1943
- idx += 1;
1970
+ const tailMdastChildren = tailMdast.children.filter((child) => {
1971
+ const start = child.position?.start?.offset;
1972
+ return !(start !== void 0 && start < injectedLen);
1973
+ });
1974
+ const tailWrapVisible = tailMdastChildren.some((child) => !isWrapInvisible(child));
1975
+ const prefixHtmlValues = prefixMdast.flatMap((c) => c.type === "html" ? [c.value] : []);
1976
+ if (hasStrayTablePart(prefixHtmlValues)) return null;
1977
+ if (rawTextRegionCrossesOut(prefixHtmlValues)) return null;
1978
+ const leadingHtml = [];
1979
+ for (const child of tailMdastChildren) {
1980
+ if (isWrapInvisible(child)) continue;
1981
+ if (child.type !== "html") break;
1982
+ if (STRAY_SYNTHESIZED_END_TAG_RE.test(child.value) || TABLE_PART_TAG_RE.test(child.value)) return null;
1983
+ leadingHtml.push(child.value);
1944
1984
  }
1945
- const rest = children.slice(idx);
1946
- if (remnant !== "") rest.unshift({ type: "text", value: remnant });
1947
- return { rest, remnantMerged };
1948
- }
1949
- function tailLeadingTextIsHoist(tailMdastChildren, tailHastChildren) {
1950
- const firstText = tailHastChildren[0];
1951
- const firstVisible = tailMdastChildren.find((c) => !isWrapInvisible(c));
1952
- if (firstVisible?.type === "html" && STRAY_SYNTHESIZED_END_TAG_RE.test(firstVisible.value)) return null;
1953
- if (!firstText) return false;
1954
- if (!isSeparatorText(firstText)) {
1955
- if (firstText.type === "text" && firstText.position === void 0 && firstVisible?.type === "html") {
1956
- if (/^\s*<\/[A-Za-z][A-Za-z0-9-]*\s*>/.test(firstVisible.value)) return true;
1957
- if (isSanitizeStrippedConstruct(firstVisible.value)) return false;
1985
+ if (headRoutedCaptureUnclosed(leadingHtml)) return null;
1986
+ const aligned = alignPrefixCut(prefixMdast, cutRegion, tailWrapVisible);
1987
+ if (aligned === null) return null;
1988
+ const hastChildren = aligned.children;
1989
+ const interiorFinalLiteral = aligned.interiorFinalLiteral;
1990
+ const stripResult = stripInjectedHast(tailMdast, tailHast, injectedLen, tailWrapVisible);
1991
+ if (stripResult === null) return null;
1992
+ const strippedTailHast = stripResult.rest;
1993
+ for (const child of tailMdastChildren) rebaseTree(child, offsetDelta, lineDelta);
1994
+ for (const child of strippedTailHast) rebaseTreeDual(child, injectedSegments, offsetDelta, lineDelta);
1995
+ const mdastChildren = prefixMdast.concat(tailMdastChildren);
1996
+ const seamMergeVerdict = stripResult.remnantMerged ?? tailLeadingTextIsHoist(tailMdastChildren, strippedTailHast);
1997
+ if (seamMergeVerdict === null) return null;
1998
+ const seamMergeAllowed = seamMergeVerdict;
1999
+ let firstTailChild = true;
2000
+ for (const child of strippedTailHast) {
2001
+ const tailEnd = hastChildren[hastChildren.length - 1];
2002
+ if (firstTailChild && child.type === "text" && child.position !== void 0) {
1958
2003
  return null;
1959
2004
  }
1960
- return false;
1961
- }
1962
- if (!firstVisible) return false;
1963
- const firstContent = tailHastChildren.find((c) => !isSeparatorText(c));
1964
- if (firstContent) {
1965
- const start = firstContent.position?.start?.offset;
1966
- const vStart = firstVisible.position?.start?.offset;
1967
- const vEnd = firstVisible.position?.end?.offset;
1968
- if (start !== void 0 && vStart !== void 0 && vEnd !== void 0) {
1969
- if (start >= vStart && start < vEnd) return true;
2005
+ if (firstTailChild && tailEnd && tailEnd.type === "text" && child.type === "text" && child.position === void 0) {
2006
+ if (interiorFinalLiteral && tailEnd.value.trim() !== "") {
2007
+ if (seamMergeAllowed) return null;
2008
+ firstTailChild = false;
2009
+ hastChildren.push(child);
2010
+ continue;
2011
+ }
2012
+ const literalSeam = tailEnd.value.trim() !== "" && !tailWrapVisible;
2013
+ if (seamMergeAllowed || literalSeam) {
2014
+ hastChildren[hastChildren.length - 1] = { type: "text", value: tailEnd.value + child.value };
2015
+ firstTailChild = false;
2016
+ continue;
2017
+ }
1970
2018
  }
2019
+ firstTailChild = false;
2020
+ hastChildren.push(child);
1971
2021
  }
1972
- if (firstVisible.type === "math") return false;
1973
- if (firstVisible.type === "html" && isSanitizeStrippedConstruct(firstVisible.value)) return false;
1974
- return null;
1975
- }
1976
- function isSanitizeStrippedConstruct(value) {
1977
- const v = value.trim();
1978
- return v.startsWith("<!--") && v.endsWith("-->") || v.startsWith("<?") && v.endsWith("?>") || v.startsWith("<![CDATA[") && v.endsWith("]]>") || /^<![A-Za-z]/.test(v) && !/^<!doctype/i.test(v) && v.endsWith(">");
1979
- }
1980
- function isExactSanitizeStrippedConstruct(value) {
1981
- if (value.startsWith("<!--")) {
1982
- if (value.length < 7 || !value.endsWith("-->")) return false;
1983
- const close = value.indexOf("-->", 4);
1984
- const bangClose = value.indexOf("--!>", 4);
1985
- if (close !== value.length - 3) return false;
1986
- return bangClose === -1 || bangClose > close;
1987
- }
1988
- if (/^<!doctype/i.test(value)) return false;
1989
- if (value.startsWith("<?") || /^<!(?:[A-Za-z]|\[CDATA\[)/.test(value)) {
1990
- return value.indexOf(">") === value.length - 1;
1991
- }
1992
- return false;
1993
- }
1994
- function isSeparatorText(node) {
1995
- return node.type === "text" && node.position === void 0 && node.value.trim() === "";
1996
- }
1997
- function ownsTrailingLiteral(el, literal, prefixMdast) {
1998
- const start = el.position?.start?.offset;
1999
- if (start === void 0) return false;
2000
- const owner = prefixMdast.find((c) => c.type === "html" && c.position?.start?.offset === start);
2001
- if (!owner || owner.type !== "html") return false;
2002
- const text = literal.value.trim();
2003
- return text !== "" && owner.value.trimEnd().endsWith(text);
2004
- }
2005
- function isTrailingLiteralText(node) {
2006
- return node.type === "text" && node.position === void 0 && node.value.trim() !== "";
2007
- }
2008
- function countTrailingNewlines(value) {
2009
- let n = 0;
2010
- for (let i = value.length - 1; i >= 0 && value[i] === "\n"; i--) n += 1;
2011
- return n;
2012
- }
2013
- function countNewlines(text, end = text.length) {
2014
- let count = 0;
2015
- for (let i = text.indexOf("\n"); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count += 1;
2016
- for (let i = text.indexOf("\r"); i !== -1 && i < end; i = text.indexOf("\r", i + 1)) {
2017
- if (text.charCodeAt(i + 1) !== 10) count += 1;
2018
- }
2019
- return count;
2022
+ if (!hastChildren.some((child) => child.position !== void 0)) return null;
2023
+ const docStart = { line: 1, column: 1, offset: 0 };
2024
+ const mdastRootPosition = tailMdast.position ? { start: docStart, end: rebasePoint(tailMdast.position.end, offsetDelta, lineDelta) } : prevMdast.position;
2025
+ const hastRootPosition = mdastRootPosition;
2026
+ const mdast = { type: "root", children: mdastChildren };
2027
+ if (mdastRootPosition) mdast.position = mdastRootPosition;
2028
+ const hast = { type: "root", children: hastChildren };
2029
+ if (hastRootPosition) hast.position = hastRootPosition;
2030
+ if (prevHast.data !== void 0) hast.data = prevHast.data;
2031
+ return { mdast, hast };
2020
2032
  }
2021
2033
 
2022
2034
  // src/components/incrementalParse/advanceIncrementalParse.ts
@@ -2138,6 +2150,38 @@ function normalizeForMatch(s) {
2138
2150
  return normalizeIdentifier3(s);
2139
2151
  }
2140
2152
 
2153
+ // src/components/blankLineScanner.ts
2154
+ function createBlankLineScanner() {
2155
+ let end = 0;
2156
+ let newline = false;
2157
+ let cr = false;
2158
+ return (source, from = 0) => {
2159
+ if (from === 0) {
2160
+ end = 0;
2161
+ newline = false;
2162
+ cr = false;
2163
+ }
2164
+ for (let i = from; i < source.length; i++) {
2165
+ const c = source[i];
2166
+ if (c === "\n") {
2167
+ if (newline) {
2168
+ end = i + 1;
2169
+ newline = false;
2170
+ } else newline = true;
2171
+ cr = false;
2172
+ } else if (newline) {
2173
+ if ((c === " " || c === " ") && !cr) continue;
2174
+ if (c === "\r" && !cr) cr = true;
2175
+ else {
2176
+ newline = false;
2177
+ cr = false;
2178
+ }
2179
+ }
2180
+ }
2181
+ return end;
2182
+ };
2183
+ }
2184
+
2141
2185
  // src/components/collectDefLabels.ts
2142
2186
  var SCANNER_BOUNDARY_PROFILE = { defListEnabled: false, mathFlow: false, referenceTaint: false };
2143
2187
  function buildProcessor() {
@@ -2169,19 +2213,12 @@ var setsEqual = (a, b) => {
2169
2213
  for (const v of a) if (!b.has(v)) return false;
2170
2214
  return true;
2171
2215
  };
2172
- var BLANK_LINE_RE = /\r?\n[ \t]*\r?\n/g;
2173
- function lastRegionStart(source) {
2174
- BLANK_LINE_RE.lastIndex = 0;
2175
- let start = 0;
2176
- for (let m = BLANK_LINE_RE.exec(source); m !== null; m = BLANK_LINE_RE.exec(source)) {
2177
- start = m.index + m[0].length;
2178
- }
2179
- return start;
2180
- }
2181
2216
  var DEF_LINE_START_RE = /^[ \t>*+\d.)-]*\[(?:[^\]\\]|\\[\s\S])*\]:/m;
2182
2217
  function createDefLabelScanner(parse = collectDefLabels) {
2183
2218
  let prevSource = null;
2184
2219
  let prevLabels = null;
2220
+ const scanBlankLines = createBlankLineScanner();
2221
+ let regionStart = 0;
2185
2222
  let frozenEnd = 0;
2186
2223
  let frozenFootnotes = /* @__PURE__ */ new Set();
2187
2224
  let frozenLinks = /* @__PURE__ */ new Set();
@@ -2194,13 +2231,16 @@ function createDefLabelScanner(parse = collectDefLabels) {
2194
2231
  };
2195
2232
  return {
2196
2233
  scan(source) {
2234
+ if (source === prevSource && prevLabels !== null) return prevLabels;
2235
+ const previousRegionStart = regionStart;
2236
+ const appended = prevSource !== null && source.startsWith(prevSource);
2237
+ regionStart = scanBlankLines(source, appended ? prevSource.length : 0);
2197
2238
  let isAppend = false;
2198
2239
  if (prevSource !== null && prevLabels !== null) {
2199
2240
  if (source === prevSource) return prevLabels;
2200
2241
  if (source.startsWith(prevSource)) {
2201
2242
  isAppend = true;
2202
- const regionStart = lastRegionStart(prevSource);
2203
- const region = prevSource.slice(regionStart) + source.slice(prevSource.length);
2243
+ const region = source.slice(previousRegionStart);
2204
2244
  if (!DEF_LINE_START_RE.test(region)) {
2205
2245
  prevSource = source;
2206
2246
  return prevLabels;
@@ -2433,8 +2473,115 @@ function* extractContributions(mdast, options = {}) {
2433
2473
  for (const c of out) yield c;
2434
2474
  }
2435
2475
 
2476
+ // src/components/registryIndex.ts
2477
+ function buildRegistryIndex(registry) {
2478
+ const index = {
2479
+ footnotes: /* @__PURE__ */ new Map(),
2480
+ links: /* @__PURE__ */ new Map(),
2481
+ numbers: /* @__PURE__ */ new Map(),
2482
+ counts: /* @__PURE__ */ new Map(),
2483
+ occurrences: /* @__PURE__ */ new Map(),
2484
+ labelOccurrences: /* @__PURE__ */ new Map()
2485
+ };
2486
+ for (const sym of registry.chunkOrder) {
2487
+ const data = registry.chunkData.get(sym);
2488
+ if (!data) continue;
2489
+ for (const label of data.defs.keys()) if (!index.footnotes.has(label)) index.footnotes.set(label, sym);
2490
+ for (const label of data.linkDefs.keys()) if (!index.links.has(label)) index.links.set(label, sym);
2491
+ const local = /* @__PURE__ */ new Map();
2492
+ index.occurrences.set(sym, local);
2493
+ for (const ref of data.refs) {
2494
+ if (ref.kind !== "footnote") continue;
2495
+ const label = ref.label;
2496
+ if (!index.numbers.has(label)) index.numbers.set(label, index.numbers.size + 1);
2497
+ const total = (index.counts.get(label) ?? 0) + 1;
2498
+ index.counts.set(label, total);
2499
+ const prior = local.get(label);
2500
+ if (prior) prior.count++;
2501
+ else {
2502
+ const range = { start: total, count: 1 };
2503
+ local.set(label, range);
2504
+ let byChunk = index.labelOccurrences.get(label);
2505
+ if (!byChunk) index.labelOccurrences.set(label, byChunk = /* @__PURE__ */ new Map());
2506
+ byChunk.set(sym, range);
2507
+ }
2508
+ }
2509
+ }
2510
+ return index;
2511
+ }
2512
+
2513
+ // src/components/registrySubscriptions.ts
2514
+ function equal(a, b) {
2515
+ if (a.owner !== b.owner || a.url !== b.url || a.title !== b.title || a.number !== b.number || a.count !== b.count)
2516
+ return false;
2517
+ if (a.occurrences?.size !== b.occurrences?.size) return false;
2518
+ if (a.occurrences) {
2519
+ for (const [chunk, range] of a.occurrences) {
2520
+ const next = b.occurrences?.get(chunk);
2521
+ if (!next || next.start !== range.start || next.count !== range.count) return false;
2522
+ }
2523
+ }
2524
+ return true;
2525
+ }
2526
+ function createRegistrySubscriptions(read) {
2527
+ const groups = { link: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() };
2528
+ const snapshot = (kind, label, { registry, index }) => {
2529
+ if (kind === "link") {
2530
+ const owner = index.links.get(label);
2531
+ const def = owner ? registry.chunkData.get(owner)?.linkDefs.get(label) : void 0;
2532
+ return { owner, url: def?.url, title: def?.title };
2533
+ }
2534
+ return {
2535
+ owner: index.footnotes.get(label),
2536
+ number: index.numbers.get(label),
2537
+ count: index.counts.get(label),
2538
+ occurrences: index.labelOccurrences.get(label)
2539
+ };
2540
+ };
2541
+ return {
2542
+ subscribe(kind, rawLabel, cb) {
2543
+ const label = normalizeId(rawLabel);
2544
+ const map = groups[kind];
2545
+ let group = map.get(label);
2546
+ if (!group) {
2547
+ group = { snapshot: snapshot(kind, label, read()), listeners: /* @__PURE__ */ new Set() };
2548
+ map.set(label, group);
2549
+ }
2550
+ const listener = () => cb();
2551
+ group.listeners.add(listener);
2552
+ return () => {
2553
+ group.listeners.delete(listener);
2554
+ if (group.listeners.size === 0 && map.get(label) === group) map.delete(label);
2555
+ };
2556
+ },
2557
+ collect() {
2558
+ if (groups.link.size === 0 && groups.footnote.size === 0) return [];
2559
+ const state = read();
2560
+ const callbacks = [];
2561
+ for (const kind of ["link", "footnote"]) {
2562
+ for (const [label, group] of groups[kind]) {
2563
+ const next = snapshot(kind, label, state);
2564
+ if (!equal(group.snapshot, next)) callbacks.push(...group.listeners);
2565
+ group.snapshot = next;
2566
+ }
2567
+ }
2568
+ return callbacks;
2569
+ }
2570
+ };
2571
+ }
2572
+
2436
2573
  // src/components/documentRegistry.ts
2437
2574
  function createRegistry(onEmpty) {
2575
+ let index;
2576
+ let indexedVersion = -1;
2577
+ const getIndex = () => {
2578
+ if (!index || indexedVersion !== reg.version) {
2579
+ index = buildRegistryIndex(reg);
2580
+ indexedVersion = reg.version;
2581
+ }
2582
+ return index;
2583
+ };
2584
+ const labels = createRegistrySubscriptions(() => ({ registry: reg, index: getIndex() }));
2438
2585
  const reg = {
2439
2586
  chunkOrder: [],
2440
2587
  chunkData: /* @__PURE__ */ new Map(),
@@ -2585,73 +2732,29 @@ function createRegistry(onEmpty) {
2585
2732
  this._subscribers.delete(cb);
2586
2733
  };
2587
2734
  },
2735
+ subscribeLabel(kind, label, cb) {
2736
+ return labels.subscribe(kind, label, cb);
2737
+ },
2588
2738
  canonicalFootnoteFor(label) {
2589
- const id = normalizeId(label);
2590
- for (const sym of this.chunkOrder) {
2591
- const data = this.chunkData.get(sym);
2592
- if (data?.defs.has(id)) return sym;
2593
- }
2594
- return null;
2739
+ return getIndex().footnotes.get(normalizeId(label)) ?? null;
2595
2740
  },
2596
2741
  canonicalLinkFor(label) {
2597
- const id = normalizeId(label);
2598
- for (const sym of this.chunkOrder) {
2599
- const data = this.chunkData.get(sym);
2600
- if (data?.linkDefs.has(id)) return sym;
2601
- }
2602
- return null;
2742
+ return getIndex().links.get(normalizeId(label)) ?? null;
2603
2743
  },
2604
2744
  globalNumber(label) {
2605
- const id = normalizeId(label);
2606
- let n = 0;
2607
- const seen = /* @__PURE__ */ new Set();
2608
- for (const sym of this.chunkOrder) {
2609
- const data = this.chunkData.get(sym);
2610
- if (!data) continue;
2611
- for (const ref of data.refs) {
2612
- if (ref.kind !== "footnote") continue;
2613
- if (!seen.has(ref.label)) {
2614
- seen.add(ref.label);
2615
- n++;
2616
- if (ref.label === id) return n;
2617
- }
2618
- }
2619
- }
2620
- return null;
2745
+ return getIndex().numbers.get(normalizeId(label)) ?? null;
2621
2746
  },
2622
2747
  resolveLinkDef(label) {
2623
- const sym = this.canonicalLinkFor(label);
2624
- if (!sym) return null;
2625
- return this.chunkData.get(sym)?.linkDefs.get(normalizeId(label)) ?? null;
2748
+ const id = normalizeId(label);
2749
+ const sym = getIndex().links.get(id);
2750
+ return sym ? this.chunkData.get(sym)?.linkDefs.get(id) ?? null : null;
2626
2751
  },
2627
2752
  getRefsForLabel(label) {
2628
- const id = normalizeId(label);
2629
- let n = 0;
2630
- for (const sym of this.chunkOrder) {
2631
- const data = this.chunkData.get(sym);
2632
- if (!data) continue;
2633
- for (const ref of data.refs) {
2634
- if (ref.kind === "footnote" && ref.label === id) n++;
2635
- }
2636
- }
2637
- return n;
2753
+ return getIndex().counts.get(normalizeId(label)) ?? 0;
2638
2754
  },
2639
2755
  globalOccurrenceForRef(chunkSym, label, localOccurrence) {
2640
- const id = normalizeId(label);
2641
- let global2 = 0;
2642
- for (const sym of this.chunkOrder) {
2643
- const data = this.chunkData.get(sym);
2644
- if (!data) continue;
2645
- let localCount = 0;
2646
- for (const ref of data.refs) {
2647
- if (ref.kind !== "footnote") continue;
2648
- if (ref.label !== id) continue;
2649
- localCount++;
2650
- global2++;
2651
- if (sym === chunkSym && localCount === localOccurrence) return global2;
2652
- }
2653
- }
2654
- return null;
2756
+ const range = getIndex().occurrences.get(chunkSym)?.get(normalizeId(label));
2757
+ return range && Number.isInteger(localOccurrence) && localOccurrence > 0 && localOccurrence <= range.count ? range.start + localOccurrence - 1 : null;
2655
2758
  },
2656
2759
  _notify() {
2657
2760
  this.version++;
@@ -2659,7 +2762,9 @@ function createRegistry(onEmpty) {
2659
2762
  this._notifyScheduled = true;
2660
2763
  queueMicrotask(() => {
2661
2764
  this._notifyScheduled = false;
2765
+ const labelCallbacks = labels.collect();
2662
2766
  for (const cb of [...this._subscribers]) cb();
2767
+ for (const cb of labelCallbacks) cb();
2663
2768
  });
2664
2769
  }
2665
2770
  };
@@ -2716,7 +2821,7 @@ var ENGINE_PLACEHOLDER_TAGS = /* @__PURE__ */ new Set([
2716
2821
  "cross-chunk-image"
2717
2822
  ]);
2718
2823
  var ENGINE_PROVENANCE_PROPERTY = "engineProvenance";
2719
- function walk(parent, provenance) {
2824
+ function walk(parent, provenance, ancestors) {
2720
2825
  const children = parent.children;
2721
2826
  let i = 0;
2722
2827
  while (i < children.length) {
@@ -2727,21 +2832,32 @@ function walk(parent, provenance) {
2727
2832
  const genuine = provenance !== "" && typeof stamped === "string" && stamped === provenance;
2728
2833
  if (genuine) {
2729
2834
  delete props[ENGINE_PROVENANCE_PROPERTY];
2730
- walk(node, provenance);
2835
+ if (ancestors && (node.tagName === "cross-chunk-link" || node.tagName === "cross-chunk-image")) {
2836
+ (node.data ??= {}).referenceAncestors = ancestors.slice();
2837
+ }
2838
+ ancestors?.push(
2839
+ node.tagName === "cross-chunk-link" ? "a" : node.tagName === "cross-chunk-image" ? "img" : node.tagName
2840
+ );
2841
+ walk(node, provenance, ancestors);
2842
+ ancestors?.pop();
2731
2843
  i += 1;
2732
2844
  } else {
2733
2845
  children.splice(i, 1, ...node.children);
2734
2846
  }
2735
2847
  continue;
2736
2848
  }
2737
- if (node.type === "element") walk(node, provenance);
2849
+ if (node.type === "element") {
2850
+ ancestors?.push(node.tagName);
2851
+ walk(node, provenance, ancestors);
2852
+ ancestors?.pop();
2853
+ }
2738
2854
  i += 1;
2739
2855
  }
2740
2856
  }
2741
2857
  function rehypeVerifyEngineTags(options) {
2742
2858
  const provenance = options?.provenance ?? "";
2743
2859
  return function transformer(tree) {
2744
- walk(tree, provenance);
2860
+ walk(tree, provenance, options?.referenceAncestors ? [] : void 0);
2745
2861
  };
2746
2862
  }
2747
2863
 
@@ -2762,16 +2878,18 @@ import remarkRemoveComments from "remark-remove-comments";
2762
2878
  // src/components/rehypeRebaseHashLinks.ts
2763
2879
  import { visit as visit5 } from "unist-util-visit";
2764
2880
  var DEFAULT_PREFIX = "user-content-";
2881
+ function rebaseHashHref(href, prefix) {
2882
+ const hashPrefix = "#" + prefix;
2883
+ return href.startsWith("#") && !href.startsWith(hashPrefix) ? hashPrefix + href.slice(1) : href;
2884
+ }
2765
2885
  var rehypeRebaseHashLinks = (options) => {
2766
2886
  const prefix = options?.prefix ?? DEFAULT_PREFIX;
2767
- const hashPrefix = "#" + prefix;
2768
2887
  return (tree) => {
2769
2888
  visit5(tree, "element", (node) => {
2770
2889
  if (node.tagName !== "a") return;
2771
2890
  const href = node.properties?.href;
2772
2891
  if (typeof href !== "string" || !href.startsWith("#")) return;
2773
- if (href.startsWith(hashPrefix)) return;
2774
- node.properties.href = hashPrefix + href.slice(1);
2892
+ node.properties.href = rebaseHashHref(href, prefix);
2775
2893
  });
2776
2894
  };
2777
2895
  };
@@ -2857,7 +2975,15 @@ function buildCoreRehypePlugins(sanitizeSchema2, clobberPrefix, options) {
2857
2975
  [rehypeRaw, { passThrough: [] }],
2858
2976
  // Unwrap forged engine placeholders BEFORE sanitize admits their tag
2859
2977
  // names. Only when the caller holds a credential (see the option's doc).
2860
- ...options ? [[rehypeVerifyEngineTags, { provenance: options.provenance }]] : [],
2978
+ ...options ? [
2979
+ [
2980
+ rehypeVerifyEngineTags,
2981
+ {
2982
+ provenance: options.provenance,
2983
+ ...sanitizeSchema2.ancestors?.a || sanitizeSchema2.ancestors?.img ? { referenceAncestors: true } : {}
2984
+ }
2985
+ ]
2986
+ ] : [],
2861
2987
  // Sanitize HTML while allowing <mark> (highlight), KaTeX class names,
2862
2988
  // and any extra protocols the caller permitted via the `sanitizeSchema`
2863
2989
  // prop. Override `clobberPrefix` with the instance-scoped value — the
@@ -2931,11 +3057,9 @@ function buildCrossChunkHandlers() {
2931
3057
  type: "element",
2932
3058
  tagName: "cross-chunk-link",
2933
3059
  properties: {
2934
- // `label` is the ORIGINAL source text (mdast's `label` field), NOT
2935
- // the normalized `identifier`. The placeholder uses it to construct
2936
- // hrefs that line up with mdast-util-to-hast's default `<li id>`
2937
- // which also preserves source case. Registry lookups normalize
2938
- // internally, so cross-chunk case-insensitive matching still works.
3060
+ // Display labels decode escapes; registry identifiers must retain
3061
+ // those bytes. Never use the display label as the lookup key.
3062
+ identifier: node.identifier,
2939
3063
  label: node.label ?? node.identifier,
2940
3064
  referenceType: node.referenceType,
2941
3065
  documentId: s.options.documentId,
@@ -2954,6 +3078,7 @@ function buildCrossChunkHandlers() {
2954
3078
  type: "element",
2955
3079
  tagName: "cross-chunk-image",
2956
3080
  properties: {
3081
+ identifier: node.identifier,
2957
3082
  label: node.label ?? node.identifier,
2958
3083
  referenceType: node.referenceType,
2959
3084
  alt: node.alt ?? "",
@@ -4216,8 +4341,8 @@ var sanitizeSchema = deepFreeze(
4216
4341
  attributes: {
4217
4342
  ...defaultSchema.attributes,
4218
4343
  code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ["math-inline", "math-display"]),
4219
- "cross-chunk-link": ["label", "referenceType", "documentId", "localUrl", "localTitle"],
4220
- "cross-chunk-image": ["label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
4344
+ "cross-chunk-link": ["identifier", "label", "referenceType", "documentId", "localUrl", "localTitle"],
4345
+ "cross-chunk-image": ["identifier", "label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
4221
4346
  "footnote-sup": ["label", "localOccurrence", "localNumber", "documentId"]
4222
4347
  },
4223
4348
  strip: [.../* @__PURE__ */ new Set([...defaultSchema.strip || [], ...STRIPPED_TAGS])]
@@ -4253,6 +4378,49 @@ function sanitizeCrossChunkUrl(rawUrl, key, tagName, urlTransform, schema) {
4253
4378
  return String(transformed);
4254
4379
  }
4255
4380
 
4381
+ // src/components/resolveCrossChunkReference.ts
4382
+ import rehypeSanitize2 from "rehype-sanitize";
4383
+ import { normalizeUri as normalizeUri3 } from "micromark-util-sanitize-uri";
4384
+ function resolveCrossChunkReference(input, schema, urlTransform, clobberPrefix) {
4385
+ const key = input.tagName === "a" ? "href" : "src";
4386
+ const element = {
4387
+ type: "element",
4388
+ tagName: input.tagName,
4389
+ properties: {
4390
+ [key]: normalizeUri3(input.url),
4391
+ ...input.tagName === "img" ? { alt: input.alt ?? "" } : {},
4392
+ ...input.title !== void 0 ? { title: input.title } : {}
4393
+ },
4394
+ children: input.tagName === "a" ? [{ type: "text", value: "__reference_children__" }] : []
4395
+ };
4396
+ const requiredAncestors = schema.ancestors?.[input.tagName];
4397
+ const recordedAncestors = input.node?.data?.referenceAncestors;
4398
+ let finalSchema = schema;
4399
+ if (requiredAncestors && Array.isArray(recordedAncestors) && requiredAncestors.some((tag) => recordedAncestors.includes(tag))) {
4400
+ const ancestors = { ...schema.ancestors };
4401
+ delete ancestors[input.tagName];
4402
+ finalSchema = { ...schema, ancestors };
4403
+ }
4404
+ const root2 = rehypeSanitize2({ ...finalSchema, clobberPrefix })({ type: "root", children: [element] });
4405
+ const node = root2.children[0];
4406
+ if (node?.type !== "element") return { element: null, keepChildren: node?.type === "text" };
4407
+ if (node.tagName === "a" && typeof node.properties.href === "string") {
4408
+ node.properties.href = rebaseHashHref(node.properties.href, clobberPrefix);
4409
+ }
4410
+ node.children = input.node?.children ?? [];
4411
+ if (input.node?.position) node.position = input.node.position;
4412
+ buildTransform({
4413
+ allowedElements: void 0,
4414
+ disallowedElements: void 0,
4415
+ allowElement: void 0,
4416
+ skipHtml: void 0,
4417
+ unwrapDisallowed: void 0,
4418
+ urlTransform
4419
+ })(node, 0, root2);
4420
+ node.children = [];
4421
+ return { element: node, keepChildren: false };
4422
+ }
4423
+
4256
4424
  // src/plugins/defs.ts
4257
4425
  function getEnginePluginInternals(plugin) {
4258
4426
  const candidate = plugin;
@@ -4469,6 +4637,8 @@ var createSmoothStreamController = (options = {}) => {
4469
4637
  let source = "";
4470
4638
  let visibleEnd = 0;
4471
4639
  let pending = [];
4640
+ let pendingHead = 0;
4641
+ const pendingCount = () => pending.length - pendingHead;
4472
4642
  let tentativeEnd = 0;
4473
4643
  let finished = false;
4474
4644
  let seam;
@@ -4513,7 +4683,7 @@ var createSmoothStreamController = (options = {}) => {
4513
4683
  cancelFrame = void 0;
4514
4684
  };
4515
4685
  const ensureScheduled = () => {
4516
- if (disposed || cancelFrame || pending.length === 0) return;
4686
+ if (disposed || cancelFrame || pendingCount() === 0) return;
4517
4687
  lastTickAt = now();
4518
4688
  credit = 0;
4519
4689
  cancelFrame = schedule(tick);
@@ -4527,31 +4697,38 @@ var createSmoothStreamController = (options = {}) => {
4527
4697
  const params = resolveParams();
4528
4698
  let rate;
4529
4699
  if (finished && drainDeadlineAt !== void 0) {
4530
- rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, drainDeadlineAt - t));
4700
+ rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, drainDeadlineAt - t));
4531
4701
  } else if (gapWindow.length > 0 && lastArrivalAt !== void 0) {
4532
4702
  const gaps = gapWindow.map((s) => s.gap).sort((a, b) => a - b);
4533
4703
  const intervalQ = gaps[Math.min(gaps.length - 1, Math.floor(gaps.length * INTERVAL_QUANTILE))];
4534
4704
  const horizon = Math.max(16, Math.min(params.bufferFactor * intervalQ + HORIZON_PAD_MS, params.maxLagMs));
4535
4705
  const deadline = Math.max(lastArrivalAt + horizon, t + DEADLINE_FLOOR_MS);
4536
- rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, deadline - t));
4706
+ rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, deadline - t));
4537
4707
  } else {
4538
- rate = Math.max(params.minCharsPerSecond, pending.length * 1e3 / Math.max(1, params.correctionTauMs));
4708
+ rate = Math.max(params.minCharsPerSecond, pendingCount() * 1e3 / Math.max(1, params.correctionTauMs));
4539
4709
  }
4540
4710
  credit += rate * dt / 1e3;
4541
- const reveal = Math.min(Math.floor(credit), pending.length);
4711
+ const reveal = Math.min(Math.floor(credit), pendingCount());
4542
4712
  if (reveal > 0) {
4543
- visibleEnd = pending[reveal - 1];
4544
- pending = pending.slice(reveal);
4545
- credit = pending.length > 0 ? credit - reveal : 0;
4713
+ visibleEnd = pending[pendingHead + reveal - 1];
4714
+ pendingHead += reveal;
4715
+ if (pendingHead === pending.length) {
4716
+ pending = [];
4717
+ pendingHead = 0;
4718
+ } else if (pendingHead >= 1024 && pendingHead * 2 >= pending.length) {
4719
+ pending = pending.slice(pendingHead);
4720
+ pendingHead = 0;
4721
+ }
4722
+ credit = pendingCount() > 0 ? credit - reveal : 0;
4546
4723
  notify();
4547
4724
  }
4548
- if (!disposed && !cancelFrame && pending.length > 0) cancelFrame = schedule(tick);
4725
+ if (!disposed && !cancelFrame && pendingCount() > 0) cancelFrame = schedule(tick);
4549
4726
  };
4550
4727
  const resegmentTail = () => {
4551
- if (seam !== void 0 && seam < source.length && pending[pending.length - 1] === seam) {
4728
+ if (pendingCount() > 0 && seam !== void 0 && seam < source.length && pending[pending.length - 1] === seam) {
4552
4729
  pending.pop();
4553
4730
  }
4554
- const from = pending.length > 0 ? pending[pending.length - 1] : visibleEnd;
4731
+ const from = pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd;
4555
4732
  let anchor = from;
4556
4733
  if (seam !== void 0 && from <= seam) {
4557
4734
  anchor = Math.max(0, from - RESUME_LOOKBACK);
@@ -4585,6 +4762,7 @@ var createSmoothStreamController = (options = {}) => {
4585
4762
  visibleEnd = next.length;
4586
4763
  tentativeEnd = next.length;
4587
4764
  pending = [];
4765
+ pendingHead = 0;
4588
4766
  seam = next.length;
4589
4767
  credit = 0;
4590
4768
  cancelScheduled();
@@ -4616,7 +4794,7 @@ var createSmoothStreamController = (options = {}) => {
4616
4794
  if (finished) return;
4617
4795
  finished = true;
4618
4796
  lastArrivalAt = void 0;
4619
- if (tentativeEnd > (pending.length > 0 ? pending[pending.length - 1] : visibleEnd)) {
4797
+ if (tentativeEnd > (pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd)) {
4620
4798
  pending.push(tentativeEnd);
4621
4799
  }
4622
4800
  const params = resolveParams();
@@ -4642,10 +4820,11 @@ var createSmoothStreamController = (options = {}) => {
4642
4820
  snap,
4643
4821
  flush() {
4644
4822
  disposed = false;
4645
- const target = finished ? source.length : pending.length > 0 ? pending[pending.length - 1] : visibleEnd;
4823
+ const target = finished ? source.length : pendingCount() > 0 ? pending[pending.length - 1] : visibleEnd;
4646
4824
  if (target <= visibleEnd) return;
4647
4825
  visibleEnd = target;
4648
4826
  pending = [];
4827
+ pendingHead = 0;
4649
4828
  credit = 0;
4650
4829
  cancelScheduled();
4651
4830
  notify();
@@ -5495,6 +5674,7 @@ export {
5495
5674
  rehypeRebaseHashLinks_default as rehypeRebaseHashLinks,
5496
5675
  rehypeVerifyEngineTags,
5497
5676
  removeComments,
5677
+ resolveCrossChunkReference,
5498
5678
  sanitizeCrossChunkUrl,
5499
5679
  sanitizeSchema,
5500
5680
  shortenDocumentId,