@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.
package/dist/index.js CHANGED
@@ -289,9 +289,9 @@ function inlineResourceEnd(text, openIdx) {
289
289
  }
290
290
  return -1;
291
291
  }
292
- function collectRefLine(cp, lnStart, lnEnd, scanText, inRawText, isBlockStart) {
293
- const defShaped = inRawText ? null : DEF_RE.exec(scanText);
294
- const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
292
+ function collectRefLine(cp, lnStart, lnEnd, scanText, rawText, inRawText, isBlockStart) {
293
+ const defShaped = inRawText ? null : DEF_RE.exec(rawText);
294
+ const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(rawText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
295
295
  const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
296
296
  const validDef = def !== null && defLineStart;
297
297
  if (validDef) {
@@ -370,16 +370,15 @@ function settleRefsAndEarliestUnresolved(cp) {
370
370
  var TYPE6_NAMES = new Set(htmlBlockNames);
371
371
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
372
372
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
373
+ var NO_ELEMENT_NAMES = /* @__PURE__ */ new Set([...DOCUMENT_STRUCTURE_NAMES, "frame", "image"]);
373
374
  var RETROACTIVE_OPENERS = [
374
375
  "<!doctype",
375
- "<html",
376
- "<head",
377
- "<body",
378
- "<frameset",
379
- "</html",
380
- "</head",
381
- "</body",
382
- "</frameset"
376
+ // DERIVED, so the trailing-partial guard cannot drift from the poison the
377
+ // confirmed lines get. It was transcribed until F28, and the transcription
378
+ // was already two names behind by then. `<frame` subsumes `<frameset`,
379
+ // which is why the derived list is SHORTER than the one it replaces and
380
+ // still covers strictly more.
381
+ ...[...NO_ELEMENT_NAMES].flatMap((name) => [`<${name}`, `</${name}`])
383
382
  ];
384
383
  function tailCarriesRetroactive(text) {
385
384
  const lower = text.toLowerCase();
@@ -509,12 +508,15 @@ var rawTextElement = (t) => t.kind === "rawText" ? t.element : t.kind === "scrip
509
508
  var VOID_TAGS = /* @__PURE__ */ new Set([
510
509
  "area",
511
510
  "base",
511
+ "basefont",
512
+ "bgsound",
512
513
  "br",
513
514
  "col",
514
515
  "embed",
515
516
  "hr",
516
517
  "img",
517
518
  "input",
519
+ "keygen",
518
520
  "link",
519
521
  "meta",
520
522
  "param",
@@ -529,7 +531,6 @@ var THEMATIC_BREAK_RE = /^(?:(?:-[ \t]*){3,}|(?:\*[ \t]*){3,}|(?:_[ \t]*){3,})$/
529
531
  var BARE_MARKER_RE = /^(?:[-*+]|\d{1,9}[.)])[ \t]*$/;
530
532
  var SETEXT_LEFTOVER_RE = /^(?:=+|--)[ \t]*$/;
531
533
  var DEF_LIST_DD_RE = /^ {0,3}:[ \t]/;
532
- var CLOSE_TAG_ONLY_RE = /^[ \t]*<\/[A-Za-z][A-Za-z0-9-]*[ \t]*>[ \t\r]*$/;
533
534
  var FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
534
535
  var MATH_RUN_RE = /^ {0,3}(\$\$+)/;
535
536
  var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->|--!>/g;
@@ -629,6 +630,7 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
629
630
  tagBalance: /* @__PURE__ */ new Map(),
630
631
  openTotal: 0,
631
632
  p5Tok: { kind: "data" },
633
+ formPointerMaybeSet: false,
632
634
  openStack: [],
633
635
  mdBlock: { kind: "none" },
634
636
  blankRun: 0,
@@ -766,6 +768,19 @@ function floatingResidue(text, commentOpenAtStart) {
766
768
  if (!open) out += text.slice(last);
767
769
  return out;
768
770
  }
771
+ var RAW_CONSTRUCT_START_RE = /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/;
772
+ var sealResumableAbove = (cp) => cp.defBlockMaybeOpen || cp.fnDefResumable || cp.containerMaybeOpen;
773
+ function sealReleaseDerived(cp, ln, isBlockStart) {
774
+ if (sealResumableAbove(cp) && !(isBlockStart && ln.indent <= 3)) return false;
775
+ if (cp.prevLineOpenContent) return false;
776
+ if (cp.tableMaybeOpen) return false;
777
+ const head = mdTrimStart(ln.text);
778
+ if (RAW_CONSTRUCT_START_RE.test(head) || TYPE1_START_RE.test(head) || isType7Line(head)) return false;
779
+ const t6 = TYPE6_START_RE.exec(head);
780
+ if (t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase())) return false;
781
+ if (DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text)) return false;
782
+ return true;
783
+ }
769
784
  function processConfirmedLine(cp, ln, text) {
770
785
  const newest = cp.candidates[cp.candidates.length - 1];
771
786
  if (newest && newest.defListSettled === null) {
@@ -773,16 +788,22 @@ function processConfirmedLine(cp, ln, text) {
773
788
  }
774
789
  const isBlockStart = cp.prevLineBlank;
775
790
  if (cp.p5SealPending && !ln.blank && cp.mdBlock.kind !== "html" && !(cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus")) {
776
- const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text) || cp.defBlockMaybeOpen || cp.fnDefResumable && !(isBlockStart && ln.indent <= 3);
777
- const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
778
- const closeTagOnly = CLOSE_TAG_ONLY_RE.test(ln.text);
779
- if (!defShapedLine && !commentOnly && !closeTagOnly) {
791
+ if (sealReleaseDerived(cp, ln, isBlockStart)) {
780
792
  cp.p5SealPending = false;
793
+ if (false) {
794
+ sealReleaseEvaluations += 1;
795
+ if (!sealReleaseEnumerated(cp, ln, isBlockStart)) {
796
+ console.error(
797
+ `[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))}).`
798
+ );
799
+ }
800
+ }
781
801
  }
782
802
  }
783
803
  const possiblyInsideForeign = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
784
804
  const honoursSelfClosing = (tag) => tag === "svg" || tag === "math";
785
805
  const foreignRawTextSwitchUnknowable = () => possiblyInsideForeign();
806
+ let discardedEndTag = false;
786
807
  const applyTag = (tag, closing) => {
787
808
  if (inRawTextTok(cp.p5Tok)) {
788
809
  if (cp.p5Tok.kind === "script" && cp.p5Tok.escaped && !closing && tag === "script") {
@@ -804,7 +825,7 @@ function processConfirmedLine(cp, ln, text) {
804
825
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
805
826
  }
806
827
  }
807
- if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;
828
+ if (NO_ELEMENT_NAMES.has(tag)) cp.phasePoisonedAt = 0;
808
829
  if (tag === "template" && !closing) cp.phasePoisonedAt = 0;
809
830
  if (closing) {
810
831
  let idx = -1;
@@ -815,14 +836,19 @@ function processConfirmedLine(cp, ln, text) {
815
836
  }
816
837
  if (SCOPE_BARRIER_NAMES.has(cp.openStack[i])) break;
817
838
  }
818
- if (idx === -1) return;
839
+ if (idx === -1) {
840
+ discardedEndTag = true;
841
+ return;
842
+ }
819
843
  cp.openStack.splice(idx, 1);
844
+ if (tag === "form") cp.formPointerMaybeSet = false;
820
845
  const count = cp.tagBalance.get(tag) ?? 0;
821
846
  if (count > 0) {
822
847
  cp.tagBalance.set(tag, count - 1);
823
848
  cp.openTotal -= 1;
824
849
  }
825
850
  } else {
851
+ if (tag === "form") cp.formPointerMaybeSet = true;
826
852
  cp.openStack.push(tag);
827
853
  cp.tagBalance.set(tag, (cp.tagBalance.get(tag) ?? 0) + 1);
828
854
  cp.openTotal += 1;
@@ -934,6 +960,9 @@ function processConfirmedLine(cp, ln, text) {
934
960
  cp.p5Tok = { kind: "data" };
935
961
  }
936
962
  }
963
+ if (cp.p5Tok.kind === "comment" && !mdHtml(cp.mdBlock, 2)) {
964
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
965
+ }
937
966
  if (cp.mdBlock.kind === "html" && cp.mdBlock.type >= 6) cp.mdBlock = { kind: "none" };
938
967
  cp.blankRun += 1;
939
968
  cp.lastBlankStart = ln.start;
@@ -946,7 +975,11 @@ function processConfirmedLine(cp, ln, text) {
946
975
  // mask suppresses them — which is exactly why `openTotal` reads 0
947
976
  // and the candidate looked safe), and the 2-5 interiors are the
948
977
  // same construct to both grammars.
949
- htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus",
978
+ htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus" && // A form pointer parse5 may still be holding makes a LATER `<form>`
979
+ // in the tail vanish from the full parse while a split parse opens
980
+ // it — forward independence fails with every other condition clean.
981
+ // See the field doc.
982
+ !cp.formPointerMaybeSet,
950
983
  hazard: cp.hazardVerdict,
951
984
  seamRisk: cp.p5SealPending,
952
985
  defListSettled: null
@@ -1001,14 +1034,14 @@ function processConfirmedLine(cp, ln, text) {
1001
1034
  }
1002
1035
  }
1003
1036
  }
1004
- const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(mdTrimStart(ln.text));
1037
+ const rawFlowStart = ln.indent <= 3 && RAW_CONSTRUCT_START_RE.test(mdTrimStart(ln.text));
1005
1038
  const htmlOwnedLine = cp.mdBlock.kind === "html" || rawOpenAtLineStart || rawFlowStart;
1006
1039
  const maskingSuppressed = htmlOwnedLine || inRawTextTok(cp.p5Tok);
1007
1040
  const { masked, unpaired } = maskingSuppressed ? { masked: null, unpaired: false } : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);
1008
1041
  if (unpaired) cp.paragraphHasUnpairedRun = true;
1009
1042
  const scanText = masked ?? ln.text;
1010
1043
  const defRawToMicromark = cp.mdBlock.kind === "html" || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);
1011
- const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, defRawToMicromark, isBlockStart);
1044
+ const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, ln.text, defRawToMicromark, isBlockStart);
1012
1045
  const rawSpans = [];
1013
1046
  let pos = 0;
1014
1047
  const poisonRawDivergence = () => {
@@ -1283,7 +1316,7 @@ function processConfirmedLine(cp, ln, text) {
1283
1316
  cursor = to;
1284
1317
  }
1285
1318
  masked2 += scanText.slice(cursor);
1286
- if (floatingResidue(masked2, bothCommentsOpenAtLineStart).length > 0) {
1319
+ if (floatingResidue(masked2, bothCommentsOpenAtLineStart).length > 0 || discardedEndTag) {
1287
1320
  cp.p5SealPending = true;
1288
1321
  }
1289
1322
  }
@@ -1336,6 +1369,21 @@ function processConfirmedLine(cp, ln, text) {
1336
1369
  }
1337
1370
  }
1338
1371
  }
1372
+ var SCANNER_NAME_LISTS = [
1373
+ ["type1", TYPE1_NAMES],
1374
+ ["rawText", RAW_TEXT_ELEMENTS],
1375
+ ["type6", TYPE6_NAMES],
1376
+ ["void", VOID_TAGS],
1377
+ ["documentStructure", DOCUMENT_STRUCTURE_NAMES],
1378
+ // Added with F28, and it is the list that would have made F28 visible: the
1379
+ // derived census alphabet partitions names by their membership across THIS
1380
+ // table, so before it existed `frame` shared one 39-name class with `div`
1381
+ // and could never be sampled apart from it.
1382
+ ["noElement", NO_ELEMENT_NAMES],
1383
+ ["tablePart", TABLE_PART_NAMES],
1384
+ ["scopeBarrier", SCOPE_BARRIER_NAMES],
1385
+ ["foreignRoot", new Set(FOREIGN_ROOT_NAMES)]
1386
+ ];
1339
1387
 
1340
1388
  // src/components/incrementalParse/spliceParse.ts
1341
1389
  import { normalizeIdentifier as normalizeIdentifier2 } from "micromark-util-normalize-identifier";