@orkestrel/markdown 0.0.17 → 0.0.18

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.
@@ -13,6 +13,17 @@ import { OptionalShape } from '@orkestrel/contract';
13
13
  import { StringShape } from '@orkestrel/contract';
14
14
  import type { TextNode as TextNode_2 } from '@orkestrel/html';
15
15
 
16
+ /**
17
+ * Accepts a rewritten node only when it fits the original node slot.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const original: TextNode = { element: 'text', value: 'hi' }
22
+ * acceptMarkdownNode(original, original, { element: 'thematicBreak' }) === original // true
23
+ * ```
24
+ */
25
+ export declare function acceptMarkdownNode(current: MarkdownNode, rebuilt: MarkdownNode, result: MarkdownNode): MarkdownNode;
26
+
16
27
  /** Represents a node that can appear at the block level of a document (or inside a list item / blockquote). */
17
28
  export declare type BlockNode = HeadingNode | ParagraphNode | ListNode | TableNode | CodeBlockNode | BlockquoteNode | ThematicBreakNode;
18
29
 
@@ -28,7 +39,8 @@ export declare interface BlockquoteNode {
28
39
  * unrecognized character, so coalescing keeps the AST clean and assertion-friendly.
29
40
  *
30
41
  * @param nodes - The inline nodes (possibly with adjacent text runs)
31
- * @param spans - The optional operation-owned node span recorder
42
+ * @param spans - The optional operation-owned span memo; inserts merged-node entries
43
+ * without deleting or replacing constituent entries
32
44
  * @returns The nodes with consecutive text nodes concatenated
33
45
  *
34
46
  * @example
@@ -160,6 +172,16 @@ export declare function collectTable(lines: readonly MarkdownSource[], start: nu
160
172
  */
161
173
  export declare function countIndent(line: string): number;
162
174
 
175
+ /**
176
+ * Counts consecutive copies of the character at the start of a scan window.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * countMarkdownRun('***x', 0, 4) // 3
181
+ * ```
182
+ */
183
+ export declare function countMarkdownRun(source: string, start: number, to: number): number;
184
+
163
185
  /**
164
186
  * Compiles the {@link codeBlockShape} into a {@link ContractInterface} for
165
187
  * {@link CodeBlockNode} — a guard, coercing parser, JSON Schema, and seeded
@@ -360,6 +382,16 @@ export declare interface EmphasisScan {
360
382
  */
361
383
  export declare const EMPTY_PROJECTION: MarkdownProjection;
362
384
 
385
+ /**
386
+ * Escapes literal text so markdown syntax remains literal when rendered.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * escapeMarkdownText('*hi*', false) // '\\*hi\\*'
391
+ * ```
392
+ */
393
+ export declare function escapeMarkdownText(value: string, bang: boolean): string;
394
+
363
395
  /**
364
396
  * Extracts a fenced-code opening line (```` ``` ```` or `~~~`, optionally with an info
365
397
  * string) into its `{ marker, lang }`, or `undefined` when `line` is not a fence
@@ -419,6 +451,16 @@ export declare interface FenceMatch {
419
451
  readonly lang: string | undefined;
420
452
  }
421
453
 
454
+ /**
455
+ * Finds the next defined markdown node at or after an array offset.
456
+ *
457
+ * @example
458
+ * ```ts
459
+ * findFollowingNode([], 0) // undefined
460
+ * ```
461
+ */
462
+ export declare function findFollowingNode(nodes: readonly MarkdownNode[], start: number): MarkdownNode | undefined;
463
+
422
464
  /**
423
465
  * Concatenates the `value` / `code` content of every descendant text / code-span /
424
466
  * code-block node under `node`, including image alternative content, in walk order —
@@ -443,6 +485,16 @@ export declare interface FenceMatch {
443
485
  */
444
486
  export declare function flattenText(node: MarkdownNode): string;
445
487
 
488
+ /**
489
+ * Dispatches one markdown node and its folded children to the matching handler.
490
+ *
491
+ * @example
492
+ * ```ts
493
+ * foldMarkdownNode({ element: 'text', value: 'hi' }, countHandlers, []) // 1
494
+ * ```
495
+ */
496
+ export declare function foldMarkdownNode<T>(node: MarkdownNode, handlers: MarkdownHandlerMap<T>, children: readonly T[]): T;
497
+
446
498
  /**
447
499
  * Folds a {@link MarkdownNode} into a `T` through a total catamorphism — children are
448
500
  * folded first (post-order), then the node's own {@link MarkdownHandler} is invoked
@@ -1025,6 +1077,19 @@ export declare interface LinkScan {
1025
1077
  readonly end: number;
1026
1078
  }
1027
1079
 
1080
+ /**
1081
+ * Lists the direct children of a markdown node in traversal order.
1082
+ *
1083
+ * @param node - The node whose direct children to list
1084
+ * @returns The children, with table cells flattened in header then body order
1085
+ *
1086
+ * @example
1087
+ * ```ts
1088
+ * listChildren({ element: 'document', children: [] }) // []
1089
+ * ```
1090
+ */
1091
+ export declare function listChildren(node: MarkdownNode): readonly MarkdownNode[];
1092
+
1028
1093
  /**
1029
1094
  * Represents the result of collecting one list — the node the construct scanner built and where
1030
1095
  * the block phase resumes.
@@ -1136,6 +1201,16 @@ export declare function locateEmphasis(source: string, start: number, to: number
1136
1201
  */
1137
1202
  export declare function locateLink(source: string, start: number, to: number): LinkBounds | undefined;
1138
1203
 
1204
+ /**
1205
+ * Locates a balanced closing delimiter while skipping backslash escapes.
1206
+ *
1207
+ * @example
1208
+ * ```ts
1209
+ * locateMarkdownDelimiter('[a]', 0, 3, '[', ']') // 2
1210
+ * ```
1211
+ */
1212
+ export declare function locateMarkdownDelimiter(source: string, start: number, to: number, open: string, close: string): number | undefined;
1213
+
1139
1214
  /**
1140
1215
  * Wraps a typed {@link MarkdownDocument} AST as a stateful, parsed markdown document
1141
1216
  * with the query (`find` / `filter` / `reduce` / iteration), rewrite (`map`), fold, and
@@ -1246,7 +1321,9 @@ export declare class Markdown implements MarkdownInterface {
1246
1321
  * ```ts
1247
1322
  * // universal - works in every ReadableStream-supporting environment
1248
1323
  * const reader = markdown.stream().getReader()
1249
- * for (let result = await reader.read(); !result.done; result = await reader.read()) {
1324
+ * for (;;) {
1325
+ * const result = await reader.read()
1326
+ * if (result.done) break
1250
1327
  * console.log(result.value) // one BlockNode
1251
1328
  * }
1252
1329
  *
@@ -1365,6 +1442,12 @@ export declare interface MarkdownHandlerMap<T> {
1365
1442
  readonly image: MarkdownHandler<ImageNode, T>;
1366
1443
  }
1367
1444
 
1445
+ /** Represents an inline construct and the source offset where scanning resumes. */
1446
+ export declare interface MarkdownInlineScan {
1447
+ readonly node: InlineNode;
1448
+ readonly end: number;
1449
+ }
1450
+
1368
1451
  /**
1369
1452
  * Represents a stateful, parsed markdown document: the typed {@link MarkdownDocument} AST plus
1370
1453
  * the query, rewrite, and fold operations over it.
@@ -1763,6 +1846,10 @@ export declare function parseInline(text: string): readonly InlineNode[];
1763
1846
  * @param markdown - The markdown source to parse.
1764
1847
  * @returns The parsed document and its node-identity span map.
1765
1848
  *
1849
+ * @remarks
1850
+ * Parsing inserts into a scratch memo. The returned map contains only nodes of the
1851
+ * final document, enumerated without the public walk's depth cap.
1852
+ *
1766
1853
  * @example
1767
1854
  * ```ts
1768
1855
  * const [document, spans] = parseProvenance('# Hi')
@@ -1871,6 +1958,16 @@ export declare function projectionToBlocks(projection: MarkdownProjection): read
1871
1958
  */
1872
1959
  export declare function projectionToInlines(projection: MarkdownProjection): readonly InlineNode[];
1873
1960
 
1961
+ /**
1962
+ * Projects one markdown node from its already projected children.
1963
+ *
1964
+ * @example
1965
+ * ```ts
1966
+ * projectMarkdownNode({ element: 'text', value: 'hi' }, []) // { category: 'text', value: 'hi' }
1967
+ * ```
1968
+ */
1969
+ export declare function projectMarkdownNode(current: MarkdownNode, children: ReadonlyArray<HTMLNode | undefined>): HTMLNode | undefined;
1970
+
1874
1971
  /**
1875
1972
  * Projects a derived text range through its segments to a half-open region of the
1876
1973
  * original markdown string.
@@ -1888,6 +1985,39 @@ export declare function projectionToInlines(projection: MarkdownProjection): rea
1888
1985
  */
1889
1986
  export declare function projectSpan(source: MarkdownSource, from: number, to: number): MarkdownSpan | undefined;
1890
1987
 
1988
+ /**
1989
+ * Rebuilds a table cell and records each input and accepted output pair.
1990
+ *
1991
+ * @example
1992
+ * ```ts
1993
+ * rebuildMarkdownCell([], [].values(), []) // []
1994
+ * ```
1995
+ */
1996
+ export declare function rebuildMarkdownCell(cell: readonly InlineNode[], outputs: Iterator<MarkdownNode, undefined>, pairs: Array<readonly [InlineNode, InlineNode]>): readonly InlineNode[];
1997
+
1998
+ /**
1999
+ * Rebuilds one markdown node when accepted child replacements change its identity.
2000
+ *
2001
+ * @example
2002
+ * ```ts
2003
+ * const original: ParagraphNode = { element: 'paragraph', children: [] }
2004
+ * rebuildMarkdownNode(original, []) === original // true
2005
+ * ```
2006
+ */
2007
+ export declare function rebuildMarkdownNode(current: MarkdownNode, children: readonly MarkdownNode[]): MarkdownNode;
2008
+
2009
+ /**
2010
+ * Appends a nonempty text node and records its original source span.
2011
+ *
2012
+ * @example
2013
+ * ```ts
2014
+ * const nodes: InlineNode[] = []
2015
+ * recordMarkdownText({ text: 'a', segments: [] }, 'a', 0, 1, new Map(), nodes)
2016
+ * nodes // [{ element: 'text', value: 'a' }]
2017
+ * ```
2018
+ */
2019
+ export declare function recordMarkdownText(source: MarkdownSource, value: string, start: number, end: number, spans: Map<MarkdownNode, MarkdownSpan>, nodes: InlineNode[]): void;
2020
+
1891
2021
  /**
1892
2022
  * Renders a {@link MarkdownNode} to sanitized canonical HTML.
1893
2023
  *
@@ -1943,6 +2073,16 @@ export declare function renderHTML(node: MarkdownNode): string;
1943
2073
  */
1944
2074
  export declare function renderMarkdown(node: MarkdownNode): string;
1945
2075
 
2076
+ /**
2077
+ * Renders one markdown node from its rendered children and escaped literal text.
2078
+ *
2079
+ * @example
2080
+ * ```ts
2081
+ * renderMarkdownNode({ element: 'thematicBreak' }, [], '', 0) // '---'
2082
+ * ```
2083
+ */
2084
+ export declare function renderMarkdownNode(current: MarkdownNode, children: readonly string[], literal: string, emphasis: number): string;
2085
+
1946
2086
  /**
1947
2087
  * Rewrites a {@link MarkdownDocument} bottom-up (copy-on-write) — each node's children
1948
2088
  * are rewritten first (post-order), then `rewrite` is applied to the node itself; the
@@ -2094,6 +2234,16 @@ export declare function scanInlineSource(source: MarkdownSource, from: number, t
2094
2234
  */
2095
2235
  export declare function scanLink(source: string, start: number, to: number, depth?: number): LinkScan | undefined;
2096
2236
 
2237
+ /**
2238
+ * Scans one inline construct and records the spans of its nested children.
2239
+ *
2240
+ * @example
2241
+ * ```ts
2242
+ * scanMarkdownInline({ text: '`x`', segments: [] }, 0, 3, new Map(), 0)?.end // 3
2243
+ * ```
2244
+ */
2245
+ export declare function scanMarkdownInline(source: MarkdownSource, index: number, to: number, spans: Map<MarkdownNode, MarkdownSpan>, depth: number): MarkdownInlineScan | undefined;
2246
+
2097
2247
  /**
2098
2248
  * Slices derived markdown text and narrows each intersecting source segment to the
2099
2249
  * same text-relative range.
@@ -2157,6 +2307,19 @@ export declare function splitTableRow(row: string): readonly string[];
2157
2307
  */
2158
2308
  export declare function splitTableSources(row: MarkdownSource): readonly MarkdownSource[];
2159
2309
 
2310
+ /**
2311
+ * Splits inline nodes into adjacent text runs and singleton non-text runs.
2312
+ *
2313
+ * @param nodes - The inline nodes in source order
2314
+ * @returns The runs with their original node identities
2315
+ *
2316
+ * @example
2317
+ * ```ts
2318
+ * splitTextRuns([{ element: 'text', value: 'a' }]).length // 1
2319
+ * ```
2320
+ */
2321
+ export declare function splitTextRuns(nodes: readonly InlineNode[]): ReadonlyArray<readonly InlineNode[]>;
2322
+
2160
2323
  /**
2161
2324
  * Checks whether the line at `index` starts a new block kind (heading / fence / thematic
2162
2325
  * break / blockquote / list / table) — the paragraph collector stops at such a line
@@ -2327,6 +2490,19 @@ element: LiteralShape<readonly ["thematicBreak"]>;
2327
2490
  */
2328
2491
  export declare function trimInlines(nodes: readonly InlineNode[]): readonly InlineNode[];
2329
2492
 
2493
+ /**
2494
+ * Trims leading whitespace when an inline run starts with a text node.
2495
+ *
2496
+ * @param nodes - The inline run to trim
2497
+ * @returns The run with its leading text trimmed or removed when empty
2498
+ *
2499
+ * @example
2500
+ * ```ts
2501
+ * trimLeading([{ element: 'text', value: ' a ' }]) // [{ element: 'text', value: 'a ' }]
2502
+ * ```
2503
+ */
2504
+ export declare function trimLeading(nodes: readonly InlineNode[]): readonly InlineNode[];
2505
+
2330
2506
  /**
2331
2507
  * Trims an offset-bearing source without losing the coordinates of its retained text.
2332
2508
  *
@@ -2341,6 +2517,19 @@ export declare function trimInlines(nodes: readonly InlineNode[]): readonly Inli
2341
2517
  */
2342
2518
  export declare function trimSource(source: MarkdownSource): MarkdownSource;
2343
2519
 
2520
+ /**
2521
+ * Trims trailing whitespace when an inline run ends with a text node.
2522
+ *
2523
+ * @param nodes - The inline run to trim
2524
+ * @returns The run with its trailing text trimmed or removed when empty
2525
+ *
2526
+ * @example
2527
+ * ```ts
2528
+ * trimTrailing([{ element: 'text', value: ' a ' }]) // [{ element: 'text', value: ' a' }]
2529
+ * ```
2530
+ */
2531
+ export declare function trimTrailing(nodes: readonly InlineNode[]): readonly InlineNode[];
2532
+
2344
2533
  /**
2345
2534
  * Resolves backslash escapes in a raw string to their literal characters — used for a
2346
2535
  * link `href` (which is not otherwise inline-parsed) and any plain text run.
@@ -2355,6 +2544,26 @@ export declare function trimSource(source: MarkdownSource): MarkdownSource;
2355
2544
  */
2356
2545
  export declare function unescapeText(text: string): string;
2357
2546
 
2547
+ /**
2548
+ * Yields UTF-16 offsets and characters within a markdown scan window.
2549
+ *
2550
+ * @example
2551
+ * ```ts
2552
+ * Array.from(walkMarkdownCharacters('ab', 0, 2)) // [[0, 'a'], [1, 'b']]
2553
+ * ```
2554
+ */
2555
+ export declare function walkMarkdownCharacters(source: string, from: number, to: number): Generator<readonly [number, string], void, unknown>;
2556
+
2557
+ /**
2558
+ * Yields line offsets through a closable markdown scan iterator.
2559
+ *
2560
+ * @example
2561
+ * ```ts
2562
+ * Array.from(walkMarkdownLines(splitLines('a\nb'), 1)) // [1]
2563
+ * ```
2564
+ */
2565
+ export declare function walkMarkdownLines(lines: readonly MarkdownSource[], start: number): Generator<number, void, unknown>;
2566
+
2358
2567
  /**
2359
2568
  * Walks a {@link MarkdownNode} depth-first, pre-order, root-inclusive — yields
2360
2569
  * the node itself, then recurses into its children (block children, list items,
@@ -13,6 +13,17 @@ import { OptionalShape } from '@orkestrel/contract';
13
13
  import { StringShape } from '@orkestrel/contract';
14
14
  import type { TextNode as TextNode_2 } from '@orkestrel/html';
15
15
 
16
+ /**
17
+ * Accepts a rewritten node only when it fits the original node slot.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const original: TextNode = { element: 'text', value: 'hi' }
22
+ * acceptMarkdownNode(original, original, { element: 'thematicBreak' }) === original // true
23
+ * ```
24
+ */
25
+ export declare function acceptMarkdownNode(current: MarkdownNode, rebuilt: MarkdownNode, result: MarkdownNode): MarkdownNode;
26
+
16
27
  /** Represents a node that can appear at the block level of a document (or inside a list item / blockquote). */
17
28
  export declare type BlockNode = HeadingNode | ParagraphNode | ListNode | TableNode | CodeBlockNode | BlockquoteNode | ThematicBreakNode;
18
29
 
@@ -28,7 +39,8 @@ export declare interface BlockquoteNode {
28
39
  * unrecognized character, so coalescing keeps the AST clean and assertion-friendly.
29
40
  *
30
41
  * @param nodes - The inline nodes (possibly with adjacent text runs)
31
- * @param spans - The optional operation-owned node span recorder
42
+ * @param spans - The optional operation-owned span memo; inserts merged-node entries
43
+ * without deleting or replacing constituent entries
32
44
  * @returns The nodes with consecutive text nodes concatenated
33
45
  *
34
46
  * @example
@@ -160,6 +172,16 @@ export declare function collectTable(lines: readonly MarkdownSource[], start: nu
160
172
  */
161
173
  export declare function countIndent(line: string): number;
162
174
 
175
+ /**
176
+ * Counts consecutive copies of the character at the start of a scan window.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * countMarkdownRun('***x', 0, 4) // 3
181
+ * ```
182
+ */
183
+ export declare function countMarkdownRun(source: string, start: number, to: number): number;
184
+
163
185
  /**
164
186
  * Compiles the {@link codeBlockShape} into a {@link ContractInterface} for
165
187
  * {@link CodeBlockNode} — a guard, coercing parser, JSON Schema, and seeded
@@ -360,6 +382,16 @@ export declare interface EmphasisScan {
360
382
  */
361
383
  export declare const EMPTY_PROJECTION: MarkdownProjection;
362
384
 
385
+ /**
386
+ * Escapes literal text so markdown syntax remains literal when rendered.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * escapeMarkdownText('*hi*', false) // '\\*hi\\*'
391
+ * ```
392
+ */
393
+ export declare function escapeMarkdownText(value: string, bang: boolean): string;
394
+
363
395
  /**
364
396
  * Extracts a fenced-code opening line (```` ``` ```` or `~~~`, optionally with an info
365
397
  * string) into its `{ marker, lang }`, or `undefined` when `line` is not a fence
@@ -419,6 +451,16 @@ export declare interface FenceMatch {
419
451
  readonly lang: string | undefined;
420
452
  }
421
453
 
454
+ /**
455
+ * Finds the next defined markdown node at or after an array offset.
456
+ *
457
+ * @example
458
+ * ```ts
459
+ * findFollowingNode([], 0) // undefined
460
+ * ```
461
+ */
462
+ export declare function findFollowingNode(nodes: readonly MarkdownNode[], start: number): MarkdownNode | undefined;
463
+
422
464
  /**
423
465
  * Concatenates the `value` / `code` content of every descendant text / code-span /
424
466
  * code-block node under `node`, including image alternative content, in walk order —
@@ -443,6 +485,16 @@ export declare interface FenceMatch {
443
485
  */
444
486
  export declare function flattenText(node: MarkdownNode): string;
445
487
 
488
+ /**
489
+ * Dispatches one markdown node and its folded children to the matching handler.
490
+ *
491
+ * @example
492
+ * ```ts
493
+ * foldMarkdownNode({ element: 'text', value: 'hi' }, countHandlers, []) // 1
494
+ * ```
495
+ */
496
+ export declare function foldMarkdownNode<T>(node: MarkdownNode, handlers: MarkdownHandlerMap<T>, children: readonly T[]): T;
497
+
446
498
  /**
447
499
  * Folds a {@link MarkdownNode} into a `T` through a total catamorphism — children are
448
500
  * folded first (post-order), then the node's own {@link MarkdownHandler} is invoked
@@ -1025,6 +1077,19 @@ export declare interface LinkScan {
1025
1077
  readonly end: number;
1026
1078
  }
1027
1079
 
1080
+ /**
1081
+ * Lists the direct children of a markdown node in traversal order.
1082
+ *
1083
+ * @param node - The node whose direct children to list
1084
+ * @returns The children, with table cells flattened in header then body order
1085
+ *
1086
+ * @example
1087
+ * ```ts
1088
+ * listChildren({ element: 'document', children: [] }) // []
1089
+ * ```
1090
+ */
1091
+ export declare function listChildren(node: MarkdownNode): readonly MarkdownNode[];
1092
+
1028
1093
  /**
1029
1094
  * Represents the result of collecting one list — the node the construct scanner built and where
1030
1095
  * the block phase resumes.
@@ -1136,6 +1201,16 @@ export declare function locateEmphasis(source: string, start: number, to: number
1136
1201
  */
1137
1202
  export declare function locateLink(source: string, start: number, to: number): LinkBounds | undefined;
1138
1203
 
1204
+ /**
1205
+ * Locates a balanced closing delimiter while skipping backslash escapes.
1206
+ *
1207
+ * @example
1208
+ * ```ts
1209
+ * locateMarkdownDelimiter('[a]', 0, 3, '[', ']') // 2
1210
+ * ```
1211
+ */
1212
+ export declare function locateMarkdownDelimiter(source: string, start: number, to: number, open: string, close: string): number | undefined;
1213
+
1139
1214
  /**
1140
1215
  * Wraps a typed {@link MarkdownDocument} AST as a stateful, parsed markdown document
1141
1216
  * with the query (`find` / `filter` / `reduce` / iteration), rewrite (`map`), fold, and
@@ -1246,7 +1321,9 @@ export declare class Markdown implements MarkdownInterface {
1246
1321
  * ```ts
1247
1322
  * // universal - works in every ReadableStream-supporting environment
1248
1323
  * const reader = markdown.stream().getReader()
1249
- * for (let result = await reader.read(); !result.done; result = await reader.read()) {
1324
+ * for (;;) {
1325
+ * const result = await reader.read()
1326
+ * if (result.done) break
1250
1327
  * console.log(result.value) // one BlockNode
1251
1328
  * }
1252
1329
  *
@@ -1365,6 +1442,12 @@ export declare interface MarkdownHandlerMap<T> {
1365
1442
  readonly image: MarkdownHandler<ImageNode, T>;
1366
1443
  }
1367
1444
 
1445
+ /** Represents an inline construct and the source offset where scanning resumes. */
1446
+ export declare interface MarkdownInlineScan {
1447
+ readonly node: InlineNode;
1448
+ readonly end: number;
1449
+ }
1450
+
1368
1451
  /**
1369
1452
  * Represents a stateful, parsed markdown document: the typed {@link MarkdownDocument} AST plus
1370
1453
  * the query, rewrite, and fold operations over it.
@@ -1763,6 +1846,10 @@ export declare function parseInline(text: string): readonly InlineNode[];
1763
1846
  * @param markdown - The markdown source to parse.
1764
1847
  * @returns The parsed document and its node-identity span map.
1765
1848
  *
1849
+ * @remarks
1850
+ * Parsing inserts into a scratch memo. The returned map contains only nodes of the
1851
+ * final document, enumerated without the public walk's depth cap.
1852
+ *
1766
1853
  * @example
1767
1854
  * ```ts
1768
1855
  * const [document, spans] = parseProvenance('# Hi')
@@ -1871,6 +1958,16 @@ export declare function projectionToBlocks(projection: MarkdownProjection): read
1871
1958
  */
1872
1959
  export declare function projectionToInlines(projection: MarkdownProjection): readonly InlineNode[];
1873
1960
 
1961
+ /**
1962
+ * Projects one markdown node from its already projected children.
1963
+ *
1964
+ * @example
1965
+ * ```ts
1966
+ * projectMarkdownNode({ element: 'text', value: 'hi' }, []) // { category: 'text', value: 'hi' }
1967
+ * ```
1968
+ */
1969
+ export declare function projectMarkdownNode(current: MarkdownNode, children: ReadonlyArray<HTMLNode | undefined>): HTMLNode | undefined;
1970
+
1874
1971
  /**
1875
1972
  * Projects a derived text range through its segments to a half-open region of the
1876
1973
  * original markdown string.
@@ -1888,6 +1985,39 @@ export declare function projectionToInlines(projection: MarkdownProjection): rea
1888
1985
  */
1889
1986
  export declare function projectSpan(source: MarkdownSource, from: number, to: number): MarkdownSpan | undefined;
1890
1987
 
1988
+ /**
1989
+ * Rebuilds a table cell and records each input and accepted output pair.
1990
+ *
1991
+ * @example
1992
+ * ```ts
1993
+ * rebuildMarkdownCell([], [].values(), []) // []
1994
+ * ```
1995
+ */
1996
+ export declare function rebuildMarkdownCell(cell: readonly InlineNode[], outputs: Iterator<MarkdownNode, undefined>, pairs: Array<readonly [InlineNode, InlineNode]>): readonly InlineNode[];
1997
+
1998
+ /**
1999
+ * Rebuilds one markdown node when accepted child replacements change its identity.
2000
+ *
2001
+ * @example
2002
+ * ```ts
2003
+ * const original: ParagraphNode = { element: 'paragraph', children: [] }
2004
+ * rebuildMarkdownNode(original, []) === original // true
2005
+ * ```
2006
+ */
2007
+ export declare function rebuildMarkdownNode(current: MarkdownNode, children: readonly MarkdownNode[]): MarkdownNode;
2008
+
2009
+ /**
2010
+ * Appends a nonempty text node and records its original source span.
2011
+ *
2012
+ * @example
2013
+ * ```ts
2014
+ * const nodes: InlineNode[] = []
2015
+ * recordMarkdownText({ text: 'a', segments: [] }, 'a', 0, 1, new Map(), nodes)
2016
+ * nodes // [{ element: 'text', value: 'a' }]
2017
+ * ```
2018
+ */
2019
+ export declare function recordMarkdownText(source: MarkdownSource, value: string, start: number, end: number, spans: Map<MarkdownNode, MarkdownSpan>, nodes: InlineNode[]): void;
2020
+
1891
2021
  /**
1892
2022
  * Renders a {@link MarkdownNode} to sanitized canonical HTML.
1893
2023
  *
@@ -1943,6 +2073,16 @@ export declare function renderHTML(node: MarkdownNode): string;
1943
2073
  */
1944
2074
  export declare function renderMarkdown(node: MarkdownNode): string;
1945
2075
 
2076
+ /**
2077
+ * Renders one markdown node from its rendered children and escaped literal text.
2078
+ *
2079
+ * @example
2080
+ * ```ts
2081
+ * renderMarkdownNode({ element: 'thematicBreak' }, [], '', 0) // '---'
2082
+ * ```
2083
+ */
2084
+ export declare function renderMarkdownNode(current: MarkdownNode, children: readonly string[], literal: string, emphasis: number): string;
2085
+
1946
2086
  /**
1947
2087
  * Rewrites a {@link MarkdownDocument} bottom-up (copy-on-write) — each node's children
1948
2088
  * are rewritten first (post-order), then `rewrite` is applied to the node itself; the
@@ -2094,6 +2234,16 @@ export declare function scanInlineSource(source: MarkdownSource, from: number, t
2094
2234
  */
2095
2235
  export declare function scanLink(source: string, start: number, to: number, depth?: number): LinkScan | undefined;
2096
2236
 
2237
+ /**
2238
+ * Scans one inline construct and records the spans of its nested children.
2239
+ *
2240
+ * @example
2241
+ * ```ts
2242
+ * scanMarkdownInline({ text: '`x`', segments: [] }, 0, 3, new Map(), 0)?.end // 3
2243
+ * ```
2244
+ */
2245
+ export declare function scanMarkdownInline(source: MarkdownSource, index: number, to: number, spans: Map<MarkdownNode, MarkdownSpan>, depth: number): MarkdownInlineScan | undefined;
2246
+
2097
2247
  /**
2098
2248
  * Slices derived markdown text and narrows each intersecting source segment to the
2099
2249
  * same text-relative range.
@@ -2157,6 +2307,19 @@ export declare function splitTableRow(row: string): readonly string[];
2157
2307
  */
2158
2308
  export declare function splitTableSources(row: MarkdownSource): readonly MarkdownSource[];
2159
2309
 
2310
+ /**
2311
+ * Splits inline nodes into adjacent text runs and singleton non-text runs.
2312
+ *
2313
+ * @param nodes - The inline nodes in source order
2314
+ * @returns The runs with their original node identities
2315
+ *
2316
+ * @example
2317
+ * ```ts
2318
+ * splitTextRuns([{ element: 'text', value: 'a' }]).length // 1
2319
+ * ```
2320
+ */
2321
+ export declare function splitTextRuns(nodes: readonly InlineNode[]): ReadonlyArray<readonly InlineNode[]>;
2322
+
2160
2323
  /**
2161
2324
  * Checks whether the line at `index` starts a new block kind (heading / fence / thematic
2162
2325
  * break / blockquote / list / table) — the paragraph collector stops at such a line
@@ -2327,6 +2490,19 @@ element: LiteralShape<readonly ["thematicBreak"]>;
2327
2490
  */
2328
2491
  export declare function trimInlines(nodes: readonly InlineNode[]): readonly InlineNode[];
2329
2492
 
2493
+ /**
2494
+ * Trims leading whitespace when an inline run starts with a text node.
2495
+ *
2496
+ * @param nodes - The inline run to trim
2497
+ * @returns The run with its leading text trimmed or removed when empty
2498
+ *
2499
+ * @example
2500
+ * ```ts
2501
+ * trimLeading([{ element: 'text', value: ' a ' }]) // [{ element: 'text', value: 'a ' }]
2502
+ * ```
2503
+ */
2504
+ export declare function trimLeading(nodes: readonly InlineNode[]): readonly InlineNode[];
2505
+
2330
2506
  /**
2331
2507
  * Trims an offset-bearing source without losing the coordinates of its retained text.
2332
2508
  *
@@ -2341,6 +2517,19 @@ export declare function trimInlines(nodes: readonly InlineNode[]): readonly Inli
2341
2517
  */
2342
2518
  export declare function trimSource(source: MarkdownSource): MarkdownSource;
2343
2519
 
2520
+ /**
2521
+ * Trims trailing whitespace when an inline run ends with a text node.
2522
+ *
2523
+ * @param nodes - The inline run to trim
2524
+ * @returns The run with its trailing text trimmed or removed when empty
2525
+ *
2526
+ * @example
2527
+ * ```ts
2528
+ * trimTrailing([{ element: 'text', value: ' a ' }]) // [{ element: 'text', value: ' a' }]
2529
+ * ```
2530
+ */
2531
+ export declare function trimTrailing(nodes: readonly InlineNode[]): readonly InlineNode[];
2532
+
2344
2533
  /**
2345
2534
  * Resolves backslash escapes in a raw string to their literal characters — used for a
2346
2535
  * link `href` (which is not otherwise inline-parsed) and any plain text run.
@@ -2355,6 +2544,26 @@ export declare function trimSource(source: MarkdownSource): MarkdownSource;
2355
2544
  */
2356
2545
  export declare function unescapeText(text: string): string;
2357
2546
 
2547
+ /**
2548
+ * Yields UTF-16 offsets and characters within a markdown scan window.
2549
+ *
2550
+ * @example
2551
+ * ```ts
2552
+ * Array.from(walkMarkdownCharacters('ab', 0, 2)) // [[0, 'a'], [1, 'b']]
2553
+ * ```
2554
+ */
2555
+ export declare function walkMarkdownCharacters(source: string, from: number, to: number): Generator<readonly [number, string], void, unknown>;
2556
+
2557
+ /**
2558
+ * Yields line offsets through a closable markdown scan iterator.
2559
+ *
2560
+ * @example
2561
+ * ```ts
2562
+ * Array.from(walkMarkdownLines(splitLines('a\nb'), 1)) // [1]
2563
+ * ```
2564
+ */
2565
+ export declare function walkMarkdownLines(lines: readonly MarkdownSource[], start: number): Generator<number, void, unknown>;
2566
+
2358
2567
  /**
2359
2568
  * Walks a {@link MarkdownNode} depth-first, pre-order, root-inclusive — yields
2360
2569
  * the node itself, then recurses into its children (block children, list items,