@ai-react-markdown/engine 2.5.5 → 2.7.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
@@ -267,7 +267,199 @@ var defaultUrlTransform = (value) => {
267
267
 
268
268
  // src/components/incrementalParse/computeFreezeBoundary.ts
269
269
  var import_micromark_util_html_tag_name = require("micromark-util-html-tag-name");
270
+
271
+ // src/components/incrementalParse/mdLineText.ts
272
+ var MD_BLANK_RE = /^[ \t\r]*$/;
273
+ var isMdBlank = (text) => MD_BLANK_RE.test(text);
274
+ var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
275
+ var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
276
+
277
+ // src/components/incrementalParse/referenceTaint.ts
270
278
  var import_micromark_util_normalize_identifier = require("micromark-util-normalize-identifier");
279
+ var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
280
+ var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
281
+ var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
282
+ function firstUnescaped(text, ch) {
283
+ for (let i = 0; i < text.length; i++) {
284
+ if (text[i] === "\\") i += 1;
285
+ else if (text[i] === ch) return i;
286
+ }
287
+ return -1;
288
+ }
289
+ function lastUnclosedBracket(text) {
290
+ let open = -1;
291
+ for (let i = 0; i < text.length; i++) {
292
+ const c = text[i];
293
+ if (c === "\\") i += 1;
294
+ else if (c === "[") open = i;
295
+ else if (c === "]") open = -1;
296
+ }
297
+ return open;
298
+ }
299
+ function normalizeLabel(label) {
300
+ const collapsed = label.replace(/[ \t\r\n]+/g, " ").replace(/^ | $/g, "");
301
+ return collapsed ? (0, import_micromark_util_normalize_identifier.normalizeIdentifier)(collapsed) : "";
302
+ }
303
+ function isPlausibleLinkDefRest(rest) {
304
+ const t = mdTrim(rest);
305
+ if (t === "") return false;
306
+ const destEnd = linkDestinationEnd(t);
307
+ if (destEnd === -1) return false;
308
+ const after = mdTrim(t.slice(destEnd));
309
+ if (after === "") return true;
310
+ const opener = after[0];
311
+ if (opener !== '"' && opener !== "'" && opener !== "(") return false;
312
+ const closer = opener === "(" ? ")" : opener;
313
+ for (let i = 1; i < after.length; i++) {
314
+ if (after[i] === "\\") {
315
+ i += 1;
316
+ continue;
317
+ }
318
+ if (after[i] === closer) return isMdBlank(after.slice(i + 1));
319
+ }
320
+ return false;
321
+ }
322
+ function linkDestinationEnd(t) {
323
+ if (t.startsWith("<")) {
324
+ for (let i2 = 1; i2 < t.length; i2++) {
325
+ const ch = t[i2];
326
+ if (ch === "\\" && (t[i2 + 1] === "<" || t[i2 + 1] === ">" || t[i2 + 1] === "\\")) {
327
+ i2 += 1;
328
+ continue;
329
+ }
330
+ if (ch === ">") return i2 + 1;
331
+ if (ch === "<") return -1;
332
+ }
333
+ return -1;
334
+ }
335
+ let balance = 0;
336
+ let i = 0;
337
+ for (; i < t.length; i++) {
338
+ const code = t.charCodeAt(i);
339
+ if (code === 32 || code === 9) break;
340
+ if (code < 32 || code === 127) return -1;
341
+ const ch = t[i];
342
+ if (ch === "\\" && (t[i + 1] === "(" || t[i + 1] === ")" || t[i + 1] === "\\")) {
343
+ i += 1;
344
+ continue;
345
+ }
346
+ if (ch === "(") balance += 1;
347
+ else if (ch === ")") {
348
+ if (balance === 0) break;
349
+ balance -= 1;
350
+ }
351
+ }
352
+ if (balance !== 0 || i === 0) return -1;
353
+ return i;
354
+ }
355
+ function inlineResourceEnd(text, openIdx) {
356
+ let i = openIdx + 1;
357
+ const skipWs = () => {
358
+ while (i < text.length && (text[i] === " " || text[i] === " ")) i += 1;
359
+ };
360
+ skipWs();
361
+ if (text[i] === ")") return i + 1;
362
+ const destEnd = linkDestinationEnd(text.slice(i));
363
+ if (destEnd === -1) return -1;
364
+ i += destEnd;
365
+ const beforeWs = i;
366
+ skipWs();
367
+ if (text[i] === ")") return i + 1;
368
+ if (i === beforeWs) return -1;
369
+ const opener = text[i];
370
+ if (opener !== '"' && opener !== "'" && opener !== "(") return -1;
371
+ const closer = opener === "(" ? ")" : opener;
372
+ for (i += 1; i < text.length; i++) {
373
+ if (text[i] === "\\") {
374
+ i += 1;
375
+ continue;
376
+ }
377
+ if (text[i] === closer) {
378
+ i += 1;
379
+ skipWs();
380
+ return text[i] === ")" ? i + 1 : -1;
381
+ }
382
+ }
383
+ return -1;
384
+ }
385
+ function collectRefLine(cp, lnStart, lnEnd, scanText, inRawText, isBlockStart) {
386
+ const defShaped = inRawText ? null : DEF_RE.exec(scanText);
387
+ const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
388
+ const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
389
+ const validDef = def !== null && defLineStart;
390
+ if (validDef) {
391
+ const label = def[1];
392
+ if (label.startsWith("^")) {
393
+ const key = normalizeLabel(label.slice(1));
394
+ if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, lnEnd);
395
+ } else {
396
+ const key = normalizeLabel(label);
397
+ if (key && !cp.defs.has(key)) cp.defs.set(key, lnEnd);
398
+ }
399
+ }
400
+ if (cp.referenceTaint) {
401
+ const pushRef = (offset, inner, followAt) => {
402
+ const follow = scanText[followAt];
403
+ if (follow === "(" && inlineResourceEnd(scanText, followAt) !== -1) return;
404
+ let label;
405
+ let footnote = false;
406
+ if (inner.startsWith("^")) {
407
+ footnote = true;
408
+ label = normalizeLabel(inner.slice(1));
409
+ } else if (follow === "[") {
410
+ const explicit = /^\[((?:[^[\]\\]|\\.)*)\]/.exec(scanText.slice(followAt));
411
+ label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);
412
+ } else {
413
+ label = normalizeLabel(inner);
414
+ }
415
+ if (label) cp.unresolvedRefs.push({ offset, label, footnote });
416
+ };
417
+ const pending = cp.openBracket;
418
+ cp.openBracket = null;
419
+ if (pending) {
420
+ const close = firstUnescaped(scanText, "]");
421
+ const open = firstUnescaped(scanText, "[");
422
+ const cont = (t) => t.replace(/^ {0,3}>[ \t]?/, "");
423
+ if (close !== -1 && (open === -1 || close < open)) {
424
+ pushRef(pending.offset, `${pending.text}
425
+ ${cont(scanText.slice(0, close))}`, close + 1);
426
+ } else if (close === -1 && open === -1) {
427
+ cp.openBracket = { offset: pending.offset, text: `${pending.text}
428
+ ${cont(scanText)}` };
429
+ }
430
+ }
431
+ if (scanText.includes("[")) {
432
+ const defBracket = validDef ? def.index + def[0].indexOf("[") : -1;
433
+ REF_RE.lastIndex = 0;
434
+ let m;
435
+ while ((m = REF_RE.exec(scanText)) !== null) {
436
+ const followAt = m.index + m[0].length;
437
+ if (scanText[followAt] === ":" && m.index === defBracket) continue;
438
+ pushRef(lnStart + m.index, m[1], followAt);
439
+ }
440
+ const trailingOpen = lastUnclosedBracket(scanText);
441
+ if (trailingOpen !== -1) {
442
+ cp.openBracket = { offset: lnStart + trailingOpen, text: scanText.slice(trailingOpen + 1) };
443
+ }
444
+ }
445
+ }
446
+ return { validDef, validLinkDef: validDef && !def[1].startsWith("^") };
447
+ }
448
+ function settleRefsAndEarliestUnresolved(cp) {
449
+ if (cp.unresolvedRefs.length > 0) {
450
+ const settled = (defEnd) => cp.lastBlankStart >= defEnd;
451
+ cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {
452
+ const table = ref.footnote ? cp.footnoteDefs : cp.defs;
453
+ const defEnd = table.get(ref.label);
454
+ return defEnd === void 0 || !settled(defEnd);
455
+ });
456
+ }
457
+ let earliestUnresolved = Infinity;
458
+ for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);
459
+ return earliestUnresolved;
460
+ }
461
+
462
+ // src/components/incrementalParse/computeFreezeBoundary.ts
271
463
  var TYPE6_NAMES = new Set(import_micromark_util_html_tag_name.htmlBlockNames);
