@ai-matrx/content-ir 0.18.4 → 0.18.5

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/source.d.cts CHANGED
@@ -328,7 +328,14 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
328
328
  * - a placeholder (`$...$`);
329
329
  * - prose, unless a TeX command or operator says otherwise: two plain
330
330
  * words (`$Tipping (fee)$`), a contraction (`$I'm$`, never `$X'Y$`), an
331
- * abbreviation (`$e.g. (x)$`).
331
+ * abbreviation (`$e.g. (x)$`);
332
+ * - a shell or template variable chain (`$USER$HOSTNAME`, `$name.$ext`,
333
+ * `${a}${b}`) — {@link isVariableChain}.
334
+ *
335
+ * `after` is the text right after the closing `$` — {@link singleDollarAfter}
336
+ * (up to {@link AFTER_WINDOW} characters; `\n` marks the end of the text). A single character still
337
+ * applies the Pandoc digit rule, but the variable-chain guard needs the
338
+ * whole following name.
332
339
  */
333
340
  declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
334
341
  /**
@@ -348,6 +355,14 @@ declare function looksLikeOpenInlineMath(partial: string): boolean;
348
355
  * closer is a `$` not followed by another `$`, and the content passes
349
356
  * {@link isSingleDollarMath}. Returns the offset just past the closing `$`.
350
357
  */
358
+ /** How much text after a closing `$` the rule reads (a glued suffix or the next variable name). */
359
+ declare const AFTER_WINDOW = 32;
360
+ /**
361
+ * The `after` argument of {@link isSingleDollarMath} for the closing `$` at
362
+ * `close`: the next {@link AFTER_WINDOW} characters, with a `\n` standing for
363
+ * the end of the text (so `$A$B` at the very end reads the whole name `B`).
364
+ */
365
+ declare function singleDollarAfter(text: string, close: number): string;
351
366
  declare function singleDollarMathEnd(text: string, open: number, limit?: number): number;
352
367
  /**
353
368
  * THE escaped-bracket rule — whether a closed `\[ … \]` is display math or
@@ -476,6 +491,13 @@ interface FenceLines {
476
491
  line(k: number): string | null;
477
492
  /** Streaming: line `k` has not ended yet, so it closes nothing. */
478
493
  openTail?(k: number): boolean;
494
+ /**
495
+ * Streaming: more lines may still arrive. The strict-CommonMark retry
496
+ * applies only while the nested reading ends inside a nested fence — a
497
+ * later line can close that nested fence, so a retry's closer is
498
+ * undecided and the fence stays open (verify-RC-B3 F3).
499
+ */
500
+ streaming?: boolean;
479
501
  }
