@ai-react-markdown/engine 2.4.3 → 2.5.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.cjs CHANGED
@@ -31,7 +31,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  DEFAULT_PAYLOAD: () => DEFAULT_PAYLOAD,
34
- DEF_LINE_START_RE: () => DEF_LINE_START_RE,
35
34
  PIPELINE_STAGES: () => PIPELINE_STAGES,
36
35
  SENTINEL_FN_CONTENT: () => SENTINEL_FN_CONTENT,
37
36
  SENTINEL_LINK_URL: () => SENTINEL_LINK_URL,
@@ -66,7 +65,6 @@ __export(src_exports, {
66
65
  hasLoneSurrogate: () => hasLoneSurrogate,
67
66
  highlight: () => highlight,
68
67
  isFootnoteSection: () => isFootnoteSection,
69
- lastRegionStart: () => lastRegionStart,
70
68
  measureStage: () => measureStage,
71
69
  mergeClassNameAllowlist: () => mergeClassNameAllowlist,
72
70
  normalizeForMatch: () => normalizeForMatch,
@@ -269,6 +267,74 @@ var defaultUrlTransform = (value) => {
269
267
  var import_micromark_util_html_tag_name = require("micromark-util-html-tag-name");
270
268
  var import_micromark_util_normalize_identifier = require("micromark-util-normalize-identifier");
271
269
  var TYPE6_NAMES = new Set(import_micromark_util_html_tag_name.htmlBlockNames);
270
+ var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
271
+ var HTML_BREAKOUT_TAGS = /* @__PURE__ */ new Set([
272
+ "b",
273
+ "big",
274
+ "blockquote",
275
+ "body",
276
+ "br",
277
+ "center",
278
+ "code",
279
+ "dd",
280
+ "div",
281
+ "dl",
282
+ "dt",
283
+ "em",
284
+ "embed",
285
+ "h1",
286
+ "h2",
287
+ "h3",
288
+ "h4",
289
+ "h5",
290
+ "h6",
291
+ "head",
292
+ "hr",
293
+ "i",
294
+ "img",
295
+ "li",
296
+ "listing",
297
+ "menu",
298
+ "meta",
299
+ "nobr",
300
+ "ol",
301
+ "p",
302
+ "pre",
303
+ "ruby",
304
+ "s",
305
+ "small",
306
+ "span",
307
+ "strong",
308
+ "strike",
309
+ "sub",
310
+ "sup",
311
+ "table",
312
+ "tt",
313
+ "u",
314
+ "ul",
315
+ "var"
316
+ ]);
317
+ var HTML_INTEGRATION_POINTS = ["foreignobject", "desc", "mi", "mo", "mn", "ms", "mtext", "annotation-xml"];
318
+ var TYPE1_NAMES = /* @__PURE__ */ new Set(["script", "pre", "style", "textarea"]);
319
+ var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set([
320
+ "script",
321
+ "style",
322
+ "textarea",
323
+ "title",
324
+ "xmp",
325
+ "iframe",
326
+ "noembed",
327
+ "noframes",
328
+ // NOT `noscript`: hast-util-raw constructs parse5 with
329
+ // `scriptingEnabled: false`, under which `<noscript>` content is ordinary
330
+ // HTML — modelling it as raw text ignored a `<b>` inside and under-blocked
331
+ // (oracle review of the r2 batch; regression caught before release).
332
+ "plaintext"
333
+ ]);
334
+ var TYPE6_START_RE = /^<\/?([A-Za-z][A-Za-z0-9-]*)(?:[ \t\r]|\/?>|$)/;
335
+ var TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \t\r]|>|$)/i;
336
+ var TYPE7_LINE_RE = /^(?:<[A-Za-z][A-Za-z0-9-]*(?:[ \t\r][^>]*|\/)?>|<\/[A-Za-z][A-Za-z0-9-]*[ \t\r]*>)[ \t\r]*$/;
337
+ var t7Name = (line) => /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(line)[1];
272
338
  var VOID_TAGS = /* @__PURE__ */ new Set([
273
339
  "area",
274
340
  "base",
@@ -292,7 +358,35 @@ var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
292
358
  var FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
293
359
  var MATH_RUN_RE = /^ {0,3}(\$\$+)/;
294
360
  var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->|--!>/g;
295
- var TRUNCATED_TAG_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)([^<>]*)$/;
361
+ var TRUNCATED_TAG_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)([^>]*)$/;
362
+ var TAG_START_LT_RE = /<\/?[A-Za-z]/g;
363
+ function scanTagAttrs(text, from, to, out) {
364
+ let st = out.state;
365
+ for (let i = from; i < to; i++) {
366
+ const c = text[i];
367
+ if (st === '"' || st === "'") {
368
+ if (c === st) st = "outside";
369
+ continue;
370
+ }
371
+ const ws = c === " " || c === " " || c === "\n" || c === "\r" || c === "\f";
372
+ if (st === "afterEq") {
373
+ if (ws) continue;
374
+ if (c === '"' || c === "'") st = c;
375
+ else if (c === ">") return i;
376
+ else st = "unquoted";
377
+ continue;
378
+ }
379
+ if (st === "unquoted") {
380
+ if (ws) st = "outside";
381
+ else if (c === ">") return i;
382
+ continue;
383
+ }
384
+ if (c === "=") st = "afterEq";
385
+ else if (c === ">") return i;
386
+ }
387
+ out.state = st;
388
+ return -1;
389
+ }
296
390
  var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
297
391
  var BACKTICK_RUN_RE = /`+/g;
298
392
  var MD_BLANK_RE = /^[ \t\r]*$/;
@@ -387,6 +481,8 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
387
481
  openTotal: 0,
388
482
  commentOpen: false,
389
483
  piOpen: false,
484
+ bogusOpen: false,
485
+ rawTextOpen: null,
390
486
  declOpen: false,
391
487
  cdataOpen: false,
392
488
  inFence: false,
@@ -407,7 +503,12 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
407
503
  htmlFlowSinceBlank: false,
408
504
  htmlSeamPending: false,
409
505
  phasePoisonedAt: Infinity,
410
- pendingTruncatedTags: []
506
+ pendingTruncatedTags: [],
507
+ pendingTruncatedCloses: [],
508
+ tagAcrossLines: false,
509
+ tagAcrossLinesIndent: 0,
510
+ tagAcrossLinesState: "outside",
511
+ htmlFlowReal: false
411
512
  };
412
513
  }
413
514
  function isPlausibleLinkDefRest(rest) {
@@ -506,11 +607,21 @@ function computeFreezeBoundary(text, options, resume) {
506
607
  let start = cp.confirmedOffset;
507
608
  let tailLine = null;
508
609
  while (start < text.length) {
509
- let end = text.indexOf("\n", start);
510
- if (end === -1) end = text.length;
511
- const confirmed = end < text.length;
512
- const rawLine = text.slice(start, end);
513
- const lineText = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
610
+ let end = text.length;
611
+ let textEnd = text.length;
612
+ {
613
+ const nl = text.indexOf("\n", start);
614
+ const cr = text.indexOf("\r", start);
615
+ if (cr !== -1 && (nl === -1 || cr < nl)) {
616
+ textEnd = cr;
617
+ end = text.charCodeAt(cr + 1) === 10 ? cr + 1 : cr;
618
+ } else if (nl !== -1) {
619
+ textEnd = nl;
620
+ end = nl;
621
+ }
622
+ }
623
+ const confirmed = end < text.length && !(end === text.length - 1 && text.charCodeAt(end) === 13);
624
+ const lineText = text.slice(start, textEnd);
514
625
  const ln = {
515
626
  start,
516
627
  end,
@@ -602,14 +713,33 @@ function processConfirmedLine(cp, ln, text) {
602
713
  newest.defListSettled = ln.blank ? true : !canBecomeDdLine(ln.text, true);
603
714
  }
604
715
  const isBlockStart = cp.prevLineBlank;
605
- if (cp.htmlSeamPending && !ln.blank && !cp.htmlFlowSinceBlank && !(cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen)) {
716
+ if (cp.htmlSeamPending && !ln.blank && !cp.htmlFlowSinceBlank && !(cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen)) {
606
717
  const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text);
607
718
  const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
608
719
  if (!defShapedLine && !commentOnly) {
609
720
  cp.htmlSeamPending = false;
610
721
  }
611
722
  }
723
+ const inForeignContent = () => (cp.tagBalance.get("svg") ?? 0) > 0 || (cp.tagBalance.get("math") ?? 0) > 0;
724
+ const honoursSelfClosing = (tag) => {
725
+ if (tag === "svg" || tag === "math") return true;
726
+ if (!inForeignContent() || HTML_BREAKOUT_TAGS.has(tag)) return false;
727
+ for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return false;
728
+ return true;
729
+ };
730
+ const htmlRulesApply = () => {
731
+ if (!inForeignContent()) return true;
732
+ for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return true;
733
+ return false;
734
+ };
612
735
  const applyTag = (tag, closing) => {
736
+ if (cp.rawTextOpen !== null) {
737
+ if (!(closing && tag === cp.rawTextOpen)) return;
738
+ cp.rawTextOpen = null;
739
+ } else if (!closing && RAW_TEXT_ELEMENTS.has(tag) && htmlRulesApply()) {
740
+ cp.rawTextOpen = tag;
741
+ if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
742
+ }
613
743
  if (closing) {
614
744
  const count = cp.tagBalance.get(tag) ?? 0;
615
745
  if (count > 0) {
@@ -622,7 +752,7 @@ function processConfirmedLine(cp, ln, text) {
622
752
  }
623
753
  };
624
754
  const commentOpenAtLineStart = cp.commentOpen;
625
- const rawOpenAtLineStart = cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen;
755
+ const rawOpenAtLineStart = cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen;
626
756
  if (cp.inFence) {
627
757
  const close = FENCE_RE.exec(ln.text);
628
758
  if (close && close[1][0] === cp.fenceChar && close[1].length >= cp.fenceLen && isMdBlank(ln.text.slice(close[0].length))) {
@@ -704,12 +834,22 @@ function processConfirmedLine(cp, ln, text) {
704
834
  for (const tag of cp.pendingTruncatedTags) applyTag(tag, true);
705
835
  cp.pendingTruncatedTags = [];
706
836
  }
837
+ cp.pendingTruncatedCloses = [];
838
+ if (cp.tagAcrossLines && (cp.tagAcrossLinesState === '"' || cp.tagAcrossLinesState === "'")) {
839
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
840
+ }
841
+ cp.tagAcrossLines = false;
842
+ cp.tagAcrossLinesState = "outside";
843
+ if (cp.bogusOpen) {
844
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
845
+ cp.bogusOpen = false;
846
+ }
707
847
  cp.blankRun += 1;
708
848
  cp.lastBlankStart = ln.start;
709
849
  cp.candidates.push({
710
850
  offset: Math.min(ln.end + 1, text.length),
711
851
  blankRun: cp.blankRun,
712
- htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen,
852
+ htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen && !cp.bogusOpen,
713
853
  hazard: cp.hazardVerdict,
714
854
  seamRisk: cp.htmlSeamPending,
715
855
  defListSettled: null
@@ -717,6 +857,7 @@ function processConfirmedLine(cp, ln, text) {
717
857
  cp.paragraphHasUnpairedRun = false;
718
858
  cp.openBracket = null;
719
859
  cp.htmlFlowSinceBlank = false;
860
+ cp.htmlFlowReal = false;
720
861
  cp.prevLineBlank = true;
721
862
  cp.prevLineWasText = false;
722
863
  cp.prevLineWasValidDef = false;
@@ -732,6 +873,16 @@ function processConfirmedLine(cp, ln, text) {
732
873
  if (tagStart) {
733
874
  cp.htmlFlowSinceBlank = true;
734
875
  if (!TYPE6_NAMES.has(tagStart[1].toLowerCase())) cp.hazardVerdict = true;
876
+ if (!cp.htmlFlowReal) {
877
+ const t = mdTrimStart(ln.text);
878
+ const t6 = TYPE6_START_RE.exec(t);
879
+ const t7 = TYPE7_LINE_RE.exec(t);
880
+ if (t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase()) || TYPE1_START_RE.test(t) || // Type 7 cannot interrupt a paragraph, and excludes the raw-text
881
+ // names (those are type 1 as start tags, paragraph as end tags).
882
+ t7 !== null && !cp.prevLineWasText && !TYPE1_NAMES.has(t7Name(t).toLowerCase())) {
883
+ cp.htmlFlowReal = true;
884
+ }
885
+ }
735
886
  }
736
887
  const inRawText = cp.htmlFlowSinceBlank || rawOpenAtLineStart;
737
888
  const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(mdTrimStart(ln.text));
@@ -830,7 +981,7 @@ ${cont(scanText)}` };
830
981
  pos = c + 3;