272
464
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
273
465
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
@@ -290,53 +482,6 @@ function tailCarriesRetroactive(text) {
290
482
  }
291
483
  return false;
292
484
  }
293
- var HTML_BREAKOUT_TAGS = /* @__PURE__ */ new Set([
294
- "b",
295
- "big",
296
- "blockquote",
297
- "body",
298
- "br",
299
- "center",
300
- "code",
301
- "dd",
302
- "div",
303
- "dl",
304
- "dt",
305
- "em",
306
- "embed",
307
- "h1",
308
- "h2",
309
- "h3",
310
- "h4",
311
- "h5",
312
- "h6",
313
- "head",
314
- "hr",
315
- "i",
316
- "img",
317
- "li",
318
- "listing",
319
- "menu",
320
- "meta",
321
- "nobr",
322
- "ol",
323
- "p",
324
- "pre",
325
- "ruby",
326
- "s",
327
- "small",
328
- "span",
329
- "strong",
330
- "strike",
331
- "sub",
332
- "sup",
333
- "table",
334
- "tt",
335
- "u",
336
- "ul",
337
- "var"
338
- ]);
339
- var HTML_INTEGRATION_POINTS = ["foreignobject", "desc", "title", "mi", "mo", "mn", "ms", "mtext", "annotation-xml"];
340
485
  var SCOPE_BARRIER_NAMES = /* @__PURE__ */ new Set([
341
486
  "applet",
342
487
  "caption",
@@ -379,6 +524,11 @@ var TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \t\r]|>|$)/i;
379
524
  var TYPE1_CLOSE_RE = /<\/(?:script|pre|style|textarea)>/i;
380
525
  var TYPE7_LINE_RE = /^(?:<[A-Za-z][A-Za-z0-9-]*(?:[ \t\r][^>]*|\/)?>|<\/[A-Za-z][A-Za-z0-9-]*[ \t\r]*>)[ \t\r]*$/;
381
526
  var t7Name = (line) => /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(line)[1];
527
+ var mdHtml = (b, type) => b.kind === "html" && b.type === type;
528
+ var mdHtml25 = (b) => b.kind === "html" && b.type >= 2 && b.type <= 5;
529
+ var commentEitherOpen = (md, p5) => mdHtml(md, 2) || p5.kind === "comment";
530
+ var inRawTextTok = (t) => t.kind === "rawText" || t.kind === "script";
531
+ var rawTextElement = (t) => t.kind === "rawText" ? t.element : t.kind === "script" ? "script" : null;
382
532
  var VOID_TAGS = /* @__PURE__ */ new Set([
383
533
  "area",
384
534
  "base",
@@ -396,9 +546,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
396
546
  "wbr"
397
547
  ]);
398
548
  var LIST_MARKER_RE = /^ {0,3}(?:[-*+]|\d{1,9}[.)])(?:[ \t]|$)/;
399
- var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
400
549
  var DEF_LIST_DD_RE = /^ {0,3}:[ \t]/;
401
- var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
402
550
  var FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
403
551
  var MATH_RUN_RE = /^ {0,3}(\$\$+)/;
404
552
  var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->|--!>/g;
@@ -431,12 +579,7 @@ function scanTagAttrs(text, from, to, out) {
431
579
  out.state = st;
432
580
  return -1;
433
581
  }
