@ai-matrx/content-ir 0.18.3 → 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/CHANGELOG.md +28 -0
- package/dist/index.cjs +184 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +182 -31
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +184 -30
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +37 -2
- package/dist/source.d.ts +37 -2
- package/dist/source.js +182 -31
- package/dist/source.js.map +1 -1
- package/package.json +1 -1
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,7 +355,28 @@ 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;
|
|
367
|
+
/**
|
|
368
|
+
* THE escaped-bracket rule — whether a closed `\[ … \]` is display math or
|
|
369
|
+
* CommonMark's escaped brackets (literal `[ … ]`). The tokenizer, the
|
|
370
|
+
* renderer's normalizer and the editor all ask it.
|
|
371
|
+
*
|
|
372
|
+
* Math only when the content is real TeX (BRACKET_TEX_SIGNAL) and the `\[`
|
|
373
|
+
* is not an index on an identifier (`arr\[i+1\]`, `f(x)\[k\]`).
|
|
374
|
+
* Everything a person writes with escaped brackets stays text: citations
|
|
375
|
+
* `\[1\]`, dates `\[2026-09-25\]`, task boxes `- \[x\]`, editorial
|
|
376
|
+
* insertions `\[was\]`, placeholders `\[site name\]` (verify-RC-B4 R3-2).
|
|
377
|
+
* `before` is the character just before the `\[` (undefined at the start).
|
|
378
|
+
*/
|
|
379
|
+
declare function isEscapedBracketMath(content: string, before: string | undefined): boolean;
|
|
352
380
|
|
|
353
381
|
interface ReadXmlTag {
|
|
354
382
|
tagName: string;
|
|
@@ -463,6 +491,13 @@ interface FenceLines {
|
|
|
463
491
|
line(k: number): string | null;
|
|
464
492
|
/** Streaming: line `k` has not ended yet, so it closes nothing. */
|
|
465
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;
|
|
466
501
|
}
|
|
467
502
|
interface FenceEnd {
|
|
468
503
|
/** The closing line when `closed`; otherwise the fence's last line (text end, or the line before its container ended). */
|
|
@@ -572,4 +607,4 @@ declare function pendingDisplayMathOpener(text: string): number;
|
|
|
572
607
|
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
573
608
|
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
574
609
|
|
|
575
|
-
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, 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,7 +355,28 @@ 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;
|
|
367
|
+
/**
|
|
368
|
+
* THE escaped-bracket rule — whether a closed `\[ … \]` is display math or
|
|
369
|
+
* CommonMark's escaped brackets (literal `[ … ]`). The tokenizer, the
|
|
370
|
+
* renderer's normalizer and the editor all ask it.
|
|
371
|
+
*
|
|
372
|
+
* Math only when the content is real TeX (BRACKET_TEX_SIGNAL) and the `\[`
|
|
373
|
+
* is not an index on an identifier (`arr\[i+1\]`, `f(x)\[k\]`).
|
|
374
|
+
* Everything a person writes with escaped brackets stays text: citations
|
|
375
|
+
* `\[1\]`, dates `\[2026-09-25\]`, task boxes `- \[x\]`, editorial
|
|
376
|
+
* insertions `\[was\]`, placeholders `\[site name\]` (verify-RC-B4 R3-2).
|
|
377
|
+
* `before` is the character just before the `\[` (undefined at the start).
|
|
378
|
+
*/
|
|
379
|
+
declare function isEscapedBracketMath(content: string, before: string | undefined): boolean;
|
|
352
380
|
|
|
353
381
|
interface ReadXmlTag {
|
|
354
382
|
tagName: string;
|
|
@@ -463,6 +491,13 @@ interface FenceLines {
|
|
|
463
491
|
line(k: number): string | null;
|
|
464
492
|
/** Streaming: line `k` has not ended yet, so it closes nothing. */
|
|
465
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;
|
|
466
501
|
}
|
|
467
502
|
interface FenceEnd {
|
|
468
503
|
/** The closing line when `closed`; otherwise the fence's last line (text end, or the line before its container ended). */
|
|
@@ -572,4 +607,4 @@ declare function pendingDisplayMathOpener(text: string): number;
|
|
|
572
607
|
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
573
608
|
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
574
609
|
|
|
575
|
-
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, 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 &&
|
|
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 &&
|
|
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,13 @@ 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
|
|
822
|
+
return isSingleDollarMath(content, singleDollarAfter(text, close)) ? close + 1 : -1;
|
|
823
|
+
}
|
|
824
|
+
var BRACKET_TEX_SIGNAL = /\\[A-Za-z]+|[\^{}=<>+]|_\{|(?:^|[^A-Za-z0-9])[A-Za-z]_[A-Za-z0-9](?![A-Za-z0-9])/;
|
|
825
|
+
function isEscapedBracketMath(content, before) {
|
|
826
|
+
if (!content.trim()) return false;
|
|
827
|
+
if (before !== void 0 && /[A-Za-z0-9_)\]]/.test(before)) return false;
|
|
828
|
+
return BRACKET_TEX_SIGNAL.test(content);
|
|
801
829
|
}
|
|
802
830
|
|
|
803
831
|
// source/xml-tag.ts
|
|
@@ -1162,18 +1190,14 @@ var Tokenizer = class {
|
|
|
1162
1190
|
/**
|
|
1163
1191
|
* Streaming: an open last line that begins with `{` is undecided — each new
|
|
1164
1192
|
* byte can balance or unbalance its braces and flip the whole line between
|
|
1165
|
-
* prose and a JSON island —
|
|
1166
|
-
* HTML tag
|
|
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}.)
|
|
1167
1195
|
*/
|
|
1168
1196
|
markOpenJsonTail() {
|
|
1169
1197
|
const last = this.lineStarts.length - 1;
|
|
1170
1198
|
if (!this.isOpenTail(last)) return;
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
const oneTag = t.startsWith("<") ? readXmlTag(t, 0) : null;
|
|
1174
|
-
const loneTag = !!oneTag && oneTag.raw === t && ALLOWED_RAW_HTML_TAGS.has(oneTag.tagName.toLowerCase());
|
|
1175
|
-
if (t.startsWith("{") || loneTag) {
|
|
1176
|
-
this.provisionalFrom = Math.min(this.provisionalFrom, start);
|
|
1199
|
+
if (this.lineText(last).trim().startsWith("{")) {
|
|
1200
|
+
this.provisionalFrom = Math.min(this.provisionalFrom, this.lineStarts[last]);
|
|
1177
1201
|
}
|
|
1178
1202
|
}
|
|
1179
1203
|
/**
|
|
@@ -1206,11 +1230,22 @@ var Tokenizer = class {
|
|
|
1206
1230
|
/** Streaming only: a paragraph ending at `pe` may still be continued by a line not yet arrived. */
|
|
1207
1231
|
paragraphMayGrow(pe) {
|
|
1208
1232
|
if (!this.streaming) return false;
|
|
1233
|
+
if (this.undecidedBreaks.has(pe)) return true;
|
|
1209
1234
|
const rest = this.n - pe;
|
|
1210
1235
|
if (rest === 0) return true;
|
|
1211
1236
|
const tail = this.text.slice(pe);
|
|
1212
|
-
return
|
|
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");
|
|
1213
1246
|
}
|
|
1247
|
+
/** Streaming: paragraph ends where an undecided, dissolvable block cut them short. */
|
|
1248
|
+
undecidedBreaks = /* @__PURE__ */ new Set();
|
|
1214
1249
|
/** Streaming only: the final line, still waiting for its terminator. */
|
|
1215
1250
|
isOpenTail(k) {
|
|
1216
1251
|
return this.streaming && k === this.lineStarts.length - 1 && (this.lineEnds[k] === this.contentEnds[k] || this.pendingCR);
|
|
@@ -1259,8 +1294,103 @@ var Tokenizer = class {
|
|
|
1259
1294
|
}
|
|
1260
1295
|
pos = this.paragraph(pos, li);
|
|
1261
1296
|
}
|
|
1297
|
+
if (this.streaming) this.holdUndecidedTail();
|
|
1262
1298
|
return this.blocks;
|
|
1263
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
|
+
}
|
|
1264
1394
|
push(block) {
|
|
1265
1395
|
if (block.end <= block.start) return;
|
|
1266
1396
|
if (block.kind === "prose" && this.isBlank(block.start, block.end)) {
|
|
@@ -1464,7 +1594,10 @@ var Tokenizer = class {
|
|
|
1464
1594
|
continue;
|
|
1465
1595
|
}
|
|
1466
1596
|
if (this.isOpenTail(k)) return this.heldFootnote(p, open[1]);
|
|
1467
|
-
if (FOOTNOTE_DEF.test(line.trimStart())
|
|
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;
|
|
1468
1601
|
last = k;
|
|
1469
1602
|
}
|
|
1470
1603
|
const end = this.contentEnds[last];
|
|
@@ -1480,7 +1613,8 @@ var Tokenizer = class {
|
|
|
1480
1613
|
return {
|
|
1481
1614
|
count: this.lineCount,
|
|
1482
1615
|
line: (k) => this.lineText(k),
|
|
1483
|
-
openTail: (k) => this.isOpenTail(k)
|
|
1616
|
+
openTail: (k) => this.isOpenTail(k),
|
|
1617
|
+
streaming: this.streaming
|
|
1484
1618
|
};
|
|
1485
1619
|
}
|
|
1486
1620
|
/**
|
|
@@ -1540,6 +1674,10 @@ var Tokenizer = class {
|
|
|
1540
1674
|
if (fenceOpenerOf(this.lineText(j))?.char === "~") continue;
|
|
1541
1675
|
const inner = this.detectBlockUncached(start, j, false);
|
|
1542
1676
|
if (!inner) continue;
|
|
1677
|
+
if (this.streaming && inner.end >= tildeEnd && this.paragraphMayGrow(inner.end)) {
|
|
1678
|
+
this.overflowComplete = false;
|
|
1679
|
+
return this.n;
|
|
1680
|
+
}
|
|
1543
1681
|
if (inner.end > end) {
|
|
1544
1682
|
end = inner.end;
|
|
1545
1683
|
this.overflowComplete = inner.complete;
|
|
@@ -1668,12 +1806,7 @@ var Tokenizer = class {
|
|
|
1668
1806
|
return this.island("html_block", p, close.index + close[0].length, true, { tag: name });
|
|
1669
1807
|
}
|
|
1670
1808
|
const typeSix = HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
1671
|
-
const
|
|
1672
|
-
if (loneTag && this.isOpenTail(li)) {
|
|
1673
|
-
this.provisionalFrom = Math.min(this.provisionalFrom, p);
|
|
1674
|
-
return null;
|
|
1675
|
-
}
|
|
1676
|
-
const typeSeven = loneTag;
|
|
1809
|
+
const typeSeven = atParaStart && t.trimEnd() === tag.raw;
|
|
1677
1810
|
if (!typeSix && !typeSeven) return null;
|
|
1678
1811
|
let end = this.contentEnds[li];
|
|
1679
1812
|
for (let k = li + 1; k < this.lineCount && !this.lineIsBlank(k); k++) {
|
|
@@ -1731,6 +1864,13 @@ var Tokenizer = class {
|
|
|
1731
1864
|
}
|
|
1732
1865
|
return null;
|
|
1733
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
|
+
}
|
|
1734
1874
|
if (net !== 0) return null;
|
|
1735
1875
|
const end = this.contentEnds[lastLine];
|
|
1736
1876
|
const content = this.text.slice(tp, end).trim();
|
|
@@ -1765,8 +1905,10 @@ var Tokenizer = class {
|
|
|
1765
1905
|
let breakLine = -1;
|
|
1766
1906
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1767
1907
|
if (this.lineIsBlank(k)) break;
|
|
1768
|
-
|
|
1908
|
+
const block = this.detectBlock(this.lineStarts[k], k, false);
|
|
1909
|
+
if (block) {
|
|
1769
1910
|
breakLine = k;
|
|
1911
|
+
if (this.mayDissolve(block)) this.undecidedBreaks.add(end);
|
|
1770
1912
|
break;
|
|
1771
1913
|
}
|
|
1772
1914
|
end = this.contentEnds[k];
|
|
@@ -1804,7 +1946,7 @@ var Tokenizer = class {
|
|
|
1804
1946
|
this.push({ kind: "prose", start: pos, end, island: null, inlines: scan2.inlines });
|
|
1805
1947
|
return end;
|
|
1806
1948
|
}
|
|
1807
|
-
const br = scan2.breakIsland;
|
|
1949
|
+
const br = { ...scan2.breakIsland, fromParagraph: true };
|
|
1808
1950
|
if (scan2.orphan) {
|
|
1809
1951
|
let start = pos;
|
|
1810
1952
|
while (this.blocks.length) {
|
|
@@ -1827,6 +1969,15 @@ var Tokenizer = class {
|
|
|
1827
1969
|
this.push({ kind: "island", start: br.start, end: br.end, island: br, inlines: [] });
|
|
1828
1970
|
return br.end;
|
|
1829
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
|
+
}
|
|
1830
1981
|
scanInline(ps, pe) {
|
|
1831
1982
|
const text = this.text;
|
|
1832
1983
|
const inlines = [];
|
|
@@ -1855,11 +2006,15 @@ var Tokenizer = class {
|
|
|
1855
2006
|
const nextCh = text[i + 1];
|
|
1856
2007
|
if (nextCh === "(" || nextCh === "[") {
|
|
1857
2008
|
const close = within(nextCh === "(" ? "\\)" : "\\]", i + 2);
|
|
1858
|
-
|
|
2009
|
+
const isMath = close !== -1 && (nextCh === "(" || isEscapedBracketMath(text.slice(i + 2, close), i > 0 ? text[i - 1] : void 0));
|
|
2010
|
+
if (close !== -1 && isMath) {
|
|
1859
2011
|
inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: nextCh === "(" ? "\\(" : "\\[" }));
|
|
1860
2012
|
i = close + 2;
|
|
1861
2013
|
continue;
|
|
1862
2014
|
}
|
|
2015
|
+
if (close === -1 && this.streaming && this.paragraphMayGrow(pe)) {
|
|
2016
|
+
return { inlines, breakIsland: null, orphan: false };
|
|
2017
|
+
}
|
|
1863
2018
|
}
|
|
1864
2019
|
i += 2;
|
|
1865
2020
|
continue;
|
|
@@ -1880,17 +2035,13 @@ var Tokenizer = class {
|
|
|
1880
2035
|
i += 2;
|
|
1881
2036
|
continue;
|
|
1882
2037
|
}
|
|
1883
|
-
if (close + 2 > pe) return stop(this.
|
|
2038
|
+
if (close + 2 > pe) return stop(this.spill("math_block", i, close + 2, pe, { delimiter: "$$" }));
|
|
1884
2039
|
inlines.push(this.island("math_inline", i, close + 2, true, { delimiter: "$$" }));
|
|
1885
2040
|
i = close + 2;
|
|
1886
2041
|
continue;
|
|
1887
2042
|
}
|
|
1888
2043
|
const end = singleDollarMathEnd(text, i, pe);
|
|
1889
2044
|
this.tick(end > 0 ? end - i : Math.min(403, pe - i));
|
|
1890
|
-
if (end > 0 && this.streaming && end === this.n) {
|
|
1891
|
-
this.provisionalFrom = Math.min(this.provisionalFrom, i);
|
|
1892
|
-
return { inlines, breakIsland: null, orphan: false };
|
|
1893
|
-
}
|
|
1894
2045
|
if (end > 0) {
|
|
1895
2046
|
inlines.push(this.island("math_inline", i, end, true, { delimiter: "$" }));
|
|
1896
2047
|
i = end;
|
|
@@ -1968,7 +2119,7 @@ var Tokenizer = class {
|
|
|
1968
2119
|
const anchor = end - i <= 64 ? PINNED_ANCHOR_RE.exec(text.slice(i, end)) : null;
|
|
1969
2120
|
const type = anchor ? "anchor" : "html_comment";
|
|
1970
2121
|
const meta = anchor ? { id: anchor[1] } : {};
|
|
1971
|
-
if (end > pe) return stop(this.
|
|
2122
|
+
if (end > pe) return stop(this.spill(type, i, end, pe, meta));
|
|
1972
2123
|
inlines.push(this.island(type, i, end, true, meta));
|
|
1973
2124
|
i = end;
|
|
1974
2125
|
continue;
|
|
@@ -1997,7 +2148,7 @@ var Tokenizer = class {
|
|
|
1997
2148
|
const blockType = isAttr ? "xml_attr" : "xml_region";
|
|
1998
2149
|
if (close === -1) return stop(this.island(blockType, i, this.n, false, { tag: name }));
|
|
1999
2150
|
const end = close + closer.length;
|
|
2000
|
-
if (end > pe) return stop(this.
|
|
2151
|
+
if (end > pe) return stop(this.spill(blockType, i, end, pe, { tag: name }));
|
|
2001
2152
|
inlines.push(this.island("xml_inline", i, end, true, { tag: name }));
|
|
2002
2153
|
i = end;
|
|
2003
2154
|
continue;
|
|
@@ -2382,6 +2533,6 @@ function mapRange(changes, start, end, unit = "utf16") {
|
|
|
2382
2533
|
return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
|
|
2383
2534
|
}
|
|
2384
2535
|
|
|
2385
|
-
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, 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 };
|
|
2386
2537
|
//# sourceMappingURL=source.js.map
|
|
2387
2538
|
//# sourceMappingURL=source.js.map
|