@ai-matrx/content-ir 0.12.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 +119 -0
- package/dist/index.cjs +546 -98
- 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 +539 -99
- package/dist/index.js.map +1 -1
- package/dist/source.cjs +546 -98
- package/dist/source.cjs.map +1 -1
- package/dist/source.d.cts +118 -14
- package/dist/source.d.ts +118 -14
- package/dist/source.js +539 -99
- 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. */
|
|
@@ -114,20 +136,30 @@ declare function blockAt(blocks: readonly SourceBlock[], offset: number): Source
|
|
|
114
136
|
* uses to carry every live anchor through the save
|
|
115
137
|
* (STORE-DESIGN §3.19 — the ProseMirror / Google Docs position-mapping
|
|
116
138
|
* model), and
|
|
117
|
-
* - an integrity
|
|
139
|
+
* - an integrity guarantee: every island not explicitly replaced must still
|
|
118
140
|
* be the same island, at its mapped position, in the new text. An edit
|
|
119
|
-
* that opens an unclosed fence and swallows a kind below it is
|
|
120
|
-
*
|
|
141
|
+
* that opens an unclosed fence and swallows a kind below it is REFUSED.
|
|
142
|
+
*
|
|
143
|
+
* ISLANDS CHANGE ONLY THROUGH `islandEdit`. A prose/range edit must hand back
|
|
144
|
+
* every island inside its range byte-identical and in order (a visual editor
|
|
145
|
+
* holds them as atoms); if one is altered or dropped the save throws
|
|
146
|
+
* `SourceSpliceError("island_edit")` naming the island. A kind editor or code
|
|
147
|
+
* view changes an island with `islandEdit(island, newRaw)`.
|
|
121
148
|
*
|
|
122
149
|
* A no-edit save (or edits whose text equals the original block) returns the
|
|
123
150
|
* original string itself — byte-identical, zero changes.
|
|
124
151
|
*/
|
|
125
152
|
|
|
126
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Replace `[start, end)` (UTF-16) of the original with `text`. A plain edit
|
|
155
|
+
* starts and ends on block boundaries; an island edit (`island: true`, made by
|
|
156
|
+
* `islandEdit`) names exactly one island's span.
|
|
157
|
+
*/
|
|
127
158
|
interface SourceEdit {
|
|
128
159
|
readonly start: number;
|
|
129
160
|
readonly end: number;
|
|
130
161
|
readonly text: string;
|
|
162
|
+
readonly island?: boolean;
|
|
131
163
|
}
|
|
132
164
|
interface SourceChange {
|
|
133
165
|
/** The block-aligned range the edit named, in the ORIGINAL text. */
|
|
@@ -168,7 +200,7 @@ interface SpliceResult {
|
|
|
168
200
|
/** Tokenization of the new text. */
|
|
169
201
|
readonly blocks: readonly SourceBlock[];
|
|
170
202
|
}
|
|
171
|
-
type SourceSpliceErrorCode = "out_of_range" | "misaligned" | "overlap" | "stale_blocks" | "integrity";
|
|
203
|
+
type SourceSpliceErrorCode = "out_of_range" | "misaligned" | "overlap" | "stale_blocks" | "island_edit" | "integrity";
|
|
172
204
|
declare class SourceSpliceError extends Error {
|
|
173
205
|
readonly code: SourceSpliceErrorCode;
|
|
174
206
|
constructor(code: SourceSpliceErrorCode, message: string);
|
|
@@ -176,11 +208,21 @@ declare class SourceSpliceError extends Error {
|
|
|
176
208
|
interface SpliceOptions {
|
|
177
209
|
/** The tokenization of `original`, when the caller already holds it. */
|
|
178
210
|
readonly blocks?: readonly SourceBlock[];
|
|
179
|
-
/**
|
|
211
|
+
/**
|
|
212
|
+
* Default `true`: a save that disturbs any island it did not explicitly
|
|
213
|
+
* replace throws `SourceSpliceError("integrity")`. `false` is for TOOLING
|
|
214
|
+
* ONLY (diagnostic scripts that want the report instead of the refusal) —
|
|
215
|
+
* no editor or persistence path may pass it.
|
|
216
|
+
*/
|
|
180
217
|
readonly requireIntegrity?: boolean;
|
|
181
218
|
}
|
|
182
219
|
/** An edit that replaces one block's raw text. */
|
|
183
220
|
declare function blockEdit(block: SourceBlock, text: string): SourceEdit;
|
|
221
|
+
/** The one door that changes an island: replace exactly its span with `text`. */
|
|
222
|
+
declare function islandEdit(island: {
|
|
223
|
+
readonly start: number;
|
|
224
|
+
readonly end: number;
|
|
225
|
+
}, text: string): SourceEdit;
|
|
184
226
|
/** An edit that replaces a contiguous run of blocks `[first, last]`. */
|
|
185
227
|
declare function blockRangeEdit(first: SourceBlock, last: SourceBlock, text: string): SourceEdit;
|
|
186
228
|
/**
|
|
@@ -252,8 +294,9 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
|
|
|
252
294
|
*
|
|
253
295
|
* Pandoc's rule — the opening `$` is not followed by whitespace, the closing
|
|
254
296
|
* `$` is not preceded by whitespace and not followed by a digit — plus a math
|
|
255
|
-
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …),
|
|
256
|
-
* 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
|
|
257
300
|
* a real TeX signal, so a price range can never read as math.
|
|
258
301
|
*/
|
|
259
302
|
declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
|
|
@@ -286,7 +329,12 @@ interface ReadXmlTag {
|
|
|
286
329
|
value: string;
|
|
287
330
|
}>;
|
|
288
331
|
}
|
|
289
|
-
|
|
332
|
+
/**
|
|
333
|
+
* `find(needle, from)` must behave like `content.indexOf(needle, from)`; the
|
|
334
|
+
* tokenizer passes a cached occurrence index so a text full of unclosed
|
|
335
|
+
* attribute quotes stays linear. Behaviour is identical either way.
|
|
336
|
+
*/
|
|
337
|
+
declare function readXmlTag(content: string, start: number, find?: (needle: string, from: number) => number): ReadXmlTag | null;
|
|
290
338
|
/**
|
|
291
339
|
* Balances ONE unknown root tag line by line, ignoring lookalike tags inside
|
|
292
340
|
* fenced code, inline code spans, comments and CDATA. `consumeLine` returns
|
|
@@ -303,4 +351,60 @@ declare class XmlContainerTracker {
|
|
|
303
351
|
consumeLine(line: string, startOffset?: number): number | null;
|
|
304
352
|
}
|
|
305
353
|
|
|
306
|
-
|
|
354
|
+
/** Fence languages whose body is itself a markdown document. */
|
|
355
|
+
declare const NESTING_FENCE_LANGUAGES: ReadonlySet<string>;
|
|
356
|
+
/** True when a fence opened with this info-string language nests inner fences. */
|
|
357
|
+
declare function fenceNestsInnerFences(language: string | undefined | null): boolean;
|
|
358
|
+
type InnerFenceLine =
|
|
359
|
+
/** Not a fence line — ordinary content of the outer fence. */
|
|
360
|
+
"content"
|
|
361
|
+
/** ```lang inside a markdown fence — content, and one level deeper. */
|
|
362
|
+
| "open-nested"
|
|
363
|
+
/** Bare ``` that closes the innermost nested fence — content, one level up. */
|
|
364
|
+
| "close-nested"
|
|
365
|
+
/** Bare ``` that closes the OUTER fence. */
|
|
366
|
+
| "close-outer";
|
|
367
|
+
/**
|
|
368
|
+
* Classify one line inside an open backtick fence, already trimmed with
|
|
369
|
+
* {@link trimFenceLine} (never a language's own `trim()`).
|
|
370
|
+
*
|
|
371
|
+
* @param trimmed the line with surrounding whitespace removed
|
|
372
|
+
* @param openTicks backtick count of the outer fence's opener
|
|
373
|
+
* @param nests whether the outer fence follows the nesting rule
|
|
374
|
+
* @param nestedDepth how many nested fences are open right now
|
|
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;
|
|
388
|
+
declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* `$$` pairing — the core's rule for which `$$` delimiters are real math.
|
|
392
|
+
*
|
|
393
|
+
* Ported from `@ai-matrx/kit/delimiter-guard` (`guardMathDelimiters`), which
|
|
394
|
+
* every math-capable renderer runs before remark-math. Its decisions:
|
|
395
|
+
* - `$$` tokens outside code (``` / ~~~ fences, `inline code`) pair in
|
|
396
|
+
* document order, open → close;
|
|
397
|
+
* - a pair whose inside reads as prose or carries markdown structure is NOT
|
|
398
|
+
* math: the renderer neutralizes its opener and the closer is retried as
|
|
399
|
+
* the next opener;
|
|
400
|
+
* - an unpaired `$$` is inert — it renders as literal text.
|
|
401
|
+
* So the tokenizer protects exactly the pairs the renderer shows as math, and
|
|
402
|
+
* a lone `$$` (a stray closer, or an opener that never closed) never locks
|
|
403
|
+
* anything. Linear time: one regex pass per code shape, one sweep.
|
|
404
|
+
*/
|
|
405
|
+
/** The guard's `looksLikeMath`, verbatim. */
|
|
406
|
+
declare function looksLikeDisplayMath(inner: string): boolean;
|
|
407
|
+
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
408
|
+
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
409
|
+
|
|
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. */
|
|
@@ -114,20 +136,30 @@ declare function blockAt(blocks: readonly SourceBlock[], offset: number): Source
|
|
|
114
136
|
* uses to carry every live anchor through the save
|
|
115
137
|
* (STORE-DESIGN §3.19 — the ProseMirror / Google Docs position-mapping
|
|
116
138
|
* model), and
|
|
117
|
-
* - an integrity
|
|
139
|
+
* - an integrity guarantee: every island not explicitly replaced must still
|
|
118
140
|
* be the same island, at its mapped position, in the new text. An edit
|
|
119
|
-
* that opens an unclosed fence and swallows a kind below it is
|
|
120
|
-
*
|
|
141
|
+
* that opens an unclosed fence and swallows a kind below it is REFUSED.
|
|
142
|
+
*
|
|
143
|
+
* ISLANDS CHANGE ONLY THROUGH `islandEdit`. A prose/range edit must hand back
|
|
144
|
+
* every island inside its range byte-identical and in order (a visual editor
|
|
145
|
+
* holds them as atoms); if one is altered or dropped the save throws
|
|
146
|
+
* `SourceSpliceError("island_edit")` naming the island. A kind editor or code
|
|
147
|
+
* view changes an island with `islandEdit(island, newRaw)`.
|
|
121
148
|
*
|
|
122
149
|
* A no-edit save (or edits whose text equals the original block) returns the
|
|
123
150
|
* original string itself — byte-identical, zero changes.
|
|
124
151
|
*/
|
|
125
152
|
|
|
126
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Replace `[start, end)` (UTF-16) of the original with `text`. A plain edit
|
|
155
|
+
* starts and ends on block boundaries; an island edit (`island: true`, made by
|
|
156
|
+
* `islandEdit`) names exactly one island's span.
|
|
157
|
+
*/
|
|
127
158
|
interface SourceEdit {
|
|
128
159
|
readonly start: number;
|
|
129
160
|
readonly end: number;
|
|
130
161
|
readonly text: string;
|
|
162
|
+
readonly island?: boolean;
|
|
131
163
|
}
|
|
132
164
|
interface SourceChange {
|
|
133
165
|
/** The block-aligned range the edit named, in the ORIGINAL text. */
|
|
@@ -168,7 +200,7 @@ interface SpliceResult {
|
|
|
168
200
|
/** Tokenization of the new text. */
|
|
169
201
|
readonly blocks: readonly SourceBlock[];
|
|
170
202
|
}
|
|
171
|
-
type SourceSpliceErrorCode = "out_of_range" | "misaligned" | "overlap" | "stale_blocks" | "integrity";
|
|
203
|
+
type SourceSpliceErrorCode = "out_of_range" | "misaligned" | "overlap" | "stale_blocks" | "island_edit" | "integrity";
|
|
172
204
|
declare class SourceSpliceError extends Error {
|
|
173
205
|
readonly code: SourceSpliceErrorCode;
|
|
174
206
|
constructor(code: SourceSpliceErrorCode, message: string);
|
|
@@ -176,11 +208,21 @@ declare class SourceSpliceError extends Error {
|
|
|
176
208
|
interface SpliceOptions {
|
|
177
209
|
/** The tokenization of `original`, when the caller already holds it. */
|
|
178
210
|
readonly blocks?: readonly SourceBlock[];
|
|
179
|
-
/**
|
|
211
|
+
/**
|
|
212
|
+
* Default `true`: a save that disturbs any island it did not explicitly
|
|
213
|
+
* replace throws `SourceSpliceError("integrity")`. `false` is for TOOLING
|
|
214
|
+
* ONLY (diagnostic scripts that want the report instead of the refusal) —
|
|
215
|
+
* no editor or persistence path may pass it.
|
|
216
|
+
*/
|
|
180
217
|
readonly requireIntegrity?: boolean;
|
|
181
218
|
}
|
|
182
219
|
/** An edit that replaces one block's raw text. */
|
|
183
220
|
declare function blockEdit(block: SourceBlock, text: string): SourceEdit;
|
|
221
|
+
/** The one door that changes an island: replace exactly its span with `text`. */
|
|
222
|
+
declare function islandEdit(island: {
|
|
223
|
+
readonly start: number;
|
|
224
|
+
readonly end: number;
|
|
225
|
+
}, text: string): SourceEdit;
|
|
184
226
|
/** An edit that replaces a contiguous run of blocks `[first, last]`. */
|
|
185
227
|
declare function blockRangeEdit(first: SourceBlock, last: SourceBlock, text: string): SourceEdit;
|
|
186
228
|
/**
|
|
@@ -252,8 +294,9 @@ declare function toUtf16Offset(text: string, codePoint: number): number;
|
|
|
252
294
|
*
|
|
253
295
|
* Pandoc's rule — the opening `$` is not followed by whitespace, the closing
|
|
254
296
|
* `$` is not preceded by whitespace and not followed by a digit — plus a math
|
|
255
|
-
* signal: a TeX command or operator (`\alpha`, `^`, `_`, `{`, `=`, …),
|
|
256
|
-
* 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
|
|
257
300
|
* a real TeX signal, so a price range can never read as math.
|
|
258
301
|
*/
|
|
259
302
|
declare function isSingleDollarMath(content: string, after: string | undefined): boolean;
|
|
@@ -286,7 +329,12 @@ interface ReadXmlTag {
|
|
|
286
329
|
value: string;
|
|
287
330
|
}>;
|
|
288
331
|
}
|
|
289
|
-
|
|
332
|
+
/**
|
|
333
|
+
* `find(needle, from)` must behave like `content.indexOf(needle, from)`; the
|
|
334
|
+
* tokenizer passes a cached occurrence index so a text full of unclosed
|
|
335
|
+
* attribute quotes stays linear. Behaviour is identical either way.
|
|
336
|
+
*/
|
|
337
|
+
declare function readXmlTag(content: string, start: number, find?: (needle: string, from: number) => number): ReadXmlTag | null;
|
|
290
338
|
/**
|
|
291
339
|
* Balances ONE unknown root tag line by line, ignoring lookalike tags inside
|
|
292
340
|
* fenced code, inline code spans, comments and CDATA. `consumeLine` returns
|
|
@@ -303,4 +351,60 @@ declare class XmlContainerTracker {
|
|
|
303
351
|
consumeLine(line: string, startOffset?: number): number | null;
|
|
304
352
|
}
|
|
305
353
|
|
|
306
|
-
|
|
354
|
+
/** Fence languages whose body is itself a markdown document. */
|
|
355
|
+
declare const NESTING_FENCE_LANGUAGES: ReadonlySet<string>;
|
|
356
|
+
/** True when a fence opened with this info-string language nests inner fences. */
|
|
357
|
+
declare function fenceNestsInnerFences(language: string | undefined | null): boolean;
|
|
358
|
+
type InnerFenceLine =
|
|
359
|
+
/** Not a fence line — ordinary content of the outer fence. */
|
|
360
|
+
"content"
|
|
361
|
+
/** ```lang inside a markdown fence — content, and one level deeper. */
|
|
362
|
+
| "open-nested"
|
|
363
|
+
/** Bare ``` that closes the innermost nested fence — content, one level up. */
|
|
364
|
+
| "close-nested"
|
|
365
|
+
/** Bare ``` that closes the OUTER fence. */
|
|
366
|
+
| "close-outer";
|
|
367
|
+
/**
|
|
368
|
+
* Classify one line inside an open backtick fence, already trimmed with
|
|
369
|
+
* {@link trimFenceLine} (never a language's own `trim()`).
|
|
370
|
+
*
|
|
371
|
+
* @param trimmed the line with surrounding whitespace removed
|
|
372
|
+
* @param openTicks backtick count of the outer fence's opener
|
|
373
|
+
* @param nests whether the outer fence follows the nesting rule
|
|
374
|
+
* @param nestedDepth how many nested fences are open right now
|
|
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;
|
|
388
|
+
declare function classifyInnerFenceLine(trimmed: string, openTicks: number, nests: boolean, nestedDepth: number): InnerFenceLine;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* `$$` pairing — the core's rule for which `$$` delimiters are real math.
|
|
392
|
+
*
|
|
393
|
+
* Ported from `@ai-matrx/kit/delimiter-guard` (`guardMathDelimiters`), which
|
|
394
|
+
* every math-capable renderer runs before remark-math. Its decisions:
|
|
395
|
+
* - `$$` tokens outside code (``` / ~~~ fences, `inline code`) pair in
|
|
396
|
+
* document order, open → close;
|
|
397
|
+
* - a pair whose inside reads as prose or carries markdown structure is NOT
|
|
398
|
+
* math: the renderer neutralizes its opener and the closer is retried as
|
|
399
|
+
* the next opener;
|
|
400
|
+
* - an unpaired `$$` is inert — it renders as literal text.
|
|
401
|
+
* So the tokenizer protects exactly the pairs the renderer shows as math, and
|
|
402
|
+
* a lone `$$` (a stray closer, or an opener that never closed) never locks
|
|
403
|
+
* anything. Linear time: one regex pass per code shape, one sweep.
|
|
404
|
+
*/
|
|
405
|
+
/** The guard's `looksLikeMath`, verbatim. */
|
|
406
|
+
declare function looksLikeDisplayMath(inner: string): boolean;
|
|
407
|
+
/** Map of `$$` opener offset → closer offset for every pair the renderer shows as math. */
|
|
408
|
+
declare function pairDisplayMath(text: string): Map<number, number>;
|
|
409
|
+
|
|
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 };
|