434
- var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
435
582
  var BACKTICK_RUN_RE = /`+/g;
436
- var MD_BLANK_RE = /^[ \t\r]*$/;
437
- var isMdBlank = (text) => MD_BLANK_RE.test(text);
438
- var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
439
- var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
440
583
  function computeIndent(text) {
441
584
  let indent = 0;
442
585
  for (const ch of text) {
@@ -446,27 +589,6 @@ function computeIndent(text) {
446
589
  }
447
590
  return indent;
448
591
  }
449
- function firstUnescaped(text, ch) {
450
- for (let i = 0; i < text.length; i++) {
451
- if (text[i] === "\\") i += 1;
452
- else if (text[i] === ch) return i;
453
- }
454
- return -1;
455
- }
456
- function lastUnclosedBracket(text) {
457
- let open = -1;
458
- for (let i = 0; i < text.length; i++) {
459
- const c = text[i];
460
- if (c === "\\") i += 1;
461
- else if (c === "[") open = i;
462
- else if (c === "]") open = -1;
463
- }
464
- return open;
465
- }
466
- function normalizeLabel(label) {
467
- const collapsed = label.replace(/[ \t\r\n]+/g, " ").replace(/^ | $/g, "");
468
- return collapsed ? (0, import_micromark_util_normalize_identifier.normalizeIdentifier)(collapsed) : "";
469
- }
470
592
  function canBecomeDdLine(text, confirmed) {
471
593
  let i = 0;
472
594
  while (i < text.length && text[i] === " ") i += 1;
@@ -523,20 +645,9 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
523
645
  unresolvedRefs: [],
524
646
  tagBalance: /* @__PURE__ */ new Map(),
525
647
  openTotal: 0,
526
- commentOpen: false,
527
- piOpen: false,
528
- bogusOpen: false,
529
- rawTextOpen: null,
648
+ p5Tok: { kind: "data" },
530
649
  openStack: [],
531
- scriptDataEscaped: false,
532
- declOpen: false,
533
- cdataOpen: false,
534
- inFence: false,
535
- fenceChar: "",
536
- fenceLen: 0,
537
- inMath: false,
538
- mathFenceLen: 0,
539
- openIndent: 0,
650
+ mdBlock: { kind: "none" },
540
651
  blankRun: 0,
541
652
  lastBlankStart: -1,
542
653
  hazardVerdict: false,
@@ -546,101 +657,14 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
546
657
  prevLineWasValidDef: false,
547
658
  paragraphHasUnpairedRun: false,
548
659
  openBracket: null,
549
- htmlFlowSinceBlank: false,
550
- htmlSeamPending: false,
660
+ mayBeRawToMicromark: false,
661
+ p5SealPending: false,
551
662
  phasePoisonedAt: Infinity,
552
663
  pendingTruncatedTags: [],
553
664
  pendingTruncatedCloses: [],
554
- tagAcrossLines: false,
555
- tagAcrossLinesIndent: 0,
556
- tagAcrossLinesState: "outside",
557
- htmlFlowReal: false,
558
- type1FlowOpen: false,
559
- rawTextInline: false
665
+ pendingTag: null
560
666
  };
561
667
  }
562
- function isPlausibleLinkDefRest(rest) {
563
- const t = mdTrim(rest);
564
- if (t === "") return false;
565
- const destEnd = linkDestinationEnd(t);
566
- if (destEnd === -1) return false;
567
- const after = mdTrim(t.slice(destEnd));
568
- if (after === "") return true;
569
- const opener = after[0];
570
- if (opener !== '"' && opener !== "'" && opener !== "(") return false;
571
- const closer = opener === "(" ? ")" : opener;
572
- for (let i = 1; i < after.length; i++) {
573
- if (after[i] === "\\") {
574
- i += 1;
575
- continue;
576
- }
577
- if (after[i] === closer) return isMdBlank(after.slice(i + 1));
578
- }
579
- return false;
580
- }
581
- function linkDestinationEnd(t) {
582
- if (t.startsWith("<")) {
583
- for (let i2 = 1; i2 < t.length; i2++) {
584
- const ch = t[i2];
585
- if (ch === "\\" && (t[i2 + 1] === "<" || t[i2 + 1] === ">" || t[i2 + 1] === "\\")) {
586
- i2 += 1;
587
- continue;
588
- }
589
- if (ch === ">") return i2 + 1;
590
- if (ch === "<") return -1;
591
- }
592
- return -1;
593
- }
594
- let balance = 0;
595
- let i = 0;
596
- for (; i < t.length; i++) {
597
- const code = t.charCodeAt(i);
598
- if (code === 32 || code === 9) break;
599
- if (code < 32 || code === 127) return -1;
600
- const ch = t[i];
601
- if (ch === "\\" && (t[i + 1] === "(" || t[i + 1] === ")" || t[i + 1] === "\\")) {
602
- i += 1;
603
- continue;
604
- }
605
- if (ch === "(") balance += 1;
606
- else if (ch === ")") {
607
- if (balance === 0) break;
608
- balance -= 1;
609
- }
610
- }
611
- if (balance !== 0 || i === 0) return -1;
612
- return i;
613
- }
614
- function inlineResourceEnd(text, openIdx) {
615
- let i = openIdx + 1;
616
- const skipWs = () => {
617
- while (i < text.length && (text[i] === " " || text[i] === " ")) i += 1;
618
- };
619
- skipWs();
620
- if (text[i] === ")") return i + 1;
621
- const destEnd = linkDestinationEnd(text.slice(i));
622
- if (destEnd === -1) return -1;
623
- i += destEnd;
624
- const beforeWs = i;
625
- skipWs();
626
- if (text[i] === ")") return i + 1;
627
- if (i === beforeWs) return -1;
628
- const opener = text[i];
629
- if (opener !== '"' && opener !== "'" && opener !== "(") return -1;
630
- const closer = opener === "(" ? ")" : opener;
631
- for (i += 1; i < text.length; i++) {
632
- if (text[i] === "\\") {
633
- i += 1;
634
- continue;
635
- }
636
- if (text[i] === closer) {
637
- i += 1;
638
- skipWs();
639
- return text[i] === ")" ? i + 1 : -1;
640
- }
641
- }
642
- return -1;
643
- }
644
668
  function classifyBlockStart(text, indent, defListEnabled) {
645
669
  if (indent >= 4) return true;
646
670
  if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;
@@ -651,7 +675,8 @@ function classifyBlockStart(text, indent, defListEnabled) {
651
675
  function computeFreezeBoundary(text, options, resume) {
652
676
  const mathFlow = options.mathFlow ?? true;
653
677
  const referenceTaint = options.referenceTaint ?? true;
654
- const cp = resume && resume.defListEnabled === options.defListEnabled && resume.mathFlow === mathFlow && resume.referenceTaint === referenceTaint && resume.confirmedOffset <= text.length ? resume : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
678
+ const prev = resume;
679
+ const cp = prev && prev.defListEnabled === options.defListEnabled && prev.mathFlow === mathFlow && prev.referenceTaint === referenceTaint && prev.confirmedOffset <= text.length ? prev : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
655
680
  let start = cp.confirmedOffset;
656
681
  let tailLine = null;
657
682
  while (start < text.length) {
@@ -685,16 +710,7 @@ function computeFreezeBoundary(text, options, resume) {
685
710
  cp.confirmedOffset = end + 1;
686
711
  start = end + 1;
687
712
  }
688
- if (cp.unresolvedRefs.length > 0) {
689
- const settled = (defEnd) => cp.lastBlankStart >= defEnd;
690
- cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {
691
- const table = ref.footnote ? cp.footnoteDefs : cp.defs;
692
- const defEnd = table.get(ref.label);
693
- return defEnd === void 0 || !settled(defEnd);
694
- });
695
- }
696
- let earliestUnresolved = Infinity;
697
- for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);
713
+ const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
698
714
  const defListSettled = (c) => {
699
715
  if (!options.defListEnabled || c.blankRun >= 2) return true;
700
716
  if (c.defListSettled !== null) return c.defListSettled;
@@ -714,6 +730,13 @@ function computeFreezeBoundary(text, options, resume) {
714
730
  }
715
731
  return { boundary, checkpoint: cp };
716
732
  }
733
+ function pendingFenceCloser(checkpoint) {
734
+ const cp = checkpoint;
735
+ if (cp.phasePoisonedAt !== Infinity) return "";
736
+ if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
737
+ if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
738
+ return "";
739
+ }
717
740
  function floatingResidue(text, commentOpenAtStart) {
718
741
  let out = "";
719
742
  let open = commentOpenAtStart;
@@ -762,53 +785,30 @@ function processConfirmedLine(cp, ln, text) {
762
785
  newest.defListSettled = ln.blank ? true : !canBecomeDdLine(ln.text, true);
763
786
  }
764
787
  const isBlockStart = cp.prevLineBlank;
765
- if (cp.htmlSeamPending && !ln.blank && !cp.htmlFlowSinceBlank && !(cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen)) {
788
+ if (cp.p5SealPending && !ln.blank && !cp.mayBeRawToMicromark && !(mdHtml25(cp.mdBlock) || cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus")) {
766
789
  const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text);
767
790
  const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
768
791
  if (!defShapedLine && !commentOnly) {
769
- cp.htmlSeamPending = false;
792
+ cp.p5SealPending = false;
770
793
  }
771
794
  }
772
- const inForeignContent = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
773
- const honoursSelfClosing = (tag) => {
774
- if (tag === "svg" || tag === "math") return true;
775
- if (!inForeignContent() || HTML_BREAKOUT_TAGS.has(tag)) return false;
776
- for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return false;
777
- return true;
778
- };
779
- const htmlRulesApply = () => {
780
- if (!inForeignContent()) return true;
781
- for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return true;
782
- return false;
783
- };
784
- const popForeignRoots = () => {
785
- for (const name of FOREIGN_ROOT_NAMES) {
786
- const count = cp.tagBalance.get(name) ?? 0;
787
- if (count > 0) {
788
- cp.tagBalance.set(name, 0);
789
- cp.openTotal -= count;
790
- }
791
- }
792
- if (cp.openStack.length > 0) cp.openStack = cp.openStack.filter((n) => !FOREIGN_ROOT_NAMES.includes(n));
793
- };
794
- const noteBreakout = (tag, closing) => {
795
- if (closing || cp.rawTextOpen !== null) return;
796
- if (HTML_BREAKOUT_TAGS.has(tag) && !htmlRulesApply()) popForeignRoots();
797
- };
795
+ const possiblyInsideForeign = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
796
+ const honoursSelfClosing = (tag) => tag === "svg" || tag === "math";
797
+ const foreignRawTextSwitchUnknowable = () => possiblyInsideForeign();
798
798
  const applyTag = (tag, closing) => {
799
- if (cp.rawTextOpen !== null) {
800
- if (cp.scriptDataEscaped && !closing && tag === "script") {
799
+ if (inRawTextTok(cp.p5Tok)) {
800
+ if (cp.p5Tok.kind === "script" && cp.p5Tok.escaped && !closing && tag === "script") {
801
801
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
802
802
  }
803
- if (!(closing && tag === cp.rawTextOpen)) return;
804
- cp.rawTextOpen = null;
805
- cp.scriptDataEscaped = false;
803
+ if (!(closing && tag === rawTextElement(cp.p5Tok))) return;
804
+ cp.p5Tok = { kind: "data" };
806
805
  } else {
807
- noteBreakout(tag, closing);
808
- if (!closing && RAW_TEXT_ELEMENTS.has(tag) && htmlRulesApply()) {
809
- cp.rawTextOpen = tag;
810
- cp.scriptDataEscaped = false;
811
- cp.rawTextInline = !cp.htmlFlowReal;
806
+ if (!closing && RAW_TEXT_ELEMENTS.has(tag) && foreignRawTextSwitchUnknowable()) {
807
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
808
+ } else if (!closing && RAW_TEXT_ELEMENTS.has(tag)) {
809
+ if (cp.p5Tok.kind !== "data") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
810
+ const openedInline = cp.mdBlock.kind !== "html";
811
+ cp.p5Tok = tag === "script" ? { kind: "script", escaped: false, openedInline } : { kind: "rawText", element: tag, openedInline };
812
812
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
813
813
  }
814
814
  }
@@ -836,15 +836,14 @@ function processConfirmedLine(cp, ln, text) {
836
836
  cp.openTotal += 1;
837
837
  }
838
838
  };
839
- const strayTablePart = (tag) => TABLE_PART_NAMES.has(tag) && (cp.tagBalance.get("table") ?? 0) === 0;
840
- const commentOpenAtLineStart = cp.commentOpen;
841
- const rawOpenAtLineStart = cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen;
842
- if (cp.inFence) {
839
+ const definitelyInsideTable = () => (cp.tagBalance.get("table") ?? 0) > 0;
840
+ const strayTablePart = (tag) => TABLE_PART_NAMES.has(tag) && !definitelyInsideTable();
841
+ const commentOpenAtLineStart = commentEitherOpen(cp.mdBlock, cp.p5Tok);
842
+ const rawOpenAtLineStart = mdHtml25(cp.mdBlock) || cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus";
843
+ if (cp.mdBlock.kind === "fence") {
843
844
  const close = FENCE_RE.exec(ln.text);
844
- if (close && close[1][0] === cp.fenceChar && close[1].length >= cp.fenceLen && isMdBlank(ln.text.slice(close[0].length))) {
845
- cp.inFence = false;
846
- cp.fenceChar = "";
847
- cp.fenceLen = 0;
845
+ if (close && close[1][0] === cp.mdBlock.char && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {
846
+ cp.mdBlock = { kind: "none" };
848
847
  }
849
848
  cp.blankRun = 0;
850
849
  cp.paragraphHasUnpairedRun = false;
@@ -854,20 +853,17 @@ function processConfirmedLine(cp, ln, text) {
854
853
  cp.prevLineWasValidDef = false;
855
854
  return;
856
855
  }
857
- if (!cp.inMath && !rawOpenAtLineStart) {
856
+ if (cp.mdBlock.kind !== "math" && !rawOpenAtLineStart) {
858
857
  const open = FENCE_RE.exec(ln.text);
859
858
  const bogusInfo = open !== null && open[1][0] === "`" && ln.text.slice(ln.text.indexOf(open[1]) + open[1].length).includes("`");
860
- if (open && !bogusInfo && cp.htmlFlowSinceBlank) {
859
+ if (open && !bogusInfo && cp.mayBeRawToMicromark) {
861
860
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
862
861
  } else if (open && !bogusInfo) {
863
862
  if (isBlockStart) {
864
863
  const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);
865
864
  if (verdict !== null) cp.hazardVerdict = verdict;
866
865
  }
867
- cp.inFence = true;
868
- cp.fenceChar = open[1][0];
869
- cp.fenceLen = open[1].length;
870
- cp.openIndent = ln.indent;
866
+ cp.mdBlock = { kind: "fence", char: open[1][0], len: open[1].length, indent: ln.indent };
871
867
  cp.blankRun = 0;
872
868
  cp.paragraphHasUnpairedRun = false;
873
869
  cp.openBracket = null;
@@ -877,11 +873,10 @@ function processConfirmedLine(cp, ln, text) {
877
873
  return;
878
874
  }
879
875
  }
880
- if (cp.inMath) {
876
+ if (cp.mdBlock.kind === "math") {
881
877
  const close = MATH_RUN_RE.exec(ln.text);
882
- if (close && close[1].length >= cp.mathFenceLen && isMdBlank(ln.text.slice(close[0].length))) {
883
- cp.inMath = false;
884
- cp.mathFenceLen = 0;
878
+ if (close && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {
879
+ cp.mdBlock = { kind: "none" };
885
880
  }
886
881
  cp.blankRun = 0;
887
882
  cp.paragraphHasUnpairedRun = false;
@@ -895,16 +890,14 @@ function processConfirmedLine(cp, ln, text) {
895
890
  if (mathRun) {
896
891
  const rest = ln.text.slice(ln.text.indexOf(mathRun[1]) + mathRun[1].length);
897
892
  if (!rest.includes("$")) {
898
- if (cp.htmlFlowSinceBlank) {
893
+ if (cp.mayBeRawToMicromark) {
899
894
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
900
895
  } else {
901
896
  if (isBlockStart) {
902
897
  const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);
903
898
  if (verdict !== null) cp.hazardVerdict = verdict;
904
899
  }
905
- cp.inMath = true;
906
- cp.mathFenceLen = mathRun[1].length;
907
- cp.openIndent = ln.indent;
900
+ cp.mdBlock = { kind: "math", len: mathRun[1].length, indent: ln.indent };
908
901
  cp.blankRun = 0;
909
902
  cp.paragraphHasUnpairedRun = false;
910
903
  cp.openBracket = null;
@@ -921,36 +914,36 @@ function processConfirmedLine(cp, ln, text) {
921
914
  cp.pendingTruncatedTags = [];
922
915
  }
923
916
  cp.pendingTruncatedCloses = [];
924
- if (cp.tagAcrossLines && (cp.tagAcrossLinesState === '"' || cp.tagAcrossLinesState === "'")) {
917
+ if (cp.pendingTag !== null && (cp.pendingTag.attr === '"' || cp.pendingTag.attr === "'")) {
925
918
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
926
919
  }
927
- cp.tagAcrossLines = false;
928
- cp.tagAcrossLinesState = "outside";
929
- if (cp.bogusOpen) {
920
+ cp.pendingTag = null;
921
+ if (cp.p5Tok.kind === "bogus") {
930
922
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
931
- cp.bogusOpen = false;
923
+ cp.p5Tok = { kind: "data" };
932
924
  }
925
+ if (cp.mdBlock.kind === "html" && cp.mdBlock.type >= 6) cp.mdBlock = { kind: "none" };
933
926
  cp.blankRun += 1;
934
927
  cp.lastBlankStart = ln.start;
935
928
  cp.candidates.push({
936
929
  offset: Math.min(ln.end + 1, text.length),
937
930
  blankRun: cp.blankRun,
938
- // `type1FlowOpen`: an unterminated type-1 block swallows this blank
939
- // and everything after it as RAW content, so nothing here is a block
940
- // boundary at all. Its tags are invisible to the balance scan
941
- // (`rawTextOpen` suppresses them), which is exactly why `openTotal`
942
- // reads 0 and the candidate looked safe.
943
- htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen && !cp.bogusOpen && !cp.type1FlowOpen,
931
+ // The html member covers types 1-5 in one check: an unterminated
932
+ // type-1 block swallows this blank and everything after it as RAW
933
+ // content (its tags are invisible to the balance scan — the raw-text
934
+ // mask suppresses them which is exactly why `openTotal` reads 0
935
+ // and the candidate looked safe), and the 2-5 interiors are the
936
+ // same construct to both grammars.
937
+ htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus",
944
938
  hazard: cp.hazardVerdict,
945
- seamRisk: cp.htmlSeamPending,
939
+ seamRisk: cp.p5SealPending,
946
940
  defListSettled: null
947
941
  });
948
942
  cp.paragraphHasUnpairedRun = false;
949
943
  cp.openBracket = null;
950
- if (!cp.type1FlowOpen) {
951
- cp.htmlFlowSinceBlank = false;
952
- cp.htmlFlowReal = false;
953
- if (cp.rawTextOpen !== null && !cp.rawTextInline) {
944
+ if (!mdHtml(cp.mdBlock, 1)) {
945
+ cp.mayBeRawToMicromark = false;
946
+ if (inRawTextTok(cp.p5Tok) && !cp.p5Tok.openedInline) {
954
947
  cp.phasePoisonedAt = 0;
955
948
  }
956
949
  }
@@ -967,86 +960,29 @@ function processConfirmedLine(cp, ln, text) {
967
960
  }
968
961
  const tagStart = ln.indent <= 3 ? /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(mdTrimStart(ln.text)) : null;
969
962
  if (tagStart) {
970
- const noRealBlockOpen = !cp.htmlFlowReal;
971
- cp.htmlFlowSinceBlank = true;
972
- if (noRealBlockOpen && TYPE1_START_RE.test(mdTrimStart(ln.text))) cp.type1FlowOpen = true;
963
+ const noRealBlockOpen = cp.mdBlock.kind !== "html";
964
+ cp.mayBeRawToMicromark = true;
965
+ if (noRealBlockOpen && TYPE1_START_RE.test(mdTrimStart(ln.text))) cp.mdBlock = { kind: "html", type: 1 };
973
966
  if (!TYPE6_NAMES.has(tagStart[1].toLowerCase())) cp.hazardVerdict = true;
974
- if (!cp.htmlFlowReal) {
967
+ if (cp.mdBlock.kind !== "html") {
975
968
  const t = mdTrimStart(ln.text);
976
969
  const t6 = TYPE6_START_RE.exec(t);
977
970
  const t7 = TYPE7_LINE_RE.exec(t);
978
- 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
971
+ const realT6 = t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase());
972
+ if (realT6 || TYPE1_START_RE.test(t) || // Type 7 cannot interrupt a paragraph, and excludes the raw-text
979
973
  // names (those are type 1 as start tags, paragraph as end tags).
980
974
  t7 !== null && !cp.prevLineWasText && !TYPE1_NAMES.has(t7Name(t).toLowerCase())) {
981
- cp.htmlFlowReal = true;
975
+ if (cp.mdBlock.kind === "none") cp.mdBlock = { kind: "html", type: realT6 ? 6 : 7 };
982
976
  }
983
977
  }
984
978
  }
985
- const inRawText = cp.htmlFlowSinceBlank || rawOpenAtLineStart;
979
+ const inRawText = cp.mayBeRawToMicromark || rawOpenAtLineStart;
986
980
  const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(mdTrimStart(ln.text));
987
981
  const { masked, unpaired } = inRawText ? { masked: null, unpaired: false } : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);
988
982
  if (unpaired) cp.paragraphHasUnpairedRun = true;
989
983
  const scanText = masked ?? ln.text;
990
- const defShaped = inRawText ? null : DEF_RE.exec(scanText);
991
- const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
992
- const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
993
- const validDef = def !== null && defLineStart;
994
- if (validDef) {
995
- const label = def[1];
996
- if (label.startsWith("^")) {
997
- const key = normalizeLabel(label.slice(1));
998
- if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, ln.end);
999
- } else {
1000
- const key = normalizeLabel(label);
1001
- if (key && !cp.defs.has(key)) cp.defs.set(key, ln.end);
1002
- }
1003
- }
1004
- if (cp.referenceTaint) {
1005
- const pushRef = (offset, inner, followAt) => {
1006
- const follow = scanText[followAt];
1007
- if (follow === "(" && inlineResourceEnd(scanText, followAt) !== -1) return;
1008
- let label;
1009
- let footnote = false;
1010
- if (inner.startsWith("^")) {
1011
- footnote = true;
1012
- label = normalizeLabel(inner.slice(1));
1013
- } else if (follow === "[") {
1014
- const explicit = /^\[((?:[^[\]\\]|\\.)*)\]/.exec(scanText.slice(followAt));
1015
- label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);
1016
- } else {
1017
- label = normalizeLabel(inner);
1018
- }
1019
- if (label) cp.unresolvedRefs.push({ offset, label, footnote });
1020
- };
1021
- const pending = cp.openBracket;
1022
- cp.openBracket = null;
1023
- if (pending) {
1024
- const close = firstUnescaped(scanText, "]");
1025
- const open = firstUnescaped(scanText, "[");
1026
- const cont = (t) => t.replace(/^ {0,3}>[ \t]?/, "");
1027
- if (close !== -1 && (open === -1 || close < open)) {
1028
- pushRef(pending.offset, `${pending.text}
1029
- ${cont(scanText.slice(0, close))}`, close + 1);
1030
- } else if (close === -1 && open === -1) {
1031
- cp.openBracket = { offset: pending.offset, text: `${pending.text}
1032
- ${cont(scanText)}` };
1033
- }
1034
- }
1035
- if (scanText.includes("[")) {
1036
- const defBracket = validDef ? def.index + def[0].indexOf("[") : -1;
1037
- REF_RE.lastIndex = 0;
1038
- let m;
1039
- while ((m = REF_RE.exec(scanText)) !== null) {
1040
- const followAt = m.index + m[0].length;
1041
- if (scanText[followAt] === ":" && m.index === defBracket) continue;
1042
- pushRef(ln.start + m.index, m[1], followAt);
1043
- }
1044
- const trailingOpen = lastUnclosedBracket(scanText);
1045
- if (trailingOpen !== -1) {
1046
- cp.openBracket = { offset: ln.start + trailingOpen, text: scanText.slice(trailingOpen + 1) };
1047
- }
1048
- }
1049
- }
984
+ const defRawToMicromark = cp.mdBlock.kind === "html" || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);
985
+ const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, defRawToMicromark, isBlockStart);
1050
986
  const rawSpans = [];
1051
987
  let pos = 0;
1052
988
  const poisonRawDivergence = () => {
@@ -1054,7 +990,7 @@ ${cont(scanText)}` };
1054
990
  };
