@brett_lamy/docstream 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,13 +3,14 @@
3
3
 
4
4
  export type HintStyle = "info" | "success" | "warning" | "danger"
5
5
 
6
- export interface TextNode {
7
- type: "text"
8
- text: string
6
+ /**
7
+ * Formatting every inline carries — text runs, chips and inline images alike, so emphasis and links can span
8
+ * them (`**ask @brett**`, `*see ![i](s)*`, `[![badge](b.svg)](url)`) — plus how the source spelled it.
9
+ */
10
+ export interface InlineMarks {
9
11
  bold?: boolean
10
12
  italic?: boolean
11
13
  strike?: boolean
12
- code?: boolean
13
14
  link?: string
14
15
  /**
15
16
  * The link sits inside the emphasis (`**[x](url)**`) rather than around it
@@ -17,31 +18,92 @@ export interface TextNode {
17
18
  */
18
19
  linkInner?: true
19
20
  /**
20
- * How the source spelled this run's formatting, outermost → innermost, when that differs from the default
21
+ * How the source spelled this inline's formatting, outermost → innermost, when that differs from the default
21
22
  * output (`_italic_`, `**bold**`, `~~strike~~`, link around its emphasis, bare autolinks). Each entry is an
22
- * emphasis marker, or a link form: `"link"` (`[x](url)`), `"<>"` (`<url>`), `"url"` (bare autolink).
23
- * E.g. `**_x_**` → `["**", "_"]`, `***x***` → `["*", "**"]`, `*x*` → `["*"]`.
23
+ * emphasis marker, or a link form (see {@link LinkForm}). E.g. `**_x_**` → `["**", "_"]`, `***x***` →
24
+ * `["*", "**"]`, `*x*` → `["*"]`, `*a *b* c*` → `["*", "*"]` for `b`.
24
25
  *
25
26
  * A hint only — the boolean marks and `link` stay authoritative: entries for marks the run no longer has are
26
27
  * ignored, marks it has without an entry get the default spelling and position. Absent on runs that
27
28
  * serialize the default way and on programmatically created nodes.
28
29
  */
29
30
  delims?: InlineDelimiter[]
31
+ /** The link's title as written between the quotes: `[x](url "title")`. */
32
+ linkTitle?: string
33
+ /**
34
+ * The reference label of a reference-style link, as written: `ref` for `[text][ref]`, and the link text
35
+ * for the collapsed `[text][]` and shortcut `[text]` forms.
36
+ */
37
+ linkRef?: string
38
+ /** The opening tag of an inline HTML link as written (`<a href="…" target="_blank">`). */
39
+ linkTag?: string
40
+ /** The closing tag of an inline HTML link, when not `</a>` (`</A>`). */
41
+ linkTagEnd?: string
42
+ /**
43
+ * Link identity: set on the runs of a link that directly follows another link to the same target
44
+ * (`[a](u)[b](u)`), so the two stay distinct instead of merging into one. Runs of one link share it.
45
+ */
46
+ linkId?: number
47
+ }
48
+
49
+ export interface TextNode extends InlineMarks {
50
+ type: "text"
51
+ text: string
52
+ code?: boolean
53
+ /**
54
+ * The source wrote every character of this run backslash-escaped (`snake\_case` → `snake`, `_` escaped,
55
+ * `case`). Only ASCII punctuation can be escaped. Kept so author escapes survive even where they aren't
56
+ * needed; the text itself is the literal characters.
57
+ */
58
+ escaped?: true
59
+ /**
60
+ * Code span in a GFM table cell: offsets (in `text`) of the `|` characters the source wrote bare instead
61
+ * of as `\|`. Serialization escapes every other pipe.
62
+ */
63
+ barePipes?: number[]
64
+ /** A code span's backtick count as written, when longer than serialization needs (```` ```x``` ````). */
65
+ ticks?: number
30
66
  }
31
67
 
32
68
  /** An emphasis marker as written in the source. */
33
69
  export type EmphasisDelimiter = "**" | "__" | "*" | "_" | "~~"
34
- /** An entry of {@link TextNode.delims}: an emphasis marker or a link form. */
35
- export type InlineDelimiter = EmphasisDelimiter | "link" | "<>" | "url"
70
+ /**
71
+ * How a link is written: `"link"` `[x](url)`, `"<>"` `<url>`, `"url"` a bare autolink, `"ref"` `[x][label]`,
72
+ * `"collapsed"` `[x][]`, `"shortcut"` `[x]` (the last three resolved through a `[label]: url` definition),
73
+ * `"html"` `<a href="url">x</a>`.
74
+ */
75
+ export type LinkForm = "link" | "<>" | "url" | "ref" | "collapsed" | "shortcut" | "html"
76
+ /** An entry of {@link InlineMarks.delims}: an emphasis marker or a link form. */
77
+ export type InlineDelimiter = EmphasisDelimiter | LinkForm
36
78
 
37
- /** Inline HTML image, optionally wrapped in a link — GitHub README badge style. */
38
- export interface InlineImageNode {
79
+ /**
80
+ * Inline image: `![alt](src "title")` (`syntax: "markdown"`), or HTML `<img …>` / `<a href><img …></a>`
81
+ * (GitHub README badge style, the default).
82
+ *
83
+ * `link` without a link form in `delims` is the HTML `<a href>` around the `<img>`; with one
84
+ * (`[![a](s)](url)`) it is an ordinary link mark that may span neighbouring text.
85
+ */
86
+ export interface InlineImageNode extends InlineMarks {
39
87
  type: "image"
40
88
  src: string
41
89
  alt?: string
42
90
  width?: string
43
91
  height?: string
44
- link?: string
92
+ /** `![alt](src "title")`'s title, as written between the quotes. */
93
+ title?: string
94
+ /** Written as Markdown `![alt](src)`. Absent: HTML `<img>`. */
95
+ syntax?: "markdown"
96
+ /**
97
+ * A Markdown image whose source comes from a definition: `![alt][label]` (`"ref"`), `![alt][]`
98
+ * (`"collapsed"`) or `![alt]` (`"shortcut"`), with `srcRef` the label as written.
99
+ */
100
+ srcForm?: "ref" | "collapsed" | "shortcut"
101
+ srcRef?: string
102
+ /**
103
+ * The HTML as written (`<img …>`, or `<a href><img …></a>` for a linked image). Serialization reuses it
104
+ * while it still says the same src / alt / width / height / link; otherwise it writes fresh HTML.
105
+ */
106
+ html?: string
45
107
  }
46
108
 
47
109
  export type ReferenceKind = "mention" | "tag" | "codebase" | "citation"
@@ -50,8 +112,10 @@ export type ReferenceKind = "mention" | "tag" | "codebase" | "citation"
50
112
  * Inline reference chip: `@mention`, `#tag`, or footnote-style citation `[^id]`.
51
113
  * `id` carries no sigil. Citations resolve `url`/`label` from their
52
114
  * `[^id]: url "Label"` definition at parse time when one exists.
115
+ *
116
+ * The inherited `link` is a link *around* the chip (`[@brett](url)`); `url` is the citation's target.
53
117
  */
54
- export interface ReferenceNode {
118
+ export interface ReferenceNode extends InlineMarks {
55
119
  type: "reference"
56
120
  kind: ReferenceKind
57
121
  id: string
@@ -68,18 +132,55 @@ export interface CitationDef {
68
132
 
69
133
  export type Inline = TextNode | InlineImageNode | ReferenceNode
70
134
 
71
- export interface ParagraphNode {
135
+ /**
136
+ * Layout the source used around a block, recorded only where it differs from the serializer's default so
137
+ * pages round-trip byte-for-byte.
138
+ */
139
+ export interface BlockSpacing {
140
+ /**
141
+ * Blank lines before this block (or tab / step / column / update / list item): by default 1 between
142
+ * siblings and 0 before the first child of a container (1 after an expandable's `<summary>`).
143
+ */
144
+ gap?: number
145
+ /** Those blank lines as written, when some hold whitespace. */
146
+ blanks?: string[]
147
+ }
148
+
149
+ /** A `{% tag %}` container's opening and closing lines as written, reused while they still say the same. */
150
+ export interface TagLines {
151
+ /** The opening tag line, when not the one serialization writes (quote style, spacing, extra attributes). */
152
+ opening?: string
153
+ /** The closing tag line, when not the canonical `{% endtag %}` ("" when the input ended first). */
154
+ closing?: string
155
+ }
156
+
157
+ /** A block's source lines as written, where they aren't what serialization writes; reused while they still parse to the same block. */
158
+ export interface RawSource {
159
+ raw?: string
160
+ }
161
+
162
+ /** Spacing inside a container, before its closing line. */
163
+ export interface ContainerSpacing extends BlockSpacing {
164
+ /** Blank lines between the last child and the closing tag (default 0; 1 in an expandable). */
165
+ gapEnd?: number
166
+ }
167
+
168
+ export interface ParagraphNode extends BlockSpacing {
72
169
  type: "paragraph"
73
170
  children: Inline[]
171
+ /** Whitespace before the paragraph's first line, as written (continuation lines keep theirs in the text). */
172
+ indent?: string
74
173
  }
75
174
 
76
- export interface HeadingNode {
175
+ export interface HeadingNode extends BlockSpacing {
77
176
  type: "heading"
78
177
  level: 1 | 2 | 3 | 4 | 5 | 6
79
178
  children: Inline[]
179
+ /** A setext heading's underline as written (`===`, `---`); absent for `#` headings. */
180
+ setext?: string
80
181
  }
81
182
 
82
- export interface CodeBlockNode {
183
+ export interface CodeBlockNode extends BlockSpacing {
83
184
  type: "code"
84
185
  language: string | null
85
186
  title: string | null
@@ -102,21 +203,31 @@ export interface CodeBlockNode {
102
203
  collapsedCodeLines?: number
103
204
  /** Maximum source lines visible before expanded code scrolls. */
104
205
  expandedCodeLines?: number
105
- }
106
-
107
- export interface HintNode {
206
+ /** The opening fence as written when not ```` ``` ```` (`~~~`, ````` ```` `````). */
207
+ fence?: string
208
+ /** The info string as written after the fence, when it isn't the one serialization writes. */
209
+ info?: string
210
+ /** The closing fence line as written, when it isn't the opening fence ("" when the input ended first). */
211
+ closingFence?: string
212
+ /** An indented (four-space) code block rather than a fence. */
213
+ indented?: true
214
+ /** The block as written when it isn't a plain fence (a `{% code %}` wrapper), reused while it still says the same. */
215
+ raw?: string
216
+ }
217
+
218
+ export interface HintNode extends ContainerSpacing, TagLines {
108
219
  type: "hint"
109
220
  style: HintStyle
110
221
  children: Block[]
111
222
  }
112
223
 
113
- export interface TabNode {
224
+ export interface TabNode extends ContainerSpacing, TagLines {
114
225
  type: "tab"
115
226
  title: string
116
227
  children: Block[]
117
228
  }
118
229
 
119
- export interface TabsNode {
230
+ export interface TabsNode extends ContainerSpacing, TagLines {
120
231
  type: "tabs"
121
232
  tabs: TabNode[]
122
233
  /**
@@ -143,7 +254,7 @@ export type PackageManager = "npm" | "pnpm" | "yarn" | "bun"
143
254
  * manager (`pnpm="…"`). The reader's manager is synced page-wide (and across
144
255
  * pages) under `sync` — `"pm"` by default, the same key install `{% tabs %}` use.
145
256
  */
146
- export interface CommandNode {
257
+ export interface CommandNode extends BlockSpacing, RawSource {
147
258
  type: "command"
148
259
  /** The npm / npx command (may span lines). */
149
260
  command: string
@@ -153,24 +264,36 @@ export interface CommandNode {
153
264
  sync?: string
154
265
  }
155
266
 
156
- export interface ExpandableNode {
267
+ export interface ExpandableNode extends ContainerSpacing {
268
+ /** The closing line, when not `</details>`. */
269
+ closing?: string
157
270
  type: "expandable"
158
271
  summary: string
159
272
  children: Block[]
273
+ /**
274
+ * The lines from `<details>` through `</summary>` as written, when not `<details>`, a blank line,
275
+ * `<summary>…</summary>`. Reused while they still say the same summary.
276
+ */
277
+ opening?: string
160
278
  }
161
279
 
162
- export interface StepNode {
280
+ export interface StepNode extends ContainerSpacing, TagLines {
163
281
  type: "step"
164
282
  title: string
165
283
  children: Block[]
284
+ /**
285
+ * The title heading as written (and any blank lines before it), when not `### title` — `## Title`,
286
+ * `### **Bold** title`. Reused while it still gives the same title.
287
+ */
288
+ heading?: string
166
289
  }
167
290
 
168
- export interface StepperNode {
291
+ export interface StepperNode extends ContainerSpacing, TagLines {
169
292
  type: "stepper"
170
293
  steps: StepNode[]
171
294
  }
172
295
 
173
- export interface EmbedNode {
296
+ export interface EmbedNode extends BlockSpacing {
174
297
  type: "embed"
175
298
  url: string
176
299
  title?: string
@@ -179,12 +302,16 @@ export interface EmbedNode {
179
302
  muted?: boolean
180
303
  controls?: boolean
181
304
  poster?: string
305
+ /** The tag as written (with its `{% endembed %}`), reused while it still says the same. */
306
+ raw?: string
182
307
  }
183
308
 
184
- export interface ContentRefNode {
309
+ export interface ContentRefNode extends BlockSpacing {
185
310
  type: "content-ref"
186
311
  url: string
187
312
  children: Inline[]
313
+ /** The block as written when it isn't the canonical `{% content-ref %}` (a `{% file %}` tag), reused while it still says the same. */
314
+ raw?: string
188
315
  }
189
316
 
190
317
  export type SourceReferenceKind = "component" | "story"
@@ -193,7 +320,7 @@ export type SourceReferenceKind = "component" | "story"
193
320
  * A reference to an export in a real source file. The source file remains the
194
321
  * authority; Markdown only stores the composition and presentation metadata.
195
322
  */
196
- export interface SourceRefNode {
323
+ export interface SourceRefNode extends BlockSpacing {
197
324
  type: "source-ref"
198
325
  /** Name of the directory mounted by the Docstream Vite plugin. */
199
326
  mount: string
@@ -203,6 +330,8 @@ export interface SourceRefNode {
203
330
  exportName: string
204
331
  kind: SourceReferenceKind
205
332
  title?: string
333
+ /** The tag as written (`{% component … %}`, an end tag), reused while it still says the same. */
334
+ raw?: string
206
335
  }
207
336
 
208
337
  export type DemoLayout = "auto" | "single" | "multi"
@@ -238,7 +367,7 @@ export interface DemoInlineFile {
238
367
  * ```
239
368
  * {% enddemo %}
240
369
  */
241
- export interface DemoNode {
370
+ export interface DemoNode extends BlockSpacing, RawSource {
242
371
  type: "demo"
243
372
  /** `<page>/<example>` folder id understood by the host's resolver. */
244
373
  src: string
@@ -276,66 +405,103 @@ export interface DemoNode {
276
405
  open?: true
277
406
  }
278
407
 
279
- export interface ColumnNode {
408
+ export interface ColumnNode extends ContainerSpacing, TagLines {
280
409
  type: "column"
281
410
  children: Block[]
282
411
  }
283
412
 
284
- export interface ColumnsNode {
413
+ export interface ColumnsNode extends ContainerSpacing, TagLines {
285
414
  type: "columns"
286
415
  columns: ColumnNode[]
287
416
  }
288
417
 
289
- export interface FigureNode {
418
+ export interface FigureNode extends BlockSpacing {
290
419
  type: "figure"
291
420
  src: string
292
421
  alt: string
293
422
  caption: string
423
+ /** `![alt](src "title")`'s title. */
424
+ title?: string
425
+ /**
426
+ * The line(s) as written (`![alt](src)`, `<img …>`, `<figure>…</figure>`). Serialization reuses them while
427
+ * they still parse to the same src / alt / caption / title; otherwise it writes a `<figure>`.
428
+ */
429
+ raw?: string
294
430
  }
295
431
 
296
- export interface ListItemNode {
432
+ export interface ListItemNode extends ContainerSpacing {
297
433
  type: "listItem"
298
434
  children: Block[]
299
435
  checked?: boolean // present only in task lists
436
+ /** The item's marker as written (`*`, `3.`), when it isn't the one its list's pattern gives it. */
437
+ marker?: string
438
+ /** Spaces between the marker and the content (default 1). */
439
+ pad?: number
440
+ /** Indent of the item's continuation lines, relative to its marker (default 2). */
441
+ indent?: number
442
+ /** A checked task written `[X]`. */
443
+ checkMark?: "X"
300
444
  }
301
445
 
302
- export interface ListNode {
446
+ export interface ListNode extends BlockSpacing {
303
447
  type: "list"
304
448
  ordered: boolean
305
449
  task: boolean
306
450
  items: ListItemNode[]
451
+ /** Bullet marker of an unordered list (default `-`). */
452
+ bullet?: "*" | "+"
453
+ /** Number of an ordered list's first item (default 1). */
454
+ start?: number
455
+ /** Ordered-list delimiter (default `.`). */
456
+ delimiter?: ")"
457
+ /** Whitespace before the list's markers, as written. */
458
+ indent?: string
307
459
  }
308
460
 
309
- export interface BlockquoteNode {
461
+ export interface BlockquoteNode extends ContainerSpacing {
310
462
  type: "blockquote"
311
463
  children: Block[]
464
+ /** Each line's `>` prefix as written (indent, spacing), when not `> ` (`>` on empty lines). */
465
+ markers?: string[]
312
466
  }
313
467
 
314
- export interface DividerNode {
468
+ export interface DividerNode extends BlockSpacing {
315
469
  type: "divider"
470
+ /** The rule as written when not `---` (`***`, `___`, `-----`). */
471
+ marker?: string
316
472
  }
317
473
 
318
- export interface TableNode {
474
+ export interface TableNode extends BlockSpacing {
319
475
  type: "table"
320
476
  header: Inline[][]
321
477
  rows: Inline[][][]
322
478
  /** GitBook table view, e.g. "cards" for <table data-view="cards"> */
323
479
  view?: string
324
- }
325
-
326
- export interface UpdateNode {
480
+ /** Written as an HTML `<table>` (without a view). */
481
+ html?: true
482
+ /** Column alignment from the delimiter row (`:---`, `:---:`, `---:`); null = default. */
483
+ align?: Array<"left" | "center" | "right" | null>
484
+ /** The delimiter row as written (`|:--|--:|`), reused while it still says the same `align`. */
485
+ delimiterRow?: string
486
+ /** An HTML table as written, reused while it still parses to the same cells. */
487
+ raw?: string
488
+ /** GFM rows as written (header first), each reused while it still parses to the same cells. */
489
+ rawRows?: string[]
490
+ }
491
+
492
+ export interface UpdateNode extends ContainerSpacing, TagLines {
327
493
  type: "update"
328
494
  date: string
329
495
  children: Block[]
330
496
  }
331
497
 
332
- export interface UpdatesNode {
498
+ export interface UpdatesNode extends ContainerSpacing, TagLines {
333
499
  type: "updates"
334
500
  format: string | null
335
501
  updates: UpdateNode[]
336
502
  }
337
503
 
338
- export interface OpenApiOperationNode {
504
+ export interface OpenApiOperationNode extends BlockSpacing, RawSource {
339
505
  type: "openapi-operation"
340
506
  spec: string
341
507
  path: string
@@ -344,7 +510,30 @@ export interface OpenApiOperationNode {
344
510
  label: string
345
511
  }
346
512
 
347
- export interface MathNode {
513
+ /**
514
+ * A reference-style link definition, `[label]: url "title"`, where the source put it. Links written
515
+ * `[text][label]`, `[text][]` or `[label]` resolve through it.
516
+ */
517
+ export interface DefinitionNode extends BlockSpacing {
518
+ type: "definition"
519
+ /** The label as written (matched case-insensitively). */
520
+ label: string
521
+ url: string
522
+ title?: string
523
+ /** The line as written, reused while it still says the same label / url / title. */
524
+ raw?: string
525
+ }
526
+
527
+ /**
528
+ * A line docstream keeps verbatim but doesn't model — an unknown `{% tag %}` (GitBook tags from other
529
+ * integrations). Renders nothing; serialized as written.
530
+ */
531
+ export interface RawNode extends BlockSpacing {
532
+ type: "raw"
533
+ markdown: string
534
+ }
535
+
536
+ export interface MathNode extends BlockSpacing, RawSource {
348
537
  type: "math"
349
538
  formula: string
350
539
  }
@@ -371,12 +560,20 @@ export type Block =
371
560
  | MathNode
372
561
  | UpdatesNode
373
562
  | OpenApiOperationNode
563
+ | DefinitionNode
564
+ | RawNode
374
565
 
375
566
  export interface DocumentNode {
376
567
  type: "doc"
377
568
  children: Block[]
378
569
  /** Footnote citation definitions, in definition order. */
379
570
  citations?: CitationDef[]
571
+ /** Blank lines before the trailing footnote definitions (default 1). */
572
+ citationsGap?: number
573
+ /** Line ending of the source when it used `\r\n` throughout. */
574
+ lineEnding?: "\r\n"
575
+ /** What the source ended with after its last line, when more than a single newline (`"\n\n"`). */
576
+ end?: string
380
577
  }
381
578
 
382
579
  export const text = (t: string, marks: Partial<Omit<TextNode, "type" | "text">> = {}): TextNode => ({