831
982
  continue;
832
983
  }
833
- if (cp.declOpen) {
984
+ if (cp.declOpen || cp.bogusOpen) {
834
985
  const c = scanText.indexOf(">", pos);
835
986
  if (c === -1) {
836
987
  rawSpans.push([pos, scanText.length]);
@@ -838,6 +989,7 @@ ${cont(scanText)}` };
838
989
  }
839
990
  rawSpans.push([pos, c + 1]);
840
991
  cp.declOpen = false;
992
+ cp.bogusOpen = false;
841
993
  pos = c + 1;
842
994
  continue;
843
995
  }
@@ -845,10 +997,16 @@ ${cont(scanText)}` };
845
997
  const cd = scanText.indexOf("<![CDATA[", pos);
846
998
  const dm = scanText.slice(pos).search(/<![A-Za-z]/);
847
999
  const decl = dm === -1 ? -1 : pos + dm;
848
- const starts = [pi, cd, decl].filter((x) => x !== -1);
1000
+ const bm = cp.htmlFlowReal ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\[CDATA\[)|<\/(?![A-Za-z])/) : -1;
1001
+ const bogus = bm === -1 ? -1 : pos + bm;
1002
+ const starts = [pi, cd, decl, bogus].filter((x) => x !== -1);
849
1003
  if (starts.length === 0) break;
850
1004
  const first = Math.min(...starts);
851
- if (first === cd) {
1005
+ if (first === bogus) {
1006
+ rawSpans.push([bogus, bogus + 2]);
1007
+ cp.bogusOpen = true;
1008
+ pos = bogus + 2;
1009
+ } else if (first === cd) {
852
1010
  rawSpans.push([cd, cd + 9]);
853
1011
  cp.cdataOpen = true;
854
1012
  pos = cd + 9;
@@ -872,11 +1030,30 @@ ${cont(scanText)}` };
872
1030
  for (const [from, to] of rawSpans) {
873
1031
  tagText = tagText.slice(0, from) + " ".repeat(to - from) + tagText.slice(to);
874
1032
  }
875
- {
1033
+ let skipTagScan = false;
1034
+ if (cp.tagAcrossLines) {
1035
+ if (ln.indent < cp.tagAcrossLinesIndent) poisonRawDivergence();
1036
+ const attrs = { state: cp.tagAcrossLinesState };
1037
+ const gt = scanTagAttrs(ln.text, 0, ln.text.length, attrs);
1038
+ if (gt === -1) {
1039
+ scanTagAttrs("\n", 0, 1, attrs);
1040
+ cp.tagAcrossLinesState = attrs.state;
1041
+ skipTagScan = true;
1042
+ } else {
1043
+ for (const tag of cp.pendingTruncatedCloses) applyTag(tag, true);
1044
+ cp.pendingTruncatedCloses = [];
1045
+ cp.tagAcrossLines = false;
1046
+ cp.tagAcrossLinesState = "outside";
1047
+ tagText = " ".repeat(gt + 1) + tagText.slice(gt + 1);
1048
+ }
1049
+ }
1050
+ let tagHandledAsTruncated = false;
1051
+ if (!skipTagScan) {
876
1052
  TAG_OR_COMMENT_RE.lastIndex = 0;
877
1053
  let m;
878
1054
  let lastCommentOpenerIdx = -1;
879
1055
  while ((m = TAG_OR_COMMENT_RE.exec(tagText)) !== null) {
1056
+ if (cp.rawTextOpen !== null && (m[0] === "<!--" || m[0] === "-->" || m[0] === "--!>")) continue;
880
1057
  if (m[0] === "<!--") {
881
1058
  const next = tagText.slice(m.index + 4, m.index + 6);
882
1059
  if (cp.commentOpen) {
@@ -902,8 +1079,32 @@ ${cont(scanText)}` };
902
1079
  if (cp.commentOpen) continue;
903
1080
  const closing = m[1] === "/";
904
1081
  const tag = m[2].toLowerCase();
905
- const selfClosing = m[3] !== void 0 && /\/\s*$/.test(m[3]);
906
- if (VOID_TAGS.has(tag) || selfClosing) continue;
1082
+ if (TABLE_PART_NAMES.has(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + m.index);
1083
+ let attrs = m[3] ?? "";
1084
+ if (cp.htmlFlowReal && (cp.rawTextOpen === null || closing && tag === cp.rawTextOpen)) {
1085
+ const attrStart = m.index + 1 + (closing ? 1 : 0) + m[2].length;
1086
+ const st = { state: "outside" };
1087
+ const gt = scanTagAttrs(tagText, attrStart, tagText.length, st);
1088
+ if (gt === -1) {
1089
+ if (!VOID_TAGS.has(tag)) {
1090
+ if (closing) cp.pendingTruncatedCloses.push(tag);
1091
+ else applyTag(tag, false);
1092
+ }
1093
+ scanTagAttrs("\n", 0, 1, st);
1094
+ cp.tagAcrossLines = true;
1095
+ cp.tagAcrossLinesIndent = ln.indent;
1096
+ cp.tagAcrossLinesState = st.state;
1097
+ tagHandledAsTruncated = true;
1098
+ break;
1099
+ }
1100
+ if (gt + 1 !== m.index + m[0].length) {
1101
+ attrs = tagText.slice(attrStart, gt);
1102
+ TAG_OR_COMMENT_RE.lastIndex = gt + 1;
1103
+ }
1104
+ }
1105
+ if (closing && !cp.htmlFlowReal && !/^\s*$/.test(attrs)) continue;
1106
+ const selfClosing = /\/\s*$/.test(attrs);
1107
+ if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
907
1108
  applyTag(tag, closing);
908
1109
  }
909
1110
  if (cp.commentOpen && lastCommentOpenerIdx !== -1 && !inRawText) {
@@ -922,22 +1123,44 @@ ${cont(scanText)}` };
922
1123
  if (startMasked || wholeVisible || inRaw(mr.index) || cp.commentOpen) continue;
923
1124
  const closing = mr[1] === "/";
924
1125
  const tag = mr[2].toLowerCase();
1126
+ if (TABLE_PART_NAMES.has(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + mr.index);
1127
+ if (closing && mr[3] !== void 0 && !/^\s*$/.test(mr[3])) continue;
925
1128
  const selfClosing = mr[3] !== void 0 && /\/\s*$/.test(mr[3]);
926
- if (VOID_TAGS.has(tag) || selfClosing) continue;
1129
+ if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
927
1130
  applyTag(tag, closing);
928
1131
  }
929
1132
  }
930
1133
  if (cp.pendingTruncatedTags.length > 0 && ln.text.includes(">")) {
1134
+ if (cp.pendingTruncatedTags.some((t) => TABLE_PART_NAMES.has(t))) {
1135
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1136
+ }
931
1137
  cp.pendingTruncatedTags = [];
932
1138
  }
933
- if (!cp.commentOpen) {
934
- const lastLt = tagText.lastIndexOf("<");
1139
+ if (!cp.commentOpen && !tagHandledAsTruncated) {
1140
+ let lastLt = -1;
1141
+ TAG_START_LT_RE.lastIndex = 0;
1142
+ for (let ms = TAG_START_LT_RE.exec(tagText); ms !== null; ms = TAG_START_LT_RE.exec(tagText)) {
1143
+ lastLt = ms.index;
1144
+ TAG_START_LT_RE.lastIndex = ms.index + 1;
1145
+ }
935
1146
  if (lastLt !== -1 && !tagText.includes(">", lastLt)) {
936
1147
  const m2 = TRUNCATED_TAG_RE.exec(tagText.slice(lastLt));
937
1148
  if (m2) {
938
1149
  const closing = m2[1] === "/";
939
1150
  const tag = m2[2].toLowerCase();
940
- if (!VOID_TAGS.has(tag)) {
1151
+ if (TABLE_PART_NAMES.has(tag) && cp.htmlFlowReal) {
1152
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastLt);
1153
+ }
1154
+ if (cp.htmlFlowReal) {
1155
+ cp.tagAcrossLines = true;
1156
+ cp.tagAcrossLinesIndent = ln.indent;
1157
+ const attrs = { state: "outside" };
1158
+ scanTagAttrs(m2[3] + "\n", 0, m2[3].length + 1, attrs);
1159
+ cp.tagAcrossLinesState = attrs.state;
1160
+ }
1161
+ if (closing) {
1162
+ if (!VOID_TAGS.has(tag) && cp.htmlFlowReal) cp.pendingTruncatedCloses.push(tag);
1163
+ } else if (!VOID_TAGS.has(tag)) {
941
1164
  applyTag(tag, closing);
942
1165
  const rawLastLt = ln.text.lastIndexOf("<");
943
1166
  const rawTruncated = rawLastLt !== -1 && !ln.text.includes(">", rawLastLt);
@@ -1480,6 +1703,9 @@ function countTrailingNewlines(value) {
1480
1703
  function countNewlines(text, end = text.length) {
1481
1704
  let count = 0;
1482
1705
  for (let i = text.indexOf("\n"); i !== -1 && i < end; i = text.indexOf("\n", i + 1)) count += 1;
1706
+ for (let i = text.indexOf("\r"); i !== -1 && i < end; i = text.indexOf("\r", i + 1)) {
1707
+ if (text.charCodeAt(i + 1) !== 10) count += 1;
1708
+ }
1483
1709
  return count;
1484
1710
  }
1485
1711
 
@@ -1599,7 +1825,7 @@ function normalizeId(s) {
1599
1825
  return (0, import_micromark_util_normalize_identifier3.normalizeIdentifier)(s);
1600
1826
  }
1601
1827
  function normalizeForMatch(s) {
1602
- return (0, import_micromark_util_normalize_identifier3.normalizeIdentifier)(s.replace(/\\(.)/g, "$1"));
1828
+ return (0, import_micromark_util_normalize_identifier3.normalizeIdentifier)(s);
1603
1829
  }
1604
1830
 
1605
1831
  // src/components/collectDefLabels.ts
@@ -1917,22 +2143,68 @@ function createRegistry(onEmpty) {
1917
2143
  labelSet: { footnoteLabels: /* @__PURE__ */ new Set(), linkLabels: /* @__PURE__ */ new Set() },
1918
2144
  version: 0,
1919
2145
  _reactIdMap: /* @__PURE__ */ new Map(),
2146
+ /** Symbol → its `documentIndex`, for chunks that supplied one. */
2147
+ _chunkIndex: /* @__PURE__ */ new Map(),
1920
2148
  _subscribers: /* @__PURE__ */ new Set(),
1921
2149
  _notifyScheduled: false,
1922
- allocateSymbol(reactId) {
2150
+ allocateSymbol(reactId, rawDocumentIndex) {
2151
+ const documentIndex = rawDocumentIndex !== void 0 && Number.isFinite(rawDocumentIndex) ? rawDocumentIndex : void 0;
2152
+ if (false) {
2153
+ console.warn(
2154
+ `[ai-react-markdown] documentIndex must be a finite number \u2014 received ${String(rawDocumentIndex)}; ignoring it for this chunk.`
2155
+ );
2156
+ }
1923
2157
  const existing = this._reactIdMap.get(reactId);
1924
2158
  if (existing) {
1925
2159
  existing.refcount++;
2160
+ const moved = documentIndex !== void 0 ? this._chunkIndex.get(existing.symbol) !== documentIndex : this._chunkIndex.has(existing.symbol);
2161
+ if (moved) {
2162
+ const at = this.chunkOrder.indexOf(existing.symbol);
2163
+ if (at !== -1) this.chunkOrder.splice(at, 1);
2164
+ this._placeChunk(existing.symbol, documentIndex);
2165
+ this._notify();
2166
+ }
1926
2167
  return existing.symbol;
1927
2168
  }
1928
2169
  const sym = Symbol(reactId);
1929
2170
  this._reactIdMap.set(reactId, { symbol: sym, refcount: 1 });
1930
- this.chunkOrder.push(sym);
2171
+ this._placeChunk(sym, documentIndex);
1931
2172
  this._notify();
1932
2173
  return sym;
1933
2174
  },
1934
- registerChunk(reactId, footnotes, links) {
1935
- const sym = this.allocateSymbol(reactId);
2175
+ /** Put `sym` into `chunkOrder` at its document position. Without an index
2176
+ * it goes last (mount order — the historical behaviour); with one it
2177
+ * sorts before the first chunk that sits later, where a chunk WITHOUT an
2178
+ * index counts as "later" so an indexed chunk never lands behind one
2179
+ * whose position is unknown. */
2180
+ _placeChunk(sym, documentIndex) {
2181
+ if (false) {
2182
+ const anyIndexed = documentIndex !== void 0 || this.chunkOrder.some((s) => this._chunkIndex.has(s));
2183
+ const anyPlain = documentIndex === void 0 || this.chunkOrder.some((s) => !this._chunkIndex.has(s));
2184
+ if (anyIndexed && anyPlain) {
2185
+ console.warn(
2186
+ "[ai-react-markdown] Some chunks of this document supply `documentIndex` and some do not. Indexed chunks always sort ahead of un-indexed ones, so footnote numbering and aggregate-footer placement will not follow document order. Pass `documentIndex` to every chunk, or to none."
2187
+ );
2188
+ }
2189
+ }
2190
+ if (documentIndex === void 0) {
2191
+ this._chunkIndex.delete(sym);
2192
+ this.chunkOrder.push(sym);
2193
+ return;
2194
+ }
2195
+ this._chunkIndex.set(sym, documentIndex);
2196
+ let at = this.chunkOrder.length;
2197
+ for (let i = 0; i < this.chunkOrder.length; i++) {
2198
+ const other = this._chunkIndex.get(this.chunkOrder[i]);
2199
+ if (other === void 0 || other > documentIndex) {
2200
+ at = i;
2201
+ break;
2202
+ }
2203
+ }
2204
+ this.chunkOrder.splice(at, 0, sym);
2205
+ },
2206
+ registerChunk(reactId, footnotes, links, documentIndex) {
2207
+ const sym = this.allocateSymbol(reactId, documentIndex);
1936
2208
  this.contributeLabels(sym, footnotes, links);
1937
2209
  return sym;
1938
2210
  },
@@ -1955,6 +2227,7 @@ function createRegistry(onEmpty) {
1955
2227
  this._reactIdMap.delete(reactId);
1956
2228
  const idx = this.chunkOrder.indexOf(entry.symbol);
1957
2229
  if (idx !== -1) this.chunkOrder.splice(idx, 1);
2230
+ this._chunkIndex.delete(entry.symbol);
1958
2231
  this.chunkData.delete(entry.symbol);
1959
2232
  const nextFn = /* @__PURE__ */ new Set();
1960
2233
  const nextLink = /* @__PURE__ */ new Set();
@@ -3581,17 +3854,28 @@ function mergeClassNameAllowlist(existing, extraClassNames) {
3581
3854
  return entries;
3582
3855
  }
3583
3856
  var crossChunkTags = ["cross-chunk-link", "cross-chunk-image", "footnote-sup"];
3584
- var sanitizeSchema = cloneDeep_default({
3585
- ...import_rehype_sanitize2.defaultSchema,
3586
- tagNames: [...import_rehype_sanitize2.defaultSchema.tagNames || [], "mark", ...crossChunkTags],
3587
- attributes: {
3588
- ...import_rehype_sanitize2.defaultSchema.attributes,
3589
- code: mergeClassNameAllowlist(import_rehype_sanitize2.defaultSchema.attributes?.code, ["math-inline", "math-display"]),
3590
- "cross-chunk-link": ["label", "referenceType", "documentId", "localUrl", "localTitle"],
3591
- "cross-chunk-image": ["label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
3592
- "footnote-sup": ["label", "localOccurrence", "localNumber", "documentId"]
3593
- }
3594
- });
3857
+ function deepFreeze(value) {
3858
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
3859
+ Object.freeze(value);
3860
+ for (const key of Object.keys(value)) deepFreeze(value[key]);
3861
+ }
3862
+ return value;
3863
+ }
3864
+ var STRIPPED_TAGS = ["script", "style", "title", "textarea", "noframes", "noembed", "xmp", "iframe", "plaintext"];
3865
+ var sanitizeSchema = deepFreeze(
3866
+ cloneDeep_default({
3867
+ ...import_rehype_sanitize2.defaultSchema,
3868
+ tagNames: [...import_rehype_sanitize2.defaultSchema.tagNames || [], "mark", ...crossChunkTags],
3869
+ attributes: {
3870
+ ...import_rehype_sanitize2.defaultSchema.attributes,
3871
+ code: mergeClassNameAllowlist(import_rehype_sanitize2.defaultSchema.attributes?.code, ["math-inline", "math-display"]),
3872
+ "cross-chunk-link": ["label", "referenceType", "documentId", "localUrl", "localTitle"],
3873
+ "cross-chunk-image": ["label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
3874
+ "footnote-sup": ["label", "localOccurrence", "localNumber", "documentId"]
3875
+ },
3876
+ strip: [.../* @__PURE__ */ new Set([...import_rehype_sanitize2.defaultSchema.strip || [], ...STRIPPED_TAGS])]
3877
+ })
3878
+ );
3595
3879
 
3596
3880
  // src/components/crossChunkUrlSanitize.ts
3597
3881
  function fakeElement(tagName, key, url) {
@@ -3902,7 +4186,12 @@ var createSmoothStreamController = (options = {}) => {
3902
4186
  return;
3903
4187
  }
3904
4188
  tentativeEnd = ends[ends.length - 1];
3905
- const confirmedEnds = finished ? ends : ends.slice(0, -1);
4189
+ let hold = 1;
4190
+ if (!finished && ends.length > 1) {
4191
+ const last = source.charCodeAt(source.length - 1);
4192
+ if (last >= 55296 && last <= 56319) hold = 2;
4193
+ }
4194
+ const confirmedEnds = finished ? ends : ends.slice(0, -hold);
3906
4195
  for (const end of confirmedEnds) pending.push(end);
3907
4196
  };
3908
4197
  const snap = (next) => {
@@ -4025,10 +4314,17 @@ function lineIndentBefore(content, pos) {
4025
4314
  function findClosingBacktickRun(content, start, n) {
4026
4315
  let i = start;
4027
4316
  while (i < content.length) {
4028
- if (content[i] === "`") {
4317
+ const ch = content[i];
4318
+ if (ch === "`") {
4029
4319
  const runLen = getRepeatedMarkerLength(content, i, "`");
4030
4320
  if (runLen === n) return i;
4031
4321
  i += runLen;
4322
+ } else if (ch === "\n" || ch === "\r") {
4323
+ let j = i + 1;
4324
+ if (ch === "\r" && content[j] === "\n") j += 1;
4325
+ while (j < content.length && (content[j] === " " || content[j] === " ")) j += 1;
4326
+ if (j >= content.length || content[j] === "\n" || content[j] === "\r") return -1;
4327
+ i += 1;
4032
4328
  } else {
4033
4329
  i += 1;
4034
4330
  }
@@ -4128,47 +4424,85 @@ function escapeMhchemCommands(text) {
4128
4424
  return text.replaceAll("$\\ce{", "$\\\\ce{").replaceAll("$\\pu{", "$\\\\pu{");
4129
4425
  }
4130
4426
  var CURRENCY_REGEX = /(?<![\\$])\$(?!\$)(?=\d+(?:,\d{3})*(?:\.\d+)?(?:[KMBkmb])?(?:\s|$|[^a-zA-Z\d]))/g;
4131
- var NO_ESCAPED_DOLLAR_REGEX = /(?<![\\$])\$(?!\$)/g;
4132
4427
  var DELIMITERS_REGEX = /(?<!!)\\\[([\S\s]*?[^\\])\\](?!\()|\\\((.*?)\\\)/g;
4133
4428
  var ARRAY_COL_SPEC_OR_PIPE_REGEX = /(\\begin\{(?:array|tabular[x*]?)\}\{[^}]*\})|(?<!\\)\|/g;
4134
- var LATEX_BLOCK_REGEX = /\$\$([\S\s]*?)\$\$|(?<![\\$])\$(?!\$)((?:[^$\n]|\\\$)*?)(?<![\\`])\$(?!\$)/g;
4429
+ var EVEN_BACKSLASHES = String.raw`(?<=(?:^|[^\\])(?:\\\\)*)`;
4430
+ var LATEX_BLOCK_REGEX = new RegExp(
4431
+ String.raw`${EVEN_BACKSLASHES}\$\$([\S\s]*?)${EVEN_BACKSLASHES}\$\$|(?<![\\$])\$(?!\$)((?:[^$\n]|\\\$)*?)(?<![\\` + "`" + String.raw`])\$(?!\$)`,
4432
+ "g"
4433
+ );
4135
4434
  var TEXT_COMMAND = "\\text{";
4136
4435
  var SINGLE_DOLLAR_REGEX = /(?<![\\$])\$(?!\$)((?:[^$\n]|\\[$])+?)(?<!\\)(?<!`)\$(?!\$)/g;
4436
+ function countBareDollars(str, from, to, prev, next) {
4437
+ let n = 0;
4438
+ for (let j = from; j < to; j++) {
4439
+ if (str.charCodeAt(j) !== 36) continue;
4440
+ const before = j > from ? str[j - 1] : prev;
4441
+ const after = j + 1 < to ? str[j + 1] : next;
4442
+ if (before !== "\\" && before !== "$" && after !== "$") n += 1;
4443
+ }
4444
+ return n;
4445
+ }
4137
4446
  function escapeCurrencyDollarSigns(text) {
4138
4447
  const parts = [];
4139
4448
  let lastIndex = 0;
4140
4449
  const currencyMatches = Array.from(text.matchAll(CURRENCY_REGEX));
4141
4450
  let currentLineProcessed = "";
4451
+ let currentLineDollars = 0;
4452
+ const appendToLine = (piece) => {
4453
+ if (piece.length === 0) return;
4454
+ const prevLast = currentLineProcessed.length > 0 ? currentLineProcessed[currentLineProcessed.length - 1] : "";
4455
+ const prevBeforeLast = currentLineProcessed.length > 1 ? currentLineProcessed[currentLineProcessed.length - 2] : "";
4456
+ const prevLastCounted = prevLast === "$" && prevBeforeLast !== "\\" && prevBeforeLast !== "$";
4457
+ if (prevLastCounted && piece[0] === "$") currentLineDollars -= 1;
4458
+ currentLineDollars += countBareDollars(piece, 0, piece.length, prevLast, "");
4459
+ currentLineProcessed += piece;
4460
+ };
4461
+ const resetLine = (rest) => {
4462
+ currentLineProcessed = "";
4463
+ currentLineDollars = 0;
4464
+ appendToLine(rest);
4465
+ };
4142
4466
  for (let i = 0; i < currencyMatches.length; i++) {
4143
4467
  const match = currencyMatches[i];
4144
4468
  const segment = text.substring(lastIndex, match.index);
4145
4469
  parts.push(segment);
4146
4470
  const newlineIdx = Math.max(segment.lastIndexOf("\n"), segment.lastIndexOf("\r"));
4147
4471
  if (newlineIdx !== -1) {
4148
- currentLineProcessed = segment.substring(newlineIdx + 1);
4472
+ resetLine(segment.substring(newlineIdx + 1));
4149
4473
  } else {
4150
- currentLineProcessed += segment;
4474
+ appendToLine(segment);
4151
4475
  }
4152
4476
  let needEscape = true;
4153
- let restBeforeNextMatchOrEnd = "";
4154
- if (i < currencyMatches.length - 1) {
4155
- const nextMatch = currencyMatches[i + 1];
4156
- if (nextMatch.index - match.index > 1) {
4157
- restBeforeNextMatchOrEnd = text.substring(match.index + 1, nextMatch.index);
4477
+ const restStart = match.index + 1;
4478
+ const restEnd = i < currencyMatches.length - 1 ? currencyMatches[i + 1].index : text.length;
4479
+ let firstLineBeforeNextMatch = "";
4480
+ if (restEnd - restStart > 0) {
4481
+ let eol = restEnd;
4482
+ for (let k = restStart; k < restEnd; k++) {
4483
+ const c = text.charCodeAt(k);
4484
+ if (c === 10 || c === 13) {
4485
+ eol = k;
4486
+ break;
4487
+ }
4158
4488
  }
4159
- } else {
4160
- restBeforeNextMatchOrEnd = text.substring(match.index + 1);
4489
+ firstLineBeforeNextMatch = text.substring(restStart, eol);
4161
4490
  }
4162
- const firstLineBeforeNextMatch = restBeforeNextMatchOrEnd.split(/\r\n|\r|\n/g)[0];
4163
- if (Array.from(firstLineBeforeNextMatch.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {
4164
- const wholeLineBeforeNextMatchWithoutCurrentDollar = currentLineProcessed + firstLineBeforeNextMatch;
4165
- if (Array.from(wholeLineBeforeNextMatchWithoutCurrentDollar.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {
4166
- needEscape = false;
4167
- }
4491
+ const restDollars = countBareDollars(firstLineBeforeNextMatch, 0, firstLineBeforeNextMatch.length, "", "");
4492
+ if (restDollars % 2 !== 0) {
4493
+ const L = currentLineProcessed;
4494
+ const lLast = L.length > 0 ? L[L.length - 1] : "";
4495
+ const lBeforeLast = L.length > 1 ? L[L.length - 2] : "";
4496
+ const lLastCounted = lLast === "$" && lBeforeLast !== "\\" && lBeforeLast !== "$";
4497
+ const f0 = firstLineBeforeNextMatch[0];
4498
+ let whole = currentLineDollars + restDollars;
4499
+ if (lLastCounted && f0 === "$") whole -= 1;
4500
+ if (f0 === "$" && (lLast === "\\" || lLast === "$") && firstLineBeforeNextMatch[1] !== "$") whole -= 1;
4501
+ if (whole % 2 !== 0) needEscape = false;
4168
4502
  }
4169
4503
  const replacement = needEscape ? "\\$" : "$";
4170
4504
  parts.push(replacement);
4171
- currentLineProcessed += replacement;
4505
+ appendToLine(replacement);
4172
4506
  lastIndex = match.index + 1;
4173
4507
  }
4174
4508
  parts.push(text.substring(lastIndex));
@@ -4236,8 +4570,7 @@ function escapeLatexPipesInUnclosed(text) {
4236
4570
  const tail = text.substring(unclosedStart + delimLen);
4237
4571
  return before + delim + replaceUnescapedPipes(tail);
4238
4572
  }
4239
- function truncateUnclosedLatexBlock(text) {
4240
- const unclosedStart = findUnclosedDelimiterStart(text, "double-only");
4573
+ function truncateUnclosedLatexBlock(text, unclosedStart = findUnclosedDelimiterStart(text, "double-only")) {
4241
4574
  if (unclosedStart === -1) return text;
4242
4575
  return text.substring(0, unclosedStart).trimEnd();
4243
4576
  }
@@ -4325,39 +4658,50 @@ function hasUnclosedTextCommand(text) {
4325
4658
  return false;
4326
4659
  }
4327
4660
  var RESIDUAL_OPEN_BRACKET_RE = /(?<!!)\\\[/;
4328
- function processSliceInstrumented(slice) {
4661
+ var LEADING_DOUBLE_DOLLAR_RE = /^\s*\$\$/;
4662
+ function processSliceInstrumented(slice, probe = true) {
4329
4663
  const segments = splitByProtectedRegions(slice);
4330
- let out = "";
4664
+ const parts = [];
4331
4665
  let quiescent = true;
4332
4666
  let truncatedAtSeamStart = false;
4333
4667
  for (let index = 0; index < segments.length; index++) {
4334
4668
  const segment = segments[index];
4335
4669
  if (segment.isCode) {
4336
- out += segment.text;
4670
+ parts.push(segment.text);
4337
4671
  continue;
4338
4672
  }
4339
4673
  let text = segment.text;
4340
4674
  text = escapeMhchemCommands(text);
4341
4675
  text = escapeCurrencyDollarSigns(text);
4342
4676
  text = convertLatexDelimiters(text);
4343
- if (RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;
4677
+ if (probe && RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;
4344
4678
  text = escapeLatexPipes(text);
4345
- if (findUnclosedDelimiterStart(text, "both") !== -1) quiescent = false;
4679
+ if (probe && findUnclosedDelimiterStart(text, "both") !== -1) quiescent = false;
4346
4680
  text = escapeLatexPipesInUnclosed(text);
4347
- if (hasUnclosedTextCommand(text)) quiescent = false;
4681
+ if (probe && hasUnclosedTextCommand(text)) quiescent = false;
4348
4682
  text = escapeTextUnderscores(text);
4349
4683
  text = convertSingleToDoubleDollar(text);
4350
- const unclosedDouble = findUnclosedDelimiterStart(text, "double-only");
4351
- if (unclosedDouble !== -1) {
4352
- quiescent = false;
4353
- if (index === 0 && text.slice(0, unclosedDouble).trim() === "") {
4354
- truncatedAtSeamStart = true;
4684
+ let unclosedDouble;
4685
+ if (probe || index === 0 && LEADING_DOUBLE_DOLLAR_RE.test(text)) {
4686
+ unclosedDouble = findUnclosedDelimiterStart(text, "double-only");
4687
+ if (unclosedDouble !== -1) {
4688
+ quiescent = false;
4689
+ if (index === 0 && text.slice(0, unclosedDouble).trim() === "") {
4690
+ truncatedAtSeamStart = true;
4691
+ }
4355
4692
  }
4356
4693
  }
4357
- text = truncateUnclosedLatexBlock(text);
4358
- out += text;
4694
+ text = truncateUnclosedLatexBlock(text, unclosedDouble);
4695
+ parts.push(text);
4359
4696
  }
4360
- return { out, quiescent, truncatedAtSeamStart };
4697
+ return { out: parts.join(""), quiescent, truncatedAtSeamStart };
4698
+ }
4699
+ function isBlankRawLine(text, from, to) {
4700
+ for (let i = from; i < to; i++) {
4701
+ const c = text.charCodeAt(i);
4702
+ if (c !== 32 && c !== 9 && c !== 13) return false;
4703
+ }
4704
+ return true;
4361
4705
  }
4362
4706
  function findRawSafeCut(active) {
4363
4707
  const segments = splitByProtectedRegions(active);
@@ -4372,10 +4716,12 @@ function findRawSafeCut(active) {
4372
4716
  continue;
4373
4717
  }
4374
4718
  const text = segment.text;
4719
+ let atLineStart = offset === 0 || active.charCodeAt(offset - 1) === 10;
4375
4720
  let lineStart = 0;
4376
4721
  while (lineStart <= text.length) {
4377
4722
  const nl = text.indexOf("\n", lineStart);
4378
4723
  const lineEnd = nl === -1 ? text.length : nl;
4724
+ if (atLineStart && nl !== -1 && isBlankRawLine(text, lineStart, lineEnd)) backtickHazard = false;
4379
4725
  for (let i = lineStart; i < lineEnd; i++) {
4380
4726
  const ch = text[i];
4381
4727
  if (ch === "`") backtickHazard = true;
@@ -4388,6 +4734,7 @@ function findRawSafeCut(active) {
4388
4734
  if (nl === -1) break;
4389
4735
  if (!backtickHazard && !latentLt) lastCut = offset + nl + 1;
4390
4736
  lineStart = nl + 1;
4737
+ atLineStart = true;
4391
4738
  }
4392
4739
  offset += text.length;
4393
4740
  }
@@ -4396,11 +4743,14 @@ function findRawSafeCut(active) {
4396
4743
  var DEFAULT_FREEZE_ATTEMPT_THRESHOLD = 512;
4397
4744
  function createIncrementalLatexPreprocessor(options) {
4398
4745
  const freezeThreshold = options?.freezeThreshold ?? DEFAULT_FREEZE_ATTEMPT_THRESHOLD;
4746
+ const onAttempt = options?.onAttempt;
4747
+ const backoff = options?.backoff ?? true;
4399
4748
  let prevSource = "";
4400
4749
  let prevOutput = "";
4401
4750
  let frozenSrcEnd = 0;
4402
4751
  let frozenOut = "";
4403
4752
  let triggered = false;
4753
+ let nextAttemptLen = 0;
4404
4754
  return function incrementalPreprocessLaTeX(source) {
4405
4755
  if (source === prevSource) return prevOutput;
4406
4756
  const isAppend = source.length > prevSource.length && source.startsWith(prevSource);
@@ -4408,6 +4758,7 @@ function createIncrementalLatexPreprocessor(options) {
4408
4758
  frozenSrcEnd = 0;
4409
4759
  frozenOut = "";
4410
4760
  triggered = false;
4761
+ nextAttemptLen = 0;
4411
4762
  }
4412
4763
  if (!triggered) {
4413
4764
  const checkFrom = isAppend ? Math.max(0, prevSource.length - 1) : 0;
@@ -4419,18 +4770,26 @@ function createIncrementalLatexPreprocessor(options) {
4419
4770
  triggered = true;
4420
4771
  }
4421
4772
  let active = source.slice(frozenSrcEnd);
4422
- if (active.length > freezeThreshold) {
4773
+ if (active.length > freezeThreshold && active.length >= nextAttemptLen) {
4774
+ const activeLength = active.length;
4775
+ let advanced = false;
4776
+ let frozenBytes = 0;
4777
+ const freeze = (cut2, slice) => {
4778
+ frozenOut += slice.out;
4779
+ frozenSrcEnd += cut2;
4780
+ active = source.slice(frozenSrcEnd);
4781
+ advanced = true;
4782
+ frozenBytes = cut2;
4783
+ };
4423
4784
  const cut = findRawSafeCut(active);
4424
4785
  if (cut > 0) {
4425
4786
  const candidate = processSliceInstrumented(active.slice(0, cut));
4426
- if (candidate.quiescent) {
4427
- frozenOut += candidate.out;
4428
- frozenSrcEnd += cut;
4429
- active = source.slice(frozenSrcEnd);
4430
- }
4787
+ if (candidate.quiescent) freeze(cut, candidate);
4431
4788
  }
4789
+ nextAttemptLen = advanced || !backoff ? 0 : active.length * 2;
4790
+ onAttempt?.({ activeLength, frozenBytes });
4432
4791
  }
4433
- const tail = processSliceInstrumented(active);
4792
+ const tail = processSliceInstrumented(active, false);
4434
4793
  const head = tail.truncatedAtSeamStart ? frozenOut.replace(/\s+$/, "") : frozenOut;
4435
4794
  const out = head + tail.out;
4436
4795
  prevSource = source;
@@ -4461,7 +4820,6 @@ function createRemendPreprocessor(options) {
4461
4820
  // Annotate the CommonJS export names for ESM import in node:
4462
4821
  0 && (module.exports = {
4463
4822
  DEFAULT_PAYLOAD,
4464
- DEF_LINE_START_RE,
4465
4823
  PIPELINE_STAGES,
4466
4824
  SENTINEL_FN_CONTENT,
4467
4825
  SENTINEL_LINK_URL,
@@ -4496,7 +4854,6 @@ function createRemendPreprocessor(options) {
4496
4854
  hasLoneSurrogate,
4497
4855
  highlight,
4498
4856
  isFootnoteSection,
4499
- lastRegionStart,
4500
4857
  measureStage,
4501
4858
  mergeClassNameAllowlist,
4502
4859
  normalizeForMatch,