1055
991
  let inlineRawOpenerIdx = -1;
1056
992
  while (pos < scanText.length) {
1057
- if (cp.piOpen) {
993
+ if (mdHtml(cp.mdBlock, 3)) {
1058
994
  const c = scanText.indexOf("?>", pos);
1059
995
  const gt = scanText.indexOf(">", pos);
1060
996
  if (gt !== -1 && (c === -1 || gt !== c + 1)) poisonRawDivergence();
@@ -1063,11 +999,11 @@ ${cont(scanText)}` };
1063
999
  break;
1064
1000
  }
1065
1001
  rawSpans.push([pos, c + 2]);
1066
- cp.piOpen = false;
1002
+ cp.mdBlock = { kind: "none" };
1067
1003
  pos = c + 2;
1068
1004
  continue;
1069
1005
  }
1070
- if (cp.cdataOpen) {
1006
+ if (mdHtml(cp.mdBlock, 5)) {
1071
1007
  const c = scanText.indexOf("]]>", pos);
1072
1008
  const gt = scanText.indexOf(">", pos);
1073
1009
  if (gt !== -1 && (c === -1 || gt !== c + 2)) poisonRawDivergence();
@@ -1076,38 +1012,51 @@ ${cont(scanText)}` };
1076
1012
  break;
1077
1013
  }
1078
1014
  rawSpans.push([pos, c + 3]);
1079
- cp.cdataOpen = false;
1015
+ cp.mdBlock = { kind: "none" };
1080
1016
  pos = c + 3;
1081
1017
  continue;
1082
1018
  }
