@orkestrel/markdown 0.0.12 → 0.0.14
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/README.md +13 -7
- package/dist/src/core/index.cjs +955 -867
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +560 -377
- package/dist/src/core/index.d.ts +560 -377
- package/dist/src/core/index.js +956 -868
- package/dist/src/core/index.js.map +1 -1
- package/package.json +12 -14
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { BooleanShape } from '@orkestrel/contract';
|
|
2
|
-
import { CommentNode } from '@orkestrel/html';
|
|
3
|
-
import { ContractInterface } from '@orkestrel/contract';
|
|
4
|
-
import { DoctypeNode } from '@orkestrel/html';
|
|
5
|
-
import { ElementNode } from '@orkestrel/html';
|
|
6
|
-
import { Guard } from '@orkestrel/contract';
|
|
7
|
-
import { HTMLDocument } from '@orkestrel/html';
|
|
8
|
-
import { HTMLNode } from '@orkestrel/html';
|
|
2
|
+
import type { CommentNode } from '@orkestrel/html';
|
|
3
|
+
import type { ContractInterface } from '@orkestrel/contract';
|
|
4
|
+
import type { DoctypeNode } from '@orkestrel/html';
|
|
5
|
+
import type { ElementNode } from '@orkestrel/html';
|
|
6
|
+
import type { Guard } from '@orkestrel/contract';
|
|
7
|
+
import type { HTMLDocument } from '@orkestrel/html';
|
|
8
|
+
import type { HTMLNode } from '@orkestrel/html';
|
|
9
9
|
import { LiteralShape } from '@orkestrel/contract';
|
|
10
10
|
import { NumberShape } from '@orkestrel/contract';
|
|
11
11
|
import { ObjectShape } from '@orkestrel/contract';
|
|
12
12
|
import { OptionalShape } from '@orkestrel/contract';
|
|
13
13
|
import { StringShape } from '@orkestrel/contract';
|
|
14
|
-
import { TextNode as TextNode_2 } from '@orkestrel/html';
|
|
14
|
+
import type { TextNode as TextNode_2 } from '@orkestrel/html';
|
|
15
15
|
|
|
16
|
-
/**
|
|
16
|
+
/** Represents a node that can appear at the block level of a document (or inside a list item / blockquote). */
|
|
17
17
|
export declare type BlockNode = HeadingNode | ParagraphNode | ListNode | TableNode | CodeBlockNode | BlockquoteNode | ThematicBreakNode;
|
|
18
18
|
|
|
19
|
-
/**
|
|
19
|
+
/** Represents a blockquote — `>`-prefixed lines; `children` the block content parsed from the de-quoted lines (so quotes nest). */
|
|
20
20
|
export declare interface BlockquoteNode {
|
|
21
21
|
readonly element: 'blockquote';
|
|
22
|
-
/**
|
|
22
|
+
/** Holds the block content of the quote (the `>`-stripped lines, re-parsed as blocks). */
|
|
23
23
|
readonly children: readonly BlockNode[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Merges adjacent text nodes into one — the inline scanner emits a text node per
|
|
28
28
|
* unrecognized character, so coalescing keeps the AST clean and assertion-friendly.
|
|
29
29
|
*
|
|
30
30
|
* @param nodes - The inline nodes (possibly with adjacent text runs)
|
|
@@ -40,21 +40,21 @@ export declare interface BlockquoteNode {
|
|
|
40
40
|
export declare function coalesceText(nodes: readonly InlineNode[], spans?: Map<MarkdownNode, MarkdownSpan>): readonly InlineNode[];
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Represents a fenced code block — ```` ```lang ````. `code` is the verbatim block content (no
|
|
44
44
|
* inner markdown; the closing fence and the trailing newline are stripped), `lang`
|
|
45
45
|
* the info-string language tag (the first word after the opening fence), absent when
|
|
46
46
|
* none was given.
|
|
47
47
|
*/
|
|
48
48
|
export declare interface CodeBlockNode {
|
|
49
49
|
readonly element: 'codeBlock';
|
|
50
|
-
/**
|
|
50
|
+
/** Holds the info-string language tag (first word after the opening fence), if any. */
|
|
51
51
|
readonly lang?: string;
|
|
52
|
-
/**
|
|
52
|
+
/** Holds the verbatim code content (no inner markdown; HTML-escaped at render). */
|
|
53
53
|
readonly code: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
57
|
+
* Describes the shape of a {@link CodeBlockNode} — a fenced code block. `lang` is
|
|
58
58
|
* optional (absent when the opening fence carries no info-string).
|
|
59
59
|
*
|
|
60
60
|
* @example
|
|
@@ -67,25 +67,36 @@ export declare interface CodeBlockNode {
|
|
|
67
67
|
* codeBlock.is({ element: 'codeBlock', code: 'x', lang: 'ts' }) // true
|
|
68
68
|
* ```
|
|
69
69
|
*/
|
|
70
|
-
export declare const codeBlockShape: ObjectShape<{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
export declare const codeBlockShape: ObjectShape< {
|
|
71
|
+
element: LiteralShape<readonly ["codeBlock"]>;
|
|
72
|
+
lang: OptionalShape<StringShape>;
|
|
73
|
+
code: StringShape;
|
|
74
74
|
}, false>;
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
77
|
+
* Represents the located extent of one inline code span — the value the inline phase's code
|
|
78
|
+
* scanner returns for a matched backtick run.
|
|
79
|
+
*/
|
|
80
|
+
export declare interface CodeSpanMatch {
|
|
81
|
+
/** Holds the span's literal text, with one padding space stripped from each end. */
|
|
82
|
+
readonly value: string;
|
|
83
|
+
/** Holds the index one past the span's closing backtick run, exclusive. */
|
|
84
|
+
readonly end: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Represents an inline code span — `` `code` ``. `value` is the verbatim span text; no inner
|
|
78
89
|
* markdown is parsed (code is literal), and the renderer HTML-escapes it inside a
|
|
79
90
|
* `<code>` element.
|
|
80
91
|
*/
|
|
81
92
|
export declare interface CodeSpanNode {
|
|
82
93
|
readonly element: 'codeSpan';
|
|
83
|
-
/**
|
|
94
|
+
/** Holds the verbatim code text (no inner markdown; HTML-escaped at render). */
|
|
84
95
|
readonly value: string;
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
/**
|
|
88
|
-
*
|
|
99
|
+
* Describes the shape of a {@link CodeSpanNode} — an inline code span (`` `code` ``).
|
|
89
100
|
*
|
|
90
101
|
* @example
|
|
91
102
|
* ```ts
|
|
@@ -96,9 +107,9 @@ export declare interface CodeSpanNode {
|
|
|
96
107
|
* codeSpan.is({ element: 'codeSpan', value: 'const x = 1' }) // true
|
|
97
108
|
* ```
|
|
98
109
|
*/
|
|
99
|
-
export declare const codeSpanShape: ObjectShape<{
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
export declare const codeSpanShape: ObjectShape< {
|
|
111
|
+
element: LiteralShape<readonly ["codeSpan"]>;
|
|
112
|
+
value: StringShape;
|
|
102
113
|
}, false>;
|
|
103
114
|
|
|
104
115
|
/**
|
|
@@ -117,10 +128,7 @@ export declare const codeSpanShape: ObjectShape<{
|
|
|
117
128
|
* collectList(splitLines('- item'), 0, 0) // { node: { element: 'list', ... }, next: 1 }
|
|
118
129
|
* ```
|
|
119
130
|
*/
|
|
120
|
-
export declare function collectList(lines: readonly MarkdownSource[], start: number, depth: number, spans?: Map<MarkdownNode, MarkdownSpan>, end?: number):
|
|
121
|
-
readonly node: ListNode;
|
|
122
|
-
readonly next: number;
|
|
123
|
-
};
|
|
131
|
+
export declare function collectList(lines: readonly MarkdownSource[], start: number, depth: number, spans?: Map<MarkdownNode, MarkdownSpan>, end?: number): ListCollection;
|
|
124
132
|
|
|
125
133
|
/**
|
|
126
134
|
* Collects a GFM table starting at a header row, parsing the header, the
|
|
@@ -136,13 +144,10 @@ export declare function collectList(lines: readonly MarkdownSource[], start: num
|
|
|
136
144
|
* collectTable(splitLines('| a |\n| - |'), 0) // { node: { element: 'table', ... }, next: 2 }
|
|
137
145
|
* ```
|
|
138
146
|
*/
|
|
139
|
-
export declare function collectTable(lines: readonly MarkdownSource[], start: number, spans?: Map<MarkdownNode, MarkdownSpan>):
|
|
140
|
-
readonly node: TableNode;
|
|
141
|
-
readonly next: number;
|
|
142
|
-
};
|
|
147
|
+
export declare function collectTable(lines: readonly MarkdownSource[], start: number, spans?: Map<MarkdownNode, MarkdownSpan>): TableCollection;
|
|
143
148
|
|
|
144
149
|
/**
|
|
145
|
-
*
|
|
150
|
+
* Counts the leading space / tab characters on `line` (a tab counts as one) — the
|
|
146
151
|
* indent that decides whether a list item's continuation belongs to the item.
|
|
147
152
|
*
|
|
148
153
|
* @param line - The line to measure
|
|
@@ -156,9 +161,9 @@ export declare function collectTable(lines: readonly MarkdownSource[], start: nu
|
|
|
156
161
|
export declare function countIndent(line: string): number;
|
|
157
162
|
|
|
158
163
|
/**
|
|
159
|
-
*
|
|
160
|
-
* {@link CodeBlockNode}
|
|
161
|
-
* generator from one shape declaration
|
|
164
|
+
* Compiles the {@link codeBlockShape} into a {@link ContractInterface} for
|
|
165
|
+
* {@link CodeBlockNode} — a guard, coercing parser, JSON Schema, and seeded
|
|
166
|
+
* generator from one shape declaration.
|
|
162
167
|
*
|
|
163
168
|
* @returns A `CodeBlockNode` contract bundling `schema` / `is` / `parse` / `generate`
|
|
164
169
|
*
|
|
@@ -173,9 +178,9 @@ export declare function countIndent(line: string): number;
|
|
|
173
178
|
export declare function createCodeBlockContract(): ContractInterface<CodeBlockNode>;
|
|
174
179
|
|
|
175
180
|
/**
|
|
176
|
-
*
|
|
177
|
-
* {@link CodeSpanNode}
|
|
178
|
-
* generator from one shape declaration
|
|
181
|
+
* Compiles the {@link codeSpanShape} into a {@link ContractInterface} for
|
|
182
|
+
* {@link CodeSpanNode} — a guard, coercing parser, JSON Schema, and seeded
|
|
183
|
+
* generator from one shape declaration.
|
|
179
184
|
*
|
|
180
185
|
* @returns A `CodeSpanNode` contract bundling `schema` / `is` / `parse` / `generate`
|
|
181
186
|
*
|
|
@@ -190,7 +195,7 @@ export declare function createCodeBlockContract(): ContractInterface<CodeBlockNo
|
|
|
190
195
|
export declare function createCodeSpanContract(): ContractInterface<CodeSpanNode>;
|
|
191
196
|
|
|
192
197
|
/**
|
|
193
|
-
*
|
|
198
|
+
* Compiles the {@link lineBreakShape} into a {@link ContractInterface} for
|
|
194
199
|
* {@link LineBreakNode}.
|
|
195
200
|
*
|
|
196
201
|
* @returns A `LineBreakNode` contract bundling `schema` / `is` / `parse` / `generate`
|
|
@@ -205,8 +210,8 @@ export declare function createCodeSpanContract(): ContractInterface<CodeSpanNode
|
|
|
205
210
|
export declare function createLineBreakContract(): ContractInterface<LineBreakNode>;
|
|
206
211
|
|
|
207
212
|
/**
|
|
208
|
-
*
|
|
209
|
-
* {@link MarkdownDocument}
|
|
213
|
+
* Creates a stateful markdown handle from a markdown string or an already-parsed
|
|
214
|
+
* {@link MarkdownDocument} — a typed AST plus the query, rewrite, and fold operations
|
|
210
215
|
* {@link MarkdownInterface} exposes.
|
|
211
216
|
*
|
|
212
217
|
* @remarks
|
|
@@ -214,9 +219,9 @@ export declare function createLineBreakContract(): ContractInterface<LineBreakNo
|
|
|
214
219
|
* fenced code / blockquotes / thematic breaks) then an inline phase (emphasis /
|
|
215
220
|
* inline code / links / images / hard breaks) to build a render-agnostic
|
|
216
221
|
* {@link MarkdownDocument}. Given a
|
|
217
|
-
* {@link MarkdownDocument}, adopts it
|
|
222
|
+
* {@link MarkdownDocument}, adopts it as-is without re-validation — gate an untrusted
|
|
218
223
|
* value with `isMarkdownDocument` first. Pure + total parse (malformed markdown
|
|
219
|
-
* degrades to text, never throws) and zero-dependency
|
|
224
|
+
* degrades to text, never throws) and zero-dependency — a hand-written scanner, no
|
|
220
225
|
* regex-only structural parse, linear-time (no ReDoS).
|
|
221
226
|
*
|
|
222
227
|
* @param input - A markdown string to parse, or an already-parsed {@link MarkdownDocument}
|
|
@@ -233,7 +238,7 @@ export declare function createLineBreakContract(): ContractInterface<LineBreakNo
|
|
|
233
238
|
export declare function createMarkdown(input: string | MarkdownDocument): MarkdownInterface;
|
|
234
239
|
|
|
235
240
|
/**
|
|
236
|
-
*
|
|
241
|
+
* Builds an HTML-to-markdown projection with absent fields defaulted from
|
|
237
242
|
* {@link EMPTY_PROJECTION} and the block/inline exclusivity invariant enforced.
|
|
238
243
|
*
|
|
239
244
|
* @remarks
|
|
@@ -255,9 +260,9 @@ export declare function createMarkdown(input: string | MarkdownDocument): Markdo
|
|
|
255
260
|
export declare function createProjection(parts?: Partial<MarkdownProjection>): MarkdownProjection;
|
|
256
261
|
|
|
257
262
|
/**
|
|
258
|
-
*
|
|
259
|
-
* {@link TextNode}
|
|
260
|
-
* generator from one shape declaration
|
|
263
|
+
* Compiles the {@link textShape} into a {@link ContractInterface} for
|
|
264
|
+
* {@link TextNode} — a guard, coercing parser, JSON Schema, and seeded
|
|
265
|
+
* generator from one shape declaration.
|
|
261
266
|
*
|
|
262
267
|
* @returns A `TextNode` contract bundling `schema` / `is` / `parse` / `generate`
|
|
263
268
|
*
|
|
@@ -272,9 +277,9 @@ export declare function createProjection(parts?: Partial<MarkdownProjection>): M
|
|
|
272
277
|
export declare function createTextContract(): ContractInterface<TextNode>;
|
|
273
278
|
|
|
274
279
|
/**
|
|
275
|
-
*
|
|
276
|
-
* {@link ThematicBreakNode}
|
|
277
|
-
* seeded generator from one shape declaration
|
|
280
|
+
* Compiles the {@link thematicBreakShape} into a {@link ContractInterface} for
|
|
281
|
+
* {@link ThematicBreakNode} — a guard, coercing parser, JSON Schema, and
|
|
282
|
+
* seeded generator from one shape declaration.
|
|
278
283
|
*
|
|
279
284
|
* @returns A `ThematicBreakNode` contract bundling `schema` / `is` / `parse` / `generate`
|
|
280
285
|
*
|
|
@@ -289,7 +294,7 @@ export declare function createTextContract(): ContractInterface<TextNode>;
|
|
|
289
294
|
export declare function createThematicBreakContract(): ContractInterface<ThematicBreakNode>;
|
|
290
295
|
|
|
291
296
|
/**
|
|
292
|
-
*
|
|
297
|
+
* Derives the per-column {@link TableAlign} list from a GFM delimiter row — `:---`
|
|
293
298
|
* left, `---:` right, `:---:` center, and `---` as the explicit no-alignment
|
|
294
299
|
* marker represented by `null`.
|
|
295
300
|
*
|
|
@@ -304,21 +309,47 @@ export declare function createThematicBreakContract(): ContractInterface<Themati
|
|
|
304
309
|
export declare function delimiterToAlignments(delimiter: string): ReadonlyArray<TableAlign | null>;
|
|
305
310
|
|
|
306
311
|
/**
|
|
307
|
-
*
|
|
312
|
+
* Represents the located content and syntax bounds of one emphasis run — the value the inline
|
|
313
|
+
* phase's emphasis locator returns for a matched marker run.
|
|
314
|
+
*/
|
|
315
|
+
export declare interface EmphasisBounds {
|
|
316
|
+
/** Holds `true` for a doubled marker (`**strong**`), `false` for a single one (`*em*`). */
|
|
317
|
+
readonly strong: boolean;
|
|
318
|
+
/** Holds the index of the run's first content character. */
|
|
319
|
+
readonly open: number;
|
|
320
|
+
/** Holds the index of the closing marker run's first character. */
|
|
321
|
+
readonly close: number;
|
|
322
|
+
/** Holds the index one past the closing marker run, exclusive. */
|
|
323
|
+
readonly end: number;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Represents emphasized inline content — `*italic*` / `_italic_` (`strong: false`) or
|
|
308
328
|
* `**bold**` / `__bold__` (`strong: true`). `children` are the nested inline nodes,
|
|
309
329
|
* so emphasis composes (a `**bold _and italic_**` is a strong node wrapping a text
|
|
310
330
|
* node and an emphasis node).
|
|
311
331
|
*/
|
|
312
332
|
export declare interface EmphasisNode {
|
|
313
333
|
readonly element: 'emphasis';
|
|
314
|
-
/** `true` for strong (`**` / `__`, → `<strong>`); `false` for ordinary emphasis (`*` / `_`, → `<em>`). */
|
|
334
|
+
/** Holds `true` for strong (`**` / `__`, → `<strong>`); `false` for ordinary emphasis (`*` / `_`, → `<em>`). */
|
|
315
335
|
readonly strong: boolean;
|
|
316
|
-
/**
|
|
336
|
+
/** Holds the emphasized inline content. */
|
|
317
337
|
readonly children: readonly InlineNode[];
|
|
318
338
|
}
|
|
319
339
|
|
|
320
340
|
/**
|
|
321
|
-
*
|
|
341
|
+
* Represents the scanned result of one emphasis run — the node the inline phase's emphasis
|
|
342
|
+
* scanner built from {@link EmphasisBounds} and where the scan resumes.
|
|
343
|
+
*/
|
|
344
|
+
export declare interface EmphasisScan {
|
|
345
|
+
/** Holds the scanned emphasis run, its content already scanned into inline children. */
|
|
346
|
+
readonly node: EmphasisNode;
|
|
347
|
+
/** Holds the index one past the closing marker run, exclusive. */
|
|
348
|
+
readonly end: number;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Holds the frozen empty HTML-to-markdown projection from which projection factories
|
|
322
353
|
* default every absent field.
|
|
323
354
|
*
|
|
324
355
|
* @example
|
|
@@ -330,7 +361,7 @@ export declare interface EmphasisNode {
|
|
|
330
361
|
export declare const EMPTY_PROJECTION: MarkdownProjection;
|
|
331
362
|
|
|
332
363
|
/**
|
|
333
|
-
*
|
|
364
|
+
* Extracts a fenced-code opening line (```` ``` ```` or `~~~`, optionally with an info
|
|
334
365
|
* string) into its `{ marker, lang }`, or `undefined` when `line` is not a fence
|
|
335
366
|
* opener. `marker` is the exact fence run (the closer must match the same character +
|
|
336
367
|
* at least the same length); `lang` is the first word of the info string.
|
|
@@ -343,10 +374,7 @@ export declare const EMPTY_PROJECTION: MarkdownProjection;
|
|
|
343
374
|
* extractFence('```ts') // { marker: '```', lang: 'ts' }
|
|
344
375
|
* ```
|
|
345
376
|
*/
|
|
346
|
-
export declare function extractFence(line: string):
|
|
347
|
-
readonly marker: string;
|
|
348
|
-
readonly lang: string | undefined;
|
|
349
|
-
} | undefined;
|
|
377
|
+
export declare function extractFence(line: string): FenceMatch | undefined;
|
|
350
378
|
|
|
351
379
|
/**
|
|
352
380
|
* Extracts an ATX heading line (`#` … `######` followed by text) into its level,
|
|
@@ -362,14 +390,10 @@ export declare function extractFence(line: string): {
|
|
|
362
390
|
* extractHeading('## Title') // { level: 2, text: 'Title', offset: 3 }
|
|
363
391
|
* ```
|
|
364
392
|
*/
|
|
365
|
-
export declare function extractHeading(line: string):
|
|
366
|
-
readonly level: number;
|
|
367
|
-
readonly text: string;
|
|
368
|
-
readonly offset: number;
|
|
369
|
-
} | undefined;
|
|
393
|
+
export declare function extractHeading(line: string): HeadingMatch | undefined;
|
|
370
394
|
|
|
371
395
|
/**
|
|
372
|
-
*
|
|
396
|
+
* Extracts a list-item line (`-` / `*` / `+` bullet, or `1.` / `1)` ordinal, followed by
|
|
373
397
|
* a space) into its {@link ListItemMatch}, or `undefined` when `line` is not a list
|
|
374
398
|
* item. `content` is the text after the marker; `marker` is the full marker-plus-space
|
|
375
399
|
* width (for measuring a continuation's indent).
|
|
@@ -385,8 +409,19 @@ export declare function extractHeading(line: string): {
|
|
|
385
409
|
export declare function extractListItem(line: string): ListItemMatch | undefined;
|
|
386
410
|
|
|
387
411
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
412
|
+
* Represents the parsed parts of a fenced-code opening line — the value the block phase's fence
|
|
413
|
+
* detector returns for a ```` ``` ```` or `~~~` opener.
|
|
414
|
+
*/
|
|
415
|
+
export declare interface FenceMatch {
|
|
416
|
+
/** Holds the exact fence run; a closer must repeat the same character at least as long. */
|
|
417
|
+
readonly marker: string;
|
|
418
|
+
/** Holds the first word of the info string, or `undefined` when the fence declares none. */
|
|
419
|
+
readonly lang: string | undefined;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Concatenates the `value` / `code` content of every descendant text / code-span /
|
|
424
|
+
* code-block node under `node`, including image alternative content, in walk order —
|
|
390
425
|
* the plain-text projection of an AST (search indexing, word counts, a text-only
|
|
391
426
|
* preview).
|
|
392
427
|
*
|
|
@@ -409,16 +444,16 @@ export declare function extractListItem(line: string): ListItemMatch | undefined
|
|
|
409
444
|
export declare function flattenText(node: MarkdownNode): string;
|
|
410
445
|
|
|
411
446
|
/**
|
|
412
|
-
*
|
|
447
|
+
* Folds a {@link MarkdownNode} into a `T` through a total catamorphism — children are
|
|
413
448
|
* folded first (post-order), then the node's own {@link MarkdownHandler} is invoked
|
|
414
449
|
* with the already-folded children.
|
|
415
450
|
*
|
|
416
451
|
* @remarks
|
|
417
|
-
* **Table contract.** A {@link TableNode} has no single `children` array
|
|
452
|
+
* **Table contract.** A {@link TableNode} has no single `children` array — its cells
|
|
418
453
|
* live in `header` (one inline-node list per column) and `rows` (a list of such
|
|
419
|
-
* rows). The `table` handler receives
|
|
420
|
-
* walk order across
|
|
421
|
-
* every body row's cells' inline nodes (row order, then column order)
|
|
454
|
+
* rows). The `table` handler receives one folded `T` per inline node, flattened in
|
|
455
|
+
* walk order across all cells — every header cell's inline nodes (column order), then
|
|
456
|
+
* every body row's cells' inline nodes (row order, then column order) — and reads
|
|
422
457
|
* `node.header[c].length` / `node.rows[r][c].length` off the table node itself to
|
|
423
458
|
* recover cell boundaries within the flat list.
|
|
424
459
|
*
|
|
@@ -426,64 +461,77 @@ export declare function flattenText(node: MarkdownNode): string;
|
|
|
426
461
|
* with an empty children list instead of recursing further.
|
|
427
462
|
*
|
|
428
463
|
* @param node - The AST node to fold
|
|
429
|
-
* @param handlers - The total {@link
|
|
464
|
+
* @param handlers - The total {@link MarkdownHandlerMap} table, one handler per element
|
|
430
465
|
* @param depth - The starting recursion depth (pass `0` at the entry point)
|
|
431
466
|
* @returns The folded `T`
|
|
432
467
|
*
|
|
433
468
|
* @example
|
|
434
469
|
* ```ts
|
|
435
|
-
* const countHandlers:
|
|
470
|
+
* const countHandlers: MarkdownHandlerMap<number> = {
|
|
436
471
|
* document: (_, children) => children.reduce((a, b) => a + b, 1),
|
|
437
472
|
* // ...one handler per element, each summing its folded children
|
|
438
473
|
* }
|
|
439
474
|
* foldNode(document, countHandlers, 0) // total node count
|
|
440
475
|
* ```
|
|
441
476
|
*/
|
|
442
|
-
export declare function foldNode<T>(node: MarkdownNode, handlers:
|
|
477
|
+
export declare function foldNode<T>(node: MarkdownNode, handlers: MarkdownHandlerMap<T>, depth: number): T;
|
|
443
478
|
|
|
444
479
|
/**
|
|
445
|
-
*
|
|
480
|
+
* Represents the parsed parts of a single ATX heading line — the value the block phase's heading
|
|
481
|
+
* detector returns for a `#` … `######` line.
|
|
482
|
+
*/
|
|
483
|
+
export declare interface HeadingMatch {
|
|
484
|
+
/** Holds the heading's level, 1 to 6. */
|
|
485
|
+
readonly level: number;
|
|
486
|
+
/** Holds the heading's raw inline text, with an optional closing `#` run stripped. */
|
|
487
|
+
readonly text: string;
|
|
488
|
+
/** Holds the offset of {@link HeadingMatch.text} inside the original line. */
|
|
489
|
+
readonly offset: number;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Represents an ATX heading — `#` … `######`. `level` is 1–6 (the number of leading `#`),
|
|
446
494
|
* `children` the inline content of the heading text.
|
|
447
495
|
*/
|
|
448
496
|
export declare interface HeadingNode {
|
|
449
497
|
readonly element: 'heading';
|
|
450
|
-
/**
|
|
498
|
+
/** Holds the heading level, 1 (`#`) through 6 (`######`). */
|
|
451
499
|
readonly level: number;
|
|
452
|
-
/**
|
|
500
|
+
/** Holds the inline content of the heading text. */
|
|
453
501
|
readonly children: readonly InlineNode[];
|
|
454
502
|
}
|
|
455
503
|
|
|
456
504
|
/**
|
|
457
|
-
*
|
|
505
|
+
* Projects an `@orkestrel/html` {@link HTMLNode} into a {@link MarkdownDocument} — the
|
|
458
506
|
* HTML→markdown direction, and the inverse of {@link markdownToHTML}.
|
|
459
507
|
*
|
|
460
508
|
* @remarks
|
|
461
|
-
* **Engine.** One total handler table
|
|
462
|
-
* {@link projectHTMLLeaf} for the leaves
|
|
509
|
+
* **Engine.** One total handler table — {@link projectHTMLNode} for the containers,
|
|
510
|
+
* {@link projectHTMLLeaf} for the leaves — folded by `@orkestrel/html`'s own `foldNode`, so
|
|
463
511
|
* depth capping, cycle safety, and bottom-up ordering are inherited rather than
|
|
464
512
|
* rebuilt. Total: hostile, cyclic, and pathologically deep input degrades instead of
|
|
465
513
|
* throwing.
|
|
466
514
|
*
|
|
467
515
|
* **Composed depth.** Both packages cap recursion at 64, and html's cap is reached
|
|
468
|
-
* first: a document nested past it projects to a chain bounded by
|
|
516
|
+
* first: a document nested past it projects to a chain bounded by that cap, with the
|
|
469
517
|
* content below it truncated before markdown ever sees it. Since the projected chain
|
|
470
518
|
* can be a level or two deeper than {@link MAX_DEPTH}, the serializer's own cap can
|
|
471
|
-
* then truncate again
|
|
519
|
+
* then truncate again — so the anchor law that follows is a law within the depth budget, and
|
|
472
520
|
* beyond it only totality is promised.
|
|
473
521
|
*
|
|
474
522
|
* **Safety.** Every `href` and `src` is re-sanitized through
|
|
475
523
|
* `sanitizeURL(value, SAFE_URL_SCHEMES)` whether or not the AST was ever sanitized,
|
|
476
524
|
* because a hand-built one never was. A refused destination empties to `''` and the
|
|
477
|
-
* link or image is
|
|
525
|
+
* link or image is kept — `[text]()` — because a bad URL is no reason to lose the words
|
|
478
526
|
* around it. An `UNSAFE_ELEMENTS` subtree contributes nothing at all, text included, so
|
|
479
527
|
* a `script` body can never resurface as prose.
|
|
480
528
|
*
|
|
481
529
|
* **The anchor law.** HTML→markdown is lossy, so the fixpoint that matters is the
|
|
482
|
-
*
|
|
530
|
+
* projected AST, not the input bytes:
|
|
483
531
|
* `parseDocument(renderMarkdown(htmlToMarkdown(x)))` deep-equals `htmlToMarkdown(x)`.
|
|
484
532
|
* The projection therefore emits canonical markdown shapes rather than literal
|
|
485
|
-
* translations
|
|
486
|
-
* break only where a line can end
|
|
533
|
+
* translations — whitespace collapsed, edges trimmed, a blank paragraph dropped, a hard
|
|
534
|
+
* break only where a line can end — because a shape markdown cannot write back is a
|
|
487
535
|
* shape this projection has no business producing.
|
|
488
536
|
*
|
|
489
537
|
* @param node - The HTML document or bare node to project
|
|
@@ -500,27 +548,27 @@ export declare interface HeadingNode {
|
|
|
500
548
|
export declare function htmlToMarkdown(node: HTMLNode): MarkdownDocument;
|
|
501
549
|
|
|
502
550
|
/**
|
|
503
|
-
*
|
|
551
|
+
* Represents an inline image — ``. `children` are the inline nodes of the
|
|
504
552
|
* alternative content and `src` is the image destination.
|
|
505
553
|
*/
|
|
506
554
|
export declare interface ImageNode {
|
|
507
555
|
readonly element: 'image';
|
|
508
|
-
/**
|
|
556
|
+
/** Holds the image destination. */
|
|
509
557
|
readonly src: string;
|
|
510
|
-
/**
|
|
558
|
+
/** Holds the inline alternative content. */
|
|
511
559
|
readonly children: readonly InlineNode[];
|
|
512
560
|
}
|
|
513
561
|
|
|
514
|
-
/**
|
|
562
|
+
/** Represents a node that can appear inside inline content (a heading / paragraph / cell / list item / link text). */
|
|
515
563
|
export declare type InlineNode = TextNode | EmphasisNode | CodeSpanNode | LineBreakNode | LinkNode | ImageNode;
|
|
516
564
|
|
|
517
565
|
/**
|
|
518
|
-
*
|
|
566
|
+
* Checks whether `line` is blank — empty, or containing only whitespace — the markdown
|
|
519
567
|
* definition of a blank line that block parsing uses to separate paragraphs, skip
|
|
520
568
|
* gaps, and end list continuations.
|
|
521
569
|
*
|
|
522
570
|
* @param line - The candidate line
|
|
523
|
-
* @returns
|
|
571
|
+
* @returns True if the line is blank; false otherwise
|
|
524
572
|
*
|
|
525
573
|
* @example
|
|
526
574
|
* ```ts
|
|
@@ -530,19 +578,19 @@ export declare type InlineNode = TextNode | EmphasisNode | CodeSpanNode | LineBr
|
|
|
530
578
|
export declare function isBlankLine(line: string): boolean;
|
|
531
579
|
|
|
532
580
|
/**
|
|
533
|
-
*
|
|
581
|
+
* Determines whether an arbitrary value is a valid {@link BlockNode} — a
|
|
534
582
|
* heading, paragraph, list, table, code block, blockquote, or thematic break,
|
|
535
583
|
* recursively validated.
|
|
536
584
|
*
|
|
537
585
|
* @remarks
|
|
538
|
-
* Total: never throws, even on cyclic or pathologically deep input
|
|
586
|
+
* Total: never throws, even on cyclic or pathologically deep input — every
|
|
539
587
|
* combinator involved (`unionOf`, `recordOf`, `arrayOf`, `lazyOf`) is
|
|
540
|
-
* throw-contained per the `@orkestrel/contract` guard contract
|
|
588
|
+
* throw-contained per the `@orkestrel/contract` guard contract.
|
|
541
589
|
* A list item's shape is inlined here (and in {@link isMarkdownNode}) rather
|
|
542
|
-
* than named separately
|
|
590
|
+
* than named separately — it is used at exactly these two sites.
|
|
543
591
|
*
|
|
544
592
|
* @param value - The value to test
|
|
545
|
-
* @returns
|
|
593
|
+
* @returns True if `value` is a well-formed {@link BlockNode}; false otherwise
|
|
546
594
|
*
|
|
547
595
|
* @example
|
|
548
596
|
* ```ts
|
|
@@ -555,7 +603,10 @@ export declare function isBlankLine(line: string): boolean;
|
|
|
555
603
|
export declare const isBlockNode: Guard<BlockNode>;
|
|
556
604
|
|
|
557
605
|
/**
|
|
558
|
-
*
|
|
606
|
+
* Determines whether a node is a blockquote block.
|
|
607
|
+
*
|
|
608
|
+
* @param node - The AST node to test
|
|
609
|
+
* @returns True if the node is a {@link BlockquoteNode}; false otherwise
|
|
559
610
|
*
|
|
560
611
|
* @example
|
|
561
612
|
* ```ts
|
|
@@ -565,7 +616,10 @@ export declare const isBlockNode: Guard<BlockNode>;
|
|
|
565
616
|
export declare function isBlockquoteNode(node: MarkdownNode): node is BlockquoteNode;
|
|
566
617
|
|
|
567
618
|
/**
|
|
568
|
-
*
|
|
619
|
+
* Determines whether a node is a fenced code block.
|
|
620
|
+
*
|
|
621
|
+
* @param node - The AST node to test
|
|
622
|
+
* @returns True if the node is a {@link CodeBlockNode}; false otherwise
|
|
569
623
|
*
|
|
570
624
|
* @example
|
|
571
625
|
* ```ts
|
|
@@ -575,12 +629,15 @@ export declare function isBlockquoteNode(node: MarkdownNode): node is Blockquote
|
|
|
575
629
|
export declare function isCodeBlockNode(node: MarkdownNode): node is CodeBlockNode;
|
|
576
630
|
|
|
577
631
|
/**
|
|
578
|
-
*
|
|
632
|
+
* Determines whether a node is an inline code span.
|
|
579
633
|
*
|
|
580
634
|
* @remarks
|
|
581
|
-
* Narrows to {@link CodeSpanNode}
|
|
635
|
+
* Narrows to {@link CodeSpanNode} — the node whose `element` discriminant is
|
|
582
636
|
* `'codeSpan'`.
|
|
583
637
|
*
|
|
638
|
+
* @param node - The AST node to test
|
|
639
|
+
* @returns True if the node is a {@link CodeSpanNode}; false otherwise
|
|
640
|
+
*
|
|
584
641
|
* @example
|
|
585
642
|
* ```ts
|
|
586
643
|
* isCodeSpanNode({ element: 'codeSpan', value: 'x' }) // true
|
|
@@ -589,7 +646,10 @@ export declare function isCodeBlockNode(node: MarkdownNode): node is CodeBlockNo
|
|
|
589
646
|
export declare function isCodeSpanNode(node: MarkdownNode): node is CodeSpanNode;
|
|
590
647
|
|
|
591
648
|
/**
|
|
592
|
-
*
|
|
649
|
+
* Determines whether a node is an emphasis run (`*em*` / `**strong**`).
|
|
650
|
+
*
|
|
651
|
+
* @param node - The AST node to test
|
|
652
|
+
* @returns True if the node is an {@link EmphasisNode}; false otherwise
|
|
593
653
|
*
|
|
594
654
|
* @example
|
|
595
655
|
* ```ts
|
|
@@ -599,11 +659,11 @@ export declare function isCodeSpanNode(node: MarkdownNode): node is CodeSpanNode
|
|
|
599
659
|
export declare function isEmphasisNode(node: MarkdownNode): node is EmphasisNode;
|
|
600
660
|
|
|
601
661
|
/**
|
|
602
|
-
*
|
|
662
|
+
* Checks whether `character` is escapable by a leading backslash — the ASCII punctuation
|
|
603
663
|
* markdown gives meaning to (so `\*` becomes `*` but `\.` stays `\.`).
|
|
604
664
|
*
|
|
605
665
|
* @param character - The single character after a backslash
|
|
606
|
-
* @returns
|
|
666
|
+
* @returns True if a backslash before it is an escape; false otherwise
|
|
607
667
|
*
|
|
608
668
|
* @example
|
|
609
669
|
* ```ts
|
|
@@ -614,12 +674,12 @@ export declare function isEmphasisNode(node: MarkdownNode): node is EmphasisNode
|
|
|
614
674
|
export declare function isEscapable(character: string): boolean;
|
|
615
675
|
|
|
616
676
|
/**
|
|
617
|
-
*
|
|
677
|
+
* Checks whether `line` closes a fence opened by `marker` — the same fence character, a run
|
|
618
678
|
* at least as long, and nothing else but surrounding whitespace.
|
|
619
679
|
*
|
|
620
680
|
* @param line - The candidate closing line
|
|
621
681
|
* @param marker - The opening fence's marker run (from {@link extractFence})
|
|
622
|
-
* @returns
|
|
682
|
+
* @returns True if `line` closes the fence; false otherwise
|
|
623
683
|
*
|
|
624
684
|
* @example
|
|
625
685
|
* ```ts
|
|
@@ -629,11 +689,11 @@ export declare function isEscapable(character: string): boolean;
|
|
|
629
689
|
export declare function isFenceClose(line: string, marker: string): boolean;
|
|
630
690
|
|
|
631
691
|
/**
|
|
632
|
-
*
|
|
692
|
+
* Checks whether `character` is a regex-`\s`-equivalent whitespace character — the
|
|
633
693
|
* character class {@link isFenceClose}'s scan treats as surrounding padding.
|
|
634
694
|
*
|
|
635
695
|
* @param character - The single character to test, or `undefined` past the end of a line
|
|
636
|
-
* @returns
|
|
696
|
+
* @returns True if it is whitespace; false otherwise
|
|
637
697
|
*
|
|
638
698
|
* @example
|
|
639
699
|
* ```ts
|
|
@@ -643,11 +703,39 @@ export declare function isFenceClose(line: string, marker: string): boolean;
|
|
|
643
703
|
*/
|
|
644
704
|
export declare function isFenceWhitespace(character: string | undefined): boolean;
|
|
645
705
|
|
|
646
|
-
/**
|
|
706
|
+
/**
|
|
707
|
+
* Checks whether `character` is whitespace under the emphasis flanking rule — a space, a
|
|
708
|
+
* tab, or a newline.
|
|
709
|
+
*
|
|
710
|
+
* @param character - The character to test
|
|
711
|
+
* @returns True if the flanking rule counts it as whitespace; false otherwise
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* ```ts
|
|
715
|
+
* isFlankingWhitespace(' ') // true
|
|
716
|
+
* isFlankingWhitespace('a') // false
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
export declare function isFlankingWhitespace(character: string): boolean;
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Determines whether a node is a heading block.
|
|
723
|
+
*
|
|
724
|
+
* @param node - The AST node to test
|
|
725
|
+
* @returns True if the node is a {@link HeadingNode}; false otherwise
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* ```ts
|
|
729
|
+
* isHeadingNode({ element: 'heading', level: 1, children: [] }) // true
|
|
730
|
+
* ```
|
|
731
|
+
*/
|
|
647
732
|
export declare function isHeadingNode(node: MarkdownNode): node is HeadingNode;
|
|
648
733
|
|
|
649
734
|
/**
|
|
650
|
-
*
|
|
735
|
+
* Determines whether a node is an image.
|
|
736
|
+
*
|
|
737
|
+
* @param node - The AST node to test
|
|
738
|
+
* @returns True if the node is an {@link ImageNode}; false otherwise
|
|
651
739
|
*
|
|
652
740
|
* @example
|
|
653
741
|
* ```ts
|
|
@@ -657,16 +745,16 @@ export declare function isHeadingNode(node: MarkdownNode): node is HeadingNode;
|
|
|
657
745
|
export declare function isImageNode(node: MarkdownNode): node is ImageNode;
|
|
658
746
|
|
|
659
747
|
/**
|
|
660
|
-
*
|
|
748
|
+
* Determines whether an arbitrary value is a valid {@link InlineNode} — a text
|
|
661
749
|
* run, emphasis, code span, hard break, link, or image, recursively validated.
|
|
662
750
|
*
|
|
663
751
|
* @remarks
|
|
664
|
-
* Total: never throws, even on cyclic or pathologically deep input
|
|
752
|
+
* Total: never throws, even on cyclic or pathologically deep input — every
|
|
665
753
|
* combinator involved (`unionOf`, `recordOf`, `arrayOf`, `lazyOf`) is
|
|
666
|
-
* throw-contained per the `@orkestrel/contract` guard contract
|
|
754
|
+
* throw-contained per the `@orkestrel/contract` guard contract.
|
|
667
755
|
*
|
|
668
756
|
* @param value - The value to test
|
|
669
|
-
* @returns
|
|
757
|
+
* @returns True if `value` is a well-formed {@link InlineNode}; false otherwise
|
|
670
758
|
*
|
|
671
759
|
* @example
|
|
672
760
|
* ```ts
|
|
@@ -679,7 +767,10 @@ export declare function isImageNode(node: MarkdownNode): node is ImageNode;
|
|
|
679
767
|
export declare const isInlineNode: Guard<InlineNode>;
|
|
680
768
|
|
|
681
769
|
/**
|
|
682
|
-
*
|
|
770
|
+
* Determines whether a node is a GFM hard line break.
|
|
771
|
+
*
|
|
772
|
+
* @param node - The AST node to test
|
|
773
|
+
* @returns True if the node is a {@link LineBreakNode}; false otherwise
|
|
683
774
|
*
|
|
684
775
|
* @example
|
|
685
776
|
* ```ts
|
|
@@ -688,11 +779,24 @@ export declare const isInlineNode: Guard<InlineNode>;
|
|
|
688
779
|
*/
|
|
689
780
|
export declare function isLineBreakNode(node: MarkdownNode): node is LineBreakNode;
|
|
690
781
|
|
|
691
|
-
/**
|
|
782
|
+
/**
|
|
783
|
+
* Determines whether a node is a link.
|
|
784
|
+
*
|
|
785
|
+
* @param node - The AST node to test
|
|
786
|
+
* @returns True if the node is a {@link LinkNode}; false otherwise
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```ts
|
|
790
|
+
* isLinkNode({ element: 'link', href: 'https://example.dev', children: [] }) // true
|
|
791
|
+
* ```
|
|
792
|
+
*/
|
|
692
793
|
export declare function isLinkNode(node: MarkdownNode): node is LinkNode;
|
|
693
794
|
|
|
694
795
|
/**
|
|
695
|
-
*
|
|
796
|
+
* Determines whether a node is a list block.
|
|
797
|
+
*
|
|
798
|
+
* @param node - The AST node to test
|
|
799
|
+
* @returns True if the node is a {@link ListNode}; false otherwise
|
|
696
800
|
*
|
|
697
801
|
* @example
|
|
698
802
|
* ```ts
|
|
@@ -702,17 +806,17 @@ export declare function isLinkNode(node: MarkdownNode): node is LinkNode;
|
|
|
702
806
|
export declare function isListNode(node: MarkdownNode): node is ListNode;
|
|
703
807
|
|
|
704
808
|
/**
|
|
705
|
-
*
|
|
809
|
+
* Determines whether an arbitrary value is a valid {@link MarkdownDocument} —
|
|
706
810
|
* the parsed-AST root {@link parseDocument} returns, recursively
|
|
707
811
|
* validated.
|
|
708
812
|
*
|
|
709
813
|
* @remarks
|
|
710
|
-
* Total: never throws, even on cyclic or pathologically deep input
|
|
814
|
+
* Total: never throws, even on cyclic or pathologically deep input — every
|
|
711
815
|
* combinator involved (`recordOf`, `arrayOf`) is throw-contained per the
|
|
712
|
-
* `@orkestrel/contract` guard contract
|
|
816
|
+
* `@orkestrel/contract` guard contract.
|
|
713
817
|
*
|
|
714
818
|
* @param value - The value to test
|
|
715
|
-
* @returns
|
|
819
|
+
* @returns True if `value` is a well-formed {@link MarkdownDocument}; false otherwise
|
|
716
820
|
*
|
|
717
821
|
* @example
|
|
718
822
|
* ```ts
|
|
@@ -725,19 +829,19 @@ export declare function isListNode(node: MarkdownNode): node is ListNode;
|
|
|
725
829
|
export declare const isMarkdownDocument: Guard<MarkdownDocument>;
|
|
726
830
|
|
|
727
831
|
/**
|
|
728
|
-
*
|
|
832
|
+
* Determines whether an arbitrary value is a valid {@link MarkdownNode} — the
|
|
729
833
|
* {@link MarkdownDocument} root, a {@link BlockNode}, a {@link ListItemNode}, or
|
|
730
834
|
* an {@link InlineNode}, recursively validated.
|
|
731
835
|
*
|
|
732
836
|
* @remarks
|
|
733
|
-
* Total: never throws, even on cyclic or pathologically deep input
|
|
837
|
+
* Total: never throws, even on cyclic or pathologically deep input — every
|
|
734
838
|
* combinator involved (`unionOf`, `recordOf`, `arrayOf`, `lazyOf`) is
|
|
735
|
-
* throw-contained per the `@orkestrel/contract` guard contract
|
|
839
|
+
* throw-contained per the `@orkestrel/contract` guard contract.
|
|
736
840
|
* A list item's shape is inlined here (and in {@link isBlockNode}) rather than
|
|
737
|
-
* named separately
|
|
841
|
+
* named separately — it is used at exactly these two sites.
|
|
738
842
|
*
|
|
739
843
|
* @param value - The value to test
|
|
740
|
-
* @returns
|
|
844
|
+
* @returns True if `value` is a well-formed {@link MarkdownNode}; false otherwise
|
|
741
845
|
*
|
|
742
846
|
* @example
|
|
743
847
|
* ```ts
|
|
@@ -750,7 +854,10 @@ export declare const isMarkdownDocument: Guard<MarkdownDocument>;
|
|
|
750
854
|
export declare const isMarkdownNode: Guard<MarkdownNode>;
|
|
751
855
|
|
|
752
856
|
/**
|
|
753
|
-
*
|
|
857
|
+
* Determines whether a node is a paragraph block.
|
|
858
|
+
*
|
|
859
|
+
* @param node - The AST node to test
|
|
860
|
+
* @returns True if the node is a {@link ParagraphNode}; false otherwise
|
|
754
861
|
*
|
|
755
862
|
* @example
|
|
756
863
|
* ```ts
|
|
@@ -760,11 +867,11 @@ export declare const isMarkdownNode: Guard<MarkdownNode>;
|
|
|
760
867
|
export declare function isParagraphNode(node: MarkdownNode): node is ParagraphNode;
|
|
761
868
|
|
|
762
869
|
/**
|
|
763
|
-
*
|
|
870
|
+
* Checks whether `line` is a blockquote line (`>` optionally indented up to three spaces) —
|
|
764
871
|
* its content is de-quoted by {@link stripQuote}.
|
|
765
872
|
*
|
|
766
873
|
* @param line - The candidate line
|
|
767
|
-
* @returns
|
|
874
|
+
* @returns True if the line begins a blockquote; false otherwise
|
|
768
875
|
*
|
|
769
876
|
* @example
|
|
770
877
|
* ```ts
|
|
@@ -773,17 +880,27 @@ export declare function isParagraphNode(node: MarkdownNode): node is ParagraphNo
|
|
|
773
880
|
*/
|
|
774
881
|
export declare function isQuote(line: string): boolean;
|
|
775
882
|
|
|
776
|
-
/**
|
|
883
|
+
/**
|
|
884
|
+
* Determines whether a node is a GFM table block.
|
|
885
|
+
*
|
|
886
|
+
* @param node - The AST node to test
|
|
887
|
+
* @returns True if the node is a {@link TableNode}; false otherwise
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* ```ts
|
|
891
|
+
* isTableNode({ element: 'table', header: [], rows: [], align: [] }) // true
|
|
892
|
+
* ```
|
|
893
|
+
*/
|
|
777
894
|
export declare function isTableNode(node: MarkdownNode): node is TableNode;
|
|
778
895
|
|
|
779
896
|
/**
|
|
780
|
-
*
|
|
897
|
+
* Checks whether the pair (`header`, `delimiter`) opens a GFM table — `delimiter` is a row of
|
|
781
898
|
* `|`-separated cells each matching `:?-+:?`, the GFM rule that a table requires a
|
|
782
|
-
* header row
|
|
899
|
+
* header row immediately followed by a delimiter row.
|
|
783
900
|
*
|
|
784
901
|
* @param header - The candidate header line
|
|
785
902
|
* @param delimiter - The line after it (the candidate delimiter)
|
|
786
|
-
* @returns
|
|
903
|
+
* @returns True if the two lines open a table; false otherwise
|
|
787
904
|
*
|
|
788
905
|
* @example
|
|
789
906
|
* ```ts
|
|
@@ -793,7 +910,10 @@ export declare function isTableNode(node: MarkdownNode): node is TableNode;
|
|
|
793
910
|
export declare function isTableStart(header: string, delimiter: string | undefined): boolean;
|
|
794
911
|
|
|
795
912
|
/**
|
|
796
|
-
*
|
|
913
|
+
* Determines whether a node is a plain text run.
|
|
914
|
+
*
|
|
915
|
+
* @param node - The AST node to test
|
|
916
|
+
* @returns True if the node is a {@link TextNode}; false otherwise
|
|
797
917
|
*
|
|
798
918
|
* @example
|
|
799
919
|
* ```ts
|
|
@@ -803,12 +923,12 @@ export declare function isTableStart(header: string, delimiter: string | undefin
|
|
|
803
923
|
export declare function isTextNode(node: MarkdownNode): node is TextNode;
|
|
804
924
|
|
|
805
925
|
/**
|
|
806
|
-
*
|
|
926
|
+
* Checks whether `line` is a thematic break (horizontal rule) — three or more of the same
|
|
807
927
|
* marker `-`, `*`, or `_` (optionally space-separated) and nothing else (`---`,
|
|
808
928
|
* `***`, `___`, `- - -`).
|
|
809
929
|
*
|
|
810
930
|
* @param line - The candidate line
|
|
811
|
-
* @returns
|
|
931
|
+
* @returns True if the line is a thematic break; false otherwise
|
|
812
932
|
*
|
|
813
933
|
* @example
|
|
814
934
|
* ```ts
|
|
@@ -818,7 +938,10 @@ export declare function isTextNode(node: MarkdownNode): node is TextNode;
|
|
|
818
938
|
export declare function isThematicBreak(line: string): boolean;
|
|
819
939
|
|
|
820
940
|
/**
|
|
821
|
-
*
|
|
941
|
+
* Determines whether a node is a thematic break (horizontal rule) block.
|
|
942
|
+
*
|
|
943
|
+
* @param node - The AST node to test
|
|
944
|
+
* @returns True if the node is a {@link ThematicBreakNode}; false otherwise
|
|
822
945
|
*
|
|
823
946
|
* @example
|
|
824
947
|
* ```ts
|
|
@@ -827,21 +950,6 @@ export declare function isThematicBreak(line: string): boolean;
|
|
|
827
950
|
*/
|
|
828
951
|
export declare function isThematicBreakNode(node: MarkdownNode): node is ThematicBreakNode;
|
|
829
952
|
|
|
830
|
-
/**
|
|
831
|
-
* Whether `character` is an inline whitespace character (space / tab / newline) - the
|
|
832
|
-
* emphasis flanking rule's space test.
|
|
833
|
-
*
|
|
834
|
-
* @param character - The character to test
|
|
835
|
-
* @returns `true` when it is inline whitespace
|
|
836
|
-
*
|
|
837
|
-
* @example
|
|
838
|
-
* ```ts
|
|
839
|
-
* isWhitespace(' ') // true
|
|
840
|
-
* isWhitespace('a') // false
|
|
841
|
-
* ```
|
|
842
|
-
*/
|
|
843
|
-
export declare function isWhitespace(character: string): boolean;
|
|
844
|
-
|
|
845
953
|
/**
|
|
846
954
|
* Joins offset-bearing markdown sources while mapping a separator to the original
|
|
847
955
|
* region between adjacent mapped sources.
|
|
@@ -858,13 +966,16 @@ export declare function isWhitespace(character: string): boolean;
|
|
|
858
966
|
*/
|
|
859
967
|
export declare function joinSources(sources: readonly MarkdownSource[], separator: string): MarkdownSource;
|
|
860
968
|
|
|
861
|
-
/**
|
|
969
|
+
/**
|
|
970
|
+
* Represents a GFM hard line break — two or more trailing spaces before a newline in
|
|
971
|
+
* markdown source, a `br` element in HTML.
|
|
972
|
+
*/
|
|
862
973
|
export declare interface LineBreakNode {
|
|
863
974
|
readonly element: 'break';
|
|
864
975
|
}
|
|
865
976
|
|
|
866
977
|
/**
|
|
867
|
-
*
|
|
978
|
+
* Describes the shape of a {@link LineBreakNode} — a GFM hard line-break leaf.
|
|
868
979
|
*
|
|
869
980
|
* @example
|
|
870
981
|
* ```ts
|
|
@@ -875,42 +986,75 @@ export declare interface LineBreakNode {
|
|
|
875
986
|
* lineBreak.is({ element: 'break' }) // true
|
|
876
987
|
* ```
|
|
877
988
|
*/
|
|
878
|
-
export declare const lineBreakShape: ObjectShape<{
|
|
879
|
-
|
|
989
|
+
export declare const lineBreakShape: ObjectShape< {
|
|
990
|
+
element: LiteralShape<readonly ["break"]>;
|
|
880
991
|
}, false>;
|
|
881
992
|
|
|
882
993
|
/**
|
|
883
|
-
*
|
|
994
|
+
* Represents the located syntax bounds of one `[text](href)` link — the value the inline phase's
|
|
995
|
+
* link locator returns for a balanced label followed by a destination.
|
|
996
|
+
*/
|
|
997
|
+
export declare interface LinkBounds {
|
|
998
|
+
/** Holds the index of the label's closing `]`. */
|
|
999
|
+
readonly close: number;
|
|
1000
|
+
/** Holds the index one past the destination's closing `)`, exclusive. */
|
|
1001
|
+
readonly end: number;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Represents an inline link — `[text](href)`. `children` are the inline nodes of the link text.
|
|
884
1006
|
* At render, html's floor removes a refused `href` attribute and the link keeps its
|
|
885
1007
|
* text; {@link htmlToMarkdown} instead stores a refused destination as `''`.
|
|
886
1008
|
*/
|
|
887
1009
|
export declare interface LinkNode {
|
|
888
1010
|
readonly element: 'link';
|
|
889
|
-
/**
|
|
1011
|
+
/** Holds the link destination (sanitized + attribute-escaped at render). */
|
|
890
1012
|
readonly href: string;
|
|
891
|
-
/**
|
|
1013
|
+
/** Holds the inline content of the link text. */
|
|
892
1014
|
readonly children: readonly InlineNode[];
|
|
893
1015
|
}
|
|
894
1016
|
|
|
895
1017
|
/**
|
|
896
|
-
*
|
|
1018
|
+
* Represents the scanned result of one `[text](href)` link — the node the inline phase's link
|
|
1019
|
+
* scanner built from {@link LinkBounds} and where the scan resumes.
|
|
1020
|
+
*/
|
|
1021
|
+
export declare interface LinkScan {
|
|
1022
|
+
/** Holds the scanned link, its text already scanned into inline children. */
|
|
1023
|
+
readonly node: LinkNode;
|
|
1024
|
+
/** Holds the index one past the destination's closing `)`, exclusive. */
|
|
1025
|
+
readonly end: number;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Represents the result of collecting one list — the node the construct scanner built and where
|
|
1030
|
+
* the block phase resumes.
|
|
1031
|
+
*/
|
|
1032
|
+
export declare interface ListCollection {
|
|
1033
|
+
/** Holds the collected list. */
|
|
1034
|
+
readonly node: ListNode;
|
|
1035
|
+
/** Holds the index of the first line after the list. */
|
|
1036
|
+
readonly next: number;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Represents the parsed parts of a single list-item line — the value the block phase's
|
|
897
1041
|
* list detector returns for a `-` / `*` / `+` bullet or a `1.` / `1)` ordinal line.
|
|
898
1042
|
*/
|
|
899
1043
|
export declare interface ListItemMatch {
|
|
900
|
-
/** `true` for an ordered (`1.` / `1)`) item, `false` for a bullet (`-` / `*` / `+`). */
|
|
1044
|
+
/** Holds `true` for an ordered (`1.` / `1)`) item, `false` for a bullet (`-` / `*` / `+`). */
|
|
901
1045
|
readonly ordered: boolean;
|
|
902
|
-
/**
|
|
1046
|
+
/** Holds the ordinal of an ordered item (its number); `1` for a bullet. */
|
|
903
1047
|
readonly start: number;
|
|
904
|
-
/**
|
|
1048
|
+
/** Holds the item's text after the marker. */
|
|
905
1049
|
readonly content: string;
|
|
906
|
-
/**
|
|
1050
|
+
/** Holds the leading-space indent of the marker. */
|
|
907
1051
|
readonly indent: number;
|
|
908
|
-
/**
|
|
1052
|
+
/** Holds the full marker width (indent + bullet/ordinal + the following space) — the continuation indent. */
|
|
909
1053
|
readonly marker: number;
|
|
910
1054
|
}
|
|
911
1055
|
|
|
912
1056
|
/**
|
|
913
|
-
*
|
|
1057
|
+
* Describes the shape of {@link ListItemMatch} — the parsed parts of a single list-item
|
|
914
1058
|
* line the block phase's list detector returns. Fully non-recursive (no
|
|
915
1059
|
* nested node fields), so every field shapes directly.
|
|
916
1060
|
*
|
|
@@ -923,39 +1067,39 @@ export declare interface ListItemMatch {
|
|
|
923
1067
|
* listItemParts.is({ ordered: false, start: 1, content: 'hi', indent: 0, marker: 2 }) // true
|
|
924
1068
|
* ```
|
|
925
1069
|
*/
|
|
926
|
-
export declare const listItemMatchShape: ObjectShape<{
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
1070
|
+
export declare const listItemMatchShape: ObjectShape< {
|
|
1071
|
+
ordered: BooleanShape;
|
|
1072
|
+
start: NumberShape;
|
|
1073
|
+
content: StringShape;
|
|
1074
|
+
indent: NumberShape;
|
|
1075
|
+
marker: NumberShape;
|
|
932
1076
|
}, false>;
|
|
933
1077
|
|
|
934
|
-
/**
|
|
1078
|
+
/** Represents one item of a {@link ListNode} — `children` the block content of the item (typically one paragraph, plus any nested list). */
|
|
935
1079
|
export declare interface ListItemNode {
|
|
936
1080
|
readonly element: 'listItem';
|
|
937
|
-
/**
|
|
1081
|
+
/** Holds the block content of the list item (its text as a paragraph, plus any nested list). */
|
|
938
1082
|
readonly children: readonly BlockNode[];
|
|
939
1083
|
}
|
|
940
1084
|
|
|
941
1085
|
/**
|
|
942
|
-
*
|
|
1086
|
+
* Represents a list — bulleted (`-` / `*` / `+`, `ordered: false`) or numbered (`1.` / `1)`,
|
|
943
1087
|
* `ordered: true`). `start` is the first ordinal of an ordered list (usually `1`).
|
|
944
1088
|
* Nesting is expressed by a {@link ListNode} appearing in a {@link ListItemNode}'s
|
|
945
1089
|
* `children`.
|
|
946
1090
|
*/
|
|
947
1091
|
export declare interface ListNode {
|
|
948
1092
|
readonly element: 'list';
|
|
949
|
-
/** `true` for an ordered (numbered) list (→ `<ol>`); `false` for a bulleted list (→ `<ul>`). */
|
|
1093
|
+
/** Holds `true` for an ordered (numbered) list (→ `<ol>`); `false` for a bulleted list (→ `<ul>`). */
|
|
950
1094
|
readonly ordered: boolean;
|
|
951
|
-
/**
|
|
1095
|
+
/** Holds the starting ordinal of an ordered list (the first item's number); `1` for a bulleted list. */
|
|
952
1096
|
readonly start: number;
|
|
953
|
-
/**
|
|
1097
|
+
/** Holds the list's items, in order. */
|
|
954
1098
|
readonly items: readonly ListItemNode[];
|
|
955
1099
|
}
|
|
956
1100
|
|
|
957
1101
|
/**
|
|
958
|
-
* Locates an emphasis run at `start` (`*` / `_`, doubled for strong)
|
|
1102
|
+
* Locates an emphasis run at `start` (`*` / `_`, doubled for strong) — finds the nearest
|
|
959
1103
|
* matching closing run of the same marker + width while skipping complete nested
|
|
960
1104
|
* runs from the other marker family, and requires non-space immediately inside both
|
|
961
1105
|
* delimiters (the CommonMark flanking simplification that blocks `* x *`). Returns
|
|
@@ -972,15 +1116,10 @@ export declare interface ListNode {
|
|
|
972
1116
|
* locateEmphasis('*em*', 0, 4) // { strong: false, open: 1, close: 3, end: 4 }
|
|
973
1117
|
* ```
|
|
974
1118
|
*/
|
|
975
|
-
export declare function locateEmphasis(source: string, start: number, to: number):
|
|
976
|
-
readonly strong: boolean;
|
|
977
|
-
readonly open: number;
|
|
978
|
-
readonly close: number;
|
|
979
|
-
readonly end: number;
|
|
980
|
-
} | undefined;
|
|
1119
|
+
export declare function locateEmphasis(source: string, start: number, to: number): EmphasisBounds | undefined;
|
|
981
1120
|
|
|
982
1121
|
/**
|
|
983
|
-
* Locates a link `[text](href)` at `start`
|
|
1122
|
+
* Locates a link `[text](href)` at `start` — the text runs to a balanced `]`, then `(`
|
|
984
1123
|
* must immediately follow and the destination runs to the matching `)` (both respect
|
|
985
1124
|
* nested delimiters + escapes). Returns the label close and syntax end, or `undefined` when the shape
|
|
986
1125
|
* does not hold (it then degrades to a literal `[`).
|
|
@@ -995,26 +1134,23 @@ export declare function locateEmphasis(source: string, start: number, to: number
|
|
|
995
1134
|
* locateLink('[text](url)', 0, 11) // { close: 5, end: 11 }
|
|
996
1135
|
* ```
|
|
997
1136
|
*/
|
|
998
|
-
export declare function locateLink(source: string, start: number, to: number):
|
|
999
|
-
readonly close: number;
|
|
1000
|
-
readonly end: number;
|
|
1001
|
-
} | undefined;
|
|
1137
|
+
export declare function locateLink(source: string, start: number, to: number): LinkBounds | undefined;
|
|
1002
1138
|
|
|
1003
1139
|
/**
|
|
1004
|
-
*
|
|
1140
|
+
* Wraps a typed {@link MarkdownDocument} AST as a stateful, parsed markdown document
|
|
1005
1141
|
* with the query (`find` / `filter` / `reduce` / iteration), rewrite (`map`), fold, and
|
|
1006
1142
|
* streaming operations {@link MarkdownInterface} declares.
|
|
1007
1143
|
*
|
|
1008
1144
|
* @remarks
|
|
1009
1145
|
* - **Construction.** Given a `string`, the constructor runs {@link parseProvenance} (the
|
|
1010
|
-
* block phase then the inline phase) once, keeping the AST and a
|
|
1011
|
-
* that parse recorded. Given a {@link MarkdownDocument}, the document is adopted
|
|
1012
|
-
* and is
|
|
1013
|
-
* - **Provenance.** {@link span} reads the region of the
|
|
1146
|
+
* block phase then the inline phase) once, keeping the AST and a copy of the span map
|
|
1147
|
+
* that parse recorded. Given a {@link MarkdownDocument}, the document is adopted as-is
|
|
1148
|
+
* and is not re-validated — gate an untrusted value with `isMarkdownDocument` first.
|
|
1149
|
+
* - **Provenance.** {@link span} reads the region of the original constructor string a
|
|
1014
1150
|
* node was produced from, and it is handle-relative: a string-constructed handle exposes
|
|
1015
1151
|
* the regions of the nodes it parsed, an adopted document exposes none, and a node from
|
|
1016
1152
|
* another handle reports `undefined` here whatever that handle reports. Each call
|
|
1017
|
-
* returns a fresh value. A node reports the region
|
|
1153
|
+
* returns a fresh value. A node reports the region this handle holds for its identity,
|
|
1018
1154
|
* else the region of the direct input a rewrite named for it, else `undefined`: a text
|
|
1019
1155
|
* run the parse joined from adjacent scanner output reports the region enclosing its
|
|
1020
1156
|
* parts, and only a rewrite output that holds no region of its own and was assembled
|
|
@@ -1022,29 +1158,28 @@ export declare function locateLink(source: string, start: number, to: number): {
|
|
|
1022
1158
|
* {@link map} carries provenance across the rewrite: an unchanged node keeps its
|
|
1023
1159
|
* region, a one-source replacement takes the region of the node it replaced, and a
|
|
1024
1160
|
* rebuilt parent takes its original's.
|
|
1025
|
-
* - **Immutable.** {@link map} never mutates the stored AST
|
|
1161
|
+
* - **Immutable.** {@link map} never mutates the stored AST — it returns a new `Markdown`
|
|
1026
1162
|
* instance; the document root invariant (`element: 'document'`) always holds. An
|
|
1027
1163
|
* identity rewrite still returns a new handle, over the same document tree.
|
|
1028
1164
|
* - **Traversal order.** {@link walk} and the `find` / `filter` / `reduce` queries built
|
|
1029
|
-
* on it walk the AST depth-first, pre-order, root-inclusive (
|
|
1030
|
-
* `stream` is shallow
|
|
1165
|
+
* on it walk the AST depth-first, pre-order, root-inclusive (through {@link walkNodes});
|
|
1166
|
+
* `stream` is shallow — only the document's direct block children.
|
|
1031
1167
|
*
|
|
1032
|
-
* @example
|
|
1168
|
+
* @example Construct from a string and narrow with a guard
|
|
1033
1169
|
* ```ts
|
|
1034
|
-
* import { Markdown, isHeadingNode
|
|
1170
|
+
* import { Markdown, isHeadingNode } from '@orkestrel/markdown'
|
|
1035
1171
|
*
|
|
1036
1172
|
* const markdown = new Markdown('# Title\n\nA **bold** [link](https://x.dev).')
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
* )
|
|
1041
|
-
* renderMarkdown(shouted.document) // '# TITLE\n\nA **BOLD** [LINK](https://x.dev).'
|
|
1173
|
+
* markdown.document.children[0] // { element: 'heading', level: 1, children: [...] }
|
|
1174
|
+
*
|
|
1175
|
+
* const heading = markdown.find(isHeadingNode) // HeadingNode | undefined, narrowed
|
|
1176
|
+
* if (heading !== undefined) heading.level // number — narrowed to HeadingNode
|
|
1042
1177
|
* ```
|
|
1043
1178
|
*/
|
|
1044
1179
|
export declare class Markdown implements MarkdownInterface {
|
|
1045
1180
|
#private;
|
|
1046
1181
|
constructor(input: string | MarkdownDocument);
|
|
1047
|
-
/**
|
|
1182
|
+
/** Holds the stored {@link MarkdownDocument} AST root. */
|
|
1048
1183
|
get document(): MarkdownDocument;
|
|
1049
1184
|
/**
|
|
1050
1185
|
* Reads the region of the original markdown string a node of this handle's tree was
|
|
@@ -1065,7 +1200,7 @@ export declare class Markdown implements MarkdownInterface {
|
|
|
1065
1200
|
*/
|
|
1066
1201
|
span(node: MarkdownNode): MarkdownSpan | undefined;
|
|
1067
1202
|
/**
|
|
1068
|
-
*
|
|
1203
|
+
* Returns the deep traversal — a lazy, depth-first, pre-order, root-inclusive generator
|
|
1069
1204
|
* over every {@link MarkdownNode} in the document. `find` / `filter` / `reduce`
|
|
1070
1205
|
* all iterate this single traversal.
|
|
1071
1206
|
*
|
|
@@ -1098,11 +1233,11 @@ export declare class Markdown implements MarkdownInterface {
|
|
|
1098
1233
|
map(rewrite: MarkdownRewriteHandler): MarkdownInterface;
|
|
1099
1234
|
/** Folds the AST depth-first, pre-order into an accumulator. */
|
|
1100
1235
|
reduce<T>(callback: (accumulator: T, node: MarkdownNode) => T, initial: T): T;
|
|
1101
|
-
/** Runs a total catamorphism over the document using a {@link
|
|
1102
|
-
fold<T>(handlers:
|
|
1236
|
+
/** Runs a total catamorphism over the document using a {@link MarkdownHandlerMap} table. */
|
|
1237
|
+
fold<T>(handlers: MarkdownHandlerMap<T>): T;
|
|
1103
1238
|
/**
|
|
1104
|
-
*
|
|
1105
|
-
* (shallow, source order)
|
|
1239
|
+
* Returns a web-standard {@link ReadableStream} over the document's top-level block nodes
|
|
1240
|
+
* (shallow, source order) — a fresh, pull-based source per call: one block is
|
|
1106
1241
|
* enqueued per `pull`, so a slow reader's backpressure is respected. Cancellable,
|
|
1107
1242
|
* async-iterable wherever the platform supports it (Node, Deno), and pipeable
|
|
1108
1243
|
* through any {@link TransformStream} / {@link WritableStream}.
|
|
@@ -1116,7 +1251,7 @@ export declare class Markdown implements MarkdownInterface {
|
|
|
1116
1251
|
* }
|
|
1117
1252
|
*
|
|
1118
1253
|
* // Node / Deno / Firefox support async iteration of ReadableStream natively;
|
|
1119
|
-
* // other environments
|
|
1254
|
+
* // other environments use the reader loop shown earlier.
|
|
1120
1255
|
* for await (const block of markdown.stream()) {
|
|
1121
1256
|
* console.log(block)
|
|
1122
1257
|
* }
|
|
@@ -1125,28 +1260,35 @@ export declare class Markdown implements MarkdownInterface {
|
|
|
1125
1260
|
stream(): ReadableStream<BlockNode>;
|
|
1126
1261
|
}
|
|
1127
1262
|
|
|
1128
|
-
/**
|
|
1263
|
+
/**
|
|
1264
|
+
* Represents one projected table cell — the inline content and alignment of a `th` / `td`.
|
|
1265
|
+
*
|
|
1266
|
+
* @remarks
|
|
1267
|
+
* {@link htmlToMarkdown} derives a projected table's header row from the source HTML
|
|
1268
|
+
* structure rather than from any flag a cell carries: the header is the first
|
|
1269
|
+
* `th`-bearing row, and every row after it becomes a body row.
|
|
1270
|
+
*/
|
|
1129
1271
|
export declare interface MarkdownCell {
|
|
1130
|
-
/**
|
|
1272
|
+
/** Holds the alignment the cell's `align` attribute declared; `undefined` when it declared none. */
|
|
1131
1273
|
readonly align: TableAlign | undefined;
|
|
1132
|
-
/**
|
|
1274
|
+
/** Holds the cell's inline content — a table cell is inline-only, so block content flattens to text. */
|
|
1133
1275
|
readonly inlines: readonly InlineNode[];
|
|
1134
1276
|
}
|
|
1135
1277
|
|
|
1136
1278
|
/**
|
|
1137
|
-
* Pairs a rewritten value with the input node each rewritten node was produced from
|
|
1279
|
+
* Pairs a rewritten value with the input node each rewritten node was produced from —
|
|
1138
1280
|
* what `rewriteDocument` returns, so provenance survives a rewrite instead of ending at
|
|
1139
1281
|
* it. `T` is the rewritten value: the document for a whole-document rewrite.
|
|
1140
1282
|
*
|
|
1141
1283
|
* @remarks
|
|
1142
|
-
* `derivations` is keyed by the nodes of the
|
|
1284
|
+
* `derivations` is keyed by the nodes of the output, and each entry names the direct
|
|
1143
1285
|
* input the rewrite drew that output from. {@link MarkdownInterface.map} resolves each
|
|
1144
1286
|
* output node against the source handle's own spans in a fixed order, and follows no
|
|
1145
1287
|
* second derivation edge:
|
|
1146
1288
|
*
|
|
1147
|
-
* - the output identity's
|
|
1148
|
-
* so an identity the rewrite reused
|
|
1149
|
-
* node the handler moved elsewhere in the tree
|
|
1289
|
+
* - the output identity's own span in the source handle wins, whatever the map says,
|
|
1290
|
+
* so an identity the rewrite reused — one node returned for several inputs, or a
|
|
1291
|
+
* node the handler moved elsewhere in the tree — keeps the region it already had;
|
|
1150
1292
|
* - otherwise the span of the direct input the entry names, where that input has one;
|
|
1151
1293
|
* - otherwise none. Where the output identity holds no region of its own, a node mapped
|
|
1152
1294
|
* to `undefined`, a node whose direct input has no span, and a node with no entry at
|
|
@@ -1163,39 +1305,39 @@ derivations: ReadonlyMap<MarkdownNode, MarkdownNode | undefined>
|
|
|
1163
1305
|
];
|
|
1164
1306
|
|
|
1165
1307
|
/**
|
|
1166
|
-
*
|
|
1308
|
+
* Represents the root of a parsed markdown AST — the ordered block children of the whole
|
|
1167
1309
|
* document. The value {@link MarkdownInterface.document} holds.
|
|
1168
1310
|
*/
|
|
1169
1311
|
export declare interface MarkdownDocument {
|
|
1170
1312
|
readonly element: 'document';
|
|
1171
|
-
/**
|
|
1313
|
+
/** Holds the document's top-level block nodes, in source order. */
|
|
1172
1314
|
readonly children: readonly BlockNode[];
|
|
1173
1315
|
}
|
|
1174
1316
|
|
|
1175
1317
|
/**
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
* {@link
|
|
1318
|
+
* Represents a fold handler for one AST element — receives the node and its children
|
|
1319
|
+
* already folded to `T`, and produces the node's own `T`. The building block of a
|
|
1320
|
+
* {@link MarkdownHandlerMap} catamorphism table.
|
|
1179
1321
|
*/
|
|
1180
1322
|
export declare type MarkdownHandler<TNode, T> = (node: TNode, children: readonly T[]) => T;
|
|
1181
1323
|
|
|
1182
1324
|
/**
|
|
1183
|
-
*
|
|
1325
|
+
* Represents the total catamorphism table for {@link MarkdownInterface.fold} — one
|
|
1184
1326
|
* {@link MarkdownHandler} per AST element, keyed by its `element` discriminant. Every
|
|
1185
1327
|
* key is required: a fold is total over the AST, so there is no element it can skip.
|
|
1186
1328
|
*/
|
|
1187
|
-
export declare interface
|
|
1329
|
+
export declare interface MarkdownHandlerMap<T> {
|
|
1188
1330
|
/** Folds a {@link MarkdownDocument} root from its already-folded block children. */
|
|
1189
1331
|
readonly document: MarkdownHandler<MarkdownDocument, T>;
|
|
1190
1332
|
/** Folds a {@link HeadingNode} from its already-folded inline children. */
|
|
1191
1333
|
readonly heading: MarkdownHandler<HeadingNode, T>;
|
|
1192
1334
|
/** Folds a {@link ParagraphNode} from its already-folded inline children. */
|
|
1193
1335
|
readonly paragraph: MarkdownHandler<ParagraphNode, T>;
|
|
1194
|
-
/** Folds a {@link ThematicBreakNode} (leaf
|
|
1336
|
+
/** Folds a {@link ThematicBreakNode} (leaf — always called with an empty children list). */
|
|
1195
1337
|
readonly thematicBreak: MarkdownHandler<ThematicBreakNode, T>;
|
|
1196
1338
|
/** Folds a {@link BlockquoteNode} from its already-folded block children. */
|
|
1197
1339
|
readonly blockquote: MarkdownHandler<BlockquoteNode, T>;
|
|
1198
|
-
/** Folds a {@link CodeBlockNode} (leaf
|
|
1340
|
+
/** Folds a {@link CodeBlockNode} (leaf — always called with an empty children list). */
|
|
1199
1341
|
readonly codeBlock: MarkdownHandler<CodeBlockNode, T>;
|
|
1200
1342
|
/** Folds a {@link ListNode} from its already-folded item children. */
|
|
1201
1343
|
readonly list: MarkdownHandler<ListNode, T>;
|
|
@@ -1203,19 +1345,19 @@ export declare interface MarkdownHandlers<T> {
|
|
|
1203
1345
|
readonly listItem: MarkdownHandler<ListItemNode, T>;
|
|
1204
1346
|
/**
|
|
1205
1347
|
* Folds a {@link TableNode} from its cells' already-folded inline nodes, flattened
|
|
1206
|
-
* to
|
|
1207
|
-
* rows' cells (row order, then column order). It is
|
|
1348
|
+
* to one folded `T` per inline node — header cells first (column order), then body
|
|
1349
|
+
* rows' cells (row order, then column order). It is not a leaf: recover cell
|
|
1208
1350
|
* boundaries from `node.header[c].length` / `node.rows[r][c].length` against the
|
|
1209
1351
|
* flat `children` list.
|
|
1210
1352
|
*/
|
|
1211
1353
|
readonly table: MarkdownHandler<TableNode, T>;
|
|
1212
|
-
/** Folds a {@link TextNode} (leaf
|
|
1354
|
+
/** Folds a {@link TextNode} (leaf — always called with an empty children list). */
|
|
1213
1355
|
readonly text: MarkdownHandler<TextNode, T>;
|
|
1214
1356
|
/** Folds an {@link EmphasisNode} from its already-folded inline children. */
|
|
1215
1357
|
readonly emphasis: MarkdownHandler<EmphasisNode, T>;
|
|
1216
|
-
/** Folds a {@link CodeSpanNode} (leaf
|
|
1358
|
+
/** Folds a {@link CodeSpanNode} (leaf — always called with an empty children list). */
|
|
1217
1359
|
readonly codeSpan: MarkdownHandler<CodeSpanNode, T>;
|
|
1218
|
-
/** Folds a {@link LineBreakNode} (leaf
|
|
1360
|
+
/** Folds a {@link LineBreakNode} (leaf — always called with an empty children list). */
|
|
1219
1361
|
readonly break: MarkdownHandler<LineBreakNode, T>;
|
|
1220
1362
|
/** Folds a {@link LinkNode} from its already-folded inline children. */
|
|
1221
1363
|
readonly link: MarkdownHandler<LinkNode, T>;
|
|
@@ -1224,20 +1366,20 @@ export declare interface MarkdownHandlers<T> {
|
|
|
1224
1366
|
}
|
|
1225
1367
|
|
|
1226
1368
|
/**
|
|
1227
|
-
*
|
|
1369
|
+
* Represents a stateful, parsed markdown document: the typed {@link MarkdownDocument} AST plus
|
|
1228
1370
|
* the query, rewrite, and fold operations over it.
|
|
1229
1371
|
*
|
|
1230
1372
|
* @remarks
|
|
1231
|
-
* - **Immutable.** {@link MarkdownInterface.map} never mutates the stored AST
|
|
1232
|
-
* returns a
|
|
1373
|
+
* - **Immutable.** {@link MarkdownInterface.map} never mutates the stored AST — it
|
|
1374
|
+
* returns a new {@link MarkdownInterface} instance; the document root invariant
|
|
1233
1375
|
* (`element: 'document'`) always holds.
|
|
1234
1376
|
* - **Traversal order.** `walk` / `find` / `filter` / `reduce` walk the AST
|
|
1235
|
-
* depth-first, pre-order, root-inclusive; `stream` is shallow
|
|
1377
|
+
* depth-first, pre-order, root-inclusive; `stream` is shallow — only the
|
|
1236
1378
|
* document's direct block children.
|
|
1237
1379
|
* - **`stream`.** Returns a web-standard {@link ReadableStream} over the top-level
|
|
1238
|
-
* blocks
|
|
1380
|
+
* blocks — a fresh, pull-based source per call: exactly one block is enqueued per
|
|
1239
1381
|
* `pull`, so a slow consumer's backpressure is respected and no work happens ahead
|
|
1240
|
-
* of demand. Cancellable
|
|
1382
|
+
* of demand. Cancellable through the returned stream's own `cancel()`, async-iterable
|
|
1241
1383
|
* wherever the platform supports it (Node, Deno, and browsers that ship the
|
|
1242
1384
|
* proposal), and pipeable through any {@link TransformStream} / {@link WritableStream}.
|
|
1243
1385
|
* - **The surface.** `document` (the AST root), `walk` (the deep traversal), `find` /
|
|
@@ -1246,10 +1388,10 @@ export declare interface MarkdownHandlers<T> {
|
|
|
1246
1388
|
* total catamorphism), and `stream` (the shallow, backpressured top-level source).
|
|
1247
1389
|
*/
|
|
1248
1390
|
export declare interface MarkdownInterface {
|
|
1249
|
-
/**
|
|
1391
|
+
/** Holds the stored {@link MarkdownDocument} AST root. */
|
|
1250
1392
|
readonly document: MarkdownDocument;
|
|
1251
1393
|
/**
|
|
1252
|
-
*
|
|
1394
|
+
* Returns the deep traversal — a lazy, depth-first, pre-order, root-inclusive
|
|
1253
1395
|
* {@link Generator} over every {@link MarkdownNode} in the document. The sync
|
|
1254
1396
|
* `for (const node of markdown.walk())` surface is also consumable by
|
|
1255
1397
|
* `for await (const node of markdown.walk())` (JavaScript accepts a sync
|
|
@@ -1258,11 +1400,17 @@ export declare interface MarkdownInterface {
|
|
|
1258
1400
|
* is shallow (top-level blocks only) and backpressure-respecting.
|
|
1259
1401
|
*/
|
|
1260
1402
|
walk(): Generator<MarkdownNode>;
|
|
1261
|
-
/**
|
|
1403
|
+
/**
|
|
1404
|
+
* Finds the first node (depth-first, pre-order) narrowed by a type guard, and returns
|
|
1405
|
+
* `undefined` when no node matches; a second overload takes a plain predicate.
|
|
1406
|
+
*/
|
|
1262
1407
|
find<T extends MarkdownNode>(guard: (node: MarkdownNode) => node is T): T | undefined;
|
|
1263
1408
|
/** Finds the first node (depth-first, pre-order) matching a predicate. */
|
|
1264
1409
|
find(predicate: (node: MarkdownNode) => boolean): MarkdownNode | undefined;
|
|
1265
|
-
/**
|
|
1410
|
+
/**
|
|
1411
|
+
* Collects every node (depth-first, pre-order) narrowed by a type guard; a second
|
|
1412
|
+
* overload takes a plain predicate.
|
|
1413
|
+
*/
|
|
1266
1414
|
filter<T extends MarkdownNode>(guard: (node: MarkdownNode) => node is T): readonly T[];
|
|
1267
1415
|
/** Collects every node (depth-first, pre-order) matching a predicate. */
|
|
1268
1416
|
filter(predicate: (node: MarkdownNode) => boolean): readonly MarkdownNode[];
|
|
@@ -1275,11 +1423,11 @@ export declare interface MarkdownInterface {
|
|
|
1275
1423
|
*
|
|
1276
1424
|
* @remarks
|
|
1277
1425
|
* Provenance is per handle and per node identity, so a node reports a region only
|
|
1278
|
-
* where
|
|
1426
|
+
* where this handle holds coordinates for it. A handle constructed from an adopted
|
|
1279
1427
|
* {@link MarkdownDocument} reports `undefined` for every node: it parsed no string,
|
|
1280
|
-
* so no coordinates exist to report. A text run the
|
|
1428
|
+
* so no coordinates exist to report. A text run the parse joined from adjacent
|
|
1281
1429
|
* scanner output reports the region enclosing its parts rather than `undefined`;
|
|
1282
|
-
* only a
|
|
1430
|
+
* only a rewrite output that holds no region of its own and was assembled from
|
|
1283
1431
|
* separate source nodes reports `undefined`. The region a node does report is the
|
|
1284
1432
|
* original source it was produced from, which can include syntax its value drops
|
|
1285
1433
|
* and characters that normalization removed. Each call returns a fresh value rather
|
|
@@ -1288,33 +1436,33 @@ export declare interface MarkdownInterface {
|
|
|
1288
1436
|
span(node: MarkdownNode): MarkdownSpan | undefined;
|
|
1289
1437
|
/** Rewrites the AST bottom-up (copy-on-write) and returns a new {@link MarkdownInterface}. */
|
|
1290
1438
|
map(rewrite: MarkdownRewriteHandler): MarkdownInterface;
|
|
1291
|
-
/** Folds the AST depth-first, pre-order into an accumulator. */
|
|
1439
|
+
/** Folds the AST depth-first, pre-order into an accumulator through a reducer callback. */
|
|
1292
1440
|
reduce<T>(callback: (accumulator: T, node: MarkdownNode) => T, initial: T): T;
|
|
1293
|
-
/** Runs a total catamorphism over the document using a {@link
|
|
1294
|
-
fold<T>(handlers:
|
|
1441
|
+
/** Runs a total catamorphism over the document using a {@link MarkdownHandlerMap} table. */
|
|
1442
|
+
fold<T>(handlers: MarkdownHandlerMap<T>): T;
|
|
1295
1443
|
/**
|
|
1296
|
-
*
|
|
1297
|
-
* (shallow, source order)
|
|
1444
|
+
* Returns a web-standard {@link ReadableStream} over the document's top-level block nodes
|
|
1445
|
+
* (shallow, source order) — a lazy, pull-based, backpressure-respecting source. A
|
|
1298
1446
|
* fresh, independently-replayable stream every call; never mutates the document.
|
|
1299
1447
|
*/
|
|
1300
1448
|
stream(): ReadableStream<BlockNode>;
|
|
1301
1449
|
}
|
|
1302
1450
|
|
|
1303
1451
|
/**
|
|
1304
|
-
*
|
|
1452
|
+
* Represents any node in a markdown AST — the {@link MarkdownDocument} root, a {@link BlockNode},
|
|
1305
1453
|
* a {@link ListItemNode}, or an {@link InlineNode}. The exhaustive set every
|
|
1306
1454
|
* projection's `switch` covers.
|
|
1307
1455
|
*/
|
|
1308
1456
|
export declare type MarkdownNode = MarkdownDocument | BlockNode | ListItemNode | InlineNode;
|
|
1309
1457
|
|
|
1310
1458
|
/**
|
|
1311
|
-
* Pairs a parsed document with the {@link MarkdownSpan} of each of its nodes
|
|
1459
|
+
* Pairs a parsed document with the {@link MarkdownSpan} of each of its nodes — what
|
|
1312
1460
|
* `parseProvenance` returns, and what `parseDocument` projects the document out of.
|
|
1313
1461
|
*
|
|
1314
1462
|
* @remarks
|
|
1315
|
-
* `spans` is keyed by node identity, so it addresses the nodes of
|
|
1316
|
-
* no other. A node the parse merged from adjacent scanner output
|
|
1317
|
-
* `coalesceText` joins
|
|
1463
|
+
* `spans` is keyed by node identity, so it addresses the nodes of that document and
|
|
1464
|
+
* no other. A node the parse merged from adjacent scanner output — the text run
|
|
1465
|
+
* `coalesceText` joins — is present and carries the region enclosing its parts, from
|
|
1318
1466
|
* the first part's `start` to the last part's `end`, which can include original text
|
|
1319
1467
|
* lying between them. Absence means the parse recorded no region for the node, not
|
|
1320
1468
|
* that the node was assembled from more than one region. Destructure it as
|
|
@@ -1326,7 +1474,7 @@ spans: ReadonlyMap<MarkdownNode, MarkdownSpan>
|
|
|
1326
1474
|
];
|
|
1327
1475
|
|
|
1328
1476
|
/**
|
|
1329
|
-
*
|
|
1477
|
+
* Represents what one HTML node projects to on the way to markdown — the fold value
|
|
1330
1478
|
* `htmlToMarkdown` carries up the AST.
|
|
1331
1479
|
*
|
|
1332
1480
|
* @remarks
|
|
@@ -1336,45 +1484,45 @@ spans: ReadonlyMap<MarkdownNode, MarkdownSpan>
|
|
|
1336
1484
|
* under a `pre`. Rather than guess, each node reports every view its ancestors could
|
|
1337
1485
|
* need, and the ancestor that knows the context takes the one it wants.
|
|
1338
1486
|
*
|
|
1339
|
-
* - `blocks` / `inlines`
|
|
1487
|
+
* - `blocks` / `inlines` — the block and inline views. They are exclusive by
|
|
1340
1488
|
* construction: as soon as a node contributes a block, the inline runs around it
|
|
1341
1489
|
* are wrapped into paragraphs, so `blocks` being non-empty means `inlines` is
|
|
1342
1490
|
* empty and no interleaving is ever lost.
|
|
1343
|
-
* - `text`
|
|
1491
|
+
* - `text` — the raw, uncollapsed, unescaped subtree text a code span and a
|
|
1344
1492
|
* `pre > code` body need verbatim. An `UNSAFE_ELEMENTS` subtree contributes none
|
|
1345
1493
|
* of it, so a script body can never resurface as prose.
|
|
1346
|
-
* - `cells` / `rows`
|
|
1494
|
+
* - `cells` / `rows` — table structure in flight. A cell travels up to its `tr` and a
|
|
1347
1495
|
* row up to its `table`, passing through the `thead` / `tbody` wrappers between
|
|
1348
1496
|
* them untouched; whatever never reaches a table degrades to paragraphs.
|
|
1349
1497
|
*/
|
|
1350
1498
|
export declare interface MarkdownProjection {
|
|
1351
|
-
/**
|
|
1499
|
+
/** Holds the node's block content, with any surrounding inline runs already wrapped into paragraphs. */
|
|
1352
1500
|
readonly blocks: readonly BlockNode[];
|
|
1353
|
-
/**
|
|
1501
|
+
/** Holds the node's inline content; empty whenever `blocks` is not. */
|
|
1354
1502
|
readonly inlines: readonly InlineNode[];
|
|
1355
|
-
/**
|
|
1503
|
+
/** Holds the raw subtree text, whitespace uncollapsed and escapes unresolved. */
|
|
1356
1504
|
readonly text: string;
|
|
1357
|
-
/**
|
|
1505
|
+
/** Holds the cells this node contributes to an enclosing row. */
|
|
1358
1506
|
readonly cells: readonly MarkdownCell[];
|
|
1359
|
-
/**
|
|
1507
|
+
/** Holds the rows this node contributes to an enclosing table — each its cells, in column order. */
|
|
1360
1508
|
readonly rows: ReadonlyArray<readonly MarkdownCell[]>;
|
|
1361
1509
|
}
|
|
1362
1510
|
|
|
1363
1511
|
/**
|
|
1364
|
-
*
|
|
1512
|
+
* Represents a copy-on-write node rewrite applied bottom-up by {@link MarkdownInterface.map} —
|
|
1365
1513
|
* receives one node (its own children already rewritten) and returns its
|
|
1366
1514
|
* replacement (the same node, unchanged, or a new node).
|
|
1367
1515
|
*/
|
|
1368
1516
|
export declare type MarkdownRewriteHandler = (node: MarkdownNode) => MarkdownNode;
|
|
1369
1517
|
|
|
1370
1518
|
/**
|
|
1371
|
-
* Maps one run of a {@link MarkdownSource} back to the region of the
|
|
1519
|
+
* Maps one run of a {@link MarkdownSource} back to the region of the original
|
|
1372
1520
|
* markdown string it was taken from.
|
|
1373
1521
|
*
|
|
1374
1522
|
* @remarks
|
|
1375
1523
|
* `offset` addresses {@link MarkdownSource.text}; `start` and `end` address the
|
|
1376
1524
|
* original string. The run's original length derives from `end - start` rather than
|
|
1377
|
-
* being stored beside them, so no length member exists to drift. The run's
|
|
1525
|
+
* being stored beside them, so no length member exists to drift. The run's derived
|
|
1378
1526
|
* extent ends where the next segment's `offset` begins, so a run may cover more of the
|
|
1379
1527
|
* original than it holds derived: the separator run `joinSources` records over a
|
|
1380
1528
|
* normalized `\r\n` terminator is one derived code unit over a two-unit original
|
|
@@ -1385,27 +1533,27 @@ export declare type MarkdownRewriteHandler = (node: MarkdownNode) => MarkdownNod
|
|
|
1385
1533
|
*
|
|
1386
1534
|
* - strictly inside the run, `p` projects to `start + (p - offset)`;
|
|
1387
1535
|
* - at the run's derived end, `p` projects to `end`, so the boundary claims the run's
|
|
1388
|
-
* whole original region instead of the prefix an affine step would reach
|
|
1536
|
+
* whole original region instead of the prefix an affine step would reach — which is
|
|
1389
1537
|
* how the one-unit `\r\n` separator run above reports its two-unit region;
|
|
1390
1538
|
* - a zero-width `p` that coincides with a later segment's `offset` resolves through the
|
|
1391
|
-
*
|
|
1539
|
+
* last segment whose `offset` equals `p`, skipping every earlier segment at that
|
|
1392
1540
|
* position whatever its extent, so a discontinuous abutment reports that final run's
|
|
1393
1541
|
* `start` rather than the earlier run's `end`.
|
|
1394
1542
|
*
|
|
1395
1543
|
* The mapping is therefore affine strictly inside a run and clamped at its end.
|
|
1396
1544
|
*/
|
|
1397
1545
|
export declare interface MarkdownSegment {
|
|
1398
|
-
/**
|
|
1546
|
+
/** Holds the first code unit of the run inside {@link MarkdownSource.text}. */
|
|
1399
1547
|
readonly offset: number;
|
|
1400
|
-
/**
|
|
1548
|
+
/** Holds the first code unit of the original-string region the run was produced from, inclusive. */
|
|
1401
1549
|
readonly start: number;
|
|
1402
|
-
/**
|
|
1550
|
+
/** Holds the code unit one past that region's last, exclusive. */
|
|
1403
1551
|
readonly end: number;
|
|
1404
1552
|
}
|
|
1405
1553
|
|
|
1406
1554
|
/**
|
|
1407
1555
|
* Pairs a piece of derived markdown text with the runs mapping it back to the
|
|
1408
|
-
* original string
|
|
1556
|
+
* original string — what `splitLines` returns per line, so every phase downstream of
|
|
1409
1557
|
* it keeps original coordinates instead of reconstructing them from node values.
|
|
1410
1558
|
*
|
|
1411
1559
|
* @remarks
|
|
@@ -1423,21 +1571,21 @@ export declare interface MarkdownSegment {
|
|
|
1423
1571
|
* coverage with `projectSpan` rather than assuming it.
|
|
1424
1572
|
*/
|
|
1425
1573
|
export declare interface MarkdownSource {
|
|
1426
|
-
/**
|
|
1574
|
+
/** Holds the derived text a parser reads. */
|
|
1427
1575
|
readonly text: string;
|
|
1428
|
-
/**
|
|
1576
|
+
/** Holds the runs mapping `text` back to the original string, in ascending `offset` order. */
|
|
1429
1577
|
readonly segments: readonly MarkdownSegment[];
|
|
1430
1578
|
}
|
|
1431
1579
|
|
|
1432
1580
|
/**
|
|
1433
|
-
* Addresses a half-open region of the
|
|
1581
|
+
* Addresses a half-open region of the original markdown string, in UTF-16 code units —
|
|
1434
1582
|
* `start` inclusive, `end` exclusive. The provenance a parse records for a node and
|
|
1435
1583
|
* {@link MarkdownInterface.span} reads back.
|
|
1436
1584
|
*
|
|
1437
1585
|
* @remarks
|
|
1438
1586
|
* The coordinates address the string the handle was constructed from, never the line
|
|
1439
1587
|
* text a later phase walks, so `markdown.slice(span.start, span.end)` returns the
|
|
1440
|
-
*
|
|
1588
|
+
* original source region the node was produced from. That region is not the node's
|
|
1441
1589
|
* value: it carries the syntax the value drops, such as a `\` escape marker, and the
|
|
1442
1590
|
* characters that normalization removed, such as a trailing space the paragraph phase
|
|
1443
1591
|
* trimmed. The text node of `'a \nb'` has the `value` `a\nb` and reports
|
|
@@ -1446,14 +1594,14 @@ export declare interface MarkdownSource {
|
|
|
1446
1594
|
* is `end - start`; no length member exists to drift from the two offsets.
|
|
1447
1595
|
*/
|
|
1448
1596
|
export declare interface MarkdownSpan {
|
|
1449
|
-
/**
|
|
1597
|
+
/** Holds the first code unit of the region, inclusive. */
|
|
1450
1598
|
readonly start: number;
|
|
1451
|
-
/**
|
|
1599
|
+
/** Holds the code unit one past the region's last, exclusive. */
|
|
1452
1600
|
readonly end: number;
|
|
1453
1601
|
}
|
|
1454
1602
|
|
|
1455
1603
|
/**
|
|
1456
|
-
*
|
|
1604
|
+
* Projects a {@link MarkdownNode} into an unsanitized {@link HTMLDocument}.
|
|
1457
1605
|
*
|
|
1458
1606
|
* @remarks
|
|
1459
1607
|
* The projection is pure and iterative. Text and attribute values remain literal for
|
|
@@ -1474,10 +1622,10 @@ export declare interface MarkdownSpan {
|
|
|
1474
1622
|
export declare function markdownToHTML(node: MarkdownNode): HTMLDocument;
|
|
1475
1623
|
|
|
1476
1624
|
/**
|
|
1477
|
-
*
|
|
1478
|
-
* `parsers.ts` helpers)
|
|
1479
|
-
* (`markdownToHTML`, `
|
|
1480
|
-
* `
|
|
1625
|
+
* Caps the recursion depth the parse pipeline (`parseDocument` and its
|
|
1626
|
+
* `parsers.ts` helpers), the `helpers.ts` traversal / projection functions
|
|
1627
|
+
* (`markdownToHTML`, `renderMarkdown`, `walkNodes`, `foldNode`, `rewriteDocument`),
|
|
1628
|
+
* and the `compilers.ts` renderer (`renderHTML`) honor before degrading, at 64. It bounds blockquote nesting, inline
|
|
1481
1629
|
* nesting (emphasis / links), and traversal / projection recursion so pathological
|
|
1482
1630
|
* or hostile input cannot exhaust the call stack. {@link htmlToMarkdown} is the
|
|
1483
1631
|
* inherited exception: its fold and depth cap belong to `@orkestrel/html`.
|
|
@@ -1485,14 +1633,14 @@ export declare function markdownToHTML(node: MarkdownNode): HTMLDocument;
|
|
|
1485
1633
|
export declare const MAX_DEPTH = 64;
|
|
1486
1634
|
|
|
1487
1635
|
/**
|
|
1488
|
-
*
|
|
1636
|
+
* Combines the projections of one node's children into the projection of that node —
|
|
1489
1637
|
* the single place inline runs become paragraphs, so no ancestor has to decide it
|
|
1490
1638
|
* twice.
|
|
1491
1639
|
*
|
|
1492
1640
|
* @remarks
|
|
1493
1641
|
* A child is either inline or block, never both, so merging preserves source order
|
|
1494
1642
|
* exactly: an inline run is held pending until a block arrives, then written out as a
|
|
1495
|
-
* paragraph
|
|
1643
|
+
* paragraph before it. That is what keeps `<div>lead<p>a</p></div>` two paragraphs in
|
|
1496
1644
|
* the order they were written rather than two lists that lost their interleaving. A
|
|
1497
1645
|
* pending run carrying no text is dropped rather than becoming a blank paragraph.
|
|
1498
1646
|
* Direct cells become one row before a later row, while cells/rows before a block
|
|
@@ -1513,21 +1661,21 @@ export declare const MAX_DEPTH = 64;
|
|
|
1513
1661
|
export declare function mergeProjections(children: readonly MarkdownProjection[]): MarkdownProjection;
|
|
1514
1662
|
|
|
1515
1663
|
/**
|
|
1516
|
-
*
|
|
1664
|
+
* Reduces an inline run to the shape markdown can actually write back: adjacent text
|
|
1517
1665
|
* coalesced, empty text dropped, and every hard break either kept as a real line
|
|
1518
1666
|
* ending or spent as a space.
|
|
1519
1667
|
*
|
|
1520
1668
|
* @remarks
|
|
1521
|
-
* A hard break is ` \n` in markdown source, so it survives a re-parse only
|
|
1669
|
+
* A hard break is ` \n` in markdown source, so it survives a re-parse only between
|
|
1522
1670
|
* two lines of content and only with no whitespace touching it: a leading or trailing
|
|
1523
1671
|
* break has no line to end, a run of breaks reads as one blank line (which would end
|
|
1524
1672
|
* the paragraph), and a space beside one is eaten by the parser's line trimming. Where
|
|
1525
|
-
* a break cannot be written at all
|
|
1673
|
+
* a break cannot be written at all — a heading and a table cell are one line each — it
|
|
1526
1674
|
* becomes the space it stood for.
|
|
1527
1675
|
*
|
|
1528
1676
|
* @param nodes - The inline run to normalize
|
|
1529
|
-
* @param breaks -
|
|
1530
|
-
*
|
|
1677
|
+
* @param breaks - If `true`, keeps each hard break as a real line ending; if `false`, spends
|
|
1678
|
+
* every break as the space it stood for, as a heading or a table cell requires
|
|
1531
1679
|
* @returns The normalized run
|
|
1532
1680
|
*
|
|
1533
1681
|
* @example
|
|
@@ -1554,10 +1702,10 @@ export declare function normalizeInlines(nodes: readonly InlineNode[], breaks: b
|
|
|
1554
1702
|
*/
|
|
1555
1703
|
export declare function normalizeParagraphLine(source: MarkdownSource, breaks: boolean): MarkdownSource;
|
|
1556
1704
|
|
|
1557
|
-
/**
|
|
1705
|
+
/** Represents a paragraph — a run of non-blank lines that is not another block; `children` its inline content. */
|
|
1558
1706
|
export declare interface ParagraphNode {
|
|
1559
1707
|
readonly element: 'paragraph';
|
|
1560
|
-
/**
|
|
1708
|
+
/** Holds the inline content of the paragraph. */
|
|
1561
1709
|
readonly children: readonly InlineNode[];
|
|
1562
1710
|
}
|
|
1563
1711
|
|
|
@@ -1579,33 +1727,52 @@ export declare interface ParagraphNode {
|
|
|
1579
1727
|
export declare function parseBlocks(lines: readonly MarkdownSource[], depth: number, spans?: Map<MarkdownNode, MarkdownSpan>, end?: number): readonly BlockNode[];
|
|
1580
1728
|
|
|
1581
1729
|
/**
|
|
1582
|
-
* Parses a markdown string into a typed {@link MarkdownDocument} AST
|
|
1583
|
-
* block phase.
|
|
1730
|
+
* Parses a markdown string into a typed {@link MarkdownDocument} AST through the
|
|
1731
|
+
* block phase — the document half of what {@link parseProvenance} returns. Malformed
|
|
1732
|
+
* markdown degrades to literal text, so the parse never throws.
|
|
1584
1733
|
*
|
|
1585
1734
|
* @param markdown - The markdown source to parse.
|
|
1586
1735
|
* @returns The parsed document.
|
|
1736
|
+
*
|
|
1737
|
+
* @example
|
|
1738
|
+
* ```ts
|
|
1739
|
+
* parseDocument('# Hi') // { element: 'document', children: [{ element: 'heading', ... }] }
|
|
1740
|
+
* ```
|
|
1587
1741
|
*/
|
|
1588
1742
|
export declare function parseDocument(markdown: string): MarkdownDocument;
|
|
1589
1743
|
|
|
1590
1744
|
/**
|
|
1591
1745
|
* Parses inline markdown text (emphasis, code spans, links, images, and hard
|
|
1592
|
-
* breaks) into inline AST nodes, coalescing adjacent text runs
|
|
1746
|
+
* breaks) into inline AST nodes, coalescing adjacent text runs and reading no block
|
|
1747
|
+
* structure. Malformed markdown degrades to literal text, so the parse never throws.
|
|
1593
1748
|
*
|
|
1594
1749
|
* @param text - The inline markdown text to parse.
|
|
1595
1750
|
* @returns The parsed inline nodes.
|
|
1751
|
+
*
|
|
1752
|
+
* @example
|
|
1753
|
+
* ```ts
|
|
1754
|
+
* parseInline('a *b*') // [{ element: 'text', value: 'a ' }, { element: 'emphasis', ... }]
|
|
1755
|
+
* ```
|
|
1596
1756
|
*/
|
|
1597
1757
|
export declare function parseInline(text: string): readonly InlineNode[];
|
|
1598
1758
|
|
|
1599
1759
|
/**
|
|
1600
|
-
* Parses a markdown string into a document and its original-source spans.
|
|
1760
|
+
* Parses a markdown string into a document and its original-source spans. Malformed
|
|
1761
|
+
* markdown degrades to literal text, so the parse never throws.
|
|
1601
1762
|
*
|
|
1602
1763
|
* @param markdown - The markdown source to parse.
|
|
1603
1764
|
* @returns The parsed document and its node-identity span map.
|
|
1765
|
+
*
|
|
1766
|
+
* @example
|
|
1767
|
+
* ```ts
|
|
1768
|
+
* const [document, spans] = parseProvenance('# Hi')
|
|
1769
|
+
* spans.get(document) // { start: 0, end: 4 }
|
|
1770
|
+
* ```
|
|
1604
1771
|
*/
|
|
1605
1772
|
export declare function parseProvenance(markdown: string): MarkdownParseResult;
|
|
1606
1773
|
|
|
1607
1774
|
/**
|
|
1608
|
-
*
|
|
1775
|
+
* Projects one HTML leaf — a text node, a comment, or a doctype — to its
|
|
1609
1776
|
* {@link MarkdownProjection}.
|
|
1610
1777
|
*
|
|
1611
1778
|
* @remarks
|
|
@@ -1626,8 +1793,8 @@ export declare function parseProvenance(markdown: string): MarkdownParseResult;
|
|
|
1626
1793
|
export declare function projectHTMLLeaf(leaf: CommentNode | DoctypeNode | TextNode_2): MarkdownProjection;
|
|
1627
1794
|
|
|
1628
1795
|
/**
|
|
1629
|
-
*
|
|
1630
|
-
* already-computed projections.
|
|
1796
|
+
* Projects one HTML container — the document root or an element — from its children's
|
|
1797
|
+
* already-computed projections. The element mapping, and the only place that decides
|
|
1631
1798
|
* what an HTML tag becomes in markdown.
|
|
1632
1799
|
*
|
|
1633
1800
|
* @remarks
|
|
@@ -1639,13 +1806,13 @@ export declare function projectHTMLLeaf(leaf: CommentNode | DoctypeNode | TextNo
|
|
|
1639
1806
|
* inline runs wrapped in paragraphs; `ul` / `ol` a list, ordered from the tag and
|
|
1640
1807
|
* numbered from `start`; `th` / `td`, `tr`, and `table` a GFM table whose column
|
|
1641
1808
|
* alignment comes from each header-position cell's `align` attribute. Every
|
|
1642
|
-
* `UNSAFE_ELEMENTS` subtree contributes nothing at all, text included. Every
|
|
1809
|
+
* `UNSAFE_ELEMENTS` subtree contributes nothing at all, text included. Every other
|
|
1643
1810
|
* element unwraps to its children, so wrapper soup melts while its content keeps its
|
|
1644
|
-
* shape
|
|
1811
|
+
* shape — `<div><p>a</p><p>b</p></div>` stays two paragraphs.
|
|
1645
1812
|
*
|
|
1646
1813
|
* Three mappings read their own node rather than only their children's projections,
|
|
1647
1814
|
* because HTML puts the fact in a position rather than in a value: a `pre` takes its
|
|
1648
|
-
* body from its `code` child's raw text, and a list takes one item per `li` child
|
|
1815
|
+
* body from its `code` child's raw text, and a list takes one item per `li` child — so
|
|
1649
1816
|
* an empty `<li>` is still an item, while the whitespace between two of them is not.
|
|
1650
1817
|
* A `tr` accepts only its own direct cells, and a table derives the first `th`-bearing
|
|
1651
1818
|
* row from its own source structure.
|
|
@@ -1663,7 +1830,7 @@ export declare function projectHTMLLeaf(leaf: CommentNode | DoctypeNode | TextNo
|
|
|
1663
1830
|
export declare function projectHTMLNode(node: ElementNode | HTMLDocument, children: readonly MarkdownProjection[]): MarkdownProjection;
|
|
1664
1831
|
|
|
1665
1832
|
/**
|
|
1666
|
-
*
|
|
1833
|
+
* Reads a projection as block content — the view a document, a blockquote, and a list
|
|
1667
1834
|
* item each need.
|
|
1668
1835
|
*
|
|
1669
1836
|
* @remarks
|
|
@@ -1684,7 +1851,7 @@ export declare function projectHTMLNode(node: ElementNode | HTMLDocument, childr
|
|
|
1684
1851
|
export declare function projectionToBlocks(projection: MarkdownProjection): readonly BlockNode[];
|
|
1685
1852
|
|
|
1686
1853
|
/**
|
|
1687
|
-
*
|
|
1854
|
+
* Reads a projection as inline content — the view a link, an emphasis, and a table cell
|
|
1688
1855
|
* each need.
|
|
1689
1856
|
*
|
|
1690
1857
|
* @remarks
|
|
@@ -1722,9 +1889,12 @@ export declare function projectionToInlines(projection: MarkdownProjection): rea
|
|
|
1722
1889
|
export declare function projectSpan(source: MarkdownSource, from: number, to: number): MarkdownSpan | undefined;
|
|
1723
1890
|
|
|
1724
1891
|
/**
|
|
1725
|
-
*
|
|
1892
|
+
* Renders a {@link MarkdownNode} to sanitized canonical HTML.
|
|
1726
1893
|
*
|
|
1727
1894
|
* @remarks
|
|
1895
|
+
* Sanitization is unconditional: the function takes one argument and declares no
|
|
1896
|
+
* options, so no call shape opts out of it.
|
|
1897
|
+
*
|
|
1728
1898
|
* Markdown widens `@orkestrel/html`'s attribute floor by exactly `src`, because image
|
|
1729
1899
|
* syntax is meaningless without its source. `src` is still a URL attribute, so the
|
|
1730
1900
|
* floor refuses `javascript:`, `data:`, `vbscript:`, and `file:` values. A stricter
|
|
@@ -1743,17 +1913,17 @@ export declare function projectSpan(source: MarkdownSource, from: number, to: nu
|
|
|
1743
1913
|
export declare function renderHTML(node: MarkdownNode): string;
|
|
1744
1914
|
|
|
1745
1915
|
/**
|
|
1746
|
-
*
|
|
1747
|
-
* projection of `renderHTML
|
|
1916
|
+
* Renders a {@link MarkdownNode} to its canonical markdown source — the inverse
|
|
1917
|
+
* projection of `renderHTML`. It is the serializer a `parse(renderMarkdown(doc))`
|
|
1748
1918
|
* round-trip is built on. Canonical forms: `*` / `**` emphasis at even emphasis
|
|
1749
1919
|
* nesting depths and `_` / `__` at odd depths, `- ` bullets, `N. ` sequential
|
|
1750
1920
|
* ordinals (from the list's `start`), `---` thematic breaks, fenced code blocks
|
|
1751
1921
|
* (backtick run widened past any 3+ backtick run inside the body), ATX headings,
|
|
1752
|
-
* `> `-prefixed blockquote lines, GFM tables (1-space-padded cells,
|
|
1753
|
-
*
|
|
1754
|
-
* and two-space hard breaks. A `text` node's literal content is backslash-escaped
|
|
1755
|
-
* wherever it would otherwise re-parse as markup
|
|
1756
|
-
*
|
|
1922
|
+
* `> `-prefixed blockquote lines, GFM tables (1-space-padded cells, a backslash
|
|
1923
|
+
* before each literal pipe, an alignment delimiter row), `[text](href)` links,
|
|
1924
|
+
* `` images, and two-space hard breaks. A `text` node's literal content is backslash-escaped
|
|
1925
|
+
* wherever it would otherwise re-parse as markup, so parsing the rendered source
|
|
1926
|
+
* returns the node it was rendered from.
|
|
1757
1927
|
*
|
|
1758
1928
|
* @remarks
|
|
1759
1929
|
* Total: never throws. At {@link MAX_DEPTH} a value-bearing node degrades to its
|
|
@@ -1774,10 +1944,10 @@ export declare function renderHTML(node: MarkdownNode): string;
|
|
|
1774
1944
|
export declare function renderMarkdown(node: MarkdownNode): string;
|
|
1775
1945
|
|
|
1776
1946
|
/**
|
|
1777
|
-
*
|
|
1947
|
+
* Rewrites a {@link MarkdownDocument} bottom-up (copy-on-write) — each node's children
|
|
1778
1948
|
* are rewritten first (post-order), then `rewrite` is applied to the node itself; the
|
|
1779
|
-
* document
|
|
1780
|
-
* always holds). A table's inline cells and a list's items
|
|
1949
|
+
* document root is never passed to `rewrite` (the `element: 'document'` invariant
|
|
1950
|
+
* always holds). A table's inline cells and a list's items are rewritten too.
|
|
1781
1951
|
*
|
|
1782
1952
|
* @remarks
|
|
1783
1953
|
* Never mutates `document`. An unchanged subtree keeps its input identity. A parent
|
|
@@ -1786,12 +1956,12 @@ export declare function renderMarkdown(node: MarkdownNode): string;
|
|
|
1786
1956
|
* whose `element` does not fit the slot it was called for (a block slot handed a
|
|
1787
1957
|
* non-{@link BlockNode}, an inline slot handed a non-{@link InlineNode}, a list-item
|
|
1788
1958
|
* slot handed a non-`listItem`), the ill-fitting result is discarded and the accepted
|
|
1789
|
-
* input child is reused
|
|
1959
|
+
* input child is reused — `rewriteDocument` stays total and never produces a
|
|
1790
1960
|
* structurally invalid document.
|
|
1791
1961
|
*
|
|
1792
1962
|
* Descent is capped at {@link MAX_DEPTH}, the same cap {@link walkNodes} and
|
|
1793
1963
|
* {@link foldNode} observe: at `depth >= MAX_DEPTH` the subtree is passed through
|
|
1794
|
-
*
|
|
1964
|
+
* unchanged (by reference, not rebuilt, and `rewrite` is not invoked on it) instead of
|
|
1795
1965
|
* recursing further, so a pathologically deep adopted document cannot exhaust the
|
|
1796
1966
|
* call stack. {@link MarkdownInterface.map} inherits this cap since it delegates here.
|
|
1797
1967
|
*
|
|
@@ -1809,8 +1979,8 @@ export declare function renderMarkdown(node: MarkdownNode): string;
|
|
|
1809
1979
|
export declare function rewriteDocument(document: MarkdownDocument, rewrite: MarkdownRewriteHandler): MarkdownDerivation<MarkdownDocument>;
|
|
1810
1980
|
|
|
1811
1981
|
/**
|
|
1812
|
-
*
|
|
1813
|
-
*
|
|
1982
|
+
* Scans an inline code span at `start` (a `` ` ``-run … a matching `` ` ``-run of the
|
|
1983
|
+
* same length, the CommonMark rule that lets a span contain backticks). Returns the
|
|
1814
1984
|
* span's literal text + end index, or `undefined` when no matching closer exists (it
|
|
1815
1985
|
* then degrades to literal backticks).
|
|
1816
1986
|
*
|
|
@@ -1824,13 +1994,10 @@ export declare function rewriteDocument(document: MarkdownDocument, rewrite: Mar
|
|
|
1824
1994
|
* scanCode('`code`', 0, 6) // { value: 'code', end: 6 }
|
|
1825
1995
|
* ```
|
|
1826
1996
|
*/
|
|
1827
|
-
export declare function scanCode(source: string, start: number, to: number):
|
|
1828
|
-
readonly value: string;
|
|
1829
|
-
readonly end: number;
|
|
1830
|
-
} | undefined;
|
|
1997
|
+
export declare function scanCode(source: string, start: number, to: number): CodeSpanMatch | undefined;
|
|
1831
1998
|
|
|
1832
1999
|
/**
|
|
1833
|
-
* Scans an emphasis run at `start` (`*` / `_`, doubled for strong)
|
|
2000
|
+
* Scans an emphasis run at `start` (`*` / `_`, doubled for strong) — finds the nearest
|
|
1834
2001
|
* matching closing run of the same marker + width while skipping complete nested runs
|
|
1835
2002
|
* from the other marker family, and requires non-space immediately inside both
|
|
1836
2003
|
* delimiters (the CommonMark flanking simplification that blocks `* x *`) through
|
|
@@ -1851,13 +2018,10 @@ export declare function scanCode(source: string, start: number, to: number): {
|
|
|
1851
2018
|
* // { node: { element: 'emphasis', strong: false, children: [{ element: 'text', value: 'em' }] }, end: 4 }
|
|
1852
2019
|
* ```
|
|
1853
2020
|
*/
|
|
1854
|
-
export declare function scanEmphasis(source: string, start: number, to: number, depth?: number):
|
|
1855
|
-
readonly node: EmphasisNode;
|
|
1856
|
-
readonly end: number;
|
|
1857
|
-
} | undefined;
|
|
2021
|
+
export declare function scanEmphasis(source: string, start: number, to: number, depth?: number): EmphasisScan | undefined;
|
|
1858
2022
|
|
|
1859
2023
|
/**
|
|
1860
|
-
*
|
|
2024
|
+
* Scans the window `[from, to)` of `source` into inline nodes — the single recursive
|
|
1861
2025
|
* engine the inline phase runs on (emphasis, link text, and image alternative
|
|
1862
2026
|
* content recurse through it). Linear:
|
|
1863
2027
|
* each character is consumed once; a failed construct emits its opening character as
|
|
@@ -1867,11 +2031,12 @@ export declare function scanEmphasis(source: string, start: number, to: number,
|
|
|
1867
2031
|
* @param from - The inclusive start of the scan window
|
|
1868
2032
|
* @param to - The exclusive end of the scan window
|
|
1869
2033
|
* @param depth - The current inline-recursion depth (defaults to 0 at the entry point);
|
|
1870
|
-
* incremented by one on every recursive descent
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
*
|
|
2034
|
+
* incremented by one on every recursive descent {@link scanInlineSource} makes into
|
|
2035
|
+
* itself for a link's text, an image's alternative content, or an emphasis run's
|
|
2036
|
+
* children. At {@link MAX_DEPTH} the window is never scanned for markup — it emits as
|
|
2037
|
+
* a single literal text node — so pathological nesting (`[[[[…`, `****…`) cannot
|
|
2038
|
+
* exhaust the call stack.
|
|
2039
|
+
* @returns The parsed inline nodes (not yet coalesced)
|
|
1875
2040
|
*
|
|
1876
2041
|
* @example
|
|
1877
2042
|
* ```ts
|
|
@@ -1888,7 +2053,9 @@ export declare function scanInline(source: string, from: number, to: number, dep
|
|
|
1888
2053
|
* @param from - The inclusive start of the scan window
|
|
1889
2054
|
* @param to - The exclusive end of the scan window
|
|
1890
2055
|
* @param spans - The operation-owned node span recorder
|
|
1891
|
-
* @param depth - The current inline-recursion depth
|
|
2056
|
+
* @param depth - The current inline-recursion depth, incremented by one on every
|
|
2057
|
+
* recursive descent this function makes into itself for a link's text, an image's
|
|
2058
|
+
* alternative content, or an emphasis run's children
|
|
1892
2059
|
* @returns The parsed inline nodes before adjacent text coalescing
|
|
1893
2060
|
*
|
|
1894
2061
|
* @example
|
|
@@ -1905,7 +2072,7 @@ export declare function scanInline(source: string, from: number, to: number, dep
|
|
|
1905
2072
|
export declare function scanInlineSource(source: MarkdownSource, from: number, to: number, spans: Map<MarkdownNode, MarkdownSpan>, depth?: number): readonly InlineNode[];
|
|
1906
2073
|
|
|
1907
2074
|
/**
|
|
1908
|
-
* Scans a link `[text](href)` at `start`
|
|
2075
|
+
* Scans a link `[text](href)` at `start` — the text runs to a balanced `]`, then `(`
|
|
1909
2076
|
* must immediately follow and the destination runs to the matching `)` (both respect
|
|
1910
2077
|
* nested delimiters + escapes) through {@link locateLink}, and returns the parsed node
|
|
1911
2078
|
* and end index. Returns `undefined` when the shape does not hold (it then degrades to
|
|
@@ -1925,10 +2092,7 @@ export declare function scanInlineSource(source: MarkdownSource, from: number, t
|
|
|
1925
2092
|
* // { node: { element: 'link', href: 'url', children: [{ element: 'text', value: 'text' }] }, end: 11 }
|
|
1926
2093
|
* ```
|
|
1927
2094
|
*/
|
|
1928
|
-
export declare function scanLink(source: string, start: number, to: number, depth?: number):
|
|
1929
|
-
readonly node: LinkNode;
|
|
1930
|
-
readonly end: number;
|
|
1931
|
-
} | undefined;
|
|
2095
|
+
export declare function scanLink(source: string, start: number, to: number, depth?: number): LinkScan | undefined;
|
|
1932
2096
|
|
|
1933
2097
|
/**
|
|
1934
2098
|
* Slices derived markdown text and narrows each intersecting source segment to the
|
|
@@ -1963,10 +2127,11 @@ export declare function sliceSource(source: MarkdownSource, from: number, to: nu
|
|
|
1963
2127
|
export declare function splitLines(markdown: string): readonly MarkdownSource[];
|
|
1964
2128
|
|
|
1965
2129
|
/**
|
|
1966
|
-
*
|
|
1967
|
-
*
|
|
1968
|
-
* empty leading / trailing cell
|
|
1969
|
-
* form from {@link splitTableSources}, which owns the
|
|
2130
|
+
* Splits one GFM table row into its cell strings — outer pipes are optional, a pipe
|
|
2131
|
+
* escaped by a leading backslash inside a cell is not a separator (it becomes a literal
|
|
2132
|
+
* pipe character), and the empty leading / trailing cell an outer pipe produces is
|
|
2133
|
+
* dropped. Derives the string form from {@link splitTableSources}, which owns the
|
|
2134
|
+
* escaped-pipe splitting rule.
|
|
1970
2135
|
*
|
|
1971
2136
|
* @param row - The raw table row line
|
|
1972
2137
|
* @returns The row's cells, in column order
|
|
@@ -1993,15 +2158,15 @@ export declare function splitTableRow(row: string): readonly string[];
|
|
|
1993
2158
|
export declare function splitTableSources(row: MarkdownSource): readonly MarkdownSource[];
|
|
1994
2159
|
|
|
1995
2160
|
/**
|
|
1996
|
-
*
|
|
1997
|
-
* break / blockquote / list / table)
|
|
2161
|
+
* Checks whether the line at `index` starts a new block kind (heading / fence / thematic
|
|
2162
|
+
* break / blockquote / list / table) — the paragraph collector stops at such a line
|
|
1998
2163
|
* so a block following a paragraph without a blank line still parses (a trusted-input
|
|
1999
2164
|
* caller writing a `##` heading directly under a paragraph, with no intervening blank
|
|
2000
2165
|
* line).
|
|
2001
2166
|
*
|
|
2002
2167
|
* @param lines - The document's lines
|
|
2003
2168
|
* @param index - The line index to test
|
|
2004
|
-
* @returns
|
|
2169
|
+
* @returns True if the line begins a different block; false otherwise
|
|
2005
2170
|
*
|
|
2006
2171
|
* @example
|
|
2007
2172
|
* ```ts
|
|
@@ -2027,17 +2192,24 @@ export declare function startsBlock(lines: readonly string[], index: number): bo
|
|
|
2027
2192
|
export declare function stripQuote(source: MarkdownSource): MarkdownSource;
|
|
2028
2193
|
|
|
2029
2194
|
/**
|
|
2030
|
-
*
|
|
2195
|
+
* Names the horizontal alignment of a GFM table column, as declared by its delimiter row
|
|
2031
2196
|
* (`:---` left, `---:` right, `:---:` center). A bare `---` delimiter is represented
|
|
2032
2197
|
* by `null` in {@link TableNode.align}: the positional array requires one entry per
|
|
2033
2198
|
* column, JSON cannot carry `undefined` in an array, and the bare delimiter is an
|
|
2034
2199
|
* explicit no-alignment marker rather than an omitted value.
|
|
2200
|
+
*
|
|
2201
|
+
* @remarks
|
|
2202
|
+
* The other place absence appears is {@link MarkdownCell.align}, which holds
|
|
2203
|
+
* `undefined` when the projected cell declared no alignment. That member is a plain
|
|
2204
|
+
* optional property on one cell rather than an entry in a positional array, so it
|
|
2205
|
+
* takes the ordinary `undefined` instead of the in-band `null` marker.
|
|
2035
2206
|
*/
|
|
2036
2207
|
export declare type TableAlign = 'left' | 'right' | 'center';
|
|
2037
2208
|
|
|
2038
2209
|
/**
|
|
2039
|
-
*
|
|
2040
|
-
* literal.
|
|
2210
|
+
* Describes the shape of a {@link TableAlign} — the per-column GFM table alignment
|
|
2211
|
+
* literal. Absence is no member of it, so the shape refuses the `null` a bare `---`
|
|
2212
|
+
* delimiter takes in a `TableNode`'s `align` list.
|
|
2041
2213
|
*
|
|
2042
2214
|
* @example
|
|
2043
2215
|
* ```ts
|
|
@@ -2053,19 +2225,30 @@ export declare type TableAlign = 'left' | 'right' | 'center';
|
|
|
2053
2225
|
export declare const tableAlignShape: LiteralShape<readonly ["left", "right", "center"]>;
|
|
2054
2226
|
|
|
2055
2227
|
/**
|
|
2056
|
-
*
|
|
2228
|
+
* Represents the result of collecting one GFM table — the node the construct scanner built and
|
|
2229
|
+
* where the block phase resumes.
|
|
2230
|
+
*/
|
|
2231
|
+
export declare interface TableCollection {
|
|
2232
|
+
/** Holds the collected table. */
|
|
2233
|
+
readonly node: TableNode;
|
|
2234
|
+
/** Holds the index of the first line after the table. */
|
|
2235
|
+
readonly next: number;
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/**
|
|
2239
|
+
* Represents a GFM table — `header` the inline content of each header cell, `rows` the body
|
|
2057
2240
|
* rows (each a list of cells, each cell inline content), `align` the per-column
|
|
2058
2241
|
* alignment from the delimiter row. A short body row is padded with empty cells; an
|
|
2059
2242
|
* over-long one is truncated to the header's column count.
|
|
2060
2243
|
*/
|
|
2061
2244
|
export declare interface TableNode {
|
|
2062
2245
|
readonly element: 'table';
|
|
2063
|
-
/**
|
|
2246
|
+
/** Holds the header row — one cell of inline content per column. */
|
|
2064
2247
|
readonly header: ReadonlyArray<readonly InlineNode[]>;
|
|
2065
|
-
/**
|
|
2248
|
+
/** Holds the body rows — each a list of cells, each cell inline content. */
|
|
2066
2249
|
readonly rows: ReadonlyArray<ReadonlyArray<readonly InlineNode[]>>;
|
|
2067
2250
|
/**
|
|
2068
|
-
*
|
|
2251
|
+
* Holds the per-column alignment from the delimiter row, in column order. `null`
|
|
2069
2252
|
* represents a bare `---` delimiter because this positional array requires one
|
|
2070
2253
|
* entry per column, JSON cannot carry `undefined` in an array, and the delimiter
|
|
2071
2254
|
* is an explicit no-alignment marker rather than an omitted value.
|
|
@@ -2074,19 +2257,19 @@ export declare interface TableNode {
|
|
|
2074
2257
|
}
|
|
2075
2258
|
|
|
2076
2259
|
/**
|
|
2077
|
-
*
|
|
2260
|
+
* Represents a run of plain text — the leaf inline node. `value` is the decoded text with
|
|
2078
2261
|
* markdown escapes (`\*`, `\_`, …) already resolved to their literal characters;
|
|
2079
2262
|
* html's text encoder escapes `&`, `<`, `>` on the way out; `"` and `'` stay literal
|
|
2080
2263
|
* in character data.
|
|
2081
2264
|
*/
|
|
2082
2265
|
export declare interface TextNode {
|
|
2083
2266
|
readonly element: 'text';
|
|
2084
|
-
/**
|
|
2267
|
+
/** Holds the literal text content (escapes resolved, not yet HTML-escaped). */
|
|
2085
2268
|
readonly value: string;
|
|
2086
2269
|
}
|
|
2087
2270
|
|
|
2088
2271
|
/**
|
|
2089
|
-
*
|
|
2272
|
+
* Describes the shape of a {@link TextNode} — a plain-text leaf inline run.
|
|
2090
2273
|
*
|
|
2091
2274
|
* @example
|
|
2092
2275
|
* ```ts
|
|
@@ -2097,18 +2280,18 @@ export declare interface TextNode {
|
|
|
2097
2280
|
* text.is({ element: 'text', value: 'hi' }) // true
|
|
2098
2281
|
* ```
|
|
2099
2282
|
*/
|
|
2100
|
-
export declare const textShape: ObjectShape<{
|
|
2101
|
-
|
|
2102
|
-
|
|
2283
|
+
export declare const textShape: ObjectShape< {
|
|
2284
|
+
element: LiteralShape<readonly ["text"]>;
|
|
2285
|
+
value: StringShape;
|
|
2103
2286
|
}, false>;
|
|
2104
2287
|
|
|
2105
|
-
/**
|
|
2288
|
+
/** Represents a thematic break — a horizontal rule (`---` / `***` / `___` on its own line). */
|
|
2106
2289
|
export declare interface ThematicBreakNode {
|
|
2107
2290
|
readonly element: 'thematicBreak';
|
|
2108
2291
|
}
|
|
2109
2292
|
|
|
2110
2293
|
/**
|
|
2111
|
-
*
|
|
2294
|
+
* Describes the shape of a {@link ThematicBreakNode} — a horizontal rule. Carries no
|
|
2112
2295
|
* fields beyond its `element` discriminant.
|
|
2113
2296
|
*
|
|
2114
2297
|
* @example
|
|
@@ -2120,13 +2303,13 @@ export declare interface ThematicBreakNode {
|
|
|
2120
2303
|
* thematicBreak.is({ element: 'thematicBreak' }) // true
|
|
2121
2304
|
* ```
|
|
2122
2305
|
*/
|
|
2123
|
-
export declare const thematicBreakShape: ObjectShape<{
|
|
2124
|
-
|
|
2306
|
+
export declare const thematicBreakShape: ObjectShape< {
|
|
2307
|
+
element: LiteralShape<readonly ["thematicBreak"]>;
|
|
2125
2308
|
}, false>;
|
|
2126
2309
|
|
|
2127
2310
|
/**
|
|
2128
|
-
*
|
|
2129
|
-
* leading text node and the trailing whitespace of a trailing one
|
|
2311
|
+
* Trims the whitespace at the two ends of an inline run — the leading whitespace of a
|
|
2312
|
+
* leading text node and the trailing whitespace of a trailing one — dropping either
|
|
2130
2313
|
* node when nothing survives.
|
|
2131
2314
|
*
|
|
2132
2315
|
* @remarks
|
|
@@ -2159,7 +2342,7 @@ export declare function trimInlines(nodes: readonly InlineNode[]): readonly Inli
|
|
|
2159
2342
|
export declare function trimSource(source: MarkdownSource): MarkdownSource;
|
|
2160
2343
|
|
|
2161
2344
|
/**
|
|
2162
|
-
*
|
|
2345
|
+
* Resolves backslash escapes in a raw string to their literal characters — used for a
|
|
2163
2346
|
* link `href` (which is not otherwise inline-parsed) and any plain text run.
|
|
2164
2347
|
*
|
|
2165
2348
|
* @param text - The raw text possibly carrying `\x` escapes
|
|
@@ -2173,7 +2356,7 @@ export declare function trimSource(source: MarkdownSource): MarkdownSource;
|
|
|
2173
2356
|
export declare function unescapeText(text: string): string;
|
|
2174
2357
|
|
|
2175
2358
|
/**
|
|
2176
|
-
*
|
|
2359
|
+
* Walks a {@link MarkdownNode} depth-first, pre-order, root-inclusive — yields
|
|
2177
2360
|
* the node itself, then recurses into its children (block children, list items,
|
|
2178
2361
|
* image/link inline children, table header/row cells' inline nodes) in walk order.
|
|
2179
2362
|
*
|