@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.js CHANGED
@@ -174,7 +174,199 @@ var defaultUrlTransform = (value) => {
174
174
 
175
175
  // src/components/incrementalParse/computeFreezeBoundary.ts
176
176
  import { htmlBlockNames } from "micromark-util-html-tag-name";
177
+
178
+ // src/components/incrementalParse/mdLineText.ts
179
+ var MD_BLANK_RE = /^[ \t\r]*$/;
180
+ var isMdBlank = (text) => MD_BLANK_RE.test(text);
181
+ var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
182
+ var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
183
+
184
+ // src/components/incrementalParse/referenceTaint.ts
177
185
  import { normalizeIdentifier } from "micromark-util-normalize-identifier";
186
+ var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
187
+ var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
188
+ var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
189
+ function firstUnescaped(text, ch) {
190
+ for (let i = 0; i < text.length; i++) {
191
+ if (text[i] === "\\") i += 1;
192
+ else if (text[i] === ch) return i;
193
+ }
194
+ return -1;
195
+ }
196
+ function lastUnclosedBracket(text) {
197
+ let open = -1;
198
+ for (let i = 0; i < text.length; i++) {
199
+ const c = text[i];
200
+ if (c === "\\") i += 1;
201
+ else if (c === "[") open = i;
202
+ else if (c === "]") open = -1;
203
+ }
204
+ return open;
205
+ }
206
+ function normalizeLabel(label) {
207
+ const collapsed = label.replace(/[ \t\r\n]+/g, " ").replace(/^ | $/g, "");
208
+ return collapsed ? normalizeIdentifier(collapsed) : "";
209
+ }
210
+ function isPlausibleLinkDefRest(rest) {
211
+ const t = mdTrim(rest);
212
+ if (t === "") return false;
213
+ const destEnd = linkDestinationEnd(t);
214
+ if (destEnd === -1) return false;
215
+ const after = mdTrim(t.slice(destEnd));
216
+ if (after === "") return true;
217
+ const opener = after[0];
218
+ if (opener !== '"' && opener !== "'" && opener !== "(") return false;
219
+ const closer = opener === "(" ? ")" : opener;
220
+ for (let i = 1; i < after.length; i++) {
221
+ if (after[i] === "\\") {
222
+ i += 1;
223
+ continue;
224
+ }
225
+ if (after[i] === closer) return isMdBlank(after.slice(i + 1));
226
+ }
227
+ return false;
228
+ }
229
+ function linkDestinationEnd(t) {
230
+ if (t.startsWith("<")) {
231
+ for (let i2 = 1; i2 < t.length; i2++) {
232
+ const ch = t[i2];
233
+ if (ch === "\\" && (t[i2 + 1] === "<" || t[i2 + 1] === ">" || t[i2 + 1] === "\\")) {
234
+ i2 += 1;
235
+ continue;
236
+ }
237
+ if (ch === ">") return i2 + 1;
238
+ if (ch === "<") return -1;
239
+ }
240
+ return -1;
241
+ }
242
+ let balance = 0;
243
+ let i = 0;
244
+ for (; i < t.length; i++) {
245
+ const code = t.charCodeAt(i);
246
+ if (code === 32 || code === 9) break;
247
+ if (code < 32 || code === 127) return -1;
248
+ const ch = t[i];
249
+ if (ch === "\\" && (t[i + 1] === "(" || t[i + 1] === ")" || t[i + 1] === "\\")) {
250
+ i += 1;
251
+ continue;
252
+ }
253
+ if (ch === "(") balance += 1;
254
+ else if (ch === ")") {
255
+ if (balance === 0) break;
256
+ balance -= 1;
257
+ }
258
+ }
259
+ if (balance !== 0 || i === 0) return -1;
260
+ return i;
261
+ }
262
+ function inlineResourceEnd(text, openIdx) {
263
+ let i = openIdx + 1;
264
+ const skipWs = () => {
265
+ while (i < text.length && (text[i] === " " || text[i] === " ")) i += 1;
266
+ };
267
+ skipWs();
268
+ if (text[i] === ")") return i + 1;
269
+ const destEnd = linkDestinationEnd(text.slice(i));
270
+ if (destEnd === -1) return -1;
271
+ i += destEnd;
272
+ const beforeWs = i;
273
+ skipWs();
274
+ if (text[i] === ")") return i + 1;
275
+ if (i === beforeWs) return -1;
276
+ const opener = text[i];
277
+ if (opener !== '"' && opener !== "'" && opener !== "(") return -1;
278
+ const closer = opener === "(" ? ")" : opener;
279
+ for (i += 1; i < text.length; i++) {
280
+ if (text[i] === "\\") {
281
+ i += 1;
282
+ continue;
283
+ }
284
+ if (text[i] === closer) {
285
+ i += 1;
286
+ skipWs();
287
+ return text[i] === ")" ? i + 1 : -1;
288
+ }
289
+ }
290
+ return -1;
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;
295
+ const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
296
+ const validDef = def !== null && defLineStart;
297
+ if (validDef) {
298
+ const label = def[1];
299
+ if (label.startsWith("^")) {
300
+ const key = normalizeLabel(label.slice(1));
301
+ if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, lnEnd);
302
+ } else {
303
+ const key = normalizeLabel(label);
304
+ if (key && !cp.defs.has(key)) cp.defs.set(key, lnEnd);
305
+ }
306
+ }
307
+ if (cp.referenceTaint) {
308
+ const pushRef = (offset, inner, followAt) => {
309
+ const follow = scanText[followAt];
310
+ if (follow === "(" && inlineResourceEnd(scanText, followAt) !== -1) return;
311
+ let label;
312
+ let footnote = false;
313
+ if (inner.startsWith("^")) {
314
+ footnote = true;
315
+ label = normalizeLabel(inner.slice(1));
316
+ } else if (follow === "[") {
317
+ const explicit = /^\[((?:[^[\]\\]|\\.)*)\]/.exec(scanText.slice(followAt));
318
+ label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);
319
+ } else {
320
+ label = normalizeLabel(inner);
321
+ }
322
+ if (label) cp.unresolvedRefs.push({ offset, label, footnote });
323
+ };
324
+ const pending = cp.openBracket;
325
+ cp.openBracket = null;
326
+ if (pending) {
327
+ const close = firstUnescaped(scanText, "]");
328
+ const open = firstUnescaped(scanText, "[");
329
+ const cont = (t) => t.replace(/^ {0,3}>[ \t]?/, "");
330
+ if (close !== -1 && (open === -1 || close < open)) {
331
+ pushRef(pending.offset, `${pending.text}
332
+ ${cont(scanText.slice(0, close))}`, close + 1);
333
+ } else if (close === -1 && open === -1) {
334
+ cp.openBracket = { offset: pending.offset, text: `${pending.text}
335
+ ${cont(scanText)}` };
336
+ }
337
+ }
338
+ if (scanText.includes("[")) {
339
+ const defBracket = validDef ? def.index + def[0].indexOf("[") : -1;
340
+ REF_RE.lastIndex = 0;
341
+ let m;
342
+ while ((m = REF_RE.exec(scanText)) !== null) {
343
+ const followAt = m.index + m[0].length;
344
+ if (scanText[followAt] === ":" && m.index === defBracket) continue;
345
+ pushRef(lnStart + m.index, m[1], followAt);
346
+ }
347
+ const trailingOpen = lastUnclosedBracket(scanText);
348
+ if (trailingOpen !== -1) {
349
+ cp.openBracket = { offset: lnStart + trailingOpen, text: scanText.slice(trailingOpen + 1) };
350
+ }
351
+ }
352
+ }
353
+ return { validDef, validLinkDef: validDef && !def[1].startsWith("^") };
354
+ }
355
+ function settleRefsAndEarliestUnresolved(cp) {
356
+ if (cp.unresolvedRefs.length > 0) {
357
+ const settled = (defEnd) => cp.lastBlankStart >= defEnd;
358
+ cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {
359
+ const table = ref.footnote ? cp.footnoteDefs : cp.defs;
360
+ const defEnd = table.get(ref.label);
361
+ return defEnd === void 0 || !settled(defEnd);
362
+ });
363
+ }
364
+ let earliestUnresolved = Infinity;
365
+ for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);
366
+ return earliestUnresolved;
367
+ }
368
+
369
+ // src/components/incrementalParse/computeFreezeBoundary.ts
178
370
  var TYPE6_NAMES = new Set(htmlBlockNames);