1083
- if (cp.declOpen || cp.bogusOpen) {
1019
+ if (mdHtml(cp.mdBlock, 4)) {
1084
1020
  const c = scanText.indexOf(">", pos);
1085
1021
  if (c === -1) {
1086
1022
  rawSpans.push([pos, scanText.length]);
1087
1023
  break;
1088
1024
  }
1089
1025
  rawSpans.push([pos, c + 1]);
1090
- cp.declOpen = false;
1091
- cp.bogusOpen = false;
1026
+ cp.mdBlock = { kind: "none" };
1027
+ if (cp.p5Tok.kind === "bogus") cp.p5Tok = { kind: "data" };
1092
1028
  pos = c + 1;
1093
1029
  continue;
1094
1030
  }
1031
+ if (cp.p5Tok.kind === "bogus") {
1032
+ const c = scanText.indexOf(">", pos);
1033
+ if (c === -1) {
1034
+ rawSpans.push([pos, scanText.length]);
1035
+ break;
1036
+ }
1037
+ rawSpans.push([pos, c + 1]);
1038
+ cp.p5Tok = { kind: "data" };
1039
+ pos = c + 1;
1040
+ continue;
1041
+ }
1042
+ if (commentOpenAtLineStart || inRawTextTok(cp.p5Tok) || mdHtml(cp.mdBlock, 1)) break;
1095
1043
  const pi = scanText.indexOf("<?", pos);
1096
1044
  const cd = scanText.indexOf("<![CDATA[", pos);
1097
1045
  const dm = scanText.slice(pos).search(/<![A-Za-z]/);
1098
1046
  const decl = dm === -1 ? -1 : pos + dm;
1099
- const bm = cp.htmlFlowReal ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\[CDATA\[)|<\/(?![A-Za-z])/) : -1;
1047
+ const bm = cp.mdBlock.kind === "html" ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\[CDATA\[)|<\/(?![A-Za-z])/) : -1;
1100
1048
  const bogus = bm === -1 ? -1 : pos + bm;
1101
1049
  const starts = [pi, cd, decl, bogus].filter((x) => x !== -1);
1102
1050
  if (starts.length === 0) break;
1103
1051
  const first = Math.min(...starts);
1104
1052
  if (first === bogus) {
1105
1053
  rawSpans.push([bogus, bogus + 2]);
1106
- cp.bogusOpen = true;
1054
+ if (cp.p5Tok.kind === "data") cp.p5Tok = { kind: "bogus" };
1055
+ else cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1107
1056
  pos = bogus + 2;
1108
1057
  } else if (first === cd) {
1109
1058
  rawSpans.push([cd, cd + 9]);
1110
- cp.cdataOpen = true;
1059
+ cp.mdBlock = { kind: "html", type: 5 };
1111
1060
  if (!isMdBlank(scanText.slice(0, cd)) || ln.indent > 3) inlineRawOpenerIdx = cd;
1112
1061
  pos = cd + 9;
1113
1062
  } else if (first === pi) {
@@ -1118,18 +1067,18 @@ ${cont(scanText)}` };
1118
1067
  continue;
1119
1068
  }
1120
1069
  rawSpans.push([pi, pi + 2]);
1121
- cp.piOpen = true;
1070
+ cp.mdBlock = { kind: "html", type: 3 };
1122
1071
  if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) inlineRawOpenerIdx = pi;
1123
1072
  pos = pi + 2;
1124
1073
  } else {
1125
1074
  rawSpans.push([decl, decl + 2]);
1126
1075
  if (ln.indent <= 3 && /^doctype/i.test(scanText.slice(decl + 2))) cp.phasePoisonedAt = 0;
1127
- cp.declOpen = true;
1076
+ cp.mdBlock = { kind: "html", type: 4 };
1128
1077
  if (!isMdBlank(scanText.slice(0, decl)) || ln.indent > 3) inlineRawOpenerIdx = decl;
1129
1078
  pos = decl + 2;
1130
1079
  }
1131
1080
  }
1132
- if (inlineRawOpenerIdx !== -1 && (cp.piOpen || cp.declOpen || cp.cdataOpen)) {
1081
+ if (inlineRawOpenerIdx !== -1 && cp.mdBlock.kind === "html" && cp.mdBlock.type >= 3) {
1133
1082
  cp.phasePoisonedAt = 0;
1134
1083
  }
1135
1084
  let tagText = scanText;
@@ -1137,19 +1086,18 @@ ${cont(scanText)}` };
1137
1086
  tagText = tagText.slice(0, from) + " ".repeat(to - from) + tagText.slice(to);
1138
1087
  }
