@ai-matrx/content-ir 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/dist/index.cjs +227 -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 +226 -21
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +227 -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 +226 -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,42 @@ 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
|
+
return /[A-Za-z]'*\(|[A-Za-z]'|\b[A-Za-z]\s+[A-Za-z]\b|\([^)]*[A-Za-z][^)]*\)/.test(content);
|
|
268
|
+
}
|
|
229
269
|
function isSingleDollarMath(content, after) {
|
|
230
270
|
if (!content || content.length > 400) return false;
|
|
231
271
|
if (/^\s/.test(content) || /\s$/.test(content)) return false;
|
|
232
272
|
if (after !== void 0 && /[0-9]/.test(after)) return false;
|
|
233
273
|
if (LONE_VARIABLE.test(content)) return true;
|
|
234
274
|
if (/^[0-9]/.test(content)) return /\\[A-Za-z]+|[\\^_{}]/.test(content);
|
|
235
|
-
return TEX_SIGNAL.test(content);
|
|
275
|
+
return TEX_SIGNAL.test(content) || isMathShape(content);
|
|
236
276
|
}
|
|
237
277
|
function singleDollarMathEnd(text, open, limit = text.length) {
|
|
238
278
|
const bound = Math.min(limit, open + 403);
|
|
@@ -468,6 +508,10 @@ var XmlContainerTracker = class {
|
|
|
468
508
|
|
|
469
509
|
// source/tokenize.ts
|
|
470
510
|
var NOT_WHITESPACE = /\S/;
|
|
511
|
+
var DIRECTIVE_OPEN = /^(:{2,})([A-Za-z][\w-]*)/;
|
|
512
|
+
var MKDOCS_OPEN = /^(!!!|\?\?\?\+?)[ \t]+([A-Za-z][\w-]*)/;
|
|
513
|
+
var CALLOUT_OPEN = /^>[ \t]*\[!([A-Za-z][\w-]*)\]([+-])?/;
|
|
514
|
+
var FOOTNOTE_DEF = /^\[\^([^\]\s]+)\]:/;
|
|
471
515
|
function countStructuralBraces(source) {
|
|
472
516
|
let opens = 0;
|
|
473
517
|
let closes = 0;
|
|
@@ -595,8 +639,9 @@ function isSplitterTreeLine(line) {
|
|
|
595
639
|
}
|
|
596
640
|
var MEDIA_REF_PREFIXES = ["[Image URL:", "[Video URL:", "[Audio URL:"];
|
|
597
641
|
var Tokenizer = class {
|
|
598
|
-
constructor(text) {
|
|
642
|
+
constructor(text, streaming = false) {
|
|
599
643
|
this.text = text;
|
|
644
|
+
this.streaming = streaming;
|
|
600
645
|
this.n = text.length;
|
|
601
646
|
this.mathPairs = pairDisplayMath(text);
|
|
602
647
|
let start = 0;
|
|
@@ -615,6 +660,7 @@ var Tokenizer = class {
|
|
|
615
660
|
}
|
|
616
661
|
}
|
|
617
662
|
text;
|
|
663
|
+
streaming;
|
|
618
664
|
n;
|
|
619
665
|
lineStarts = [];
|
|
620
666
|
contentEnds = [];
|
|
@@ -652,6 +698,10 @@ var Tokenizer = class {
|
|
|
652
698
|
}
|
|
653
699
|
return lo < list.length ? list[lo] : -1;
|
|
654
700
|
}
|
|
701
|
+
/** Streaming only: the final line, still waiting for its terminator. */
|
|
702
|
+
isOpenTail(k) {
|
|
703
|
+
return this.streaming && k === this.lineStarts.length - 1 && this.lineEnds[k] === this.contentEnds[k];
|
|
704
|
+
}
|
|
655
705
|
get lineCount() {
|
|
656
706
|
return this.lineStarts.length;
|
|
657
707
|
}
|
|
@@ -733,6 +783,22 @@ var Tokenizer = class {
|
|
|
733
783
|
const fm = this.frontMatter(li, t);
|
|
734
784
|
if (fm) return fm;
|
|
735
785
|
}
|
|
786
|
+
if (indent <= 3 && t.startsWith("::")) {
|
|
787
|
+
const directive = this.directive(p, li, t);
|
|
788
|
+
if (directive) return directive;
|
|
789
|
+
}
|
|
790
|
+
if (indent === 0 && (t.startsWith("!!!") || t.startsWith("???"))) {
|
|
791
|
+
const admonition = this.mkdocsAdmonition(p, li, t);
|
|
792
|
+
if (admonition) return admonition;
|
|
793
|
+
}
|
|
794
|
+
if (indent <= 3 && t.startsWith(">")) {
|
|
795
|
+
const callout = this.callout(p, li, t);
|
|
796
|
+
if (callout) return callout;
|
|
797
|
+
}
|
|
798
|
+
if (atParaStart && indent <= 3 && t.startsWith("[^")) {
|
|
799
|
+
const footnote = this.footnoteDefinition(p, li, t);
|
|
800
|
+
if (footnote) return footnote;
|
|
801
|
+
}
|
|
736
802
|
if (t.startsWith("```")) return this.backtickFence(p, li, t);
|
|
737
803
|
if (indent <= 3 && t.startsWith("~~~")) {
|
|
738
804
|
const tilde = this.tildeFence(p, li, t);
|
|
@@ -770,19 +836,110 @@ var Tokenizer = class {
|
|
|
770
836
|
return { type, start, end, complete, meta };
|
|
771
837
|
}
|
|
772
838
|
frontMatter(li, t) {
|
|
773
|
-
|
|
839
|
+
const fence = this.lineText(li);
|
|
840
|
+
if (fence !== "---" && fence !== "+++" || t !== fence) return null;
|
|
841
|
+
const toml = fence === "+++";
|
|
774
842
|
let sawContent = false;
|
|
775
843
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
776
844
|
const line = this.lineText(k);
|
|
777
|
-
if (line ===
|
|
778
|
-
return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true) : null;
|
|
845
|
+
if (line === fence || !toml && line === "...") {
|
|
846
|
+
return sawContent ? this.island("front_matter", 0, this.contentEnds[k], true, { format: toml ? "toml" : "yaml" }) : null;
|
|
779
847
|
}
|
|
780
848
|
if (!NOT_WHITESPACE.test(line)) continue;
|
|
781
|
-
|
|
849
|
+
const shaped = toml ? /^\s*(?:[A-Za-z0-9_."-]+\s*=|\[|#)/.test(line) : /^(?:[A-Za-z0-9_"'-][^:]*:(?:\s|$)|\s+\S|-\s|#)/.test(line);
|
|
850
|
+
if (!shaped) return null;
|
|
782
851
|
sawContent = true;
|
|
783
852
|
}
|
|
784
853
|
return null;
|
|
785
854
|
}
|
|
855
|
+
/**
|
|
856
|
+
* `:::name[label]{attrs}` … closing `:::` (a colon run at least as long as
|
|
857
|
+
* the opener's, nesting counted), or a leaf `::name[…]{…}` line. The whole
|
|
858
|
+
* container is ONE island: its grammar (fence lengths, labels, attributes,
|
|
859
|
+
* nested tabs) is exactly what a visual editor would re-serialize wrongly.
|
|
860
|
+
*/
|
|
861
|
+
directive(p, li, t) {
|
|
862
|
+
const open = DIRECTIVE_OPEN.exec(t);
|
|
863
|
+
if (!open) return null;
|
|
864
|
+
const colons = open[1].length;
|
|
865
|
+
const name = open[2];
|
|
866
|
+
if (colons === 2) {
|
|
867
|
+
return this.island("directive", p, this.contentEnds[li], true, { name, leaf: true });
|
|
868
|
+
}
|
|
869
|
+
const stack = [colons];
|
|
870
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
871
|
+
const line = this.lineText(k).trim();
|
|
872
|
+
const inner = DIRECTIVE_OPEN.exec(line);
|
|
873
|
+
if (inner && inner[1].length >= 3) {
|
|
874
|
+
stack.push(inner[1].length);
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
const close = /^(:{3,})\s*$/.exec(line);
|
|
878
|
+
if (close && close[1].length >= stack[stack.length - 1]) {
|
|
879
|
+
stack.pop();
|
|
880
|
+
if (stack.length === 0) return this.island("directive", p, this.contentEnds[k], true, { name });
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return this.island("directive", p, this.n, false, { name });
|
|
884
|
+
}
|
|
885
|
+
/** MkDocs `!!! type "Title"` / `??? type` / `???+ type` and its indented (or blank-separated indented) body. */
|
|
886
|
+
mkdocsAdmonition(p, li, t) {
|
|
887
|
+
const open = MKDOCS_OPEN.exec(t);
|
|
888
|
+
if (!open) return null;
|
|
889
|
+
let last = li;
|
|
890
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
891
|
+
const line = this.lineText(k);
|
|
892
|
+
if (/^(?: {4}|\t)/.test(line) && NOT_WHITESPACE.test(line)) {
|
|
893
|
+
last = k;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
if (!NOT_WHITESPACE.test(line)) continue;
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
return this.island("directive", p, this.contentEnds[last], true, {
|
|
900
|
+
name: open[2].toLowerCase(),
|
|
901
|
+
syntax: "mkdocs"
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
/** A blockquote whose first line is `> [!TYPE]…` — every following `>` line belongs to it. */
|
|
905
|
+
callout(p, li, t) {
|
|
906
|
+
const open = CALLOUT_OPEN.exec(t);
|
|
907
|
+
if (!open) return null;
|
|
908
|
+
let last = li;
|
|
909
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
910
|
+
if (!/^ {0,3}>/.test(this.lineText(k))) break;
|
|
911
|
+
last = k;
|
|
912
|
+
}
|
|
913
|
+
return this.island("callout", p, this.contentEnds[last], true, {
|
|
914
|
+
name: open[1].toLowerCase(),
|
|
915
|
+
...open[2] ? { fold: open[2] === "-" ? "closed" : "open" } : {}
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
/** `[^id]: text` plus its continuation lines (indented, or lazy text before a blank line). */
|
|
919
|
+
footnoteDefinition(p, li, t) {
|
|
920
|
+
const open = FOOTNOTE_DEF.exec(t);
|
|
921
|
+
if (!open) return null;
|
|
922
|
+
let last = li;
|
|
923
|
+
for (let k = li + 1; k < this.lineCount; k++) {
|
|
924
|
+
const line = this.lineText(k);
|
|
925
|
+
if (!NOT_WHITESPACE.test(line)) {
|
|
926
|
+
let j = k + 1;
|
|
927
|
+
while (j < this.lineCount && !NOT_WHITESPACE.test(this.lineText(j))) j++;
|
|
928
|
+
if (j < this.lineCount && /^(?: {4}|\t)/.test(this.lineText(j))) {
|
|
929
|
+
k = j - 1;
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
if (/^(?: {4}|\t)/.test(line)) {
|
|
935
|
+
last = k;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
if (FOOTNOTE_DEF.test(line.trimStart()) || this.detectBlock(this.lineStarts[k], k, false)) break;
|
|
939
|
+
last = k;
|
|
940
|
+
}
|
|
941
|
+
return this.island("footnote_def", p, this.contentEnds[last], true, { id: open[1] });
|
|
942
|
+
}
|
|
786
943
|
/**
|
|
787
944
|
* Backtick fence — the renderer splitter's close rules: JSON-string aware for
|
|
788
945
|
* ```json, and THE nested-fence rule (source/fence-nesting.ts) for markdown
|
|
@@ -811,8 +968,9 @@ var Tokenizer = class {
|
|
|
811
968
|
let nestedDepth = 0;
|
|
812
969
|
let sawNested = false;
|
|
813
970
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
971
|
+
if (this.isOpenTail(k)) continue;
|
|
814
972
|
const line = this.lineText(k);
|
|
815
|
-
const trimmedLine = line
|
|
973
|
+
const trimmedLine = trimFenceLine(line);
|
|
816
974
|
if (trimmedLine.startsWith("```")) {
|
|
817
975
|
const at2 = line.indexOf("```");
|
|
818
976
|
if (isJson) {
|
|
@@ -842,7 +1000,7 @@ var Tokenizer = class {
|
|
|
842
1000
|
}
|
|
843
1001
|
}
|
|
844
1002
|
const closeTicks = backtickRunLength(line, at);
|
|
845
|
-
const after = line.slice(at + closeTicks)
|
|
1003
|
+
const after = trimFenceLine(line.slice(at + closeTicks));
|
|
846
1004
|
if (closeTicks >= openTicks && after === "" && nestedDepth === 0) return k;
|
|
847
1005
|
if (isJson) state = jsonStringState(line, 0, line.length, state);
|
|
848
1006
|
continue;
|
|
@@ -869,6 +1027,7 @@ var Tokenizer = class {
|
|
|
869
1027
|
if (normalized && SPECIAL_CODE_LANGUAGES.has(normalized)) meta.special = normalized;
|
|
870
1028
|
const close = new RegExp(`^ {0,3}~{${ticks},}[ \\t]*$`);
|
|
871
1029
|
for (let k = li + 1; k < this.lineCount; k++) {
|
|
1030
|
+
if (this.isOpenTail(k)) continue;
|
|
872
1031
|
if (close.test(this.lineText(k))) {
|
|
873
1032
|
return this.island("fence", p, this.contentEnds[k], true, meta);
|
|
874
1033
|
}
|
|
@@ -1258,6 +1417,21 @@ var Tokenizer = class {
|
|
|
1258
1417
|
i++;
|
|
1259
1418
|
continue;
|
|
1260
1419
|
}
|
|
1420
|
+
if (ch === "[" && text[i + 1] === "[" || ch === "!" && text[i + 1] === "[" && text[i + 2] === "[") {
|
|
1421
|
+
const open = ch === "!" ? i + 3 : i + 2;
|
|
1422
|
+
const close = within("]]", open);
|
|
1423
|
+
const newline = this.next("\n", open);
|
|
1424
|
+
const inner = close === -1 ? "" : text.slice(open, close);
|
|
1425
|
+
if (close !== -1 && (newline === -1 || newline > close) && inner.trim() && !/[[\]]/.test(inner)) {
|
|
1426
|
+
const cut = inner.search(/\\?\|/);
|
|
1427
|
+
const target = (cut < 0 ? inner : inner.slice(0, cut)).trim();
|
|
1428
|
+
inlines.push(
|
|
1429
|
+
this.island("wikilink", i, close + 2, true, ch === "!" ? { target, embed: true } : { target })
|
|
1430
|
+
);
|
|
1431
|
+
i = close + 2;
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1261
1435
|
if (ch === "[") {
|
|
1262
1436
|
const media = MEDIA_REF_PREFIXES.find((prefix) => text.startsWith(prefix, i));
|
|
1263
1437
|
if (media) {
|
|
@@ -1339,8 +1513,8 @@ var Tokenizer = class {
|
|
|
1339
1513
|
return { inlines, breakIsland: null, orphan: false };
|
|
1340
1514
|
}
|
|
1341
1515
|
};
|
|
1342
|
-
function tokenizeSource(text) {
|
|
1343
|
-
const raw = new Tokenizer(text).run();
|
|
1516
|
+
function tokenizeSource(text, options = {}) {
|
|
1517
|
+
const raw = new Tokenizer(text, options.streaming ?? false).run();
|
|
1344
1518
|
const cp = buildCodePointIndex(text);
|
|
1345
1519
|
const inline = (island) => ({
|
|
1346
1520
|
islandType: island.type,
|
|
@@ -1389,7 +1563,7 @@ function listIslands(blocks) {
|
|
|
1389
1563
|
raw: block.raw
|
|
1390
1564
|
});
|
|
1391
1565
|
} else {
|
|
1392
|
-
|
|
1566
|
+
for (const inline of block.inlines) out.push(inline);
|
|
1393
1567
|
}
|
|
1394
1568
|
}
|
|
1395
1569
|
return out;
|
|
@@ -1425,15 +1599,37 @@ function islandEdit(island, text) {
|
|
|
1425
1599
|
function blockRangeEdit(first, last, text) {
|
|
1426
1600
|
return { start: first.start, end: last.end, text };
|
|
1427
1601
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1602
|
+
var CONTEXT_WINDOW = 64;
|
|
1603
|
+
function locateIsland(text, raw, from, expected, expectedFromEnd, oldText, oldStart, oldEnd) {
|
|
1604
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
1605
|
+
if (expected >= from && text.startsWith(raw, expected)) candidates.add(expected);
|
|
1606
|
+
if (expectedFromEnd >= from && text.startsWith(raw, expectedFromEnd)) candidates.add(expectedFromEnd);
|
|
1431
1607
|
const after = text.indexOf(raw, Math.max(from, expected));
|
|
1608
|
+
if (after !== -1) candidates.add(after);
|
|
1432
1609
|
const before = expected > from ? text.lastIndexOf(raw, expected) : -1;
|
|
1433
|
-
|
|
1434
|
-
if (
|
|
1435
|
-
if (
|
|
1436
|
-
|
|
1610
|
+
if (before >= from) candidates.add(before);
|
|
1611
|
+
if (candidates.size === 0) return text.indexOf(raw, from);
|
|
1612
|
+
if (candidates.size === 1) return candidates.values().next().value;
|
|
1613
|
+
let best = -1;
|
|
1614
|
+
let bestScore = -1;
|
|
1615
|
+
for (const at of candidates) {
|
|
1616
|
+
let score = 0;
|
|
1617
|
+
for (let k = 0; k < CONTEXT_WINDOW; k++) {
|
|
1618
|
+
const n = text[at + raw.length + k];
|
|
1619
|
+
if (n === void 0 || n !== oldText[oldEnd + k]) break;
|
|
1620
|
+
score++;
|
|
1621
|
+
}
|
|
1622
|
+
for (let k = 1; k <= CONTEXT_WINDOW; k++) {
|
|
1623
|
+
const n = text[at - k];
|
|
1624
|
+
if (n === void 0 || n !== oldText[oldStart - k]) break;
|
|
1625
|
+
score++;
|
|
1626
|
+
}
|
|
1627
|
+
if (score > bestScore || score === bestScore && at === expected) {
|
|
1628
|
+
best = at;
|
|
1629
|
+
bestScore = score;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return best;
|
|
1437
1633
|
}
|
|
1438
1634
|
function commonPrefix(a, b) {
|
|
1439
1635
|
const max = Math.min(a.length, b.length);
|
|
@@ -1510,7 +1706,16 @@ function spliceSave(original, edits, options = {}) {
|
|
|
1510
1706
|
let oldCursor2 = edit.start;
|
|
1511
1707
|
let newCursor2 = 0;
|
|
1512
1708
|
for (const island of inside) {
|
|
1513
|
-
const at = locateIsland(
|
|
1709
|
+
const at = locateIsland(
|
|
1710
|
+
edit.text,
|
|
1711
|
+
island.raw,
|
|
1712
|
+
newCursor2,
|
|
1713
|
+
newCursor2 + (island.start - oldCursor2),
|
|
1714
|
+
edit.text.length - (edit.end - island.start),
|
|
1715
|
+
original.slice(edit.start, edit.end),
|
|
1716
|
+
island.start - edit.start,
|
|
1717
|
+
island.end - edit.start
|
|
1718
|
+
);
|
|
1514
1719
|
if (at === -1) {
|
|
1515
1720
|
const name = island.meta.tag ?? island.meta.name ?? island.meta.lang ?? "";
|
|
1516
1721
|
throw new SourceSpliceError(
|
|
@@ -1648,6 +1853,6 @@ function mapRange(changes, start, end, unit = "utf16") {
|
|
|
1648
1853
|
return { start: newStart, end: newEnd, touched, collapsed: newEnd === newStart && end > start };
|
|
1649
1854
|
}
|
|
1650
1855
|
|
|
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 };
|
|
1856
|
+
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
1857
|
//# sourceMappingURL=source.js.map
|
|
1653
1858
|
//# sourceMappingURL=source.js.map
|