@ai-react-markdown/engine 2.5.1 → 2.5.3

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.d.cts CHANGED
@@ -482,6 +482,23 @@ interface FreezeScanCheckpoint {
482
482
  * htmlFlowSinceBlank swallowed them — a new under-block). Sticky to the
483
483
  * blank; a type 6/1 start on a later line of a non-real run promotes it. */
484
484
  htmlFlowReal: boolean;
485
+ /** The run since the last blank was OPENED by a CommonMark type-1 block
486
+ * (`<script` / `<pre` / `<style` / `<textarea`). Type 1 is the one block
487
+ * that ends at its CLOSER line rather than at a blank, so `htmlFlowReal`
488
+ * being "sticky to the blank" over-ran it: the line after `</script>` is
489
+ * a fresh PARAGRAPH to micromark, but the scanner still treated it as
490
+ * raw html flow — and in a real run end tags may carry attributes, so a
491
+ * `</div a="b">` there was counted as a REAL close. `p <div> x </div
492
+ * a="b"> y` after a `</script>` line therefore froze past an element the
493
+ * actual parse leaves OPEN, nesting the whole rest of the document
494
+ * inside it (2026-08-20 soak leg 2; identical for pre/style/textarea,
495
+ * and correct as-is for a type-6 run, which really does reach the blank).
496
+ * Only set when the type-1 opener is the line that STARTED the run — a
497
+ * `<script>` nested inside an open type-6 block must not end it. */
498
+ type1FlowOpen: boolean;
499
+ /** The currently open raw-text element (`rawTextOpen`) was opened INLINE —
500
+ * in paragraph context rather than in a real html-flow run. */
501
+ rawTextInline: boolean;
485
502
  }
486
503
  /** parse5 tokenizer position inside a tag's attribute area, tracked across
487
504
  * line endings for `tagAcrossLines` (2026-08-19 review r2 P1-2 / P2-3):
@@ -1460,6 +1477,28 @@ declare const defaultEnginePlugins: readonly AIMarkdownEnginePlugin[];
1460
1477
  * `tagName === 'section'` AND presence of the `dataFootnotes` property.
1461
1478
  */
1462
1479
  declare function isFootnoteSection(node: Element): boolean;
1480
+ /**
1481
+ * Whitespace-only text node. `mdast-util-to-hast`'s `state.wrap(content,
1482
+ * true)` interleaves `\n` text nodes between (and around) the block-level
1483
+ * children of an `<li>`, so any code reasoning about a list item's real
1484
+ * children has to look past them.
1485
+ */
1486
+ declare function isWhitespaceText(c: ElementContent): boolean;
1487
+ /**
1488
+ * Index of the last child that is not a whitespace-only text node, or -1 if
1489
+ * there is none.
1490
+ *
1491
+ * Both footnote-footer paths need exactly this and for the same reason.
1492
+ * Appending a backref follows mdast-util-to-hast's contract — "if the tail of
1493
+ * the `<li>`'s content is a `<p>`, push into it, else push onto the `<li>`" —
1494
+ * and stripping one has to find that tail again. Read the trailing
1495
+ * wrap-emitted `\n` as the tail and the `<p>` path is bypassed in one case
1496
+ * and the wrong node stripped in the other.
1497
+ *
1498
+ * Lived in two copies until 2.5.2 (core's aggregate footer and the engine's
1499
+ * body extractor), one on each side of the 2.3.0 package split.
1500
+ */
1501
+ declare function lastMeaningfulIdx(children: ElementContent[]): number;
1463
1502
 
1464
1503
  declare function normalizeId(s: string): string;
1465
1504
  /**
@@ -2021,4 +2060,4 @@ type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;
2021
2060
  */
2022
2061
  declare function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor;
2023
2062
 
2024
- export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
2063
+ export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, isWhitespaceText, lastMeaningfulIdx, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
package/dist/index.d.ts CHANGED
@@ -482,6 +482,23 @@ interface FreezeScanCheckpoint {
482
482
  * htmlFlowSinceBlank swallowed them — a new under-block). Sticky to the