1139
1088
  let skipTagScan = false;
1140
- if (cp.tagAcrossLines) {
1141
- if (ln.indent < cp.tagAcrossLinesIndent) poisonRawDivergence();
1142
- const attrs = { state: cp.tagAcrossLinesState };
1089
+ if (cp.pendingTag !== null) {
1090
+ if (ln.indent < cp.pendingTag.indent) poisonRawDivergence();
1091
+ const attrs = { state: cp.pendingTag.attr };
1143
1092
  const gt = scanTagAttrs(ln.text, 0, ln.text.length, attrs);
1144
1093
  if (gt === -1) {
1145
1094
  scanTagAttrs("\n", 0, 1, attrs);
1146
- cp.tagAcrossLinesState = attrs.state;
1095
+ cp.pendingTag = { attr: attrs.state, indent: cp.pendingTag.indent };
1147
1096
  skipTagScan = true;
1148
1097
  } else {
1149
1098
  for (const tag of cp.pendingTruncatedCloses) applyTag(tag, true);
1150
1099
  cp.pendingTruncatedCloses = [];
1151
- cp.tagAcrossLines = false;
1152
- cp.tagAcrossLinesState = "outside";
1100
+ cp.pendingTag = null;
1153
1101
  tagText = " ".repeat(gt + 1) + tagText.slice(gt + 1);
1154
1102
  }
1155
1103
  }
@@ -1159,38 +1107,49 @@ ${cont(scanText)}` };
1159
1107
  let m;
1160
1108
  let lastCommentOpenerIdx = -1;
1161
1109
  while ((m = TAG_OR_COMMENT_RE.exec(tagText)) !== null) {
1162
- if (cp.rawTextOpen !== null && (m[0] === "<!--" || m[0] === "-->" || m[0] === "--!>")) {
1163
- if (cp.rawTextOpen === "script" && m[0] === "<!--") cp.scriptDataEscaped = true;
1110
+ if (inRawTextTok(cp.p5Tok) && (m[0] === "<!--" || m[0] === "-->" || m[0] === "--!>")) {
1111
+ if (cp.p5Tok.kind === "script") {
1112
+ if (m[0] === "<!--") cp.p5Tok = { ...cp.p5Tok, escaped: true };
1113
+ if (m[0] === "-->") cp.p5Tok = { ...cp.p5Tok, escaped: false };
1114
+ }
1164
1115
  continue;
1165
1116
  }
1166
1117
  if (m[0] === "<!--") {
1167
1118
  const next = tagText.slice(m.index + 4, m.index + 6);
1168
- if (cp.commentOpen) {
1169
- if (next.startsWith(">") || next === "->") cp.commentOpen = false;
1170
- else if (next === "!>" || next === "-!") poisonRawDivergence();
1119
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) {
1120
+ if (next.startsWith(">") || next === "->") {
1121
+ if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: "none" };
1122
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1123
+ } else if (next === "!>" || next === "-!") {
1124
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1125
+ poisonRawDivergence();
1126
+ }
1171
1127
  continue;
1172
1128
  }
1173
1129
  if (next.startsWith(">") || next === "->") {
1174
1130
  continue;
1175
1131
  }
1176
- cp.commentOpen = true;
1132
+ if (cp.mdBlock.kind === "none") cp.mdBlock = { kind: "html", type: 2 };
1133
+ if (cp.p5Tok.kind === "data") cp.p5Tok = { kind: "comment" };
1177
1134
  lastCommentOpenerIdx = m.index;
1178
1135
  continue;
1179
1136
  }
1180
1137
  if (m[0] === "-->") {
1181
- cp.commentOpen = false;
1138
+ if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: "none" };
1139
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1182
1140
  continue;
1183
1141
  }
1184
1142
  if (m[0] === "--!>") {
1185
- if (cp.commentOpen) poisonRawDivergence();
1143
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) poisonRawDivergence();
1144
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1186
1145
  continue;
1187
1146
  }
1188
- if (cp.commentOpen) continue;
1147
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;
1189
1148
  const closing = m[1] === "/";
1190
1149
  const tag = m[2].toLowerCase();
1191
1150
  if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + m.index);
1192
1151
  let attrs = m[3] ?? "";
1193
- if (cp.htmlFlowReal && (cp.rawTextOpen === null || closing && tag === cp.rawTextOpen)) {
1152
+ if (cp.mdBlock.kind === "html" && (!inRawTextTok(cp.p5Tok) || closing && tag === rawTextElement(cp.p5Tok))) {
1194
1153
  const attrStart = m.index + 1 + (closing ? 1 : 0) + m[2].length;
1195
1154
  const st = { state: "outside" };
1196
1155
  const gt = scanTagAttrs(tagText, attrStart, tagText.length, st);
@@ -1200,9 +1159,7 @@ ${cont(scanText)}` };
1200
1159
  else applyTag(tag, false);