480
502
  interface FenceEnd {
481
503
  /** The closing line when `closed`; otherwise the fence's last line (text end, or the line before its container ended). */
@@ -585,4 +607,4 @@ declare function pendingDisplayMathOpener(text: string): number;
585
607
  /** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
586
608
  declare function pairDisplayMath(text: string): Map<number, number>;
587
609
 
588
- export { BacktickRuns, type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type CodeRange, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type FenceEnd, type FenceLineKind, type FenceLines, type FenceOpener, FenceReader, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
610
+ export { AFTER_WINDOW, BacktickRuns, type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type CodeRange, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type FenceEnd, type FenceLineKind, type FenceLines, type FenceOpener, FenceReader, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarAfter, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.d.ts CHANGED
@@ -328,7 +328,14 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
328
328
  * - a placeholder (`$...$`);
329
329
  * - prose, unless a TeX command or operator says otherwise: two plain
330
330
  * words (`$Tipping (fee)$`), a contraction (`$I'm$`, never `$X'Y$`), an
331
- * abbreviation (`$e.g. (x)$`).
331
+ * abbreviation (`$e.g. (x)$`);
332
+ * - a shell or template variable chain (`$USER$HOSTNAME`, `$name.$ext`,
333
+ * `${a}${b}`) — {@link isVariableChain}.
334
+ *
335
+ * `after` is the text right after the closing `$` — {@link singleDollarAfter}
336
+ * (up to {@link AFTER_WINDOW} characters; `\n` marks the end of the text). A single character still
337
+ * applies the Pandoc digit rule, but the variable-chain guard needs the
338
+ * whole following name.
332
339
  */
333
340
  declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
334
341
  /**
@@ -348,6 +355,14 @@ declare function looksLikeOpenInlineMath(partial: string): boolean;
348
355
  * closer is a `$` not followed by another `$`, and the content passes
349
356
  * {@link isSingleDollarMath}. Returns the offset just past the closing `$`.
350
357
  */
358
+ /** How much text after a closing `$` the rule reads (a glued suffix or the next variable name). */
359
+ declare const AFTER_WINDOW = 32;
360
+ /**
361
+ * The `after` argument of {@link isSingleDollarMath} for the closing `$` at
362
+ * `close`: the next {@link AFTER_WINDOW} characters, with a `\n` standing for
363
+ * the end of the text (so `$A$B` at the very end reads the whole name `B`).
364
+ */
365
+ declare function singleDollarAfter(text: string, close: number): string;
351
366
  declare function singleDollarMathEnd(text: string, open: number, limit?: number): number;
352
367
  /**
353
368
  * THE escaped-bracket rule — whether a closed `\[ … \]` is display math or
@@ -476,6 +491,13 @@ interface FenceLines {
476
491
  line(k: number): string | null;
477
492
  /** Streaming: line `k` has not ended yet, so it closes nothing. */
478
493
  openTail?(k: number): boolean;
494
+ /**
495
+ * Streaming: more lines may still arrive. The strict-CommonMark retry
496
+ * applies only while the nested reading ends inside a nested fence — a
497
+ * later line can close that nested fence, so a retry's closer is
498
+ * undecided and the fence stays open (verify-RC-B3 F3).
499
+ */
500
+ streaming?: boolean;
479
501
  }
