@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.
@@ -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 (rawDocumentIndex !== void 0 && documentIndex === void 0) {
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 (this.chunkOrder.length > 0) {
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) {
@@ -3914,7 +4198,12 @@ var createSmoothStreamController = (options = {}) => {
3914
4198
  return;
3915
4199
  }
3916
4200
  tentativeEnd = ends[ends.length - 1];
3917
- const confirmedEnds = finished ? ends : ends.slice(0, -1);
4201
+ let hold = 1;
4202
+ if (!finished && ends.length > 1) {
4203
+ const last = source.charCodeAt(source.length - 1);
4204
+ if (last >= 55296 && last <= 56319) hold = 2;
4205
+ }
4206
+ const confirmedEnds = finished ? ends : ends.slice(0, -hold);
3918
4207
  for (const end of confirmedEnds) pending.push(end);
3919
4208
  };
3920
4209
  const snap = (next) => {
@@ -4037,10 +4326,17 @@ function lineIndentBefore(content, pos) {
4037
4326
  function findClosingBacktickRun(content, start, n) {
4038
4327
  let i = start;
4039
4328
  while (i < content.length) {
4040
- if (content[i] === "`") {
4329
+ const ch = content[i];
4330
+ if (ch === "`") {
4041
4331
  const runLen = getRepeatedMarkerLength(content, i, "`");
4042
4332
  if (runLen === n) return i;
4043
4333
  i += runLen;
4334
+ } else if (ch === "\n" || ch === "\r") {
4335
+ let j = i + 1;
4336
+ if (ch === "\r" && content[j] === "\n") j += 1;
4337
+ while (j < content.length && (content[j] === " " || content[j] === " ")) j += 1;
4338
+ if (j >= content.length || content[j] === "\n" || content[j] === "\r") return -1;
4339
+ i += 1;
4044
4340
  } else {
4045
4341
  i += 1;
4046
4342
  }
@@ -4140,47 +4436,85 @@ function escapeMhchemCommands(text) {
4140
4436
  return text.replaceAll("$\\ce{", "$\\\\ce{").replaceAll("$\\pu{", "$\\\\pu{");
4141
4437
  }
4142
4438
  var CURRENCY_REGEX = /(?<![\\$])\$(?!\$)(?=\d+(?:,\d{3})*(?:\.\d+)?(?:[KMBkmb])?(?:\s|$|[^a-zA-Z\d]))/g;
4143
- var NO_ESCAPED_DOLLAR_REGEX = /(?<![\\$])\$(?!\$)/g;
4144
4439
  var DELIMITERS_REGEX = /(?<!!)\\\[([\S\s]*?[^\\])\\](?!\()|\\\((.*?)\\\)/g;
4145
4440
  var ARRAY_COL_SPEC_OR_PIPE_REGEX = /(\\begin\{(?:array|tabular[x*]?)\}\{[^}]*\})|(?<!\\)\|/g;
4146
- var LATEX_BLOCK_REGEX = /\$\$([\S\s]*?)\$\$|(?<![\\$])\$(?!\$)((?:[^$\n]|\\\$)*?)(?<![\\`])\$(?!\$)/g;
4441
+ var EVEN_BACKSLASHES = String.raw`(?<=(?:^|[^\\])(?:\\\\)*)`;
4442
+ var LATEX_BLOCK_REGEX = new RegExp(
4443
+ String.raw`${EVEN_BACKSLASHES}\$\$([\S\s]*?)${EVEN_BACKSLASHES}\$\$|(?<![\\$])\$(?!\$)((?:[^$\n]|\\\$)*?)(?<![\\` + "`" + String.raw`])\$(?!\$)`,
4444
+ "g"
4445
+ );
4147
4446
  var TEXT_COMMAND = "\\text{";
4148
4447
  var SINGLE_DOLLAR_REGEX = /(?<![\\$])\$(?!\$)((?:[^$\n]|\\[$])+?)(?<!\\)(?<!`)\$(?!\$)/g;
4448
+ function countBareDollars(str, from, to, prev, next) {
4449
+ let n = 0;
4450
+ for (let j = from; j < to; j++) {
4451
+ if (str.charCodeAt(j) !== 36) continue;
4452
+ const before = j > from ? str[j - 1] : prev;
4453
+ const after = j + 1 < to ? str[j + 1] : next;
4454
+ if (before !== "\\" && before !== "$" && after !== "$") n += 1;
4455
+ }
4456
+ return n;
4457
+ }
4149
4458
  function escapeCurrencyDollarSigns(text) {
4150
4459
  const parts = [];
4151
4460
  let lastIndex = 0;
4152
4461
  const currencyMatches = Array.from(text.matchAll(CURRENCY_REGEX));
4153
4462
  let currentLineProcessed = "";
4463
+ let currentLineDollars = 0;
4464
+ const appendToLine = (piece) => {
4465
+ if (piece.length === 0) return;
4466
+ const prevLast = currentLineProcessed.length > 0 ? currentLineProcessed[currentLineProcessed.length - 1] : "";
4467
+ const prevBeforeLast = currentLineProcessed.length > 1 ? currentLineProcessed[currentLineProcessed.length - 2] : "";
4468
+ const prevLastCounted = prevLast === "$" && prevBeforeLast !== "\\" && prevBeforeLast !== "$";
4469
+ if (prevLastCounted && piece[0] === "$") currentLineDollars -= 1;
4470
+ currentLineDollars += countBareDollars(piece, 0, piece.length, prevLast, "");
4471
+ currentLineProcessed += piece;
4472
+ };
4473
+ const resetLine = (rest) => {
4474
+ currentLineProcessed = "";
4475
+ currentLineDollars = 0;
4476
+ appendToLine(rest);
4477
+ };
4154
4478
  for (let i = 0; i < currencyMatches.length; i++) {
4155
4479
  const match = currencyMatches[i];
4156
4480
  const segment = text.substring(lastIndex, match.index);
4157
4481
  parts.push(segment);
4158
4482
  const newlineIdx = Math.max(segment.lastIndexOf("\n"), segment.lastIndexOf("\r"));
4159
4483
  if (newlineIdx !== -1) {
4160
- currentLineProcessed = segment.substring(newlineIdx + 1);
4484
+ resetLine(segment.substring(newlineIdx + 1));
4161
4485
  } else {
4162
- currentLineProcessed += segment;
4486
+ appendToLine(segment);
4163
4487
  }
4164
4488
  let needEscape = true;
4165
- let restBeforeNextMatchOrEnd = "";
4166
- if (i < currencyMatches.length - 1) {
4167
- const nextMatch = currencyMatches[i + 1];
4168
- if (nextMatch.index - match.index > 1) {
4169
- restBeforeNextMatchOrEnd = text.substring(match.index + 1, nextMatch.index);
4489
+ const restStart = match.index + 1;
4490
+ const restEnd = i < currencyMatches.length - 1 ? currencyMatches[i + 1].index : text.length;
4491
+ let firstLineBeforeNextMatch = "";
4492
+ if (restEnd - restStart > 0) {
4493
+ let eol = restEnd;
4494
+ for (let k = restStart; k < restEnd; k++) {
4495
+ const c = text.charCodeAt(k);
4496
+ if (c === 10 || c === 13) {
4497
+ eol = k;
4498
+ break;
4499
+ }
4170
4500
  }
4171
- } else {
4172
- restBeforeNextMatchOrEnd = text.substring(match.index + 1);
4501
+ firstLineBeforeNextMatch = text.substring(restStart, eol);
4173
4502
  }
4174
- const firstLineBeforeNextMatch = restBeforeNextMatchOrEnd.split(/\r\n|\r|\n/g)[0];
4175
- if (Array.from(firstLineBeforeNextMatch.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {
4176
- const wholeLineBeforeNextMatchWithoutCurrentDollar = currentLineProcessed + firstLineBeforeNextMatch;
4177
- if (Array.from(wholeLineBeforeNextMatchWithoutCurrentDollar.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {
4178
- needEscape = false;
4179
- }
4503
+ const restDollars = countBareDollars(firstLineBeforeNextMatch, 0, firstLineBeforeNextMatch.length, "", "");
4504
+ if (restDollars % 2 !== 0) {
4505
+ const L = currentLineProcessed;
4506
+ const lLast = L.length > 0 ? L[L.length - 1] : "";
4507
+ const lBeforeLast = L.length > 1 ? L[L.length - 2] : "";
4508
+ const lLastCounted = lLast === "$" && lBeforeLast !== "\\" && lBeforeLast !== "$";
4509
+ const f0 = firstLineBeforeNextMatch[0];
4510
+ let whole = currentLineDollars + restDollars;
4511
+ if (lLastCounted && f0 === "$") whole -= 1;
4512
+ if (f0 === "$" && (lLast === "\\" || lLast === "$") && firstLineBeforeNextMatch[1] !== "$") whole -= 1;
4513
+ if (whole % 2 !== 0) needEscape = false;
4180
4514
  }
4181
4515
  const replacement = needEscape ? "\\$" : "$";
4182
4516
  parts.push(replacement);
4183
- currentLineProcessed += replacement;
4517
+ appendToLine(replacement);
4184
4518
  lastIndex = match.index + 1;
4185
4519
  }
4186
4520
  parts.push(text.substring(lastIndex));
@@ -4248,8 +4582,7 @@ function escapeLatexPipesInUnclosed(text) {
4248
4582
  const tail = text.substring(unclosedStart + delimLen);
4249
4583
  return before + delim + replaceUnescapedPipes(tail);
4250
4584
  }
4251
- function truncateUnclosedLatexBlock(text) {
4252
- const unclosedStart = findUnclosedDelimiterStart(text, "double-only");
4585
+ function truncateUnclosedLatexBlock(text, unclosedStart = findUnclosedDelimiterStart(text, "double-only")) {
4253
4586
  if (unclosedStart === -1) return text;
4254
4587
  return text.substring(0, unclosedStart).trimEnd();
4255
4588
  }
@@ -4337,39 +4670,50 @@ function hasUnclosedTextCommand(text) {
4337
4670
  return false;
4338
4671
  }
4339
4672
  var RESIDUAL_OPEN_BRACKET_RE = /(?<!!)\\\[/;
4340
- function processSliceInstrumented(slice) {
4673
+ var LEADING_DOUBLE_DOLLAR_RE = /^\s*\$\$/;
4674
+ function processSliceInstrumented(slice, probe = true) {
4341
4675
  const segments = splitByProtectedRegions(slice);
4342
- let out = "";
4676
+ const parts = [];
4343
4677
  let quiescent = true;
4344
4678
  let truncatedAtSeamStart = false;
4345
4679
  for (let index = 0; index < segments.length; index++) {
4346
4680
  const segment = segments[index];
4347
4681
  if (segment.isCode) {
4348
- out += segment.text;
4682
+ parts.push(segment.text);
4349
4683
  continue;
4350
4684
  }
4351
4685
  let text = segment.text;
4352
4686
  text = escapeMhchemCommands(text);
4353
4687
  text = escapeCurrencyDollarSigns(text);
4354
4688
  text = convertLatexDelimiters(text);
4355
- if (RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;
4689
+ if (probe && RESIDUAL_OPEN_BRACKET_RE.test(text)) quiescent = false;
4356
4690
  text = escapeLatexPipes(text);
4357
- if (findUnclosedDelimiterStart(text, "both") !== -1) quiescent = false;
4691
+ if (probe && findUnclosedDelimiterStart(text, "both") !== -1) quiescent = false;
4358
4692
  text = escapeLatexPipesInUnclosed(text);
4359
- if (hasUnclosedTextCommand(text)) quiescent = false;
4693
+ if (probe && hasUnclosedTextCommand(text)) quiescent = false;
4360
4694
  text = escapeTextUnderscores(text);
4361
4695
  text = convertSingleToDoubleDollar(text);
4362
- const unclosedDouble = findUnclosedDelimiterStart(text, "double-only");
4363
- if (unclosedDouble !== -1) {
4364
- quiescent = false;
4365
- if (index === 0 && text.slice(0, unclosedDouble).trim() === "") {
4366
- truncatedAtSeamStart = true;
4696
+ let unclosedDouble;
4697
+ if (probe || index === 0 && LEADING_DOUBLE_DOLLAR_RE.test(text)) {
4698
+ unclosedDouble = findUnclosedDelimiterStart(text, "double-only");
4699
+ if (unclosedDouble !== -1) {
4700
+ quiescent = false;
4701
+ if (index === 0 && text.slice(0, unclosedDouble).trim() === "") {
4702
+ truncatedAtSeamStart = true;
4703
+ }
4367
4704
  }
4368
4705
  }
4369
- text = truncateUnclosedLatexBlock(text);
4370
- out += text;
4706
+ text = truncateUnclosedLatexBlock(text, unclosedDouble);
4707
+ parts.push(text);
4371
4708
  }
4372
- return { out, quiescent, truncatedAtSeamStart };
4709
+ return { out: parts.join(""), quiescent, truncatedAtSeamStart };
4710
+ }
4711
+ function isBlankRawLine(text, from, to) {
4712
+ for (let i = from; i < to; i++) {
4713
+ const c = text.charCodeAt(i);
4714
+ if (c !== 32 && c !== 9 && c !== 13) return false;
4715
+ }
4716
+ return true;
4373
4717
  }
4374
4718
  function findRawSafeCut(active) {
4375
4719
  const segments = splitByProtectedRegions(active);
@@ -4384,10 +4728,12 @@ function findRawSafeCut(active) {
4384
4728
  continue;
4385
4729
  }
4386
4730
  const text = segment.text;
4731
+ let atLineStart = offset === 0 || active.charCodeAt(offset - 1) === 10;
4387
4732
  let lineStart = 0;
4388
4733
  while (lineStart <= text.length) {
4389
4734
  const nl = text.indexOf("\n", lineStart);
4390
4735
  const lineEnd = nl === -1 ? text.length : nl;
4736
+ if (atLineStart && nl !== -1 && isBlankRawLine(text, lineStart, lineEnd)) backtickHazard = false;
4391
4737
  for (let i = lineStart; i < lineEnd; i++) {
4392
4738
  const ch = text[i];
4393
4739
  if (ch === "`") backtickHazard = true;
@@ -4400,6 +4746,7 @@ function findRawSafeCut(active) {
4400
4746
  if (nl === -1) break;
4401
4747
  if (!backtickHazard && !latentLt) lastCut = offset + nl + 1;
4402
4748
  lineStart = nl + 1;
4749
+ atLineStart = true;
4403
4750
  }
4404
4751
  offset += text.length;
4405
4752
  }
@@ -4408,11 +4755,14 @@ function findRawSafeCut(active) {
4408
4755
  var DEFAULT_FREEZE_ATTEMPT_THRESHOLD = 512;
4409
4756
  function createIncrementalLatexPreprocessor(options) {
4410
4757
  const freezeThreshold = options?.freezeThreshold ?? DEFAULT_FREEZE_ATTEMPT_THRESHOLD;
4758
+ const onAttempt = options?.onAttempt;
4759
+ const backoff = options?.backoff ?? true;
4411
4760
  let prevSource = "";
4412
4761
  let prevOutput = "";
4413
4762
  let frozenSrcEnd = 0;
4414
4763
  let frozenOut = "";
4415
4764
  let triggered = false;
4765
+ let nextAttemptLen = 0;
4416
4766
  return function incrementalPreprocessLaTeX(source) {
4417
4767
  if (source === prevSource) return prevOutput;
4418
4768
  const isAppend = source.length > prevSource.length && source.startsWith(prevSource);
@@ -4420,6 +4770,7 @@ function createIncrementalLatexPreprocessor(options) {
4420
4770
  frozenSrcEnd = 0;
4421
4771
  frozenOut = "";
4422
4772
  triggered = false;
4773
+ nextAttemptLen = 0;
4423
4774
  }
4424
4775
  if (!triggered) {
4425
4776
  const checkFrom = isAppend ? Math.max(0, prevSource.length - 1) : 0;
@@ -4431,18 +4782,26 @@ function createIncrementalLatexPreprocessor(options) {
4431
4782
  triggered = true;
4432
4783
  }
4433
4784
  let active = source.slice(frozenSrcEnd);
4434
- if (active.length > freezeThreshold) {
4785
+ if (active.length > freezeThreshold && active.length >= nextAttemptLen) {
4786
+ const activeLength = active.length;
4787
+ let advanced = false;
4788
+ let frozenBytes = 0;
4789
+ const freeze = (cut2, slice) => {
4790
+ frozenOut += slice.out;
4791
+ frozenSrcEnd += cut2;
4792
+ active = source.slice(frozenSrcEnd);
4793
+ advanced = true;
4794
+ frozenBytes = cut2;
4795
+ };
4435
4796
  const cut = findRawSafeCut(active);
4436
4797
  if (cut > 0) {
4437
4798
  const candidate = processSliceInstrumented(active.slice(0, cut));
4438
- if (candidate.quiescent) {
4439
- frozenOut += candidate.out;
4440
- frozenSrcEnd += cut;
4441
- active = source.slice(frozenSrcEnd);
4442
- }
4799
+ if (candidate.quiescent) freeze(cut, candidate);
4443
4800
  }
4801
+ nextAttemptLen = advanced || !backoff ? 0 : active.length * 2;
4802
+ onAttempt?.({ activeLength, frozenBytes });
4444
4803
  }
4445
- const tail = processSliceInstrumented(active);
4804
+ const tail = processSliceInstrumented(active, false);
4446
4805
  const head = tail.truncatedAtSeamStart ? frozenOut.replace(/\s+$/, "") : frozenOut;
4447
4806
  const out = head + tail.out;
4448
4807
  prevSource = source;
@@ -4473,7 +4832,6 @@ function createRemendPreprocessor(options) {
4473
4832
  // Annotate the CommonJS export names for ESM import in node:
4474
4833
  0 && (module.exports = {
4475
4834
  DEFAULT_PAYLOAD,
4476
- DEF_LINE_START_RE,
4477
4835
  PIPELINE_STAGES,
4478
4836
  SENTINEL_FN_CONTENT,
4479
4837
  SENTINEL_LINK_URL,
@@ -4508,7 +4866,6 @@ function createRemendPreprocessor(options) {
4508
4866
  hasLoneSurrogate,
4509
4867
  highlight,
4510
4868
  isFootnoteSection,
4511
- lastRegionStart,
4512
4869
  measureStage,
4513
4870
  mergeClassNameAllowlist,
4514
4871
  normalizeForMatch,