1201
1160
  }
1202
1161
  scanTagAttrs("\n", 0, 1, st);
1203
- cp.tagAcrossLines = true;
1204
- cp.tagAcrossLinesIndent = ln.indent;
1205
- cp.tagAcrossLinesState = st.state;
1162
+ cp.pendingTag = { attr: st.state, indent: ln.indent };
1206
1163
  tagHandledAsTruncated = true;
1207
1164
  break;
1208
1165
  }
@@ -1211,16 +1168,15 @@ ${cont(scanText)}` };
1211
1168
  TAG_OR_COMMENT_RE.lastIndex = gt + 1;
1212
1169
  }
1213
1170
  }
1214
- if (closing && !cp.htmlFlowReal && !/^\s*$/.test(attrs)) {
1171
+ if (closing && cp.mdBlock.kind !== "html" && !/^\s*$/.test(attrs)) {
1215
1172
  TAG_OR_COMMENT_RE.lastIndex = m.index + 2 + m[2].length;
1216
1173
  continue;
1217
1174
  }
1218
1175
  const selfClosing = /\/\s*$/.test(attrs);
1219
- noteBreakout(tag, closing);
1220
1176
  if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
1221
1177
  applyTag(tag, closing);
1222
1178
  }
1223
- if (cp.commentOpen && lastCommentOpenerIdx !== -1) {
1179
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok) && lastCommentOpenerIdx !== -1) {
1224
1180
  if (!isMdBlank(tagText.slice(0, lastCommentOpenerIdx)) || ln.indent > 3) {
1225
1181
  cp.phasePoisonedAt = 0;
1226
1182
  }
@@ -1233,13 +1189,12 @@ ${cont(scanText)}` };
1233
1189
  if (mr[0] === "<!--" || mr[0] === "-->" || mr[0] === "--!>") continue;