483
483
  * blank; a type 6/1 start on a later line of a non-real run promotes it. */
484
484
  htmlFlowReal: boolean;
485
+ /** The run since the last blank was OPENED by a CommonMark type-1 block
486
+ * (`<script` / `<pre` / `<style` / `<textarea`). Type 1 is the one block
487
+ * that ends at its CLOSER line rather than at a blank, so `htmlFlowReal`
488
+ * being "sticky to the blank" over-ran it: the line after `</script>` is
489
+ * a fresh PARAGRAPH to micromark, but the scanner still treated it as
490
+ * raw html flow — and in a real run end tags may carry attributes, so a
491
+ * `</div a="b">` there was counted as a REAL close. `p <div> x </div
492
+ * a="b"> y` after a `</script>` line therefore froze past an element the
493
+ * actual parse leaves OPEN, nesting the whole rest of the document
494
+ * inside it (2026-08-20 soak leg 2; identical for pre/style/textarea,
495
+ * and correct as-is for a type-6 run, which really does reach the blank).
496
+ * Only set when the type-1 opener is the line that STARTED the run — a
497
+ * `<script>` nested inside an open type-6 block must not end it. */
498
+ type1FlowOpen: boolean;
499
+ /** The currently open raw-text element (`rawTextOpen`) was opened INLINE —
500
+ * in paragraph context rather than in a real html-flow run. */
501
+ rawTextInline: boolean;
485
502
  }
486
503
  /** parse5 tokenizer position inside a tag's attribute area, tracked across
487
504
  * line endings for `tagAcrossLines` (2026-08-19 review r2 P1-2 / P2-3):
@@ -1460,6 +1477,28 @@ declare const defaultEnginePlugins: readonly AIMarkdownEnginePlugin[];
1460
1477
  * `tagName === 'section'` AND presence of the `dataFootnotes` property.
1461
1478
  */
1462
1479
  declare function isFootnoteSection(node: Element): boolean;
1480
+ /**
1481
+ * Whitespace-only text node. `mdast-util-to-hast`'s `state.wrap(content,
1482
+ * true)` interleaves `\n` text nodes between (and around) the block-level
1483
+ * children of an `<li>`, so any code reasoning about a list item's real
1484
+ * children has to look past them.
1485
+ */
1486
+ declare function isWhitespaceText(c: ElementContent): boolean;
1487
+ /**
1488
+ * Index of the last child that is not a whitespace-only text node, or -1 if
1489
+ * there is none.
1490
+ *
1491
+ * Both footnote-footer paths need exactly this and for the same reason.
1492
+ * Appending a backref follows mdast-util-to-hast's contract — "if the tail of
1493
+ * the `<li>`'s content is a `<p>`, push into it, else push onto the `<li>`" —
1494
+ * and stripping one has to find that tail again. Read the trailing
1495
+ * wrap-emitted `\n` as the tail and the `<p>` path is bypassed in one case
1496
+ * and the wrong node stripped in the other.
1497
+ *
1498
+ * Lived in two copies until 2.5.2 (core's aggregate footer and the engine's
1499
+ * body extractor), one on each side of the 2.3.0 package split.
1500
+ */
1501
+ declare function lastMeaningfulIdx(children: ElementContent[]): number;
1463
1502
 
1464
1503
  declare function normalizeId(s: string): string;
1465
1504
  /**
@@ -2021,4 +2060,4 @@ type RemendPreprocessorOptions = Omit<RemendOptions, 'katex' | 'inlineKatex'>;
2021
2060
  */
2022
2061
  declare function createRemendPreprocessor(options?: RemendPreprocessorOptions): AIMDContentPreprocessor;
2023
2062
 