179
371
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
180
372
  var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
@@ -197,53 +389,6 @@ function tailCarriesRetroactive(text) {
197
389
  }
198
390
  return false;
199
391
  }
200
- var HTML_BREAKOUT_TAGS = /* @__PURE__ */ new Set([
201
- "b",
202
- "big",
203
- "blockquote",
204
- "body",
205
- "br",
206
- "center",
207
- "code",
208
- "dd",
209
- "div",
210
- "dl",
211
- "dt",
212
- "em",
213
- "embed",
214
- "h1",
215
- "h2",
216
- "h3",
217
- "h4",
218
- "h5",
219
- "h6",
220
- "head",
221
- "hr",
222
- "i",
223
- "img",
224
- "li",
225
- "listing",
226
- "menu",
227
- "meta",
228
- "nobr",
229
- "ol",
230
- "p",
231
- "pre",
232
- "ruby",
233
- "s",
234
- "small",
235
- "span",
236
- "strong",
237
- "strike",
238
- "sub",
239
- "sup",
240
- "table",
241
- "tt",
242
- "u",
243
- "ul",
244
- "var"
245
- ]);
246
- var HTML_INTEGRATION_POINTS = ["foreignobject", "desc", "title", "mi", "mo", "mn", "ms", "mtext", "annotation-xml"];
247
392
  var SCOPE_BARRIER_NAMES = /* @__PURE__ */ new Set([
248
393
  "applet",
249
394
  "caption",
@@ -286,6 +431,11 @@ var TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \t\r]|>|$)/i;
286
431
  var TYPE1_CLOSE_RE = /<\/(?:script|pre|style|textarea)>/i;
287
432
  var TYPE7_LINE_RE = /^(?:<[A-Za-z][A-Za-z0-9-]*(?:[ \t\r][^>]*|\/)?>|<\/[A-Za-z][A-Za-z0-9-]*[ \t\r]*>)[ \t\r]*$/;
288
433
  var t7Name = (line) => /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(line)[1];
434
+ var mdHtml = (b, type) => b.kind === "html" && b.type === type;
435
+ var mdHtml25 = (b) => b.kind === "html" && b.type >= 2 && b.type <= 5;
436
+ var commentEitherOpen = (md, p5) => mdHtml(md, 2) || p5.kind === "comment";
437
+ var inRawTextTok = (t) => t.kind === "rawText" || t.kind === "script";
438
+ var rawTextElement = (t) => t.kind === "rawText" ? t.element : t.kind === "script" ? "script" : null;
289
439
  var VOID_TAGS = /* @__PURE__ */ new Set([
290
440
  "area",
291
441
  "base",
@@ -303,9 +453,7 @@ var VOID_TAGS = /* @__PURE__ */ new Set([
303
453
  "wbr"
304
454
  ]);
305
455
  var LIST_MARKER_RE = /^ {0,3}(?:[-*+]|\d{1,9}[.)])(?:[ \t]|$)/;
306
- var FOOTNOTE_DEF_RE = /^ {0,3}\[\^[^\]]*\]:/;
307
456
  var DEF_LIST_DD_RE = /^ {0,3}:[ \t]/;
