@ai-matrx/content-ir 0.13.0 → 0.14.1
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 +85 -0
- package/dist/index.cjs +228 -20
- 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 +227 -21
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +228 -20
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +44 -8
- package/dist/source.d.ts +44 -8
- package/dist/source.js +227 -21
- package/dist/source.js.map +1 -1
- package/package.json +1 -1
package/dist/source.d.cts
CHANGED
|
@@ -51,12 +51,25 @@ type BlockIslandType =
|
|
|
51
51
|
| "anchor"
|
|
52
52
|
/** `$$ … $$` display math on its own lines. */
|
|
53
53
|
| "math_block"
|
|
54
|
-
/** YAML front matter at the start of the text. */
|
|
54
|
+
/** YAML (`---`) or TOML (`+++`) front matter at the start of the text (meta.format). */
|
|
55
55
|
| "front_matter"
|
|
56
56
|
/** A box-drawing tree diagram. */
|
|
57
|
-
| "tree"
|
|
57
|
+
| "tree"
|
|
58
|
+
/**
|
|
59
|
+
* A generic-directive container `:::name[label]{attrs}` … `:::` (tabs,
|
|
60
|
+
* columns, details, figures, callouts, TOC — meta.name), a leaf directive
|
|
61
|
+
* `::name` on its own line (meta.leaf), or a MkDocs admonition
|
|
62
|
+
* `!!! type "Title"` / `??? type` with its indented body (meta.syntax "mkdocs").
|
|
63
|
+
*/
|
|
64
|
+
| "directive"
|
|
65
|
+
/** A GitHub alert / Obsidian callout: a blockquote opening `> [!TYPE]` (meta.name). */
|
|
66
|
+
| "callout"
|
|
67
|
+
/** A footnote definition `[^id]: …` with its indented continuation lines (meta.id). */
|
|
68
|
+
| "footnote_def";
|
|
58
69
|
/** Island types that live inside a prose block. */
|
|
59
|
-
type InlineIslandType = "variable" | "cite" | "math_inline" | "html_tag" | "xml_tag" | "xml_inline" | "html_comment" | "anchor" | "kind_json" | "media_ref"
|
|
70
|
+
type InlineIslandType = "variable" | "cite" | "math_inline" | "html_tag" | "xml_tag" | "xml_inline" | "html_comment" | "anchor" | "kind_json" | "media_ref"
|
|
71
|
+
/** `[[Page]]`, `[[Page|alias]]` (meta.target) — or `![[Page]]` (meta.embed). */
|
|
72
|
+
| "wikilink";
|
|
60
73
|
type IslandType = BlockIslandType | InlineIslandType;
|
|
61
74
|
type IslandMeta = Readonly<Record<string, string | number | boolean>>;
|
|
62
75
|
interface SourceSpan {
|
|
@@ -92,7 +105,16 @@ interface SourceBlock extends SourceSpan {
|
|
|
92
105
|
* Cut `text` into blocks whose raw concatenation is exactly `text`.
|
|
93
106
|
* Never throws; unclosed constructs are islands with `complete: false`.
|
|
94
107
|
*/
|
|
95
|
-
|
|
108
|
+
interface TokenizeOptions {
|
|
109
|
+
/**
|
|
110
|
+
* The text is a prefix of a message still arriving. The final line (no
|
|
111
|
+
* terminator yet) can still grow — a bare ``` there may become ```bash — so
|
|
112
|
+
* it closes no fence until its newline arrives (verify-RC-B3 residual R2).
|
|
113
|
+
* Omit for stored text: a complete document's last line is final.
|
|
114
|
+
*/
|
|
115
|
+
readonly streaming?: boolean;
|
|
116
|
+
}
|
|
117
|
+
declare function tokenizeSource(text: string, options?: TokenizeOptions): SourceBlock[];
|
|
96
118
|
/** The exact source the blocks were cut from. */
|
|
97
119
|
declare function joinSource(blocks: readonly SourceBlock[]): string;
|
|
98
120
|
/** Every island — block-level and inline — in document order. */
|
|
@@ -272,8 +294,9 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
|
|
|
272
294
|
*
|
|
273
295
|
* Pandoc's rule — the opening `$` is not followed by whitespace, the closing
|
|
274
296
|
* `$` is not preceded by whitespace and not followed by a digit — plus a math
|
|
275
|
-
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …),
|
|
276
|
-
* lone variable (`$x$`, `$n$`, `$x'$`)
|
|
297
|
+
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …), a
|
|
298
|
+
* lone variable (`$x$`, `$n$`, `$x'$`), or a single-letter math shape
|
|
299
|
+
* (`$f(g(x))$`, `$u v$`, `$f'(x)$` — see `isMathShape`). Content that opens with a digit needs
|
|
277
300
|
* a real TeX signal, so a price range can never read as math.
|
|
278
301
|
*/
|
|
279
302
|
declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
|
|
@@ -342,13 +365,26 @@ type InnerFenceLine =
|
|
|
342
365
|
/** Bare ``` that closes the OUTER fence. */
|
|
343
366
|
| "close-outer";
|
|
344
367
|
/**
|
|
345
|
-
* Classify one
|
|
368
|
+
* Classify one line inside an open backtick fence, already trimmed with
|
|
369
|
+
* {@link trimFenceLine} (never a language's own `trim()`).
|
|
346
370
|
*
|
|
347
371
|
* @param trimmed the line with surrounding whitespace removed
|
|
348
372
|
* @param openTicks backtick count of the outer fence's opener
|
|
349
373
|
* @param nests whether the outer fence follows the nesting rule
|
|
350
374
|
* @param nestedDepth how many nested fences are open right now
|
|
351
375
|
*/
|
|
376
|
+
/**
|
|
377
|
+
* The whitespace a fence line may carry around its backticks and info string:
|
|
378
|
+
* CommonMark's ASCII whitespace — space, tab, LF, CR, form feed, vertical tab.
|
|
379
|
+
* Defined HERE, not by a language's `trim()`: JavaScript's `trim()` also strips
|
|
380
|
+
* U+FEFF, U+00A0 and the Unicode spaces, while Python's `strip()` also strips
|
|
381
|
+
* U+0085 and U+001C–U+001F — which made the two twins disagree on lines such
|
|
382
|
+
* as ```` ```\uFEFF ```` (verify-RC-B3 residual R4). Every caller trims a line
|
|
383
|
+
* with `trimFenceLine` before classifying it; the Python twin mirrors both.
|
|
384
|
+
*/
|
|
385
|
+
declare const FENCE_WHITESPACE = " \t\n\r\f\v";
|
|
386
|
+
/** Strip {@link FENCE_WHITESPACE} (and nothing else) from both ends of a line. */
|
|
387
|
+
declare function trimFenceLine(line: string): string;
|
|
352
388
|
declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
|
|
353
389
|
|
|
354
390
|
/**
|
|
@@ -371,4 +407,4 @@ declare function looksLikeDisplayMath(inner: string): boolean;
|
|
|
371
407
|
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
372
408
|
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
373
409
|
|
|
374
|
-
export { type BlockIslandType, type CodePointIndex, type DisturbedIsland, 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, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource };
|
|
410
|
+
export { type BlockIslandType, type CodePointIndex, type DisturbedIsland, FENCE_WHITESPACE, 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, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
|
package/dist/source.d.ts
CHANGED
|
@@ -51,12 +51,25 @@ type BlockIslandType =
|
|
|
51
51
|
| "anchor"
|
|
52
52
|
/** `$$ … $$` display math on its own lines. */
|
|
53
53
|
| "math_block"
|
|
54
|
-
/** YAML front matter at the start of the text. */
|
|
54
|
+
/** YAML (`---`) or TOML (`+++`) front matter at the start of the text (meta.format). */
|
|
55
55
|
| "front_matter"
|
|
56
56
|
/** A box-drawing tree diagram. */
|
|
57
|
-
| "tree"
|
|
57
|
+
| "tree"
|
|
58
|
+
/**
|
|
59
|
+
* A generic-directive container `:::name[label]{attrs}` … `:::` (tabs,
|
|
60
|
+
* columns, details, figures, callouts, TOC — meta.name), a leaf directive
|
|
61
|
+
* `::name` on its own line (meta.leaf), or a MkDocs admonition
|
|
62
|
+
* `!!! type "Title"` / `??? type` with its indented body (meta.syntax "mkdocs").
|
|
63
|
+
*/
|
|
64
|
+
| "directive"
|
|
65
|
+
/** A GitHub alert / Obsidian callout: a blockquote opening `> [!TYPE]` (meta.name). */
|
|
66
|
+
| "callout"
|
|
67
|
+
/** A footnote definition `[^id]: …` with its indented continuation lines (meta.id). */
|
|
68
|
+
| "footnote_def";
|
|
58
69
|
/** Island types that live inside a prose block. */
|
|
59
|
-
type InlineIslandType = "variable" | "cite" | "math_inline" | "html_tag" | "xml_tag" | "xml_inline" | "html_comment" | "anchor" | "kind_json" | "media_ref"
|
|
70
|
+
type InlineIslandType = "variable" | "cite" | "math_inline" | "html_tag" | "xml_tag" | "xml_inline" | "html_comment" | "anchor" | "kind_json" | "media_ref"
|
|
71
|
+
/** `[[Page]]`, `[[Page|alias]]` (meta.target) — or `![[Page]]` (meta.embed). */
|
|
72
|
+
| "wikilink";
|
|
60
73
|
type IslandType = BlockIslandType | InlineIslandType;
|
|
61
74
|
type IslandMeta = Readonly<Record<string, string | number | boolean>>;
|
|
62
75
|
interface SourceSpan {
|
|
@@ -92,7 +105,16 @@ interface SourceBlock extends SourceSpan {
|
|
|
92
105
|
* Cut `text` into blocks whose raw concatenation is exactly `text`.
|
|
93
106
|
* Never throws; unclosed constructs are islands with `complete: false`.
|
|
94
107
|
*/
|
|
95
|
-
|
|
108
|
+
interface TokenizeOptions {
|
|
109
|
+
/**
|
|
110
|
+
* The text is a prefix of a message still arriving. The final line (no
|
|
111
|
+
* terminator yet) can still grow — a bare ``` there may become ```bash — so
|
|
112
|
+
* it closes no fence until its newline arrives (verify-RC-B3 residual R2).
|
|
113
|
+
* Omit for stored text: a complete document's last line is final.
|
|
114
|
+
*/
|
|
115
|
+
readonly streaming?: boolean;
|
|
116
|
+
}
|
|
117
|
+
declare function tokenizeSource(text: string, options?: TokenizeOptions): SourceBlock[];
|
|
96
118
|
/** The exact source the blocks were cut from. */
|
|
97
119
|
declare function joinSource(blocks: readonly SourceBlock[]): string;
|
|
98
120
|
/** Every island — block-level and inline — in document order. */
|
|
@@ -272,8 +294,9 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
|
|
|
272
294
|
*
|
|
273
295
|
* Pandoc's rule — the opening `$` is not followed by whitespace, the closing
|
|
274
296
|
* `$` is not preceded by whitespace and not followed by a digit — plus a math
|
|
275
|
-
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …),
|
|
276
|
-
* lone variable (`$x$`, `$n$`, `$x'$`)
|
|
297
|
+
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …), a
|
|
298
|
+
* lone variable (`$x$`, `$n$`, `$x'$`), or a single-letter math shape
|
|
299
|
+
* (`$f(g(x))$`, `$u v$`, `$f'(x)$` — see `isMathShape`). Content that opens with a digit needs
|
|
277
300
|
* a real TeX signal, so a price range can never read as math.
|
|
278
301
|
*/
|
|
279
302
|
declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
|
|
@@ -342,13 +365,26 @@ type InnerFenceLine =
|
|
|
342
365
|
/** Bare ``` that closes the OUTER fence. */
|
|
343
366
|
| "close-outer";
|
|
344
367
|
/**
|
|
345
|
-
* Classify one
|
|
368
|
+
* Classify one line inside an open backtick fence, already trimmed with
|
|
369
|
+
* {@link trimFenceLine} (never a language's own `trim()`).
|
|
346
370
|
*
|
|
347
371
|
* @param trimmed the line with surrounding whitespace removed
|
|
348
372
|
* @param openTicks backtick count of the outer fence's opener
|
|
349
373
|
* @param nests whether the outer fence follows the nesting rule
|
|
350
374
|
* @param nestedDepth how many nested fences are open right now
|
|
351
375
|
*/
|
|
376
|
+
/**
|
|
377
|
+
* The whitespace a fence line may carry around its backticks and info string:
|
|
378
|
+
* CommonMark's ASCII whitespace — space, tab, LF, CR, form feed, vertical tab.
|
|
379
|
+
* Defined HERE, not by a language's `trim()`: JavaScript's `trim()` also strips
|
|
380
|
+
* U+FEFF, U+00A0 and the Unicode spaces, while Python's `strip()` also strips
|
|
381
|
+
* U+0085 and U+001C–U+001F — which made the two twins disagree on lines such
|
|
382
|
+
* as ```` ```\uFEFF ```` (verify-RC-B3 residual R4). Every caller trims a line
|
|
383
|
+
* with `trimFenceLine` before classifying it; the Python twin mirrors both.
|
|
384
|
+
*/
|
|
385
|
+
declare const FENCE_WHITESPACE = " \t\n\r\f\v";
|
|
386
|
+
/** Strip {@link FENCE_WHITESPACE} (and nothing else) from both ends of a line. */
|
|
387
|
+
declare function trimFenceLine(line: string): string;
|
|
352
388
|
declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
|
|
353
389
|
|
|
354
390
|
/**
|
|
@@ -371,4 +407,4 @@ declare function looksLikeDisplayMath(inner: string): boolean;
|
|
|
371
407
|
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
372
408
|
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
373
409
|
|
|
374
|
-
export { type BlockIslandType, type CodePointIndex, type DisturbedIsland, 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, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource };
|
|
410
|
+
export { type BlockIslandType, type CodePointIndex, type DisturbedIsland, FENCE_WHITESPACE, 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, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
|
package/dist/source.js
CHANGED
|
@@ -209,11 +209,22 @@ var NESTING_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
|
209
209
|
function fenceNestsInnerFences(language) {
|
|
210
210
|
return !!language && NESTING_FENCE_LANGUAGES.has(language.toLowerCase());
|
|
211
211
|
}
|
|
212
|
+
var FENCE_WHITESPACE = " \n\r\f\v";
|
|
213
|
+
function isFenceWhitespace(ch) {
|
|
214
|
+
return ch !== void 0 && ch !== "" && FENCE_WHITESPACE.includes(ch);
|
|
215
|
+
}
|
|
216
|
+
function trimFenceLine(line) {
|
|
217
|
+
let start = 0;
|
|
218
|
+
let end = line.length;
|
|
219
|
+
while (start < end && isFenceWhitespace(line[start])) start++;
|
|
220
|
+
while (end > start && isFenceWhitespace(line[end - 1])) end--;
|
|
221
|
+
return start === 0 && end === line.length ? line : line.slice(start, end);
|
|
222
|
+
}
|
|
212
223
|
function classifyInnerFenceLine(trimmed, openTicks, nests, nestedDepth) {
|
|
213
224
|
let ticks = 0;
|
|
214
225
|
while (ticks < trimmed.length && trimmed[ticks] === "`") ticks++;
|
|
215
226
|
if (ticks < 3) return "content";
|
|
216
|
-
const info = trimmed.slice(ticks)
|
|
227
|
+
const info = trimFenceLine(trimmed.slice(ticks));
|
|
217
228
|
if (info === "") {
|
|
218
229
|
if (ticks < openTicks) return "content";
|
|
219
230
|
if (nests && nestedDepth > 0) return "close-nested";
|
|
@@ -226,13 +237,43 @@ function classifyInnerFenceLine(trimmed, openTicks, nests, nestedDepth) {
|
|
|
226
237
|
// source/math.ts
|
|
227
238
|
var TEX_SIGNAL = /\\[A-Za-z]+|[\\^_{}=<>+]/;
|
|
228
239
|
var LONE_VARIABLE = /^[A-Za-z](?:'|[0-9])?$/;
|
|
240
|
+
var MATH_SHAPE_CHARS = /^[A-Za-z0-9'\s(),.*\/-]+$/;
|
|
241
|
+
var FUNCTION_NAMES = /* @__PURE__ */ new Set([
|
|
242
|
+
"sin",
|
|
243
|
+
"cos",
|
|
244
|
+
"tan",
|
|
245
|
+
"sec",
|
|
246
|
+
"csc",
|
|
247
|
+
"cot",
|
|
248
|
+
"log",
|
|
249
|
+
"ln",
|
|
250
|
+
"exp",
|
|
251
|
+
"lim",
|
|
252
|
+
"max",
|
|
253
|
+
"min",
|
|
254
|
+
"det",
|
|
255
|
+
"gcd",
|
|
256
|
+
"mod",
|
|
257
|
+
"arg",
|
|
258
|
+
"sinh",
|
|
259
|
+
"cosh",
|
|
260
|
+
"tanh"
|
|
261
|
+
]);
|
|
262
|
+
function isMathShape(content) {
|
|
263
|
+
if (!MATH_SHAPE_CHARS.test(content)) return false;
|
|
264
|
+
const words = content.match(/[A-Za-z]+/g);
|
|
265
|
+
if (!words) return false;
|
|
266
|
+
if (!words.every((w) => w.length === 1 || FUNCTION_NAMES.has(w))) return false;
|
|
267
|
+
if (/[A-Za-z]'+[A-Za-z]/.test(content) || /(?:^|[\s(,])[A-Za-z]\.(?:[A-Za-z]\.|\s|$)/.test(content)) return false;
|
|
268
|
+
return /[A-Za-z]'*\(|[A-Za-z]'|\b[A-Za-z]\s+[A-Za-z]\b|\([^)]*[A-Za-z][^)]*\)/.test(content);
|
|
269
|
+
}
|
|
229
270
|
function isSingleDollarMath(content, after) {
|
|
230
271
|
if (!content || content.length > 400) return false;
|
|
231
272
|
if (/^\s/.test(content) || /\s$/.test(content)) return false;
|
|
232
273
|
if (after !== void 0 && /[0-9]/.test(after)) return false;
|
|
233
274
|
if (LONE_VARIABLE.test(content)) return true;
|
|
234
275
|
if (/^[0-9]/.test(content)) return /\\[A-Za-z]+|[\\^_{}]/.test(content);
|
|
235
|
-
return TEX_SIGNAL.test(content);
|
|
276
|
+
return TEX_SIGNAL.test(content) || isMathShape(content);
|
|
236
277
|
}
|
|
237
278
|
function singleDollarMathEnd(text, open, limit = text.length) {
|
|
238
279
|
const bound = Math.min(limit, open + 403);
|
|
@@ -468,6 +509,10 @@ var XmlContainerTracker = class {
|
|
|
468
509
|
|
|
469
510
|
// source/tokenize.ts
|
|
470
511
|
var NOT_WHITESPACE = /\S/;
|
|
512
|
+
var DIRECTIVE_OPEN = /^(:{2,})([A-Za-z][\w-]*)/;
|
|
513
|
+
var MKDOCS_OPEN = /^(!!!|\?\?\?\+?)[ \t]+([A-Za-z][\w-]*)/;
|
|
514
|
+
var CALLOUT_OPEN = /^>[ \t]*\[!([A-Za-z][\w-]*)\]([+-])?/;
|
|
515
|
+
var FOOTNOTE_DEF = /^\[\^([^\]\s]+)\]:/;
|
|
471
516
|
function countStructuralBraces(source) {
|
|
472
517
|
let opens = 0;
|
|
473
518
|
let closes = 0;
|
|
@@ -595,8 +640,9 @@ function isSplitterTreeLine(line) {
|
|
|
595
640
|
}
|
|
596
641
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
597
642
|
var Tokenizer = class {
|
|
598
|
-
constructor(text) {
|
|
643
|
+
constructor(text, streaming = false) {
|
|
599
644
|
this.text = text;
|
|
645
|
+
this.streaming = streaming;
|
|
600
646
|
this.n = text.length;
|
|
601
647
|
this.mathPairs = pairDisplayMath(text);
|
|
602
648
|
let start = 0;
|
|
@@ -615,6 +661,7 @@ var Tokenizer = class {
|
|
|
615
661
|
}
|
|
616
662
|
}
|
|
617
663
|
text;
|
|
664
|
+
streaming;
|
|
618
665
|
n;
|
|
619
666
|
lineStarts = [];
|
|
620
667
|
contentEnds = [];
|
|
@@ -652,6 +699,10 @@ var Tokenizer = class {
|
|
|
652
699
|
}
|
|
653
700
|
return lo < list.length ? list[lo] : -1;
|
|
654
701
|
}
|
|
702
|
+
/** Streaming only: the final line, still waiting for its terminator. */
|
|
703
|
+
isOpenTail(k) {
|
|
704
|
+
return this.streaming && k === this.lineStarts.length - 1 && this.lineEnds[k] === this.contentEnds[k];
|
|
705
|
+
}
|
|
655
706
|
get lineCount() {
|
|
656
707
|
return this.lineStarts.length;
|
|
657
708
|
}
|
|
@@ -733,6 +784,22 @@ var Tokenizer = class {
|
|
|
733
784
|
const fm = this.frontMatter(li, t);
|
|
734
785
|
if (fm) return fm;
|
|
735
786
|
}
|
|
787
|
+
if (indent <= 3 && t.startsWith("::")) {
|
|
788
|
+
const directive = this.directive(p, li, t);
|
|
789
|
+
if (directive) return directive;
|
|
790
|
+
}
|
|
791
|
+
if (indent === 0 && (t.startsWith("!!!") || t.startsWith("???"))) {
|
|
792
|
+
const admonition = this.mkdocsAdmonition(p, li, t);
|
|
793
|
+
if (admonition) return admonition;
|
|
794
|
+
}
|
|
795
|
+
if (indent <= 3 && t.startsWith(">")) {
|
|
796
|
+
const callout = this.callout(p, li, t);
|
|
797
|
+
if (callout) return callout;
|
|
798
|
+
}
|
|
799
|
+
if (atParaStart && indent <= 3 && t.startsWith("[^")) {
|
|
800
|
+
const footnote = this.footnoteDefinition(p, li, t);
|
|
801
|
+
if (footnote) return footnote;
|
|
802
|
+
}
|
|
736
803
|
if (t.startsWith("```")) return this.backtickFence(p, li, t);
|
|
737
804
|
if (indent <= 3 && t.startsWith("~~~")) {
|
|
738
805
|
const tilde = this.tildeFence(p, li, t);
|
|
@@ -770,19 +837,110 @@ var Tokenizer = class {
|
|
|
770
837
|
return { type, start, end, complete, meta };
|
|
771
838
|
}
|
|
772
839
|
frontMatter(li, t) {
|
|
773
|
-
|
|
840
|
+
const fence = this.lineText(li);
|
|
841
|
+
if (fence !== "---" && fence !== "+++" || t !== fence) return null;
|
|
842
|
+
const toml = fence === "+++";
|
|
774
843
|
let sawContent = false;
|
|
775
844
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
776
845
|
const line = this.lineText(k);
|
|
777
|
-
if (line ===
|
|
778
|
-
return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true) : null;
|
|
846
|
+
if (line === fence || !toml && line === "...") {
|
|
847
|
+
return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true, { format: toml ? "toml" : "yaml" }) : null;
|
|
779
848
|
}
|
|
780
849
|
if (!NOT_WHITESPACE.test(line)) continue;
|
|
781
|
-
|
|
850
|
+
const shaped = toml ? /^\s*(?:[A-Za-z0-9_."-]+\s*=|\[|#)/.test(line) : /^(?:[A-Za-z0-9_"'-][^:]*:(?:\s|$)|\s+\S|-\s|#)/.test(line);
|
|
851
|
+
if (!shaped) return null;
|
|
782
852
|
sawContent = true;
|
|
783
853
|
}
|
|
784
854
|
return null;
|
|
785
855
|
}
|
|
856
|
+
/**
|
|
857
|
+
* `:::name[label]{attrs}` … closing `:::` (a colon run at least as long as
|
|
858
|
+
* the opener's, nesting counted), or a leaf `::name[…]{…}` line. The whole
|
|
859
|
+
* container is ONE island: its grammar (fence lengths, labels, attributes,
|
|
860
|
+
* nested tabs) is exactly what a visual editor would re-serialize wrongly.
|
|
861
|
+
*/
|
|
862
|
+
directive(p, li, t) {
|
|
863
|
+
const open = DIRECTIVE_OPEN.exec(t);
|
|
864
|
+
if (!open) return null;
|
|
865
|
+
const colons = open[1].length;
|
|
866
|
+
const name = open[2];
|
|
867
|
+
if (colons === 2) {
|
|
868
|
+
return this.island("directive", p, this.contentEnds[li], true, { name, leaf: true });
|
|
869
|
+
}
|
|
870
|
+
const stack = [colons];
|
|
871
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
872
|
+
const line = this.lineText(k).trim();
|
|
873
|
+
const inner = DIRECTIVE_OPEN.exec(line);
|
|
874
|
+
if (inner && inner[1].length >= 3) {
|
|
875
|
+
stack.push(inner[1].length);
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
const close = /^(:{3,})\s*$/.exec(line);
|
|
879
|
+
if (close && close[1].length >= stack[stack.length - 1]) {
|
|
880
|
+
stack.pop();
|
|
881
|
+
if (stack.length === 0) return this.island("directive", p, this.contentEnds[k], true, { name });
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return this.island("directive", p, this.n, false, { name });
|
|
885
|
+
}
|
|
886
|
+
/** MkDocs `!!! type "Title"` / `??? type` / `???+ type` and its indented (or blank-separated indented) body. */
|
|
887
|
+
mkdocsAdmonition(p, li, t) {
|
|
888
|
+
const open = MKDOCS_OPEN.exec(t);
|
|
889
|
+
if (!open) return null;
|
|
890
|
+
let last = li;
|
|
891
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
892
|
+
const line = this.lineText(k);
|
|
893
|
+
if (/^(?: {4}|\t)/.test(line) && NOT_WHITESPACE.test(line)) {
|
|
894
|
+
last = k;
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
if (!NOT_WHITESPACE.test(line)) continue;
|
|
898
|
+
break;
|
|
899
|
+
}
|
|
900
|
+
return this.island("directive", p, this.contentEnds[last], true, {
|
|
901
|
+
name: open[2].toLowerCase(),
|
|
902
|
+
syntax: "mkdocs"
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
/** A blockquote whose first line is `> [!TYPE]…` — every following `>` line belongs to it. */
|
|
906
|
+
callout(p, li, t) {
|
|
907
|
+
const open = CALLOUT_OPEN.exec(t);
|
|
908
|
+
if (!open) return null;
|
|
909
|
+
let last = li;
|
|
910
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
911
|
+
if (!/^ {0,3}>/.test(this.lineText(k))) break;
|
|
912
|
+
last = k;
|
|
913
|
+
}
|
|
914
|
+
return this.island("callout", p, this.contentEnds[last], true, {
|
|
915
|
+
name: open[1].toLowerCase(),
|
|
916
|
+
...open[2] ? { fold: open[2] === "-" ? "closed" : "open" } : {}
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
/** `[^id]: text` plus its continuation lines (indented, or lazy text before a blank line). */
|
|
920
|
+
footnoteDefinition(p, li, t) {
|
|
921
|
+
const open = FOOTNOTE_DEF.exec(t);
|
|
922
|
+
if (!open) return null;
|
|
923
|
+
let last = li;
|
|
924
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
925
|
+
const line = this.lineText(k);
|
|
926
|
+
if (!NOT_WHITESPACE.test(line)) {
|
|
927
|
+
let j = k + 1;
|
|
928
|
+
while (j < this.lineCount && !NOT_WHITESPACE.test(this.lineText(j))) j++;
|
|
929
|
+
if (j < this.lineCount && /^(?: {4}|\t)/.test(this.lineText(j))) {
|
|
930
|
+
k = j - 1;
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
if (/^(?: {4}|\t)/.test(line)) {
|
|
936
|
+
last = k;
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
940
|
+
last = k;
|
|
941
|
+
}
|
|
942
|
+
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
943
|
+
}
|
|
786
944
|
/**
|
|
787
945
|
* Backtick fence — the renderer splitter's close rules: JSON-string aware for
|
|
788
946
|
* ```json, and THE nested-fence rule (source/fence-nesting.ts) for markdown
|
|
@@ -811,8 +969,9 @@ var Tokenizer = class {
|
|
|
811
969
|
let nestedDepth = 0;
|
|
812
970
|
let sawNested = false;
|
|
813
971
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
972
|
+
if (this.isOpenTail(k)) continue;
|
|
814
973
|
const line = this.lineText(k);
|
|
815
|
-
const trimmedLine = line
|
|
974
|
+
const trimmedLine = trimFenceLine(line);
|
|
816
975
|
if (trimmedLine.startsWith("```")) {
|
|
817
976
|
const at2 = line.indexOf("```");
|
|
818
977
|
if (isJson) {
|
|
@@ -842,7 +1001,7 @@ var Tokenizer = class {
|
|
|
842
1001
|
}
|
|
843
1002
|
}
|
|
844
1003
|
const closeTicks = backtickRunLength(line, at);
|
|
845
|
-
const after = line.slice(at + closeTicks)
|
|
1004
|
+
const after = trimFenceLine(line.slice(at + closeTicks));
|
|
846
1005
|
if (closeTicks >= openTicks && after === "" && nestedDepth === 0) return k;
|
|
847
1006
|
if (isJson) state = jsonStringState(line, 0, line.length, state);
|
|
848
1007
|
continue;
|
|
@@ -869,6 +1028,7 @@ var Tokenizer = class {
|
|
|
869
1028
|
if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
|
|
870
1029
|
const close = new RegExp(`^ {0,3}~{${ticks},}[ \\t]*$`);
|
|
871
1030
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1031
|
+
if (this.isOpenTail(k)) continue;
|
|
872
1032
|
if (close.test(this.lineText(k))) {
|
|
873
1033
|
return this.island("fence", p, this.contentEnds[k], true, meta);
|
|
874
1034
|
}
|
|
@@ -1258,6 +1418,21 @@ var Tokenizer = class {
|
|
|
1258
1418
|
i++;
|
|
1259
1419
|
continue;
|
|
1260
1420
|
}
|
|
1421
|
+
if (ch === "[" && text[i + 1] === "[" || ch === "!" && text[i + 1] === "[" && text[i + 2] === "[") {
|
|
1422
|
+
const open = ch === "!" ? i + 3 : i + 2;
|
|
1423
|
+
const close = within("]]", open);
|
|
1424
|
+
const newline = this.next("\n", open);
|
|
1425
|
+
const inner = close === -1 ? "" : text.slice(open, close);
|
|
1426
|
+
if (close !== -1 && (newline === -1 || newline > close) && inner.trim() && !/[[\]]/.test(inner)) {
|
|
1427
|
+
const cut = inner.search(/\\?\|/);
|
|
1428
|
+
const target = (cut < 0 ? inner : inner.slice(0, cut)).trim();
|
|
1429
|
+
inlines.push(
|
|
1430
|
+
this.island("wikilink", i, close + 2, true, ch === "!" ? { target, embed: true } : { target })
|
|
1431
|
+
);
|
|
1432
|
+
i = close + 2;
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1261
1436
|
if (ch === "[") {
|
|
1262
1437
|
const media = MEDIA_REF_PREFIXES.find((prefix) => text.startsWith(prefix, i));
|
|
1263
1438
|
if (media) {
|
|
@@ -1339,8 +1514,8 @@ var Tokenizer = class {
|
|
|
1339
1514
|
return { inlines, breakIsland: null, orphan: false };
|
|
1340
1515
|
}
|
|
1341
1516
|
};
|
|
1342
|
-
function tokenizeSource(text) {
|
|
1343
|
-
const raw = new Tokenizer(text).run();
|
|
1517
|
+
function tokenizeSource(text, options = {}) {
|
|
1518
|
+
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
1344
1519
|
const cp = buildCodePointIndex(text);
|
|
1345
1520
|
const inline = (island) => ({
|
|
1346
1521
|
islandType: island.type,
|
|
@@ -1389,7 +1564,7 @@ function listIslands(blocks) {
|
|
|
1389
1564
|
raw: block.raw
|
|
1390
1565
|
});
|
|
1391
1566
|
} else {
|
|
1392
|
-
|
|
1567
|
+
for (const inline of block.inlines) out.push(inline);
|
|
1393
1568
|
}
|
|
1394
1569
|
}
|
|
1395
1570
|
return out;
|
|
@@ -1425,15 +1600,37 @@ function islandEdit(island, text) {
|
|
|
1425
1600
|
function blockRangeEdit(first, last, text) {
|
|
1426
1601
|
return { start: first.start, end: last.end, text };
|
|
1427
1602
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1603
|
+
var CONTEXT_WINDOW = 64;
|
|
1604
|
+
function locateIsland(text, raw, from, expected, expectedFromEnd, oldText, oldStart, oldEnd) {
|
|
1605
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
1606
|
+
if (expected >= from && text.startsWith(raw, expected)) candidates.add(expected);
|
|
1607
|
+
if (expectedFromEnd >= from && text.startsWith(raw, expectedFromEnd)) candidates.add(expectedFromEnd);
|
|
1431
1608
|
const after = text.indexOf(raw, Math.max(from, expected));
|
|
1609
|
+
if (after !== -1) candidates.add(after);
|
|
1432
1610
|
const before = expected > from ? text.lastIndexOf(raw, expected) : -1;
|
|
1433
|
-
|
|
1434
|
-
if (
|
|
1435
|
-
if (
|
|
1436
|
-
|
|
1611
|
+
if (before >= from) candidates.add(before);
|
|
1612
|
+
if (candidates.size === 0) return text.indexOf(raw, from);
|
|
1613
|
+
if (candidates.size === 1) return candidates.values().next().value;
|
|
1614
|
+
let best = -1;
|
|
1615
|
+
let bestScore = -1;
|
|
1616
|
+
for (const at of candidates) {
|
|
1617
|
+
let score = 0;
|
|
1618
|
+
for (let k = 0; k < CONTEXT_WINDOW; k++) {
|
|
1619
|
+
const n = text[at + raw.length + k];
|
|
1620
|
+
if (n === void 0 || n !== oldText[oldEnd + k]) break;
|
|
1621
|
+
score++;
|
|
1622
|
+
}
|
|
1623
|
+
for (let k = 1; k <= CONTEXT_WINDOW; k++) {
|
|
1624
|
+
const n = text[at - k];
|
|
1625
|
+
if (n === void 0 || n !== oldText[oldStart - k]) break;
|
|
1626
|
+
score++;
|
|
1627
|
+
}
|
|
1628
|
+
if (score > bestScore || score === bestScore && at === expected) {
|
|
1629
|
+
best = at;
|
|
1630
|
+
bestScore = score;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
return best;
|
|
1437
1634
|
}
|
|
1438
1635
|
function commonPrefix(a, b) {
|
|
1439
1636
|
const max = Math.min(a.length, b.length);
|
|
@@ -1510,7 +1707,16 @@ function spliceSave(original, edits, options = {}) {
|
|
|
1510
1707
|
let oldCursor2 = edit.start;
|
|
1511
1708
|
let newCursor2 = 0;
|
|
1512
1709
|
for (const island of inside) {
|
|
1513
|
-
const at = locateIsland(
|
|
1710
|
+
const at = locateIsland(
|
|
1711
|
+
edit.text,
|
|
1712
|
+
island.raw,
|
|
1713
|
+
newCursor2,
|
|
1714
|
+
newCursor2 + (island.start - oldCursor2),
|
|
1715
|
+
edit.text.length - (edit.end - island.start),
|
|
1716
|
+
original.slice(edit.start, edit.end),
|
|
1717
|
+
island.start - edit.start,
|
|
1718
|
+
island.end - edit.start
|
|
1719
|
+
);
|
|
1514
1720
|
if (at === -1) {
|
|
1515
1721
|
const name = island.meta.tag ?? island.meta.name ?? island.meta.lang ?? "";
|
|
1516
1722
|
throw new SourceSpliceError(
|
|
@@ -1648,6 +1854,6 @@ function mapRange(changes, start, end, unit = "utf16") {
|
|
|
1648
1854
|
return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
|
|
1649
1855
|
}
|
|
1650
1856
|
|
|
1651
|
-
export { NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource };
|
|
1857
|
+
export { FENCE_WHITESPACE, NESTING_FENCE_LANGUAGES, SourceSpliceError, XmlContainerTracker, blockAt, blockEdit, blockRangeEdit, buildCodePointIndex, classifyInnerFenceLine, fenceNestsInnerFences, isSingleDollarMath, islandEdit, joinSource, listIslands, looksLikeDisplayMath, mapPosition, mapRange, pairDisplayMath, readXmlTag, singleDollarMathEnd, spliceSave, splitsSurrogatePair, toCodePointOffset, toUtf16Offset, tokenizeSource, trimFenceLine };
|
|
1652
1858
|
//# sourceMappingURL=source.js.map
|
|
1653
1859
|
//# sourceMappingURL=source.js.map
|