1234
1190
  const startMasked = masked[mr.index] !== ln.text[mr.index];
1235
1191
  const wholeVisible = masked.slice(mr.index, mr.index + mr[0].length) === mr[0];
1236
- if (startMasked || wholeVisible || inRaw(mr.index) || cp.commentOpen) continue;
1192
+ if (startMasked || wholeVisible || inRaw(mr.index) || commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;
1237
1193
  const closing = mr[1] === "/";
1238
1194
  const tag = mr[2].toLowerCase();
1239
1195
  if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + mr.index);
1240
1196
  if (closing && mr[3] !== void 0 && !/^\s*$/.test(mr[3])) continue;
1241
1197
  const selfClosing = mr[3] !== void 0 && /\/\s*$/.test(mr[3]);
1242
- noteBreakout(tag, closing);
1243
1198
  if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
1244
1199
  applyTag(tag, closing);
1245
1200
  }
@@ -1250,7 +1205,7 @@ ${cont(scanText)}` };
1250
1205
  }
1251
1206
  cp.pendingTruncatedTags = [];
1252
1207
  }
1253
- if (!cp.commentOpen && !tagHandledAsTruncated) {
1208
+ if (!commentEitherOpen(cp.mdBlock, cp.p5Tok) && !tagHandledAsTruncated) {
1254
1209
  let lastLt = -1;
1255
1210
  TAG_START_LT_RE.lastIndex = 0;
1256
1211
  for (let ms = TAG_START_LT_RE.exec(tagText); ms !== null; ms = TAG_START_LT_RE.exec(tagText)) {
@@ -1262,18 +1217,16 @@ ${cont(scanText)}` };
1262
1217
  if (m2) {
1263
1218
  const closing = m2[1] === "/";
1264
1219
  const tag = m2[2].toLowerCase();
1265
- if (strayTablePart(tag) && cp.htmlFlowReal) {
1220
+ if (strayTablePart(tag) && cp.mdBlock.kind === "html") {
1266
1221
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastLt);
1267
1222
  }
1268
- if (cp.htmlFlowReal) {
1269
- cp.tagAcrossLines = true;
1270
- cp.tagAcrossLinesIndent = ln.indent;
1223
+ if (cp.mdBlock.kind === "html") {
1271
1224
  const attrs = { state: "outside" };
1272
1225
  scanTagAttrs(m2[3] + "\n", 0, m2[3].length + 1, attrs);
1273
- cp.tagAcrossLinesState = attrs.state;
1226
+ cp.pendingTag = { attr: attrs.state, indent: ln.indent };
1274
1227
  }
1275
1228
  if (closing) {
1276
- if (!VOID_TAGS.has(tag) && cp.htmlFlowReal) cp.pendingTruncatedCloses.push(tag);
1229
+ if (!VOID_TAGS.has(tag) && cp.mdBlock.kind === "html") cp.pendingTruncatedCloses.push(tag);
1277
1230
  } else if (!VOID_TAGS.has(tag)) {
1278
1231
  applyTag(tag, closing);
1279
1232
  const rawLastLt = ln.text.lastIndexOf("<");
@@ -1294,21 +1247,20 @@ ${cont(scanText)}` };
1294
1247
  }
1295
1248
  masked2 += scanText.slice(cursor);
1296
1249
  if (floatingResidue(masked2, commentOpenAtLineStart).length > 0) {
1297
- cp.htmlSeamPending = true;
1250
+ cp.p5SealPending = true;
1298
1251
  }
1299
1252
  }
1300
- if (cp.rawTextOpen !== null && cp.rawTextInline) {
1253
+ if (inRawTextTok(cp.p5Tok) && cp.p5Tok.openedInline) {
1301
1254
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1302
1255
  }
1303
- if (cp.type1FlowOpen && TYPE1_CLOSE_RE.test(ln.text)) {
1304
- cp.type1FlowOpen = false;
1305
- cp.htmlFlowSinceBlank = false;
1306
- cp.htmlFlowReal = false;
1256
+ if (mdHtml(cp.mdBlock, 1) && TYPE1_CLOSE_RE.test(ln.text)) {
1257
+ cp.mdBlock = { kind: "none" };
1258
+ cp.mayBeRawToMicromark = false;
1307
1259
  }
1308
1260
  cp.blankRun = 0;
1309
1261
  cp.prevLineBlank = false;
1310
1262
  cp.prevLineWasText = true;
1311
- cp.prevLineWasValidDef = validDef && !def[1].startsWith("^");
1263
+ cp.prevLineWasValidDef = validLinkDef;
1312
1264
  }
1313
1265
 
1314
1266
  // src/components/incrementalParse/spliceParse.ts
@@ -2265,12 +2217,10 @@ function phantomSuffixCloser(content) {
2265
2217
  const endsWithNewline = content.endsWith("\n");
2266
2218
  const confirmed = endsWithNewline ? content : content + "\n";
2267
2219
  const { checkpoint } = computeFreezeBoundary(confirmed, { defListEnabled: false, referenceTaint: false });
2268
- if (checkpoint.phasePoisonedAt !== Infinity) return "";
2269
- if (checkpoint.openIndent !== 0) return "";
2270
- const nl = endsWithNewline ? "" : "\n";
2271
- if (checkpoint.inFence) return `${nl}${checkpoint.fenceChar.repeat(checkpoint.fenceLen)}`;
2272
- if (checkpoint.inMath) return `${nl}${"$".repeat(checkpoint.mathFenceLen)}`;
2273
- return "";
2220
+ const closer = pendingFenceCloser(checkpoint);
2221
+ if (closer === "") return "";
2222
+ return endsWithNewline ? closer : `
2223
+ ${closer}`;
2274
2224
  }
2275
2225
 
2276
2226
  // src/components/extractContributions.ts