308
- var DEF_RE = /^ {0,3}\[((?:[^[\]\\]|\\.)+)\]:/;
309
457
  var FENCE_RE = /^ {0,3}(`{3,}|~{3,})/;
310
458
  var MATH_RUN_RE = /^ {0,3}(\$\$+)/;
311
459
  var TAG_OR_COMMENT_RE = /<(\/?)([A-Za-z][A-Za-z0-9-]*)(?=[\s/>])([^>]*)>|<!--|-->|--!>/g;
@@ -338,12 +486,7 @@ function scanTagAttrs(text, from, to, out) {
338
486
  out.state = st;
339
487
  return -1;
340
488
  }
341
- var REF_RE = /!?\[((?:[^[\]\\]|\\.)*)\]/g;
342
489
  var BACKTICK_RUN_RE = /`+/g;
343
- var MD_BLANK_RE = /^[ \t\r]*$/;
344
- var isMdBlank = (text) => MD_BLANK_RE.test(text);
345
- var mdTrim = (text) => text.replace(/^[ \t\r]+|[ \t\r]+$/g, "");
346
- var mdTrimStart = (text) => text.replace(/^[ \t\r]+/, "");
347
490
  function computeIndent(text) {
348
491
  let indent = 0;
349
492
  for (const ch of text) {
@@ -353,27 +496,6 @@ function computeIndent(text) {
353
496
  }
354
497
  return indent;
355
498
  }
356
- function firstUnescaped(text, ch) {
357
- for (let i = 0; i < text.length; i++) {
358
- if (text[i] === "\\") i += 1;
359
- else if (text[i] === ch) return i;
360
- }
361
- return -1;
362
- }
363
- function lastUnclosedBracket(text) {
364
- let open = -1;
365
- for (let i = 0; i < text.length; i++) {
366
- const c = text[i];
367
- if (c === "\\") i += 1;
368
- else if (c === "[") open = i;
369
- else if (c === "]") open = -1;
370
- }
371
- return open;
372
- }
373
- function normalizeLabel(label) {
374
- const collapsed = label.replace(/[ \t\r\n]+/g, " ").replace(/^ | $/g, "");
375
- return collapsed ? normalizeIdentifier(collapsed) : "";
376
- }
377
499
  function canBecomeDdLine(text, confirmed) {
378
500
  let i = 0;
379
501
  while (i < text.length && text[i] === " ") i += 1;
@@ -430,20 +552,9 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
430
552
  unresolvedRefs: [],
431
553
  tagBalance: /* @__PURE__ */ new Map(),
432
554
  openTotal: 0,
433
- commentOpen: false,
434
- piOpen: false,
435
- bogusOpen: false,
436
- rawTextOpen: null,
555
+ p5Tok: { kind: "data" },
437
556
  openStack: [],
438
- scriptDataEscaped: false,
439
- declOpen: false,
440
- cdataOpen: false,
441
- inFence: false,
442
- fenceChar: "",
443
- fenceLen: 0,
444
- inMath: false,
445
- mathFenceLen: 0,
446
- openIndent: 0,
557
+ mdBlock: { kind: "none" },
447
558
  blankRun: 0,
448
559
  lastBlankStart: -1,
449
560
  hazardVerdict: false,
@@ -453,101 +564,14 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
453
564
  prevLineWasValidDef: false,
454
565
  paragraphHasUnpairedRun: false,
455
566
  openBracket: null,
456
- htmlFlowSinceBlank: false,
457
- htmlSeamPending: false,
567
+ mayBeRawToMicromark: false,
568
+ p5SealPending: false,
458
569
  phasePoisonedAt: Infinity,
459
570
  pendingTruncatedTags: [],
460
571
  pendingTruncatedCloses: [],
461
- tagAcrossLines: false,
462
- tagAcrossLinesIndent: 0,
463
- tagAcrossLinesState: "outside",
464
- htmlFlowReal: false,
465
- type1FlowOpen: false,
466
- rawTextInline: false
572
+ pendingTag: null
467
573
  };
468
574
  }
469
- function isPlausibleLinkDefRest(rest) {
470
- const t = mdTrim(rest);
471
- if (t === "") return false;
472
- const destEnd = linkDestinationEnd(t);
473
- if (destEnd === -1) return false;
474
- const after = mdTrim(t.slice(destEnd));
475
- if (after === "") return true;
476
- const opener = after[0];
477
- if (opener !== '"' && opener !== "'" && opener !== "(") return false;
478
- const closer = opener === "(" ? ")" : opener;
479
- for (let i = 1; i < after.length; i++) {
480
- if (after[i] === "\\") {
481
- i += 1;
482
- continue;
483
- }
484
- if (after[i] === closer) return isMdBlank(after.slice(i + 1));
485
- }
486
- return false;
487
- }
488
- function linkDestinationEnd(t) {
489
- if (t.startsWith("<")) {
490
- for (let i2 = 1; i2 < t.length; i2++) {
491
- const ch = t[i2];
492
- if (ch === "\\" && (t[i2 + 1] === "<" || t[i2 + 1] === ">" || t[i2 + 1] === "\\")) {
493
- i2 += 1;
494
- continue;
495
- }
496
- if (ch === ">") return i2 + 1;
497
- if (ch === "<") return -1;
498
- }
499
- return -1;
500
- }
501
- let balance = 0;
502
- let i = 0;
503
- for (; i < t.length; i++) {
504
- const code = t.charCodeAt(i);
505
- if (code === 32 || code === 9) break;
506
- if (code < 32 || code === 127) return -1;
507
- const ch = t[i];
508
- if (ch === "\\" && (t[i + 1] === "(" || t[i + 1] === ")" || t[i + 1] === "\\")) {
509
- i += 1;
510
- continue;
511
- }
512
- if (ch === "(") balance += 1;
513
- else if (ch === ")") {
514
- if (balance === 0) break;
515
- balance -= 1;
516
- }
517
- }
518
- if (balance !== 0 || i === 0) return -1;
519
- return i;
520
- }
521
- function inlineResourceEnd(text, openIdx) {
522
- let i = openIdx + 1;
523
- const skipWs = () => {
524
- while (i < text.length && (text[i] === " " || text[i] === " ")) i += 1;
525
- };
526
- skipWs();
527
- if (text[i] === ")") return i + 1;
528
- const destEnd = linkDestinationEnd(text.slice(i));
529
- if (destEnd === -1) return -1;
530
- i += destEnd;
531
- const beforeWs = i;
532
- skipWs();
533
- if (text[i] === ")") return i + 1;
534
- if (i === beforeWs) return -1;
535
- const opener = text[i];
536
- if (opener !== '"' && opener !== "'" && opener !== "(") return -1;
537
- const closer = opener === "(" ? ")" : opener;
538
- for (i += 1; i < text.length; i++) {
539
- if (text[i] === "\\") {
540
- i += 1;
541
- continue;
542
- }
543
- if (text[i] === closer) {
544
- i += 1;
545
- skipWs();
546
- return text[i] === ")" ? i + 1 : -1;
547
- }
548
- }
549
- return -1;
550
- }
551
575
  function classifyBlockStart(text, indent, defListEnabled) {
552
576
  if (indent >= 4) return true;
553
577
  if (LIST_MARKER_RE.test(text) || FOOTNOTE_DEF_RE.test(text)) return true;
@@ -558,7 +582,8 @@ function classifyBlockStart(text, indent, defListEnabled) {
558
582
  function computeFreezeBoundary(text, options, resume) {
559
583
  const mathFlow = options.mathFlow ?? true;
560
584
  const referenceTaint = options.referenceTaint ?? true;
561
- const cp = resume && resume.defListEnabled === options.defListEnabled && resume.mathFlow === mathFlow && resume.referenceTaint === referenceTaint && resume.confirmedOffset <= text.length ? resume : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
585
+ const prev = resume;
586
+ const cp = prev && prev.defListEnabled === options.defListEnabled && prev.mathFlow === mathFlow && prev.referenceTaint === referenceTaint && prev.confirmedOffset <= text.length ? prev : freshCheckpoint(options.defListEnabled, mathFlow, referenceTaint);
562
587
  let start = cp.confirmedOffset;
563
588
  let tailLine = null;
564
589
  while (start < text.length) {
@@ -592,16 +617,7 @@ function computeFreezeBoundary(text, options, resume) {
592
617
  cp.confirmedOffset = end + 1;
593
618
  start = end + 1;
594
619
  }
595
- if (cp.unresolvedRefs.length > 0) {
596
- const settled = (defEnd) => cp.lastBlankStart >= defEnd;
597
- cp.unresolvedRefs = cp.unresolvedRefs.filter((ref) => {
598
- const table = ref.footnote ? cp.footnoteDefs : cp.defs;
599
- const defEnd = table.get(ref.label);
600
- return defEnd === void 0 || !settled(defEnd);
601
- });
602
- }
603
- let earliestUnresolved = Infinity;
604
- for (const ref of cp.unresolvedRefs) earliestUnresolved = Math.min(earliestUnresolved, ref.offset);
620
+ const earliestUnresolved = settleRefsAndEarliestUnresolved(cp);
605
621
  const defListSettled = (c) => {
606
622
  if (!options.defListEnabled || c.blankRun >= 2) return true;
607
623
  if (c.defListSettled !== null) return c.defListSettled;
@@ -621,6 +637,13 @@ function computeFreezeBoundary(text, options, resume) {
621
637
  }
622
638
  return { boundary, checkpoint: cp };
623
639
  }
640
+ function pendingFenceCloser(checkpoint) {
641
+ const cp = checkpoint;
642
+ if (cp.phasePoisonedAt !== Infinity) return "";
643
+ if (cp.mdBlock.kind === "fence" && cp.mdBlock.indent === 0) return cp.mdBlock.char.repeat(cp.mdBlock.len);
644
+ if (cp.mdBlock.kind === "math" && cp.mdBlock.indent === 0) return "$".repeat(cp.mdBlock.len);
645
+ return "";
646
+ }
624
647
  function floatingResidue(text, commentOpenAtStart) {
625
648
  let out = "";
626
649
  let open = commentOpenAtStart;
@@ -669,53 +692,30 @@ function processConfirmedLine(cp, ln, text) {
669
692
  newest.defListSettled = ln.blank ? true : !canBecomeDdLine(ln.text, true);
670
693
  }
671
694
  const isBlockStart = cp.prevLineBlank;
672
- if (cp.htmlSeamPending && !ln.blank && !cp.htmlFlowSinceBlank && !(cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen)) {
695
+ if (cp.p5SealPending && !ln.blank && !cp.mayBeRawToMicromark && !(mdHtml25(cp.mdBlock) || cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus")) {
673
696
  const defShapedLine = DEF_RE.test(ln.text) || FOOTNOTE_DEF_RE.test(ln.text);
674
697
  const commentOnly = ln.text.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!--[\s\S]*$/, " ").replace(/[ \t\r]/g, "") === "";
675
698
  if (!defShapedLine && !commentOnly) {
676
- cp.htmlSeamPending = false;
699
+ cp.p5SealPending = false;
677
700
  }
678
701
  }
679
- const inForeignContent = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
680
- const honoursSelfClosing = (tag) => {
681
- if (tag === "svg" || tag === "math") return true;
682
- if (!inForeignContent() || HTML_BREAKOUT_TAGS.has(tag)) return false;
683
- for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return false;
684
- return true;
685
- };
686
- const htmlRulesApply = () => {
687
- if (!inForeignContent()) return true;
688
- for (const ip of HTML_INTEGRATION_POINTS) if ((cp.tagBalance.get(ip) ?? 0) > 0) return true;
689
- return false;
690
- };
691
- const popForeignRoots = () => {
692
- for (const name of FOREIGN_ROOT_NAMES) {
693
- const count = cp.tagBalance.get(name) ?? 0;
694
- if (count > 0) {
695
- cp.tagBalance.set(name, 0);
696
- cp.openTotal -= count;
697
- }
698
- }
699
- if (cp.openStack.length > 0) cp.openStack = cp.openStack.filter((n) => !FOREIGN_ROOT_NAMES.includes(n));
700
- };
701
- const noteBreakout = (tag, closing) => {
702
- if (closing || cp.rawTextOpen !== null) return;
703
- if (HTML_BREAKOUT_TAGS.has(tag) && !htmlRulesApply()) popForeignRoots();
704
- };
702
+ const possiblyInsideForeign = () => FOREIGN_ROOT_NAMES.some((name) => (cp.tagBalance.get(name) ?? 0) > 0);
703
+ const honoursSelfClosing = (tag) => tag === "svg" || tag === "math";
704
+ const foreignRawTextSwitchUnknowable = () => possiblyInsideForeign();
705
705
  const applyTag = (tag, closing) => {
706
- if (cp.rawTextOpen !== null) {
707
- if (cp.scriptDataEscaped && !closing && tag === "script") {
706
+ if (inRawTextTok(cp.p5Tok)) {
707
+ if (cp.p5Tok.kind === "script" && cp.p5Tok.escaped && !closing && tag === "script") {
708
708
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
709
709
  }
710
- if (!(closing && tag === cp.rawTextOpen)) return;
711
- cp.rawTextOpen = null;
712
- cp.scriptDataEscaped = false;
710
+ if (!(closing && tag === rawTextElement(cp.p5Tok))) return;
711
+ cp.p5Tok = { kind: "data" };
713
712
  } else {
714
- noteBreakout(tag, closing);
715
- if (!closing && RAW_TEXT_ELEMENTS.has(tag) && htmlRulesApply()) {
716
- cp.rawTextOpen = tag;
717
- cp.scriptDataEscaped = false;
718
- cp.rawTextInline = !cp.htmlFlowReal;
713
+ if (!closing && RAW_TEXT_ELEMENTS.has(tag) && foreignRawTextSwitchUnknowable()) {
714
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
715
+ } else if (!closing && RAW_TEXT_ELEMENTS.has(tag)) {
716
+ if (cp.p5Tok.kind !== "data") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
717
+ const openedInline = cp.mdBlock.kind !== "html";
718
+ cp.p5Tok = tag === "script" ? { kind: "script", escaped: false, openedInline } : { kind: "rawText", element: tag, openedInline };
719
719
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
720
720
  }
721
721
  }
@@ -743,15 +743,14 @@ function processConfirmedLine(cp, ln, text) {
743
743
  cp.openTotal += 1;
744
744
  }
745
745
  };
746
- const strayTablePart = (tag) => TABLE_PART_NAMES.has(tag) && (cp.tagBalance.get("table") ?? 0) === 0;
747
- const commentOpenAtLineStart = cp.commentOpen;
748
- const rawOpenAtLineStart = cp.commentOpen || cp.piOpen || cp.declOpen || cp.cdataOpen || cp.bogusOpen;
749
- if (cp.inFence) {
746
+ const definitelyInsideTable = () => (cp.tagBalance.get("table") ?? 0) > 0;
747
+ const strayTablePart = (tag) => TABLE_PART_NAMES.has(tag) && !definitelyInsideTable();
748
+ const commentOpenAtLineStart = commentEitherOpen(cp.mdBlock, cp.p5Tok);
749
+ const rawOpenAtLineStart = mdHtml25(cp.mdBlock) || cp.p5Tok.kind === "comment" || cp.p5Tok.kind === "bogus";
750
+ if (cp.mdBlock.kind === "fence") {
750
751
  const close = FENCE_RE.exec(ln.text);
751
- if (close && close[1][0] === cp.fenceChar && close[1].length >= cp.fenceLen && isMdBlank(ln.text.slice(close[0].length))) {
752
- cp.inFence = false;
753
- cp.fenceChar = "";
754
- cp.fenceLen = 0;
752
+ if (close && close[1][0] === cp.mdBlock.char && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {
753
+ cp.mdBlock = { kind: "none" };
755
754
  }
756
755
  cp.blankRun = 0;
757
756
  cp.paragraphHasUnpairedRun = false;
@@ -761,20 +760,17 @@ function processConfirmedLine(cp, ln, text) {
761
760
  cp.prevLineWasValidDef = false;
762
761
  return;
763
762
  }
764
- if (!cp.inMath && !rawOpenAtLineStart) {
763
+ if (cp.mdBlock.kind !== "math" && !rawOpenAtLineStart) {
765
764
  const open = FENCE_RE.exec(ln.text);
766
765
  const bogusInfo = open !== null && open[1][0] === "`" && ln.text.slice(ln.text.indexOf(open[1]) + open[1].length).includes("`");
767
- if (open && !bogusInfo && cp.htmlFlowSinceBlank) {
766
+ if (open && !bogusInfo && cp.mayBeRawToMicromark) {
768
767
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
769
768
  } else if (open && !bogusInfo) {
770
769
  if (isBlockStart) {
771
770
  const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);
772
771
  if (verdict !== null) cp.hazardVerdict = verdict;
773
772
  }
774
- cp.inFence = true;
775
- cp.fenceChar = open[1][0];
776
- cp.fenceLen = open[1].length;
777
- cp.openIndent = ln.indent;
773
+ cp.mdBlock = { kind: "fence", char: open[1][0], len: open[1].length, indent: ln.indent };
778
774
  cp.blankRun = 0;
779
775
  cp.paragraphHasUnpairedRun = false;
780
776
  cp.openBracket = null;
@@ -784,11 +780,10 @@ function processConfirmedLine(cp, ln, text) {
784
780
  return;
785
781
  }
786
782
  }
787
- if (cp.inMath) {
783
+ if (cp.mdBlock.kind === "math") {
788
784
  const close = MATH_RUN_RE.exec(ln.text);
789
- if (close && close[1].length >= cp.mathFenceLen && isMdBlank(ln.text.slice(close[0].length))) {
790
- cp.inMath = false;
791
- cp.mathFenceLen = 0;
785
+ if (close && close[1].length >= cp.mdBlock.len && isMdBlank(ln.text.slice(close[0].length))) {
786
+ cp.mdBlock = { kind: "none" };
792
787
  }
793
788
  cp.blankRun = 0;
794
789
  cp.paragraphHasUnpairedRun = false;
@@ -802,16 +797,14 @@ function processConfirmedLine(cp, ln, text) {
802
797
  if (mathRun) {
803
798
  const rest = ln.text.slice(ln.text.indexOf(mathRun[1]) + mathRun[1].length);
804
799
  if (!rest.includes("$")) {
805
- if (cp.htmlFlowSinceBlank) {
800
+ if (cp.mayBeRawToMicromark) {
806
801
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
807
802
  } else {
808
803
  if (isBlockStart) {
809
804
  const verdict = classifyBlockStart(ln.text, ln.indent, cp.defListEnabled);
810
805
  if (verdict !== null) cp.hazardVerdict = verdict;
811
806
  }
812
- cp.inMath = true;
813
- cp.mathFenceLen = mathRun[1].length;
814
- cp.openIndent = ln.indent;
807
+ cp.mdBlock = { kind: "math", len: mathRun[1].length, indent: ln.indent };
815
808
  cp.blankRun = 0;
816
809
  cp.paragraphHasUnpairedRun = false;
817
810
  cp.openBracket = null;
@@ -828,36 +821,36 @@ function processConfirmedLine(cp, ln, text) {
828
821
  cp.pendingTruncatedTags = [];
829
822
  }
830
823
  cp.pendingTruncatedCloses = [];
831
- if (cp.tagAcrossLines && (cp.tagAcrossLinesState === '"' || cp.tagAcrossLinesState === "'")) {
824
+ if (cp.pendingTag !== null && (cp.pendingTag.attr === '"' || cp.pendingTag.attr === "'")) {
832
825
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
833
826
  }
834
- cp.tagAcrossLines = false;
835
- cp.tagAcrossLinesState = "outside";
836
- if (cp.bogusOpen) {
827
+ cp.pendingTag = null;
828
+ if (cp.p5Tok.kind === "bogus") {
837
829
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
838
- cp.bogusOpen = false;
830
+ cp.p5Tok = { kind: "data" };
839
831
  }
832
+ if (cp.mdBlock.kind === "html" && cp.mdBlock.type >= 6) cp.mdBlock = { kind: "none" };
840
833
  cp.blankRun += 1;
841
834
  cp.lastBlankStart = ln.start;
842
835
  cp.candidates.push({
843
836
  offset: Math.min(ln.end + 1, text.length),
844
837
  blankRun: cp.blankRun,
845
- // `type1FlowOpen`: an unterminated type-1 block swallows this blank
846
- // and everything after it as RAW content, so nothing here is a block
847
- // boundary at all. Its tags are invisible to the balance scan
848
- // (`rawTextOpen` suppresses them), which is exactly why `openTotal`
849
- // reads 0 and the candidate looked safe.
850
- htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen && !cp.bogusOpen && !cp.type1FlowOpen,
838
+ // The html member covers types 1-5 in one check: an unterminated
839
+ // type-1 block swallows this blank and everything after it as RAW
840
+ // content (its tags are invisible to the balance scan — the raw-text
841
+ // mask suppresses them which is exactly why `openTotal` reads 0
842
+ // and the candidate looked safe), and the 2-5 interiors are the
843
+ // same construct to both grammars.
844
+ htmlBalanced: cp.openTotal === 0 && cp.mdBlock.kind !== "html" && cp.p5Tok.kind !== "bogus",
851
845
  hazard: cp.hazardVerdict,
852
- seamRisk: cp.htmlSeamPending,
846
+ seamRisk: cp.p5SealPending,
853
847
  defListSettled: null
854
848
  });
855
849
  cp.paragraphHasUnpairedRun = false;
856
850
  cp.openBracket = null;
857
- if (!cp.type1FlowOpen) {
858
- cp.htmlFlowSinceBlank = false;
859
- cp.htmlFlowReal = false;
860
- if (cp.rawTextOpen !== null && !cp.rawTextInline) {
851
+ if (!mdHtml(cp.mdBlock, 1)) {
852
+ cp.mayBeRawToMicromark = false;
853
+ if (inRawTextTok(cp.p5Tok) && !cp.p5Tok.openedInline) {
861
854
  cp.phasePoisonedAt = 0;
862
855
  }
863
856
  }
@@ -874,86 +867,29 @@ function processConfirmedLine(cp, ln, text) {
874
867
  }
875
868
  const tagStart = ln.indent <= 3 ? /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(mdTrimStart(ln.text)) : null;
876
869
  if (tagStart) {
877
- const noRealBlockOpen = !cp.htmlFlowReal;
878
- cp.htmlFlowSinceBlank = true;
879
- if (noRealBlockOpen && TYPE1_START_RE.test(mdTrimStart(ln.text))) cp.type1FlowOpen = true;
870
+ const noRealBlockOpen = cp.mdBlock.kind !== "html";
871
+ cp.mayBeRawToMicromark = true;
872
+ if (noRealBlockOpen && TYPE1_START_RE.test(mdTrimStart(ln.text))) cp.mdBlock = { kind: "html", type: 1 };
880
873
  if (!TYPE6_NAMES.has(tagStart[1].toLowerCase())) cp.hazardVerdict = true;
881
- if (!cp.htmlFlowReal) {
874
+ if (cp.mdBlock.kind !== "html") {
882
875
  const t = mdTrimStart(ln.text);
883
876
  const t6 = TYPE6_START_RE.exec(t);
884
877
  const t7 = TYPE7_LINE_RE.exec(t);
885
- 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
878
+ const realT6 = t6 !== null && TYPE6_NAMES.has(t6[1].toLowerCase());
879
+ if (realT6 || TYPE1_START_RE.test(t) || // Type 7 cannot interrupt a paragraph, and excludes the raw-text
886
880
  // names (those are type 1 as start tags, paragraph as end tags).
887
881
  t7 !== null && !cp.prevLineWasText && !TYPE1_NAMES.has(t7Name(t).toLowerCase())) {
888
- cp.htmlFlowReal = true;
882
+ if (cp.mdBlock.kind === "none") cp.mdBlock = { kind: "html", type: realT6 ? 6 : 7 };
889
883
  }
890
884
  }
891
885
  }
892
- const inRawText = cp.htmlFlowSinceBlank || rawOpenAtLineStart;
886
+ const inRawText = cp.mayBeRawToMicromark || rawOpenAtLineStart;
893
887
  const rawFlowStart = ln.indent <= 3 && /^<(?:!--|\?|![A-Za-z]|!\[CDATA\[)/.test(mdTrimStart(ln.text));
894
888
  const { masked, unpaired } = inRawText ? { masked: null, unpaired: false } : maskIntraLineCodeSpans(ln.text, cp.paragraphHasUnpairedRun);
895
889
  if (unpaired) cp.paragraphHasUnpairedRun = true;
896
890
  const scanText = masked ?? ln.text;
897
- const defShaped = inRawText ? null : DEF_RE.exec(scanText);
898
- const def = defShaped !== null && (defShaped[1].startsWith("^") || isPlausibleLinkDefRest(scanText.slice(defShaped.index + defShaped[0].length))) ? defShaped : null;
899
- const defLineStart = isBlockStart || !cp.prevLineWasText || cp.prevLineWasValidDef;
900
- const validDef = def !== null && defLineStart;
901
- if (validDef) {
902
- const label = def[1];
903
- if (label.startsWith("^")) {
904
- const key = normalizeLabel(label.slice(1));
905
- if (key && !cp.footnoteDefs.has(key)) cp.footnoteDefs.set(key, ln.end);
906
- } else {
907
- const key = normalizeLabel(label);
908
- if (key && !cp.defs.has(key)) cp.defs.set(key, ln.end);
909
- }
910
- }
911
- if (cp.referenceTaint) {
912
- const pushRef = (offset, inner, followAt) => {
913
- const follow = scanText[followAt];
914
- if (follow === "(" && inlineResourceEnd(scanText, followAt) !== -1) return;
915
- let label;
916
- let footnote = false;
917
- if (inner.startsWith("^")) {
918
- footnote = true;
919
- label = normalizeLabel(inner.slice(1));
920
- } else if (follow === "[") {
921
- const explicit = /^\[((?:[^[\]\\]|\\.)*)\]/.exec(scanText.slice(followAt));
922
- label = normalizeLabel(explicit && explicit[1] ? explicit[1] : inner);
923
- } else {
924
- label = normalizeLabel(inner);
925
- }
926
- if (label) cp.unresolvedRefs.push({ offset, label, footnote });
927
- };
928
- const pending = cp.openBracket;
929
- cp.openBracket = null;
930
- if (pending) {
931
- const close = firstUnescaped(scanText, "]");
932
- const open = firstUnescaped(scanText, "[");
933
- const cont = (t) => t.replace(/^ {0,3}>[ \t]?/, "");
934
- if (close !== -1 && (open === -1 || close < open)) {
935
- pushRef(pending.offset, `${pending.text}
936
- ${cont(scanText.slice(0, close))}`, close + 1);
937
- } else if (close === -1 && open === -1) {
938
- cp.openBracket = { offset: pending.offset, text: `${pending.text}
939
- ${cont(scanText)}` };
940
- }
941
- }
942
- if (scanText.includes("[")) {
943
- const defBracket = validDef ? def.index + def[0].indexOf("[") : -1;
944
- REF_RE.lastIndex = 0;
945
- let m;
946
- while ((m = REF_RE.exec(scanText)) !== null) {
947
- const followAt = m.index + m[0].length;
948
- if (scanText[followAt] === ":" && m.index === defBracket) continue;
949
- pushRef(ln.start + m.index, m[1], followAt);
950
- }
951
- const trailingOpen = lastUnclosedBracket(scanText);
952
- if (trailingOpen !== -1) {
953
- cp.openBracket = { offset: ln.start + trailingOpen, text: scanText.slice(trailingOpen + 1) };
954
- }
955
- }
956
- }
891
+ const defRawToMicromark = cp.mdBlock.kind === "html" || rawOpenAtLineStart || inRawTextTok(cp.p5Tok);
892
+ const { validLinkDef } = collectRefLine(cp, ln.start, ln.end, scanText, defRawToMicromark, isBlockStart);
957
893
  const rawSpans = [];
958
894
  let pos = 0;
959
895
  const poisonRawDivergence = () => {
@@ -961,7 +897,7 @@ ${cont(scanText)}` };
961
897
  };
962
898
  let inlineRawOpenerIdx = -1;
963
899
  while (pos < scanText.length) {
964
- if (cp.piOpen) {
900
+ if (mdHtml(cp.mdBlock, 3)) {
965
901
  const c = scanText.indexOf("?>", pos);
966
902
  const gt = scanText.indexOf(">", pos);
967
903
  if (gt !== -1 && (c === -1 || gt !== c + 1)) poisonRawDivergence();
@@ -970,11 +906,11 @@ ${cont(scanText)}` };
970
906
  break;
971
907
  }
972
908
  rawSpans.push([pos, c + 2]);
973
- cp.piOpen = false;
909
+ cp.mdBlock = { kind: "none" };
974
910
  pos = c + 2;
975
911
  continue;
976
912
  }
977
- if (cp.cdataOpen) {
913
+ if (mdHtml(cp.mdBlock, 5)) {
978
914
  const c = scanText.indexOf("]]>", pos);
979
915
  const gt = scanText.indexOf(">", pos);
980
916
  if (gt !== -1 && (c === -1 || gt !== c + 2)) poisonRawDivergence();
@@ -983,38 +919,51 @@ ${cont(scanText)}` };
983
919
  break;
984
920
  }
985
921
  rawSpans.push([pos, c + 3]);
986
- cp.cdataOpen = false;
922
+ cp.mdBlock = { kind: "none" };
987
923
  pos = c + 3;
988
924
  continue;
989
925
  }
990
- if (cp.declOpen || cp.bogusOpen) {
926
+ if (mdHtml(cp.mdBlock, 4)) {
991
927
  const c = scanText.indexOf(">", pos);
992
928
  if (c === -1) {
993
929
  rawSpans.push([pos, scanText.length]);
994
930
  break;
995
931
  }
996
932
  rawSpans.push([pos, c + 1]);
997
- cp.declOpen = false;
998
- cp.bogusOpen = false;
933
+ cp.mdBlock = { kind: "none" };
934
+ if (cp.p5Tok.kind === "bogus") cp.p5Tok = { kind: "data" };
999
935
  pos = c + 1;
1000
936
  continue;
1001
937
  }
938
+ if (cp.p5Tok.kind === "bogus") {
939
+ const c = scanText.indexOf(">", pos);
940
+ if (c === -1) {
941
+ rawSpans.push([pos, scanText.length]);
942
+ break;
943
+ }
944
+ rawSpans.push([pos, c + 1]);
945
+ cp.p5Tok = { kind: "data" };
946
+ pos = c + 1;
947
+ continue;
948
+ }
949
+ if (commentOpenAtLineStart || inRawTextTok(cp.p5Tok) || mdHtml(cp.mdBlock, 1)) break;
1002
950
  const pi = scanText.indexOf("<?", pos);
1003
951
  const cd = scanText.indexOf("<![CDATA[", pos);
1004
952
  const dm = scanText.slice(pos).search(/<![A-Za-z]/);
1005
953
  const decl = dm === -1 ? -1 : pos + dm;
1006
- const bm = cp.htmlFlowReal ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\[CDATA\[)|<\/(?![A-Za-z])/) : -1;
954
+ const bm = cp.mdBlock.kind === "html" ? scanText.slice(pos).search(/<!(?!--|[A-Za-z]|\[CDATA\[)|<\/(?![A-Za-z])/) : -1;
1007
955
  const bogus = bm === -1 ? -1 : pos + bm;
1008
956
  const starts = [pi, cd, decl, bogus].filter((x) => x !== -1);
1009
957
  if (starts.length === 0) break;
1010
958
  const first = Math.min(...starts);
1011
959
  if (first === bogus) {
1012
960
  rawSpans.push([bogus, bogus + 2]);
1013
- cp.bogusOpen = true;
961
+ if (cp.p5Tok.kind === "data") cp.p5Tok = { kind: "bogus" };
962
+ else cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1014
963
  pos = bogus + 2;
1015
964
  } else if (first === cd) {
1016
965
  rawSpans.push([cd, cd + 9]);
1017
- cp.cdataOpen = true;
966
+ cp.mdBlock = { kind: "html", type: 5 };
1018
967
  if (!isMdBlank(scanText.slice(0, cd)) || ln.indent > 3) inlineRawOpenerIdx = cd;
1019
968
  pos = cd + 9;
1020
969
  } else if (first === pi) {
@@ -1025,18 +974,18 @@ ${cont(scanText)}` };
1025
974
  continue;
1026
975
  }
1027
976
  rawSpans.push([pi, pi + 2]);
1028
- cp.piOpen = true;
977
+ cp.mdBlock = { kind: "html", type: 3 };
1029
978
  if (!isMdBlank(scanText.slice(0, pi)) || ln.indent > 3) inlineRawOpenerIdx = pi;
1030
979
  pos = pi + 2;
1031
980
  } else {
1032
981
  rawSpans.push([decl, decl + 2]);
1033
982
  if (ln.indent <= 3 && /^doctype/i.test(scanText.slice(decl + 2))) cp.phasePoisonedAt = 0;
1034
- cp.declOpen = true;
983
+ cp.mdBlock = { kind: "html", type: 4 };
1035
984
  if (!isMdBlank(scanText.slice(0, decl)) || ln.indent > 3) inlineRawOpenerIdx = decl;
1036
985
  pos = decl + 2;
1037
986
  }
1038
987
  }
1039
- if (inlineRawOpenerIdx !== -1 && (cp.piOpen || cp.declOpen || cp.cdataOpen)) {
988
+ if (inlineRawOpenerIdx !== -1 && cp.mdBlock.kind === "html" && cp.mdBlock.type >= 3) {
1040
989
  cp.phasePoisonedAt = 0;
1041
990
  }
1042
991
  let tagText = scanText;
@@ -1044,19 +993,18 @@ ${cont(scanText)}` };
1044
993
  tagText = tagText.slice(0, from) + " ".repeat(to - from) + tagText.slice(to);
1045
994
  }
1046
995
  let skipTagScan = false;
1047
- if (cp.tagAcrossLines) {
1048
- if (ln.indent < cp.tagAcrossLinesIndent) poisonRawDivergence();
1049
- const attrs = { state: cp.tagAcrossLinesState };
996
+ if (cp.pendingTag !== null) {
997
+ if (ln.indent < cp.pendingTag.indent) poisonRawDivergence();
998
+ const attrs = { state: cp.pendingTag.attr };
1050
999
  const gt = scanTagAttrs(ln.text, 0, ln.text.length, attrs);
1051
1000
  if (gt === -1) {
1052
1001
  scanTagAttrs("\n", 0, 1, attrs);
1053
- cp.tagAcrossLinesState = attrs.state;
1002
+ cp.pendingTag = { attr: attrs.state, indent: cp.pendingTag.indent };
1054
1003
  skipTagScan = true;
1055
1004
  } else {
1056
1005
  for (const tag of cp.pendingTruncatedCloses) applyTag(tag, true);
1057
1006
  cp.pendingTruncatedCloses = [];
1058
- cp.tagAcrossLines = false;
1059
- cp.tagAcrossLinesState = "outside";
1007
+ cp.pendingTag = null;
1060
1008
  tagText = " ".repeat(gt + 1) + tagText.slice(gt + 1);
1061
1009
  }
1062
1010
  }
@@ -1066,38 +1014,49 @@ ${cont(scanText)}` };
1066
1014
  let m;
1067
1015
  let lastCommentOpenerIdx = -1;
1068
1016
  while ((m = TAG_OR_COMMENT_RE.exec(tagText)) !== null) {
1069
- if (cp.rawTextOpen !== null && (m[0] === "<!--" || m[0] === "-->" || m[0] === "--!>")) {
1070
- if (cp.rawTextOpen === "script" && m[0] === "<!--") cp.scriptDataEscaped = true;
1017
+ if (inRawTextTok(cp.p5Tok) && (m[0] === "<!--" || m[0] === "-->" || m[0] === "--!>")) {
1018
+ if (cp.p5Tok.kind === "script") {
1019
+ if (m[0] === "<!--") cp.p5Tok = { ...cp.p5Tok, escaped: true };
1020
+ if (m[0] === "-->") cp.p5Tok = { ...cp.p5Tok, escaped: false };
1021
+ }
1071
1022
  continue;
1072
1023
  }
1073
1024
  if (m[0] === "<!--") {
1074
1025
  const next = tagText.slice(m.index + 4, m.index + 6);
1075
- if (cp.commentOpen) {
1076
- if (next.startsWith(">") || next === "->") cp.commentOpen = false;
1077
- else if (next === "!>" || next === "-!") poisonRawDivergence();
1026
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) {
1027
+ if (next.startsWith(">") || next === "->") {
1028
+ if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: "none" };
1029
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1030
+ } else if (next === "!>" || next === "-!") {
1031
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1032
+ poisonRawDivergence();
1033
+ }
1078
1034
  continue;
1079
1035
  }
1080
1036
  if (next.startsWith(">") || next === "->") {
1081
1037
  continue;
1082
1038
  }
1083
- cp.commentOpen = true;
1039
+ if (cp.mdBlock.kind === "none") cp.mdBlock = { kind: "html", type: 2 };
1040
+ if (cp.p5Tok.kind === "data") cp.p5Tok = { kind: "comment" };
1084
1041
  lastCommentOpenerIdx = m.index;
1085
1042
  continue;
1086
1043
  }
1087
1044
  if (m[0] === "-->") {
1088
- cp.commentOpen = false;
1045
+ if (mdHtml(cp.mdBlock, 2)) cp.mdBlock = { kind: "none" };
1046
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1089
1047
  continue;
1090
1048
  }
1091
1049
  if (m[0] === "--!>") {
1092
- if (cp.commentOpen) poisonRawDivergence();
1050
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) poisonRawDivergence();
1051
+ if (cp.p5Tok.kind === "comment") cp.p5Tok = { kind: "data" };
1093
1052
  continue;
1094
1053
  }
1095
- if (cp.commentOpen) continue;
1054
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;
1096
1055
  const closing = m[1] === "/";
1097
1056
  const tag = m[2].toLowerCase();
1098
1057
  if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + m.index);
1099
1058
  let attrs = m[3] ?? "";
1100
- if (cp.htmlFlowReal && (cp.rawTextOpen === null || closing && tag === cp.rawTextOpen)) {
1059
+ if (cp.mdBlock.kind === "html" && (!inRawTextTok(cp.p5Tok) || closing && tag === rawTextElement(cp.p5Tok))) {
1101
1060
  const attrStart = m.index + 1 + (closing ? 1 : 0) + m[2].length;
1102
1061
  const st = { state: "outside" };
1103
1062
  const gt = scanTagAttrs(tagText, attrStart, tagText.length, st);
@@ -1107,9 +1066,7 @@ ${cont(scanText)}` };
1107
1066
  else applyTag(tag, false);
1108
1067
  }
1109
1068
  scanTagAttrs("\n", 0, 1, st);
1110
- cp.tagAcrossLines = true;
1111
- cp.tagAcrossLinesIndent = ln.indent;
1112
- cp.tagAcrossLinesState = st.state;
1069
+ cp.pendingTag = { attr: st.state, indent: ln.indent };
1113
1070
  tagHandledAsTruncated = true;
1114
1071
  break;
1115
1072
  }
@@ -1118,16 +1075,15 @@ ${cont(scanText)}` };
1118
1075
  TAG_OR_COMMENT_RE.lastIndex = gt + 1;
1119
1076
  }
1120
1077
  }
1121
- if (closing && !cp.htmlFlowReal && !/^\s*$/.test(attrs)) {
1078
+ if (closing && cp.mdBlock.kind !== "html" && !/^\s*$/.test(attrs)) {
1122
1079
  TAG_OR_COMMENT_RE.lastIndex = m.index + 2 + m[2].length;
1123
1080
  continue;
1124
1081
  }
1125
1082
  const selfClosing = /\/\s*$/.test(attrs);
1126
- noteBreakout(tag, closing);
1127
1083
  if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
1128
1084
  applyTag(tag, closing);
1129
1085
  }
1130
- if (cp.commentOpen && lastCommentOpenerIdx !== -1) {
1086
+ if (commentEitherOpen(cp.mdBlock, cp.p5Tok) && lastCommentOpenerIdx !== -1) {
1131
1087
  if (!isMdBlank(tagText.slice(0, lastCommentOpenerIdx)) || ln.indent > 3) {
1132
1088
  cp.phasePoisonedAt = 0;
1133
1089
  }
@@ -1140,13 +1096,12 @@ ${cont(scanText)}` };
1140
1096
  if (mr[0] === "<!--" || mr[0] === "-->" || mr[0] === "--!>") continue;
1141
1097
  const startMasked = masked[mr.index] !== ln.text[mr.index];
1142
1098
  const wholeVisible = masked.slice(mr.index, mr.index + mr[0].length) === mr[0];
1143
- if (startMasked || wholeVisible || inRaw(mr.index) || cp.commentOpen) continue;
1099
+ if (startMasked || wholeVisible || inRaw(mr.index) || commentEitherOpen(cp.mdBlock, cp.p5Tok)) continue;
1144
1100
  const closing = mr[1] === "/";
1145
1101
  const tag = mr[2].toLowerCase();
1146
1102
  if (strayTablePart(tag)) cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + mr.index);
1147
1103
  if (closing && mr[3] !== void 0 && !/^\s*$/.test(mr[3])) continue;
1148
1104
  const selfClosing = mr[3] !== void 0 && /\/\s*$/.test(mr[3]);
1149
- noteBreakout(tag, closing);
1150
1105
  if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
1151
1106
  applyTag(tag, closing);
1152
1107
  }
@@ -1157,7 +1112,7 @@ ${cont(scanText)}` };
1157
1112
  }
1158
1113
  cp.pendingTruncatedTags = [];
1159
1114
  }
1160
- if (!cp.commentOpen && !tagHandledAsTruncated) {
1115
+ if (!commentEitherOpen(cp.mdBlock, cp.p5Tok) && !tagHandledAsTruncated) {
1161
1116
  let lastLt = -1;
1162
1117
  TAG_START_LT_RE.lastIndex = 0;
1163
1118
  for (let ms = TAG_START_LT_RE.exec(tagText); ms !== null; ms = TAG_START_LT_RE.exec(tagText)) {
@@ -1169,18 +1124,16 @@ ${cont(scanText)}` };
1169
1124
  if (m2) {
1170
1125
  const closing = m2[1] === "/";
1171
1126
  const tag = m2[2].toLowerCase();
1172
- if (strayTablePart(tag) && cp.htmlFlowReal) {
1127
+ if (strayTablePart(tag) && cp.mdBlock.kind === "html") {
1173
1128
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start + lastLt);
1174
1129
  }
1175
- if (cp.htmlFlowReal) {
1176
- cp.tagAcrossLines = true;
1177
- cp.tagAcrossLinesIndent = ln.indent;
1130
+ if (cp.mdBlock.kind === "html") {
1178
1131
  const attrs = { state: "outside" };
1179
1132
  scanTagAttrs(m2[3] + "\n", 0, m2[3].length + 1, attrs);
1180
- cp.tagAcrossLinesState = attrs.state;
1133
+ cp.pendingTag = { attr: attrs.state, indent: ln.indent };
1181
1134
  }
1182
1135
  if (closing) {
1183
- if (!VOID_TAGS.has(tag) && cp.htmlFlowReal) cp.pendingTruncatedCloses.push(tag);
1136
+ if (!VOID_TAGS.has(tag) && cp.mdBlock.kind === "html") cp.pendingTruncatedCloses.push(tag);
1184
1137
  } else if (!VOID_TAGS.has(tag)) {
1185
1138
  applyTag(tag, closing);
1186
1139
  const rawLastLt = ln.text.lastIndexOf("<");
@@ -1201,21 +1154,20 @@ ${cont(scanText)}` };
1201
1154
  }
1202
1155
  masked2 += scanText.slice(cursor);
1203
1156
  if (floatingResidue(masked2, commentOpenAtLineStart).length > 0) {
1204
- cp.htmlSeamPending = true;
1157
+ cp.p5SealPending = true;
1205
1158
  }
1206
1159
  }
1207
- if (cp.rawTextOpen !== null && cp.rawTextInline) {
1160
+ if (inRawTextTok(cp.p5Tok) && cp.p5Tok.openedInline) {
1208
1161
  cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1209
1162
  }
1210
- if (cp.type1FlowOpen && TYPE1_CLOSE_RE.test(ln.text)) {
1211
- cp.type1FlowOpen = false;
1212
- cp.htmlFlowSinceBlank = false;
1213
- cp.htmlFlowReal = false;
1163
+ if (mdHtml(cp.mdBlock, 1) && TYPE1_CLOSE_RE.test(ln.text)) {
1164
+ cp.mdBlock = { kind: "none" };
1165
+ cp.mayBeRawToMicromark = false;
1214
1166
  }
1215
1167
  cp.blankRun = 0;
1216
1168
  cp.prevLineBlank = false;
1217
1169
  cp.prevLineWasText = true;
1218
- cp.prevLineWasValidDef = validDef && !def[1].startsWith("^");
1170
+ cp.prevLineWasValidDef = validLinkDef;
1219
1171
  }
1220
1172
 
1221
1173
  // src/components/incrementalParse/spliceParse.ts
@@ -2172,12 +2124,10 @@ function phantomSuffixCloser(content) {
2172
2124
  const endsWithNewline = content.endsWith("\n");
2173
2125
  const confirmed = endsWithNewline ? content : content + "\n";
2174
2126
  const { checkpoint } = computeFreezeBoundary(confirmed, { defListEnabled: false, referenceTaint: false });
2175
- if (checkpoint.phasePoisonedAt !== Infinity) return "";
2176
- if (checkpoint.openIndent !== 0) return "";
2177
- const nl = endsWithNewline ? "" : "\n";
2178
- if (checkpoint.inFence) return `${nl}${checkpoint.fenceChar.repeat(checkpoint.fenceLen)}`;
2179
- if (checkpoint.inMath) return `${nl}${"$".repeat(checkpoint.mathFenceLen)}`;
2180
- return "";
2127
+ const closer = pendingFenceCloser(checkpoint);
2128
+ if (closer === "") return "";
2129
+ return endsWithNewline ? closer : `
2130
+ ${closer}`;
2181
2131
  }
2182
2132
 
2183
2133
  // src/components/extractContributions.ts