@ai-react-markdown/engine 2.3.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.dev.js CHANGED
@@ -198,7 +198,7 @@ var DEF_LIST_DD_RE = /^ {0,3}:[ \t]/;
198
198
  var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
199
199
  var FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
200
200
  var MATH_RUN_RE = /^ {0,3}(\$\$+)/;
201
- var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->/g;
201
+ var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->|--!>/g;
202
202
  var TRUNCATED_TAG_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)([^<>]*)$/;
203
203
  var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
204
204
  var BACKTICK_RUN_RE = /`+/g;
@@ -280,6 +280,7 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
280
280
  fenceLen: 0,
281
281
  inMath: false,
282
282
  mathFenceLen: 0,
283
+ openIndent: 0,
283
284
  blankRun: 0,
284
285
  lastBlankStart: -1,
285
286
  hazardVerdict: false,
@@ -290,21 +291,15 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
290
291
  paragraphHasUnpairedRun: false,
291
292
  htmlFlowSinceBlank: false,
292
293
  htmlSeamPending: false,
293
- phasePoisonedAt: Infinity
294
+ phasePoisonedAt: Infinity,
295
+ pendingTruncatedTags: []
294
296
  };
295
297
  }
296
298
  function isPlausibleLinkDefRest(rest) {
297
299
  const t = rest.trim();
298
300
  if (t === "") return false;
299
- let destEnd;
300
- if (t.startsWith("<")) {
301
- const close = t.indexOf(">");
302
- if (close === -1) return false;
303
- destEnd = close + 1;
304
- } else {
305
- const ws = t.search(/[ \t]/);
306
- destEnd = ws === -1 ? t.length : ws;
307
- }
301
+ const destEnd = linkDestinationEnd(t);
302
+ if (destEnd === -1) return false;
308
303
  const after = t.slice(destEnd).trim();
309
304
  if (after === "") return true;
310
305
  const opener = after[0];
@@ -319,6 +314,39 @@ function isPlausibleLinkDefRest(rest) {
319
314
  }
320
315
  return false;
321
316
  }
317
+ function linkDestinationEnd(t) {
318
+ if (t.startsWith("<")) {
319
+ for (let i2 = 1; i2 < t.length; i2++) {
320
+ const ch = t[i2];
321
+ if (ch === "\\" && (t[i2 + 1] === "<" || t[i2 + 1] === ">" || t[i2 + 1] === "\\")) {
322
+ i2 += 1;
323
+ continue;
324
+ }
325
+ if (ch === ">") return i2 + 1;
326
+ if (ch === "<") return -1;
327
+ }
328
+ return -1;
329
+ }
330
+ let balance = 0;
331
+ let i = 0;
332
+ for (; i < t.length; i++) {
333
+ const code = t.charCodeAt(i);
334
+ if (code === 32 || code === 9) break;
335
+ if (code < 32 || code === 127) return -1;
336
+ const ch = t[i];
337
+ if (ch === "\\" && (t[i + 1] === "(" || t[i + 1] === ")" || t[i + 1] === "\\")) {
338
+ i += 1;
339
+ continue;
340
+ }
341
+ if (ch === "(") balance += 1;
342
+ else if (ch === ")") {
343
+ if (balance === 0) break;
344
+ balance -= 1;
345
+ }
346
+ }
347
+ if (balance !== 0 || i === 0) return -1;
348
+ return i;
349
+ }
322
350
  function classifyBlockStart(text, indent, defListEnabled) {
323
351
  if (indent >= 4) return true;
324
352
  if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;
@@ -380,6 +408,48 @@ function computeFreezeBoundary(text, options, resume) {
380
408
  }
381
409
  return { boundary, checkpoint: cp };
382
410
  }
411
+ function floatingResidue(text, commentOpenAtStart) {
412
+ let out = "";
413
+ let open = commentOpenAtStart;
414
+ let last = 0;
415
+ TAG_OR_COMMENT_RE.lastIndex = 0;
416
+ let m;
417
+ while ((m = TAG_OR_COMMENT_RE.exec(text)) !== null) {
418
+ if (m[0] === "<!--") {
419
+ const next = text.slice(m.index + 4, m.index + 6);
420
+ const overlapLen = next.startsWith(">") ? 5 : next === "->" ? 6 : 0;
421
+ if (open) {
422
+ if (overlapLen) {
423
+ open = false;
424
+ last = m.index + overlapLen;
425
+ TAG_OR_COMMENT_RE.lastIndex = last;
426
+ }
427
+ continue;
428
+ }
429
+ out += text.slice(last, m.index);
430
+ if (overlapLen) {
431
+ last = m.index + overlapLen;
432
+ TAG_OR_COMMENT_RE.lastIndex = last;
433
+ continue;
434
+ }
435
+ open = true;
436
+ continue;
437
+ }
438
+ if (m[0] === "-->") {
439
+ if (open) {
440
+ open = false;
441
+ last = m.index + 3;
442
+ }
443
+ continue;
444
+ }
445
+ if (m[0] === "--!>") continue;
446
+ if (open) continue;
447
+ out += text.slice(last, m.index);
448
+ last = m.index + m[0].length;
449
+ }
450
+ if (!open) out += text.slice(last);
451
+ return out;
452
+ }
383
453
  function processConfirmedLine(cp, ln, text) {
384
454
  const newest = cp.candidates[cp.candidates.length - 1];
385
455
  if (newest && newest.defListSettled === null) {
@@ -434,6 +504,7 @@ function processConfirmedLine(cp, ln, text) {
434
504
  cp.inFence = true;
435
505
  cp.fenceChar = open[1][0];
436
506
  cp.fenceLen = open[1].length;
507
+ cp.openIndent = ln.indent;
437
508
  cp.blankRun = 0;
438
509
  cp.paragraphHasUnpairedRun = false;
439
510
  cp.prevLineBlank = false;
@@ -468,6 +539,7 @@ function processConfirmedLine(cp, ln, text) {
468
539
  }
469
540
  cp.inMath = true;
470
541
  cp.mathFenceLen = mathRun[1].length;
542
+ cp.openIndent = ln.indent;
471
543
  cp.blankRun = 0;
472
544
  cp.paragraphHasUnpairedRun = false;
473
545
  cp.prevLineBlank = false;
@@ -478,6 +550,10 @@ function processConfirmedLine(cp, ln, text) {
478
550
  }
479
551
  }
480
552
  if (ln.blank) {
553
+ if (cp.pendingTruncatedTags.length > 0) {
554
+ for (const tag of cp.pendingTruncatedTags) applyTag(tag, true);
555
+ cp.pendingTruncatedTags = [];
556
+ }
481
557
  cp.blankRun += 1;
482
558
  cp.lastBlankStart = ln.start;
483
559
  cp.candidates.push({
@@ -507,6 +583,7 @@ function processConfirmedLine(cp, ln, text) {
507
583
  if (!TYPE6_NAMES.has(tagStart[1].toLowerCase())) cp.hazardVerdict = true;
508
584
  }
509
585
  const inRawText = cp.htmlFlowSinceBlank || rawOpenAtLineStart;
586
+ const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(ln.text.trimStart());
510
587
  const { masked, unpaired } = inRawText ? { masked: null, unpaired: false } : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);
511
588
  if (unpaired) cp.paragraphHasUnpairedRun = true;
512
589
  const scanText = masked ?? ln.text;
@@ -551,9 +628,14 @@ function processConfirmedLine(cp, ln, text) {
551
628
  const rawOpenAtStart = cp.piOpen || cp.declOpen || cp.cdataOpen;
552
629
  const rawSpans = [];
553
630
  let pos = 0;
631
+ const poisonRawDivergence = () => {
632
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
633
+ };
554
634
  while (pos < scanText.length) {
555
635
  if (cp.piOpen) {
556
636
  const c = scanText.indexOf("?>", pos);
637
+ const gt = scanText.indexOf(">", pos);
638
+ if (gt !== -1 && (c === -1 || gt !== c + 1)) poisonRawDivergence();
557
639
  if (c === -1) {
558
640
  rawSpans.push([pos, scanText.length]);
559
641
  break;
@@ -565,6 +647,8 @@ function processConfirmedLine(cp, ln, text) {
565
647
  }
566
648
  if (cp.cdataOpen) {
567
649
  const c = scanText.indexOf("]]>", pos);
650
+ const gt = scanText.indexOf(">", pos);
651
+ if (gt !== -1 && (c === -1 || gt !== c + 2)) poisonRawDivergence();
568
652
  if (c === -1) {
569
653
  rawSpans.push([pos, scanText.length]);
570
654
  break;
@@ -597,6 +681,12 @@ function processConfirmedLine(cp, ln, text) {
597
681
  cp.cdataOpen = true;
598
682
  pos = cd + 9;
599
683
  } else if (first === pi) {
684
+ if (scanText[pi + 2] === ">") {
685
+ rawSpans.push([pi, pi + 3]);
686
+ pos = pi + 3;
687
+ if (scanText.slice(0, pi).trim() !== "" || ln.indent > 3) poisonRawDivergence();
688
+ continue;
689
+ }
600
690
  rawSpans.push([pi, pi + 2]);
601
691
  cp.piOpen = true;
602
692
  pos = pi + 2;
@@ -613,6 +703,15 @@ function processConfirmedLine(cp, ln, text) {
613
703
  let lastCommentOpenerIdx = -1;
614
704
  while ((m = TAG_OR_COMMENT_RE.exec(scanText)) !== null) {
615
705
  if (m[0] === "<!--") {
706
+ const next = scanText.slice(m.index + 4, m.index + 6);
707
+ if (cp.commentOpen) {
708
+ if (next.startsWith(">") || next === "->") cp.commentOpen = false;
709
+ else if (next === "!>" || next === "-!") poisonRawDivergence();
710
+ continue;
711
+ }
712
+ if (next.startsWith(">") || next === "->") {
713
+ continue;
714
+ }
616
715
  cp.commentOpen = true;
617
716
  lastCommentOpenerIdx = m.index;
618
717
  continue;
@@ -621,6 +720,10 @@ function processConfirmedLine(cp, ln, text) {
621
720
  cp.commentOpen = false;
622
721
  continue;
623
722
  }
723
+ if (m[0] === "--!>") {
724
+ if (cp.commentOpen) poisonRawDivergence();
725
+ continue;
726
+ }
624
727
  if (cp.commentOpen) continue;
625
728
  const closing = m[1] === "/";
626
729
  const tag = m[2].toLowerCase();
@@ -633,6 +736,9 @@ function processConfirmedLine(cp, ln, text) {
633
736
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastCommentOpenerIdx);
634
737
  }
635
738
  }
739
+ if (cp.pendingTruncatedTags.length > 0 && scanText.includes(">")) {
740
+ cp.pendingTruncatedTags = [];
741
+ }
636
742
  if (!cp.commentOpen) {
637
743
  const lastLt = scanText.lastIndexOf("<");
638
744
  if (lastLt !== -1 && !scanText.includes(">", lastLt)) {
@@ -640,22 +746,20 @@ function processConfirmedLine(cp, ln, text) {
640
746
  if (m2) {
641
747
  const closing = m2[1] === "/";
642
748
  const tag = m2[2].toLowerCase();
643
- if (!VOID_TAGS.has(tag)) applyTag(tag, closing);
749
+ if (!VOID_TAGS.has(tag)) {
750
+ applyTag(tag, closing);
751
+ if (!closing && !inRawText) cp.pendingTruncatedTags.push(tag);
752
+ }
644
753
  }
645
754
  }
646
755
  }
647
756
  }
648
- if (inRawText && cp.openTotal === 0) {
649
- let residue = scanText;
757
+ if ((inRawText || rawFlowStart) && cp.openTotal === 0) {
758
+ let masked2 = scanText;
650
759
  for (const [from, to] of rawSpans) {
651
- residue = residue.slice(0, from) + " ".repeat(to - from) + residue.slice(to);
652
- }
653
- residue = residue.replace(/<!--[\s\S]*?-->/g, " ");
654
- if (commentOpenAtLineStart) {
655
- residue = residue.includes("-->") ? residue.replace(/[\s\S]*?-->/, " ") : "";
760
+ masked2 = masked2.slice(0, from) + " ".repeat(to - from) + masked2.slice(to);
656
761
  }
657
- residue = residue.replace(TAG_OR_COMMENT_RE, "");
658
- if (residue.trim() !== "") {
762
+ if (floatingResidue(masked2, commentOpenAtLineStart).trim() !== "") {
659
763
  cp.htmlSeamPending = true;
660
764
  }
661
765
  }
@@ -665,6 +769,9 @@ function processConfirmedLine(cp, ln, text) {
665
769
  cp.prevLineWasValidDef = validDef && !def[1].startsWith("^");
666
770
  }
667
771
 
772
+ // src/components/incrementalParse/spliceParse.ts
773
+ import { normalizeIdentifier as normalizeIdentifier2 } from "micromark-util-normalize-identifier";
774
+
668
775
  // src/components/hastPredicates.ts
669
776
  function isFootnoteSection(node) {
670
777
  if (node.tagName !== "section") return false;
@@ -759,16 +866,20 @@ function collectPrefixInjection(mdast, content, boundary, resume) {
759
866
  for (const child of children) visit6(child, true);
760
867
  }
761
868
  };
869
+ let lastStart = -1;
762
870
  for (const child of mdast.children) {
763
871
  const start = child.position?.start?.offset;
872
+ if (start !== void 0) {
873
+ if (start < lastStart) return { events: [], uninjectable: true, cacheable: false };
874
+ lastStart = start;
875
+ }
764
876
  if (start === void 0) {
765
877
  if (resumeAt > 0) return collectPrefixInjection(mdast, content, boundary, null);
766
878
  cacheable = false;
767
879
  visit6(child, false);
768
880
  continue;
769
881
  }
770
- if (start >= boundary) break;
771
- if (start < resumeAt) continue;
882
+ if (start >= boundary || start < resumeAt) continue;
772
883
  visit6(child, false);
773
884
  }
774
885
  return { events, uninjectable, cacheable };
@@ -782,7 +893,7 @@ function cloneEventsForAppend(events) {
782
893
  var TERMINATOR_LABEL = "__aimd_injection_terminator__";
783
894
  var INJECTION_TERMINATOR = `[${TERMINATOR_LABEL}]: __aimd_sentinel_link__`;
784
895
  function tailMentionsTerminator(tailSource) {
785
- return tailSource.includes(`[${TERMINATOR_LABEL}`);
896
+ return normalizeIdentifier2(tailSource).includes(`[${normalizeIdentifier2(TERMINATOR_LABEL)}`);
786
897
  }
787
898
  function buildInjectionPrefix(events) {
788
899
  if (events.length === 0) return { text: "", segments: [] };
@@ -1230,11 +1341,12 @@ import remarkGfm from "remark-gfm";
1230
1341
  import { visit } from "unist-util-visit";
1231
1342
 
1232
1343
  // src/components/normalizeId.ts
1344
+ import { normalizeIdentifier as normalizeIdentifier3 } from "micromark-util-normalize-identifier";
1233
1345
  function normalizeId(s) {
1234
- return s.replace(/\s+/g, " ").toUpperCase();
1346
+ return normalizeIdentifier3(s);
1235
1347
  }
1236
1348
  function normalizeForMatch(s) {
1237
- return s.replace(/\\(.)/g, "$1").replace(/\s+/g, " ").toUpperCase();
1349
+ return normalizeIdentifier3(s.replace(/\\(.)/g, "$1"));
1238
1350
  }
1239
1351
 
1240
1352
  // src/components/collectDefLabels.ts
@@ -1489,6 +1601,18 @@ function buildPhantomSuffix(phantoms) {
1489
1601
  }
1490
1602
  return suffix;
1491
1603
  }
1604
+ function phantomSuffixCloser(content) {
1605
+ if (content === "") return "";
1606
+ const endsWithNewline = content.endsWith("\n");
1607
+ const confirmed = endsWithNewline ? content : content + "\n";
1608
+ const { checkpoint } = computeFreezeBoundary(confirmed, { defListEnabled: false, referenceTaint: false });
1609
+ if (checkpoint.phasePoisonedAt !== Infinity) return "";
1610
+ const nl = endsWithNewline ? "" : "\n";
1611
+ const indent = " ".repeat(checkpoint.openIndent);
1612
+ if (checkpoint.inFence) return `${nl}${indent}${checkpoint.fenceChar.repeat(checkpoint.fenceLen)}`;
1613
+ if (checkpoint.inMath) return `${nl}${indent}${"$".repeat(checkpoint.mathFenceLen)}`;
1614
+ return "";
1615
+ }
1492
1616
 
1493
1617
  // src/components/extractContributions.ts
1494
1618
  function fakeAnchorElement(url) {
@@ -1567,6 +1691,14 @@ function createRegistry(onEmpty) {
1567
1691
  releaseSymbol(reactId) {
1568
1692
  const entry = this._reactIdMap.get(reactId);
1569
1693
  if (!entry) return;
1694
+ if (entry.refcount <= 0) {
1695
+ if (true) {
1696
+ console.warn(
1697
+ `[ai-react-markdown] Registry.releaseSymbol("${reactId}") called with no matching allocateSymbol \u2014 ignoring (unbalanced release).`
1698
+ );
1699
+ }
1700
+ return;
1701
+ }
1570
1702
  entry.refcount--;
1571
1703
  if (entry.refcount === 0) {
1572
1704
  queueMicrotask(() => {
@@ -1863,6 +1995,11 @@ function buildCoreRemarkRehypeOptions(enableDefinitionList) {
1863
1995
  }
1864
1996
 
1865
1997
  // src/components/customMdastHandlers.ts
1998
+ function localDefProps(s, id) {
1999
+ const def = s.definitionById.get(id);
2000
+ if (!def || typeof def.url !== "string" || def.url === SENTINEL_LINK_URL) return {};
2001
+ return def.title ? { localUrl: def.url, localTitle: def.title } : { localUrl: def.url };
2002
+ }
1866
2003
  function buildCrossChunkHandlers() {
1867
2004
  return {
1868
2005
  footnoteDefinition: (state, node) => {
@@ -1873,6 +2010,7 @@ function buildCrossChunkHandlers() {
1873
2010
  }
1874
2011
  if (s.options.preserveOrphan && !s.footnoteOrder.includes(id)) {
1875
2012
  s.footnoteOrder.push(id);
2013
+ if (!s.footnoteCounts.has(id)) s.footnoteCounts.set(id, 0);
1876
2014
  }
1877
2015
  return void 0;
1878
2016
  },
@@ -1894,7 +2032,8 @@ function buildCrossChunkHandlers() {
1894
2032
  // internally, so cross-chunk case-insensitive matching still works.
1895
2033
  label: node.label ?? node.identifier,
1896
2034
  referenceType: node.referenceType,
1897
- documentId: s.options.documentId
2035
+ documentId: s.options.documentId,
2036
+ ...localDefProps(s, id)
1898
2037
  },
1899
2038
  children: s.all(node)
1900
2039
  };
@@ -1911,7 +2050,8 @@ function buildCrossChunkHandlers() {
1911
2050
  label: node.label ?? node.identifier,
1912
2051
  referenceType: node.referenceType,
1913
2052
  alt: node.alt ?? "",
1914
- documentId: s.options.documentId
2053
+ documentId: s.options.documentId,
2054
+ ...localDefProps(s, id)
1915
2055
  },
1916
2056
  children: []
1917
2057
  };
@@ -1940,6 +2080,12 @@ function buildCrossChunkHandlers() {
1940
2080
  properties: {
1941
2081
  label: node.identifier,
1942
2082
  localOccurrence,
2083
+ // The number mdast-util-to-hast would give this reference in a
2084
+ // standalone render (footnoteOrder position) — the placeholder's
2085
+ // fallback while the registry has no global number (server render /
2086
+ // first client frame), where the local synthetic footer is what
2087
+ // renders, so marks and footer agree (core-render-02).
2088
+ localNumber: s.footnoteOrder.indexOf(id) + 1,
1943
2089
  documentId: s.options.documentId
1944
2090
  },
1945
2091
  children: []
@@ -3148,9 +3294,9 @@ var sanitizeSchema = cloneDeep_default({
3148
3294
  attributes: {
3149
3295
  ...defaultSchema.attributes,
3150
3296
  code: mergeClassNameAllowlist(defaultSchema.attributes?.code, ["math-inline", "math-display"]),
3151
- "cross-chunk-link": ["label", "referenceType", "documentId"],
3152
- "cross-chunk-image": ["label", "referenceType", "documentId", "alt"],
3153
- "footnote-sup": ["label", "localOccurrence", "documentId"]
3297
+ "cross-chunk-link": ["label", "referenceType", "documentId", "localUrl", "localTitle"],
3298
+ "cross-chunk-image": ["label", "referenceType", "documentId", "alt", "localUrl", "localTitle"],
3299
+ "footnote-sup": ["label", "localOccurrence", "localNumber", "documentId"]
3154
3300
  }
3155
3301
  });
3156
3302
 
@@ -3531,9 +3677,9 @@ var createSmoothStreamController = (options = {}) => {
3531
3677
  snap,
3532
3678
  flush() {
3533
3679
  disposed = false;
3534
- if (visibleEnd === source.length) return;
3535
- visibleEnd = source.length;
3536
- tentativeEnd = source.length;
3680
+ const target = finished ? source.length : pending.length > 0 ? pending[pending.length - 1] : visibleEnd;
3681
+ if (target <= visibleEnd) return;
3682
+ visibleEnd = target;
3537
3683
  pending = [];
3538
3684
  credit = 0;
3539
3685
  cancelScheduled();
@@ -4059,6 +4205,7 @@ export {
4059
4205
  normalizeId,
4060
4206
  pangu,
4061
4207
  parseStage,
4208
+ phantomSuffixCloser,
4062
4209
  preprocessAIMDContent,
4063
4210
  preprocessLaTeX,
4064
4211
  rehypeFooterAdorn,