480
502
  interface FenceEnd {
481
503
  /** The closing line when `closed`; otherwise the fence's last line (text end, or the line before its container ended). */
@@ -585,4 +607,4 @@ declare function pendingDisplayMathOpener(text: string): number;
585
607
  /** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
586
608
  declare function pairDisplayMath(text: string): Map<number, number>;
587
609
 
588
- export { BacktickRuns, type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type CodeRange, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type FenceEnd, type FenceLineKind, type FenceLines, type FenceOpener, FenceReader, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
610
+ export { AFTER_WINDOW, BacktickRuns, type BlockIslandType, CALLOUT_NAMES, type CodePointIndex, type CodeRange, type DisturbedIsland, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, type FenceEnd, type FenceLineKind, type FenceLines, type FenceOpener, FenceReader, type InlineIslandType, type InnerFenceLine, type IslandMeta, type IslandType, type MapOptions, type MappedPosition, type MappedRange, NESTING_FENCE_LANGUAGES, type ReadXmlTag, type SourceBlock, type SourceBlockKind, type SourceChange, type SourceEdit, type SourceIsland, type SourceSpan, SourceSpliceError, type SourceSpliceErrorCode, type SpliceIntegrity, type SpliceOptions, type SpliceResult, type TokenizeOptions, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarAfter, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
package/dist/source.js CHANGED
@@ -321,6 +321,7 @@ var FenceReader = class {
321
321
  function closeFence(src, open, opener) {
322
322
  const first = readFence(src, open, new FenceReader(opener));
323
323
  if (first.closed || !first.reader.sawNested || first.reader.nestedDepth <= 0) return { line: first.line, closed: first.closed };
324
+ if (src.streaming) return { line: first.line, closed: false };
324
325
  const strict = readFence(src, open, new FenceReader(opener, { nesting: false }));
325
326
  return { line: strict.line, closed: strict.closed };
326
327
  }
@@ -584,6 +585,8 @@ function fenceLineKinds(text) {
584
585
  function pendingCodeSpanStart(text) {
585
586
  const n = text.length;
586
587
  if (n === 0 || /\n[ \t]*\n[ \t]*$/.test(text)) return -1;
588
+ const lastLine = text.slice(text.lastIndexOf("\n") + 1);
589
+ if (lastLine && /^(?: {0,3}>[ \t]?)*[ \t]*$/.test(lastLine)) return pendingCodeSpanStart(`${text}x`);
587
590
  const s = scan(text);
588
591
  const para = s.pendingPara;
589
592
  if (s.endsInFence || para === -1) return -1;
@@ -730,13 +733,26 @@ var MATH_SHAPE_CHARS = /^[A-Za-z0-9'\s(),.*\/-]+$/;
730
733
  function isSingleDollarMath(content, after) {
731
734
  if (!content || content.length > 400) return false;
732
735
  if (/^\s/.test(content) || /\s$/.test(content)) return false;
733
- if (after !== void 0 && /[0-9]/.test(after)) return false;
736
+ if (after !== void 0 && /^[0-9]/.test(after)) return false;
737
+ if (isVariableChain(content, after)) return false;
734
738
  if (/(?:^|[^\\])%/.test(content)) return false;
735
739
  if (/^[)\]}"/]/.test(content) || /[(\[{":;,/]$/.test(content)) return false;
736
- if (/^[0-9]/.test(content) && after !== void 0 && /[A-Za-z]/.test(after)) return false;
740
+ if (/^[0-9]/.test(content) && after !== void 0 && /^[A-Za-z]/.test(after)) return false;
737
741
  if (isMathPlaceholder(content)) return false;
738
742
  return TEX_SIGNAL.test(content) || !readsAsProse(content);
739
743
  }
744
+ var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
745
+ var MATH_SUFFIX = /^(?:s|es|th|st|nd|rd)$/i;
746
+ function isVariableChain(content, after) {
747
+ if (/^\{[A-Za-z_][\w.]*\}$/.test(content)) return true;
748
+ if (!after) return false;
749
+ if (after[0] === "{") return IDENTIFIER.test(content);
750
+ const run = /^[A-Za-z0-9_]+/.exec(after)?.[0];
751
+ if (!run) return false;
752
+ if (after.length === 1) return false;
753
+ if (/^[A-Za-z_][A-Za-z0-9_]*[.@-]$/.test(content)) return true;
754
+ return IDENTIFIER.test(content) && !MATH_SUFFIX.test(run);
755
+ }
740
756
  var FUNCTION_NAMES = /* @__PURE__ */ new Set([
741
757
  "sin",
742
758
  "cos",
@@ -780,6 +796,12 @@ function isMathShape(content) {
780
796
  if (/[A-Za-z]'+[A-Za-z]/.test(content) || /(?:^|[\s(,])[A-Za-z]\.(?:[A-Za-z]\.|\s|$)/.test(content)) return false;
781
797
  return /[A-Za-z]'*\(|[A-Za-z]'|\b[A-Za-z]\s+[A-Za-z]\b|\([^)]*[A-Za-z][^)]*\)/.test(content);
782
798
  }
799
+ var AFTER_WINDOW = 32;
800
+ function singleDollarAfter(text, close) {
801
+ const rest = text.slice(close + 1, close + 1 + AFTER_WINDOW);
802
+ return rest.length < AFTER_WINDOW ? `${rest}
803
+ ` : rest;
804
+ }
783
805
  function singleDollarMathEnd(text, open, limit = text.length) {
784
806
  const bound = Math.min(limit, open + 403);
785
807
  let close = -1;
@@ -797,7 +819,7 @@ function singleDollarMathEnd(text, open, limit = text.length) {
797
819
  }
798
820
  if (close === -1 || text[close + 1] === "$") return -1;
799
821
  const content = text.slice(open + 1, close);
800
- return isSingleDollarMath(content, text[close + 1]) ? close + 1 : -1;
822
+ return isSingleDollarMath(content, singleDollarAfter(text, close)) ? close + 1 : -1;
801
823
  }
802
824
  var BRACKET_TEX_SIGNAL = /\\[A-Za-z]+|[\^{}=<>+]|_\{|(?:^|[^A-Za-z0-9])[A-Za-z]_[A-Za-z0-9](?![A-Za-z0-9])/;
803
825
  function isEscapedBracketMath(content, before) {
@@ -1168,18 +1190,14 @@ var Tokenizer = class {
1168
1190
  /**
1169
1191
  * Streaming: an open last line that begins with `{` is undecided — each new
1170
1192
  * byte can balance or unbalance its braces and flip the whole line between
1171
- * prose and a JSON island — and so is a line that is exactly one allowed
1172
- * HTML tag so far; both are provisional until they end (G5).
1193
+ * prose and a JSON island — so it is provisional until it ends (G5).
1194
+ * (A lone HTML tag on that line is held by {@link holdUndecidedTail}.)
1173
1195
  */
1174
1196
  markOpenJsonTail() {
1175
1197
  const last = this.lineStarts.length - 1;
1176
1198
  if (!this.isOpenTail(last)) return;
1177
- const start = this.lineStarts[last];
1178
- const t = this.lineText(last).trim();
1179
- const oneTag = t.startsWith("<") ? readXmlTag(t, 0) : null;
1180
- const loneTag = !!oneTag && oneTag.raw === t && ALLOWED_RAW_HTML_TAGS.has(oneTag.tagName.toLowerCase());
1181
- if (t.startsWith("{") || loneTag) {
1182
- this.provisionalFrom = Math.min(this.provisionalFrom, start);
1199
+ if (this.lineText(last).trim().startsWith("{")) {
1200
+ this.provisionalFrom = Math.min(this.provisionalFrom, this.lineStarts[last]);
1183
1201
  }
1184
1202
  }
1185
1203
  /**
@@ -1212,11 +1230,22 @@ var Tokenizer = class {
1212
1230
  /** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
1213
1231
  paragraphMayGrow(pe) {
1214
1232
  if (!this.streaming) return false;
1233
+ if (this.undecidedBreaks.has(pe)) return true;
1215
1234
  const rest = this.n - pe;
1216
1235
  if (rest === 0) return true;
1217
1236
  const tail = this.text.slice(pe);
1218
- return tail === "\n" || tail === "\r\n" || tail === "\r";
1237
+ return /^(?:\r\n|\r|\n)[ \t]*$/.test(tail);
1238
+ }
1239
+ /**
1240
+ * Streaming: an open block that may still turn back into prose — a `$$`
1241
+ * pair whose closer is on the open last line (prose after it makes it
1242
+ * inline), or a JSON head whose braces have not balanced (it may never parse).
1243
+ */
1244
+ mayDissolve(block) {
1245
+ return this.streaming && !block.complete && (block.type === "math_block" || block.type === "json");
1219
1246
  }
1247
+ /** Streaming: paragraph ends where an undecided, dissolvable block cut them short. */
1248
+ undecidedBreaks = /* @__PURE__ */ new Set();
1220
1249
  /** Streaming only: the final line, still waiting for its terminator. */
1221
1250
  isOpenTail(k) {
1222
1251
  return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
@@ -1265,8 +1294,103 @@ var Tokenizer = class {
1265
1294
  }
1266
1295
  pos = this.paragraph(pos, li);
1267
1296
  }
1297
+ if (this.streaming) this.holdUndecidedTail();
1268
1298
  return this.blocks;
1269
1299
  }
1300
+ /**
1301
+ * Streaming: settle nothing the next bytes can still change (verify-RC-B3 F3).
1302
+ *
1303
+ * 1. A block island that ends on the open last line is undecided — the next
1304
+ * bytes on that line can re-read it or dissolve it (`<!--@a:k1-->` +
1305
+ * ` more` is an inline anchor, `<br>` + `x` is prose). It runs open to
1306
+ * the end of the text.
1307
+ * 2. A box-drawing tree still forming at the end of the text claims, as its
1308
+ * root label, the lines directly above its first connector (the
1309
+ * renderer's `findTreeBlockStart`), and the open last line itself may
1310
+ * become one of its connector lines — so inlines on those lines are held
1311
+ * back as prose until a blank line, a heading or a tree line decides.
1312
+ * This also holds everything a closer still able to arrive on the open
1313
+ * last line could change (`$x$` + `5` is currency, G4; `{{v}}` + `}`).
1314
+ */
1315
+ holdUndecidedTail() {
1316
+ const last = this.lineStarts.length - 1;
1317
+ if (last < 0) return;
1318
+ if (this.isOpenTail(last)) {
1319
+ const lineStart = this.lineStarts[last];
1320
+ for (const block2 of this.blocks) {
1321
+ if (block2.kind === "prose" && block2.end > lineStart) {
1322
+ block2.inlines = block2.inlines.filter((inline) => inline.end <= lineStart);
1323
+ }
1324
+ }
1325
+ let b = this.blocks.length - 1;
1326
+ while (b >= 0 && this.blocks[b].kind === "gap") b--;
1327
+ const block = this.blocks[b];
1328
+ if (block?.island?.complete && block.island.end > this.lineStarts[last]) {
1329
+ block.island.complete = false;
1330
+ block.island.end = this.n;
1331
+ block.end = this.n;
1332
+ this.blocks.length = b + 1;
1333
+ }
1334
+ }
1335
+ const from = this.treeRootHoldFrom();
1336
+ for (let b = this.blocks.length - 1; b >= 0; b--) {
1337
+ const block = this.blocks[b];
1338
+ if (block.end <= from) break;
1339
+ if (block.kind === "prose") block.inlines = block.inlines.filter((inline) => inline.end <= from);
1340
+ if (block.island) this.blocks[b] = { kind: "prose", start: block.start, end: block.end, island: null, inlines: [] };
1341
+ }
1342
+ }
1343
+ /**
1344
+ * Streaming: where a tree that may still form at the end of the text would
1345
+ * start claiming lines (`n` when none can). Only paragraph lines can be
1346
+ * claimed — a line that starts inside an island (a fence body, an XML
1347
+ * region…) is never a tree line nor a root label, so it stops the walk.
1348
+ */
1349
+ treeRootHoldFrom() {
1350
+ const claimable = (k2) => {
1351
+ for (; ; ) {
1352
+ const block = this.blockAt(this.lineStarts[k2]);
1353
+ if (!block || block.kind !== "island" || block.island?.fromParagraph === true) return true;
1354
+ const opened = this.lineOf(block.start);
1355
+ if (this.lineStarts[opened] === block.start || opened === k2) return false;
1356
+ k2 = opened;
1357
+ }
1358
+ };
1359
+ let k = this.lineCount - 1;
1360
+ let start = this.lineCount;
1361
+ if (k >= 0 && this.isOpenTail(k)) {
1362
+ if (!claimable(k)) return this.n;
1363
+ start = k;
1364
+ k--;
1365
+ }
1366
+ for (; k >= 0 && claimable(k); k--) {
1367
+ this.tick(1);
1368
+ if (this.lineIsBlank(k)) continue;
1369
+ if (!TREE_GLYPHS.test(this.lineText(k))) break;
1370
+ start = k;
1371
+ }
1372
+ let root = start;
1373
+ for (let j = start - 1; j >= 0 && claimable(j); j--) {
1374
+ const trimmed = this.lineText(j).trim();
1375
+ this.tick(trimmed.length + 1);
1376
+ if (!trimmed || isSplitterTreeLine(trimmed) || /^#{1,6}\s/.test(trimmed)) break;
1377
+ root = j;
1378
+ }
1379
+ return root < this.lineCount ? this.lineStarts[root] : this.n;
1380
+ }
1381
+ /** The block (so far) containing offset `pos`, or null. */
1382
+ blockAt(pos) {
1383
+ let lo = 0;
1384
+ let hi = this.blocks.length - 1;
1385
+ while (lo <= hi) {
1386
+ const mid = lo + hi >>> 1;
1387
+ const block = this.blocks[mid];
1388
+ if (pos < block.start) hi = mid - 1;
1389
+ else if (pos >= block.end) lo = mid + 1;
1390
+ else return block;
1391
+ }
1392
+ return null;
1393
+ }
1270
1394
  push(block) {
1271
1395
  if (block.end <= block.start) return;
1272
1396
  if (block.kind === "prose" && this.isBlank(block.start, block.end)) {
@@ -1470,7 +1594,10 @@ var Tokenizer = class {
1470
1594
  continue;
1471
1595
  }
1472
1596
  if (this.isOpenTail(k)) return this.heldFootnote(p, open[1]);
1473
- if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
1597
+ if (FOOTNOTE_DEF.test(line.trimStart())) break;
1598
+ const block = this.detectBlock(this.lineStarts[k], k, false);
1599
+ if (block && this.mayDissolve(block)) return this.heldFootnote(p, open[1]);
1600
+ if (block) break;
1474
1601
  last = k;
1475
1602
  }
1476
1603
  const end = this.contentEnds[last];
@@ -1486,7 +1613,8 @@ var Tokenizer = class {
1486
1613
  return {
1487
1614
  count: this.lineCount,
1488
1615
  line: (k) => this.lineText(k),
1489
- openTail: (k) => this.isOpenTail(k)
1616
+ openTail: (k) => this.isOpenTail(k),
1617
+ streaming: this.streaming
1490
1618
  };
1491
1619
  }
1492
1620
  /**
@@ -1546,6 +1674,10 @@ var Tokenizer = class {
1546
1674
  if (fenceOpenerOf(this.lineText(j))?.char === "~") continue;
1547
1675
  const inner = this.detectBlockUncached(start, j, false);
1548
1676
  if (!inner) continue;
1677
+ if (this.streaming && inner.end >= tildeEnd && this.paragraphMayGrow(inner.end)) {
1678
+ this.overflowComplete = false;
1679
+ return this.n;
1680
+ }
1549
1681
  if (inner.end > end) {
1550
1682
  end = inner.end;
1551
1683
  this.overflowComplete = inner.complete;
@@ -1674,12 +1806,7 @@ var Tokenizer = class {
1674
1806
  return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
1675
1807
  }
1676
1808
  const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
1677
- const loneTag = atParaStart && t.trimEnd() === tag.raw;
1678
- if (loneTag && this.isOpenTail(li)) {
1679
- this.provisionalFrom = Math.min(this.provisionalFrom, p);
1680
- return null;
1681
- }
1682
- const typeSeven = loneTag;
1809
+ const typeSeven = atParaStart && t.trimEnd() === tag.raw;
1683
1810
  if (!typeSix && !typeSeven) return null;
1684
1811
  let end = this.contentEnds[li];
1685
1812
  for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
@@ -1737,6 +1864,13 @@ var Tokenizer = class {
1737
1864
  }
1738
1865
  return null;
1739
1866
  }
1867
+ if (this.isOpenTail(lastLine)) {
1868
+ if (isRecognizedJsonHead(this.text.slice(tp, tp + 512))) {
1869
+ return this.island("json", p, this.n, false, jsonMeta(this.text.slice(tp)));
1870
+ }
1871
+ this.provisionalFrom = Math.min(this.provisionalFrom, p);
1872
+ return null;
1873
+ }
1740
1874
  if (net !== 0) return null;
1741
1875
  const end = this.contentEnds[lastLine];
1742
1876
  const content = this.text.slice(tp, end).trim();
@@ -1771,8 +1905,10 @@ var Tokenizer = class {
1771
1905
  let breakLine = -1;
1772
1906
  for (let k = li + 1; k < this.lineCount; k++) {
1773
1907
  if (this.lineIsBlank(k)) break;
1774
- if (this.detectBlock(this.lineStarts[k], k, false)) {
1908
+ const block = this.detectBlock(this.lineStarts[k], k, false);
1909
+ if (block) {
1775
1910
  breakLine = k;
1911
+ if (this.mayDissolve(block)) this.undecidedBreaks.add(end);
1776
1912
  break;
1777
1913
  }
1778
1914
  end = this.contentEnds[k];
@@ -1810,7 +1946,7 @@ var Tokenizer = class {
1810
1946
  this.push({ kind: "prose", start: pos, end, island: null, inlines: scan2.inlines });
1811
1947
  return end;
1812
1948
  }
1813
- const br = scan2.breakIsland;
1949
+ const br = { ...scan2.breakIsland, fromParagraph: true };
1814
1950
  if (scan2.orphan) {
1815
1951
  let start = pos;
1816
1952
  while (this.blocks.length) {
@@ -1833,6 +1969,15 @@ var Tokenizer = class {
1833
1969
  this.push({ kind: "island", start: br.start, end: br.end, island: br, inlines: [] });
1834
1970
  return br.end;
1835
1971
  }
1972
+ /**
1973
+ * An island that opens inside a paragraph and closes past its end becomes a
1974
+ * block. Streaming: while the paragraph may still grow over its closer, the
1975
+ * island may yet be inline — undecided, so it runs open to the end (F3).
1976
+ */
1977
+ spill(type, start, end, pe, meta) {
1978
+ if (this.paragraphMayGrow(pe)) return this.island(type, start, this.n, false, meta);
1979
+ return this.island(type, start, end, true, meta);
1980
+ }
1836
1981
  scanInline(ps, pe) {
1837
1982
  const text = this.text;
1838
1983
  const inlines = [];
@@ -1867,6 +2012,9 @@ var Tokenizer = class {
1867
2012
  i = close + 2;
1868
2013
  continue;
1869
2014
  }
2015
+ if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
2016
+ return { inlines, breakIsland: null, orphan: false };
2017
+ }
1870
2018
  }
1871
2019
  i += 2;
1872
2020
  continue;
@@ -1887,17 +2035,13 @@ var Tokenizer = class {
1887
2035
  i += 2;
1888
2036
  continue;
1889
2037
  }
1890
- if (close + 2 > pe) return stop(this.island("math_block", i, close + 2, true, { delimiter: "$$" }));
2038
+ if (close + 2 > pe) return stop(this.spill("math_block", i, close + 2, pe, { delimiter: "$$" }));
1891
2039
  inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: "$$" }));
1892
2040
  i = close + 2;
1893
2041
  continue;
1894
2042
  }
1895
2043
  const end = singleDollarMathEnd(text, i, pe);
1896
2044
  this.tick(end > 0 ? end - i : Math.min(403, pe - i));
1897
- if (end > 0 && this.streaming && end === this.n) {
1898
- this.provisionalFrom = Math.min(this.provisionalFrom, i);
1899
- return { inlines, breakIsland: null, orphan: false };
1900
- }
1901
2045
  if (end > 0) {
1902
2046
  inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
1903
2047
  i = end;
@@ -1975,7 +2119,7 @@ var Tokenizer = class {
1975
2119
  const anchor = end - i <= 64 ? PINNED_ANCHOR_RE.exec(text.slice(i, end)) : null;
1976
2120
  const type = anchor ? "anchor" : "html_comment";
1977
2121
  const meta = anchor ? { id: anchor[1] } : {};
1978
- if (end > pe) return stop(this.island(type, i, end, true, meta));
2122
+ if (end > pe) return stop(this.spill(type, i, end, pe, meta));
1979
2123
  inlines.push(this.island(type, i, end, true, meta));
1980
2124
  i = end;
1981
2125
  continue;
@@ -2004,7 +2148,7 @@ var Tokenizer = class {
2004
2148
  const blockType = isAttr ? "xml_attr" : "xml_region";
2005
2149
  if (close === -1) return stop(this.island(blockType, i, this.n, false, { tag: name }));
2006
2150
  const end = close + closer.length;
2007
- if (end > pe) return stop(this.island(blockType, i, end, true, { tag: name }));
2151
+ if (end > pe) return stop(this.spill(blockType, i, end, pe, { tag: name }));
2008
2152
  inlines.push(this.island("xml_inline", i, end, true, { tag: name }));
2009
2153
  i = end;
2010
2154
  continue;
@@ -2389,6 +2533,6 @@ function mapRange(changes, start, end, unit = "utf16") {
2389
2533
  return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
2390
2534
  }
2391
2535
 
2392
- export { BacktickRuns, CALLOUT_NAMES, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, FenceReader, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
2536
+ export { AFTER_WINDOW, BacktickRuns, CALLOUT_NAMES, FENCE_OPENER_WHITESPACE, FENCE_WHITESPACE, FenceReader, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, closeFence, codeSpanText, fenceLineKinds, fenceNestsInnerFences, fenceOpenerOf, fenceParts, findCodeRanges, isEscapedBracketMath, isMathPlaceholder, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, looksLikeOpenInlineMath, mapCodeRanges, mapPosition, mapRange, pairDisplayMath, parseFenceOpener, pendingDisplayMathOpener, readXmlTag, singleDollarAfter, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
2393
2537
  //# sourceMappingURL=source.js.map
2394
2538
  //# sourceMappingURL=source.js.map