2024
- export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
2063
+ export { type AIMDContentPreprocessor, type AIMarkdownEnginePlugin, type AIMarkdownEnginePluginName, type AdvanceOptions, type AdvanceResult, type AllowElement, type ChunkData, type Contribution, type CrossChunkHandlerOptions, DEFAULT_PAYLOAD, type DefLabelScanner, type DefLabels, type Deprecation, type EnginePluginInternals, type EnginePluginStage, type ExtractContributionsOptions, type FootnoteDef, type FreezeBoundaryOptions, type IncrementalParseState, type IncrementalStage, type LinkDef, PIPELINE_STAGES, type ParsedMarkdown, type PhantomLabels, type PipelineOptions, type PipelineStage, type RefKind, type RefRecord, type Registry, type RegistryInternal, type RehypePlugins, type RehypeRebaseHashLinksOptions, type RemarkPlugins, type RemarkRehypeOptions, type RemendPreprocessorOptions, SENTINEL_FN_CONTENT, SENTINEL_LINK_URL, SMOOTH_STREAM_PACING_PRESETS, STAGE_MEASURE_PREFIX, type SanitizeSchema, type SmoothStreamController, type SmoothStreamOptions, type SmoothStreamPacing, type SmoothStreamPacingParams, type TransformContext, type UrlAttrKey, type UrlAttrTag, type UrlTransform, advanceIncrementalParse, attributeHastChildren, buildCoreRehypePlugins, buildCoreRemarkPlugins, buildCoreRemarkRehypeOptions, buildCrossChunkHandlers, buildPhantomSuffix, buildTransform, codePointSnapshots, collectDefLabels, computeFreezeBoundary, createDefLabelScanner, createFile, createIncrementalLatexPreprocessor, createProcessor, createRegistry, createRemendPreprocessor, createSmoothStreamController, defaultEnginePlugins, defaultUrlTransform, definitionList, extendSanitizeSchema, extractContributions, extractDefBodiesFromHast, footnoteSafeId, getEnginePluginInternals, hasLoneSurrogate, highlight, isFootnoteSection, isWhitespaceText, lastMeaningfulIdx, measureStage, mergeClassNameAllowlist, normalizeForMatch, normalizeId, pangu, parseStage, phantomSuffixCloser, preprocessAIMDContent, preprocessLaTeX, rehypeFooterAdorn, rehypeRebaseHashLinks, removeComments, sanitizeCrossChunkUrl, sanitizeSchema, shortenDocumentId, smartypants, sourceIdFromFootnoteLiId, splitByProtectedRegions, subscribeStageTimings, transformStage, withDefs };
@@ -65,6 +65,8 @@ __export(src_exports, {
65
65
  hasLoneSurrogate: () => hasLoneSurrogate,
66
66
  highlight: () => highlight,
67
67
  isFootnoteSection: () => isFootnoteSection,
68
+ isWhitespaceText: () => isWhitespaceText,
69
+ lastMeaningfulIdx: () => lastMeaningfulIdx,
68
70
  measureStage: () => measureStage,
69
71
  mergeClassNameAllowlist: () => mergeClassNameAllowlist,
70
72
  normalizeForMatch: () => normalizeForMatch,
@@ -268,6 +270,26 @@ var import_micromark_util_html_tag_name = require("micromark-util-html-tag-name"
268
270
  var import_micromark_util_normalize_identifier = require("micromark-util-normalize-identifier");
269
271
  var TYPE6_NAMES = new Set(import_micromark_util_html_tag_name.htmlBlockNames);
270
272
  var TABLE_PART_NAMES = /* @__PURE__ */ new Set(["td", "th", "tr", "tbody", "thead", "tfoot", "caption", "col", "colgroup"]);
273
+ var DOCUMENT_STRUCTURE_NAMES = /* @__PURE__ */ new Set(["html", "head", "body", "frameset"]);
274
+ var RETROACTIVE_OPENERS = [
275
+ "<!doctype",
276
+ "<html",
277
+ "<head",
278
+ "<body",
279
+ "<frameset",
280
+ "</html",
281
+ "</head",
282
+ "</body",
283
+ "</frameset"
284
+ ];
285
+ function tailCarriesRetroactive(text) {
286
+ const lower = text.toLowerCase();
287
+ for (let i = lower.indexOf("<"); i !== -1; i = lower.indexOf("<", i + 1)) {
288
+ const rest = lower.slice(i);
289
+ for (const op of RETROACTIVE_OPENERS) if (rest.startsWith(op)) return true;
290
+ }
291
+ return false;
292
+ }
271
293
  var HTML_BREAKOUT_TAGS = /* @__PURE__ */ new Set([
272
294
  "b",
273
295
  "big",
@@ -333,6 +355,7 @@ var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set([
333
355
  ]);
334
356
  var TYPE6_START_RE = /^<\/?([A-Za-z][A-Za-z0-9-]*)(?:[ \t\r]|\/?>|$)/;
335
357
  var TYPE1_START_RE = /^<(script|pre|style|textarea)(?:[ \t\r]|>|$)/i;
358
+ var TYPE1_CLOSE_RE = /<\/(?:script|pre|style|textarea)>/i;
336
359
  var TYPE7_LINE_RE = /^(?:<[A-Za-z][A-Za-z0-9-]*(?:[ \t\r][^>]*|\/)?>|<\/[A-Za-z][A-Za-z0-9-]*[ \t\r]*>)[ \t\r]*$/;
337
360
  var t7Name = (line) => /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(line)[1];
338
361
  var VOID_TAGS = /* @__PURE__ */ new Set([
@@ -508,7 +531,9 @@ function freshCheckpoint(defListEnabled, mathFlow, referenceTaint) {
508
531
  tagAcrossLines: false,
509
532
  tagAcrossLinesIndent: 0,
510
533
  tagAcrossLinesState: "outside",
511
- htmlFlowReal: false
534
+ htmlFlowReal: false,
535
+ type1FlowOpen: false,
536
+ rawTextInline: false
512
537
  };
513
538
  }
514
539
  function isPlausibleLinkDefRest(rest) {
@@ -653,8 +678,9 @@ function computeFreezeBoundary(text, options, resume) {
653
678
  if (tailLine) return !canBecomeDdLine(tailLine.text, false);
654
679
  return false;
655
680
  };
681
+ const tailRetroactive = tailLine !== null && tailCarriesRetroactive(tailLine.text);
656
682
  let boundary = 0;
657
- for (let i = cp.candidates.length - 1; i >= 0; i--) {
683
+ for (let i = cp.candidates.length - 1; i >= 0 && !tailRetroactive; i--) {
658
684
  const c = cp.candidates[i];
659
685
  if (!c.htmlBalanced || c.hazard || c.seamRisk) continue;
660
686
  if (c.offset > cp.phasePoisonedAt) continue;
@@ -738,8 +764,10 @@ function processConfirmedLine(cp, ln, text) {
738
764
  cp.rawTextOpen = null;
739
765
  } else if (!closing && RAW_TEXT_ELEMENTS.has(tag) && htmlRulesApply()) {
740
766
  cp.rawTextOpen = tag;
767
+ cp.rawTextInline = !cp.htmlFlowReal;
741
768
  if (tag === "plaintext") cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
742
769
  }
770
+ if (DOCUMENT_STRUCTURE_NAMES.has(tag)) cp.phasePoisonedAt = 0;
743
771
  if (closing) {
744
772
  const count = cp.tagBalance.get(tag) ?? 0;
745
773
  if (count > 0) {
@@ -850,15 +878,22 @@ function processConfirmedLine(cp, ln, text) {
850
878
  cp.candidates.push({
851
879
  offset: Math.min(ln.end + 1, text.length),
852
880
  blankRun: cp.blankRun,
853
- htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen && !cp.bogusOpen,
881
+ // `type1FlowOpen`: an unterminated type-1 block swallows this blank
882
+ // and everything after it as RAW content, so nothing here is a block
883
+ // boundary at all. Its tags are invisible to the balance scan
884
+ // (`rawTextOpen` suppresses them), which is exactly why `openTotal`
885
+ // reads 0 and the candidate looked safe.
886
+ htmlBalanced: cp.openTotal === 0 && !cp.commentOpen && !cp.piOpen && !cp.declOpen && !cp.cdataOpen && !cp.bogusOpen && !cp.type1FlowOpen,
854
887
  hazard: cp.hazardVerdict,
855
888
  seamRisk: cp.htmlSeamPending,
856
889
  defListSettled: null
857
890
  });
858
891
  cp.paragraphHasUnpairedRun = false;
859
892
  cp.openBracket = null;
860
- cp.htmlFlowSinceBlank = false;
861
- cp.htmlFlowReal = false;
893
+ if (!cp.type1FlowOpen) {
894
+ cp.htmlFlowSinceBlank = false;
895
+ cp.htmlFlowReal = false;
896
+ }
862
897
  cp.prevLineBlank = true;
863
898
  cp.prevLineWasText = false;
864
899
  cp.prevLineWasValidDef = false;
@@ -872,7 +907,9 @@ function processConfirmedLine(cp, ln, text) {
872
907
  }
873
908
  const tagStart = ln.indent <= 3 ? /^<\/?([A-Za-z][A-Za-z0-9-]*)/.exec(mdTrimStart(ln.text)) : null;
874
909
  if (tagStart) {
910
+ const noRealBlockOpen = !cp.htmlFlowReal;
875
911
  cp.htmlFlowSinceBlank = true;
912
+ if (noRealBlockOpen && TYPE1_START_RE.test(mdTrimStart(ln.text))) cp.type1FlowOpen = true;
876
913
  if (!TYPE6_NAMES.has(tagStart[1].toLowerCase())) cp.hazardVerdict = true;
877
914
  if (!cp.htmlFlowReal) {
878
915
  const t = mdTrimStart(ln.text);
@@ -1023,6 +1060,7 @@ ${cont(scanText)}` };
1023
1060
  pos = pi + 2;
1024
1061
  } else {
1025
1062
  rawSpans.push([decl, decl + 2]);
1063
+ if (ln.indent <= 3 && /^doctype/i.test(scanText.slice(decl + 2))) cp.phasePoisonedAt = 0;
1026
1064
  cp.declOpen = true;
1027
1065
  pos = decl + 2;
1028
1066
  }
@@ -1103,7 +1141,10 @@ ${cont(scanText)}` };
1103
1141
  TAG_OR_COMMENT_RE.lastIndex = gt + 1;
1104
1142
  }
1105
1143
  }
1106
- if (closing && !cp.htmlFlowReal && !/^\s*$/.test(attrs)) continue;
1144
+ if (closing && !cp.htmlFlowReal && !/^\s*$/.test(attrs)) {
1145
+ TAG_OR_COMMENT_RE.lastIndex = m.index + 2 + m[2].length;
1146
+ continue;
1147
+ }
1107
1148
  const selfClosing = /\/\s*$/.test(attrs);
1108
1149
  if (VOID_TAGS.has(tag) || selfClosing && honoursSelfClosing(tag)) continue;
1109
1150
  applyTag(tag, closing);
@@ -1184,6 +1225,14 @@ ${cont(scanText)}` };
1184
1225
  cp.htmlSeamPending = true;
1185
1226
  }
1186
1227
  }
1228
+ if (cp.rawTextOpen !== null && cp.rawTextInline) {
1229
+ cp.phasePoisonedAt = Math.min(cp.phasePoisonedAt, ln.start);
1230
+ }
1231
+ if (cp.type1FlowOpen && TYPE1_CLOSE_RE.test(ln.text)) {
1232
+ cp.type1FlowOpen = false;
1233
+ cp.htmlFlowSinceBlank = false;
1234
+ cp.htmlFlowReal = false;
1235
+ }
1187
1236
  cp.blankRun = 0;
1188
1237
  cp.prevLineBlank = false;
1189
1238
  cp.prevLineWasText = true;
@@ -1199,6 +1248,15 @@ function isFootnoteSection(node) {
1199
1248
  const props = node.properties;
1200
1249
  return props?.dataFootnotes !== void 0;
1201
1250
  }
1251
+ function isWhitespaceText(c) {
1252
+ return c.type === "text" && /^\s*$/.test(c.value);
1253
+ }
1254
+ function lastMeaningfulIdx(children) {
1255
+ for (let i = children.length - 1; i >= 0; i--) {
1256
+ if (!isWhitespaceText(children[i])) return i;
1257
+ }
1258
+ return -1;
1259
+ }
1202
1260
 
1203
1261
  // src/components/incrementalParse/attributeHastChildren.ts
1204
1262
  function attributeHastChildren(mdast, hast, stopAt = Infinity) {
@@ -1981,16 +2039,6 @@ function isBackrefAnchor(c) {
1981
2039
  if (el.tagName !== "a") return false;
1982
2040
  return Boolean(el.properties && "dataFootnoteBackref" in el.properties);
1983
2041
  }
1984
- function isWhitespaceText(c) {
1985
- if (c.type !== "text") return false;
1986
- return /^\s*$/.test(c.value);
1987
- }
1988
- function lastMeaningfulIdx(children) {
1989
- for (let i = children.length - 1; i >= 0; i--) {
1990
- if (!isWhitespaceText(children[i])) return i;
1991
- }
1992
- return -1;
1993
- }
1994
2042
  function dropTrailingBackrefs(children) {
1995
2043
  let trailingWsStart = children.length;
1996
2044
  while (trailingWsStart > 0 && isWhitespaceText(children[trailingWsStart - 1])) {
@@ -4669,21 +4717,7 @@ function convertSingleToDoubleDollar(text) {
4669
4717
  }
4670
4718
  function preprocessLaTeX(str) {
4671
4719
  if (!hasLatexTrigger(str)) return str;
4672
- const segments = splitByProtectedRegions(str);
4673
- const result = segments.map((segment) => {
4674
- if (segment.isCode) return segment.text;
4675
- let text = segment.text;
4676
- text = escapeMhchemCommands(text);
4677
- text = escapeCurrencyDollarSigns(text);
4678
- text = convertLatexDelimiters(text);
4679
- text = escapeLatexPipes(text);
4680
- text = escapeLatexPipesInUnclosed(text);
4681
- text = escapeTextUnderscores(text);
4682
- text = convertSingleToDoubleDollar(text);
4683
- text = truncateUnclosedLatexBlock(text);
4684
- return text;
4685
- });
4686
- return result.join("");
4720
+ return processSlice(str, false).out;
4687
4721
  }
4688
4722
  function hasLatexTrigger(str) {
4689
4723
  return str.includes("$") || str.includes("\\[") || str.includes("\\(");
@@ -4712,7 +4746,7 @@ function hasUnclosedTextCommand(text) {
4712
4746
  }
4713
4747
  var RESIDUAL_OPEN_BRACKET_RE = /(?<!!)\\\[/;
4714
4748
  var LEADING_DOUBLE_DOLLAR_RE = /^\s*\$\$/;
4715
- function processSliceInstrumented(slice, probe = true) {
4749
+ function processSlice(slice, probe = true) {
4716
4750
  const segments = splitByProtectedRegions(slice);
4717
4751
  const parts = [];
4718
4752
  let quiescent = true;
@@ -4836,13 +4870,13 @@ function createIncrementalLatexPreprocessor(options) {
4836
4870
  };
4837
4871
  const cut = findRawSafeCut(active);
4838
4872
  if (cut > 0) {
4839
- const candidate = processSliceInstrumented(active.slice(0, cut));
4873
+ const candidate = processSlice(active.slice(0, cut));
4840
4874
  if (candidate.quiescent) freeze(cut, candidate);
4841
4875
  }
4842
4876
  nextAttemptLen = advanced || !backoff ? 0 : active.length * 2;
4843
4877
  onAttempt?.({ activeLength, frozenBytes });
4844
4878
  }
4845
- const tail = processSliceInstrumented(active, false);
4879
+ const tail = processSlice(active, false);
4846
4880
  const head = tail.truncatedAtSeamStart ? frozenOut.replace(/\s+$/, "") : frozenOut;
4847
4881
  const out = head + tail.out;
4848
4882
  prevSource = source;
@@ -4907,6 +4941,8 @@ function createRemendPreprocessor(options) {
4907
4941
  hasLoneSurrogate,
4908
4942
  highlight,
4909
4943
  isFootnoteSection,
4944
+ isWhitespaceText,
4945
+ lastMeaningfulIdx,
4910
4946
  measureStage,
4911
4947
  mergeClassNameAllowlist,
4912
4948
  normalizeForMatch,