@ai-react-markdown/engine 2.8.2 → 2.9.1

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.
@@ -378,9 +378,9 @@ function inlineResourceEnd(text, openIdx) {
378
378
  }
379
379
  return -1;
380
380
  }
381
- function collectRefLine(cp, lnStart, lnEnd, scanText, inRawText, isBlockStart) {
382
- const defShaped = inRawText ? null : DEF_RE.exec(scanText);
383
- const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
381
+ function collectRefLine(cp, lnStart, lnEnd, scanText, rawText, inRawText, isBlockStart) {
382
+ const defShaped = inRawText ? null : DEF_RE.exec(rawText);
383
+ const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(rawText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
384
384
  const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
385
385
  const validDef = def !== null && defLineStart;
386
386
  if (validDef) {
@@ -459,16 +459,15 @@ function settleRefsAndEarliestUnresolved(cp) {
459
459
  var TYPE6_NAMES = new Set(import_micromark_util_html_tag_name.htmlBlockNames);
460
460
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
461
461
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
462
+ var NO_ELEMENT_NAMES = /* @__PURE__ */ new Set([...DOCUMENT_STRUCTURE_NAMES, "frame", "image"]);
462
463
  var RETROACTIVE_OPENERS = [
463
464
  "<!doctype",
464
- "<html",
465
- "<head",
466
- "<body",
467
- "<frameset",
468
- "</html",
469
- "</head",
470
- "</body",
471
- "</frameset"
465
+ // DERIVED, so the trailing-partial guard cannot drift from the poison the
466
+ // confirmed lines get. It was transcribed until F28, and the transcription
467
+ // was already two names behind by then. `<frame` subsumes `<frameset`,
468
+ // which is why the derived list is SHORTER than the one it replaces and
469
+ // still covers strictly more.
470
+ ...[...NO_ELEMENT_NAMES].flatMap((name) => [`<${name}`, `</${name}`])
472
471
  ];
473
472
  function tailCarriesRetroactive(text) {
474
473
  const lower = text.toLowerCase();
@@ -598,12 +597,15 @@ var rawTextElement = (t) => t.kind === "rawText" ? t.element : t.kind === "scrip
598
597
  var VOID_TAGS = /* @__PURE__ */ new Set([
599
598
  "area",
600
599
  "base",
600
+ "basefont",
601
+ "bgsound",
601
602
  "br",
602
603
  "col",
603
604
  "embed",
604
605
  "hr",
605
606
  "img",
606
607
  "input",
608
+ "keygen",
607
609
  "link",
608
610
  "meta",
609
611
  "param",
@@ -718,6 +720,7 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
718
720
  tagBalance: /* @__PURE__ */ new Map(),
719
721
  openTotal: 0,
720
722
  p5Tok: { kind: "data" },
723
+ formPointerMaybeSet: false,
721
724
  openStack: [],
722
725
  mdBlock: { kind: "none" },
723
726
  blankRun: 0,
@@ -855,6 +858,25 @@ function floatingResidue(text, commentOpenAtStart) {
855
858
  if (!open) out += text.slice(last);
856
859
  return out;
857
860
  }
861
+ var RAW_CONSTRUCT_START_RE = /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/;
862
+ var sealResumableAbove = (cp) => cp.defBlockMaybeOpen || cp.fnDefResumable || cp.containerMaybeOpen;
863
+ function sealReleaseDerived(cp, ln, isBlockStart) {
864
+ if (sealResumableAbove(cp) && !(isBlockStart && ln.indent <= 3)) return false;
865
+ if (cp.prevLineOpenContent) return false;
866
+ if (cp.tableMaybeOpen) return false;
867
+ const head = mdTrimStart(ln.text);
868
+ if (RAW_CONSTRUCT_START_RE.test(head) || TYPE1_START_RE.test(head) || isType7Line(head)) return false;
869
+ const t6 = TYPE6_START_RE.exec(head);
870
+ if (t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase())) return false;
871
+ if (DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text)) return false;
872
+ return true;
873
+ }
874
+ var sealReleaseEvaluations = 0;
875
+ function sealReleaseEnumerated(cp, ln, isBlockStart) {
876
+ const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text) || cp.defBlockMaybeOpen || cp.fnDefResumable && !(isBlockStart && ln.indent <= 3);
877
+ const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
878
+ return !defShapedLine && !commentOnly && !CLOSE_TAG_ONLY_RE.test(ln.text);
879
+ }
858
880
  function processConfirmedLine(cp, ln, text) {
859
881
  const newest = cp.candidates[cp.candidates.length - 1];
860
882
  if (newest && newest.defListSettled === null) {
@@ -862,16 +884,22 @@ function processConfirmedLine(cp, ln, text) {
862
884
  }
863
885
  const isBlockStart = cp.prevLineBlank;
864
886
  if (cp.p5SealPending && !ln.blank && cp.mdBlock.kind !== "html" && !(cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus")) {
865
- const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text) || cp.defBlockMaybeOpen || cp.fnDefResumable && !(isBlockStart && ln.indent <= 3);
866
- const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
867
- const closeTagOnly = CLOSE_TAG_ONLY_RE.test(ln.text);
868
- if (!defShapedLine && !commentOnly && !closeTagOnly) {
887
+ if (sealReleaseDerived(cp, ln, isBlockStart)) {
869
888
  cp.p5SealPending = false;
889
+ if (true) {
890
+ sealReleaseEvaluations += 1;
891
+ if (!sealReleaseEnumerated(cp, ln, isBlockStart)) {
892
+ console.error(
893
+ `[ai-react-markdown] seal-release containment broken at offset ${ln.start}: the derived predicate released a line the retired enumeration withheld (${JSON.stringify(ln.text.slice(0, 80))}).`
894
+ );
895
+ }
896
+ }
870
897
  }
871
898
  }
872
899
  const possiblyInsideForeign = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
873
900
  const honoursSelfClosing = (tag) => tag === "svg" || tag === "math";
874
901
  const foreignRawTextSwitchUnknowable = () => possiblyInsideForeign();
902
+ let discardedEndTag = false;
875
903
  const applyTag = (tag, closing) => {
876
904
  if (inRawTextTok(cp.p5Tok)) {
877
905
  if (cp.p5Tok.kind === "script" && cp.p5Tok.escaped && !closing && tag === "script") {
@@ -893,7 +921,7 @@ function processConfirmedLine(cp, ln, text) {
893
921
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
894
922
  }
895
923
  }
896
- if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;
924
+ if (NO_ELEMENT_NAMES.has(tag)) cp.phasePoisonedAt = 0;
897
925
  if (tag === "template" && !closing) cp.phasePoisonedAt = 0;
898
926
  if (closing) {
899
927
  let idx = -1;
@@ -904,14 +932,19 @@ function processConfirmedLine(cp, ln, text) {
904
932
  }
905
933
  if (SCOPE_BARRIER_NAMES.has(cp.openStack[i])) break;
906
934
  }
907
- if (idx === -1) return;
935
+ if (idx === -1) {
936
+ discardedEndTag = true;
937
+ return;
938
+ }
908
939
  cp.openStack.splice(idx, 1);
940
+ if (tag === "form") cp.formPointerMaybeSet = false;
909
941
  const count = cp.tagBalance.get(tag) ?? 0;
910
942
  if (count > 0) {
911
943
  cp.tagBalance.set(tag, count - 1);
912
944
  cp.openTotal -= 1;
913
945
  }
914
946
  } else {
947
+ if (tag === "form") cp.formPointerMaybeSet = true;
915
948
  cp.openStack.push(tag);
916
949
  cp.tagBalance.set(tag, (cp.tagBalance.get(tag) ?? 0) + 1);
917
950
  cp.openTotal += 1;
@@ -1023,6 +1056,9 @@ function processConfirmedLine(cp, ln, text) {
1023
1056
  cp.p5Tok = { kind: "data" };
1024
1057
  }
1025
1058
  }
1059
+ if (cp.p5Tok.kind === "comment" && !mdHtml(cp.mdBlock, 2)) {
1060
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1061
+ }
1026
1062
  if (cp.mdBlock.kind === "html" && cp.mdBlock.type >= 6) cp.mdBlock = { kind: "none" };
1027
1063
  cp.blankRun += 1;
1028
1064
  cp.lastBlankStart = ln.start;
@@ -1035,7 +1071,11 @@ function processConfirmedLine(cp, ln, text) {
1035
1071
  // mask suppresses them — which is exactly why `openTotal` reads 0
1036
1072
  // and the candidate looked safe), and the 2-5 interiors are the
1037
1073
  // same construct to both grammars.
1038
- htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus",
1074
+ htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus" && // A form pointer parse5 may still be holding makes a LATER `<form>`
1075
+ // in the tail vanish from the full parse while a split parse opens
1076
+ // it — forward independence fails with every other condition clean.
1077
+ // See the field doc.
1078
+ !cp.formPointerMaybeSet,
1039
1079
  hazard: cp.hazardVerdict,
1040
1080
  seamRisk: cp.p5SealPending,
1041
1081
  defListSettled: null
@@ -1090,14 +1130,14 @@ function processConfirmedLine(cp, ln, text) {
1090
1130
  }
1091
1131
  }
1092
1132
  }
1093
- const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(mdTrimStart(ln.text));
1133
+ const rawFlowStart = ln.indent <= 3 && RAW_CONSTRUCT_START_RE.test(mdTrimStart(ln.text));
1094
1134
  const htmlOwnedLine = cp.mdBlock.kind === "html" || rawOpenAtLineStart || rawFlowStart;
1095
1135
  const maskingSuppressed = htmlOwnedLine || inRawTextTok(cp.p5Tok);
1096
1136
  const { masked, unpaired } = maskingSuppressed ? { masked: null, unpaired: false } : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);
1097
1137
  if (unpaired) cp.paragraphHasUnpairedRun = true;
1098
1138
  const scanText = masked ?? ln.text;
1099
1139
  const defRawToMicromark = cp.mdBlock.kind === "html" || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);
1100
- const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, defRawToMicromark, isBlockStart);
1140
+ const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, ln.text, defRawToMicromark, isBlockStart);
1101
1141
  const rawSpans = [];
1102
1142
  let pos = 0;
1103
1143
  const poisonRawDivergence = () => {
@@ -1372,7 +1412,7 @@ function processConfirmedLine(cp, ln, text) {
1372
1412
  cursor = to;
1373
1413
  }
1374
1414
  masked2 += scanText.slice(cursor);
1375
- if (floatingResidue(masked2, bothCommentsOpenAtLineStart).length > 0) {
1415
+ if (floatingResidue(masked2, bothCommentsOpenAtLineStart).length > 0 || discardedEndTag) {
1376
1416
  cp.p5SealPending = true;
1377
1417
  }
1378
1418
  }
@@ -1425,6 +1465,21 @@ function processConfirmedLine(cp, ln, text) {
1425
1465
  }
1426
1466
  }
1427
1467
  }
1468
+ var SCANNER_NAME_LISTS = [
1469
+ ["type1", TYPE1_NAMES],
1470
+ ["rawText", RAW_TEXT_ELEMENTS],
1471
+ ["type6", TYPE6_NAMES],
1472
+ ["void", VOID_TAGS],
1473
+ ["documentStructure", DOCUMENT_STRUCTURE_NAMES],
1474
+ // Added with F28, and it is the list that would have made F28 visible: the
1475
+ // derived census alphabet partitions names by their membership across THIS
1476
+ // table, so before it existed `frame` shared one 39-name class with `div`
1477
+ // and could never be sampled apart from it.
1478
+ ["noElement", NO_ELEMENT_NAMES],
1479
+ ["tablePart", TABLE_PART_NAMES],
1480
+ ["scopeBarrier", SCOPE_BARRIER_NAMES],
1481
+ ["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
1482
+ ];
1428
1483
 
1429
1484
  // src/components/incrementalParse/spliceParse.ts
1430
1485
  var import_micromark_util_normalize_identifier2 = require("micromark-util-normalize-identifier");