@tabnas/markdown 0.4.2 → 0.5.1
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 +131 -10
- package/dist/ast.d.ts +113 -0
- package/dist/ast.js +273 -0
- package/dist/ast.js.map +1 -0
- package/dist/block.d.ts +10 -0
- package/dist/block.js +1411 -0
- package/dist/block.js.map +1 -0
- package/dist/common.d.ts +49 -0
- package/dist/common.js +155 -0
- package/dist/common.js.map +1 -0
- package/dist/commonmark.d.ts +14 -0
- package/dist/commonmark.js +31 -0
- package/dist/commonmark.js.map +1 -0
- package/dist/entities.d.ts +1 -0
- package/dist/entities.js +14 -0
- package/dist/entities.js.map +1 -0
- package/dist/html.d.ts +16 -0
- package/dist/html.js +393 -0
- package/dist/html.js.map +1 -0
- package/dist/inline.d.ts +19 -0
- package/dist/inline.js +1331 -0
- package/dist/inline.js.map +1 -0
- package/dist/markdown.d.ts +21 -84
- package/dist/markdown.js +80 -687
- package/dist/markdown.js.map +1 -1
- package/dist/node.d.ts +112 -0
- package/dist/node.js +203 -0
- package/dist/node.js.map +1 -0
- package/dist/options.d.ts +26 -0
- package/dist/options.js +16 -0
- package/dist/options.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/src/ast.ts +406 -0
- package/src/block.ts +1579 -0
- package/src/common.ts +166 -0
- package/src/commonmark.ts +34 -0
- package/src/entities.ts +14 -0
- package/src/html.ts +446 -0
- package/src/inline.ts +1495 -0
- package/src/markdown.ts +132 -770
- package/src/node.ts +293 -0
- package/src/options.ts +44 -0
- package/src/tsconfig.json +2 -0
package/README.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# @tabnas/markdown (TypeScript)
|
|
2
2
|
|
|
3
|
-
A [Tabnas](https://github.com/tabnas/parser)
|
|
3
|
+
A CommonMark parser for the [Tabnas](https://github.com/tabnas/parser) engine.
|
|
4
|
+
|
|
5
|
+
**This parser is conformant to CommonMark 0.31.2** — all 652 examples, across all 26
|
|
6
|
+
sections of the spec suite, in both runtimes. The suite is vendored in this repository, so
|
|
7
|
+
the claim is checkable: `npm run conformance` reports 652/652, with no build step and no
|
|
8
|
+
engine installed. It runs with the GFM extensions off, which is what measuring CommonMark
|
|
9
|
+
conformance means — with `gfm: true` the extensions deliberately change nine of those
|
|
10
|
+
examples. It also implements **all five GFM extensions** — tables, task list
|
|
11
|
+
items, autolink literals, strikethrough and disallowed raw HTML — 24/24 on the vendored
|
|
12
|
+
GFM corpus, via `npm run conformance-gfm`.
|
|
13
|
+
|
|
14
|
+
This is the canonical implementation; [`go/`](../go/README.md) is a port of it.
|
|
4
15
|
|
|
5
16
|
[](https://npmjs.com/package/@tabnas/markdown)
|
|
6
17
|
[](https://github.com/tabnas/markdown/actions/workflows/build.yml)
|
|
@@ -8,6 +19,78 @@ A [Tabnas](https://github.com/tabnas/parser) grammar plugin that parses **Common
|
|
|
8
19
|
|  | This open source module is sponsored and supported by [Voxgig](https://www.voxgig.com). |
|
|
9
20
|
| ---------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
10
21
|
|
|
22
|
+
## Two outputs
|
|
23
|
+
|
|
24
|
+
**The AST is the primary output.** `parseDocument()` returns it directly; the renderer
|
|
25
|
+
does not run.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { parseDocument } from '@tabnas/markdown'
|
|
29
|
+
|
|
30
|
+
const doc = parseDocument('# Hello\n\nHello *world*')
|
|
31
|
+
|
|
32
|
+
doc.children[0] // => { type: 'heading', depth: 1, children: [ { type: 'text', value: 'Hello' } ] }
|
|
33
|
+
doc.children[1] // => { type: 'paragraph', children: [ { type: 'text', value: 'Hello ' }, { type: 'emphasis', children: [ { type: 'text', value: 'world' } ] } ] }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**HTML is available, on request, via `toHtml()`.** The CommonMark suite scores HTML
|
|
37
|
+
output, so the renderer is what makes the 652/652 claim measurable; that it is useful to
|
|
38
|
+
callers is a consequence.
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import { toHtml } from '@tabnas/markdown'
|
|
42
|
+
|
|
43
|
+
toHtml('# Hello\n\nHello *world*') // => '<h1>Hello</h1>\n<p>Hello <em>world</em></p>\n'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**The HTML is not sanitized.** Raw HTML blocks and inline tags pass through verbatim, as
|
|
47
|
+
CommonMark specifies. Put a sanitizer downstream of any untrusted Markdown.
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
import { toHtml } from '@tabnas/markdown'
|
|
51
|
+
|
|
52
|
+
toHtml('<img onerror="alert(1)">') // => '<img onerror="alert(1)">\n'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
GFM's disallowed-raw-HTML filter (on with `gfm`, the default) rewrites the leading `<` of
|
|
56
|
+
nine tag names — `title`, `textarea`, `style`, `xmp`, `iframe`, `noembed`, `noframes`,
|
|
57
|
+
`script`, `plaintext` — and touches nothing else:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import { toHtml } from '@tabnas/markdown'
|
|
61
|
+
|
|
62
|
+
toHtml('<script>alert(1)</script>') // => '<script>alert(1)</script>\n'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
As a Tabnas plugin, `parse()` returns the same AST as `parseDocument()`:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
import { Tabnas } from '@tabnas/parser'
|
|
69
|
+
import { Markdown } from '@tabnas/markdown'
|
|
70
|
+
|
|
71
|
+
const tn = new Tabnas().use(Markdown)
|
|
72
|
+
|
|
73
|
+
tn.parse('# Hello') // => { type: 'document', children: [ { type: 'heading', depth: 1, children: [ { type: 'text', value: 'Hello' } ] } ] }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`parseTree()` returns the native CommonMark node tree instead — it keeps `sourcepos` on
|
|
77
|
+
block nodes, and can be walked or mutated and then rendered. See the
|
|
78
|
+
[reference](doc/reference.md).
|
|
79
|
+
|
|
80
|
+
GFM tables add three node types, in mdast's shape — `table`, `tableRow` and `tableCell`.
|
|
81
|
+
`align` has one entry per column, `null` where the delimiter cell had no colon; there is
|
|
82
|
+
no header flag, so the first row is the header row by convention, and every row has
|
|
83
|
+
exactly as many cells as `align` has entries.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
import { parseDocument } from '@tabnas/markdown'
|
|
87
|
+
|
|
88
|
+
const doc = parseDocument('| a | b |\n| :- | -: |\n| 1 | 2 |')
|
|
89
|
+
|
|
90
|
+
doc.children[0].align // => [ 'left', 'right' ]
|
|
91
|
+
doc.children[0].children[0].children[0] // => { type: 'tableCell', children: [ { type: 'text', value: 'a' } ] }
|
|
92
|
+
```
|
|
93
|
+
|
|
11
94
|
## Install
|
|
12
95
|
|
|
13
96
|
```bash
|
|
@@ -16,21 +99,59 @@ npm install @tabnas/markdown @tabnas/parser
|
|
|
16
99
|
|
|
17
100
|
`@tabnas/parser` (>=0) is the only peer dependency. Requires Node >=24.
|
|
18
101
|
|
|
19
|
-
##
|
|
102
|
+
## Specific to this runtime
|
|
103
|
+
|
|
104
|
+
The parser is **engine-free**: nothing under `src/commonmark.ts` imports `@tabnas/parser`.
|
|
105
|
+
Only `src/markdown.ts`, the plugin wiring, does. That is what lets the conformance runner
|
|
106
|
+
work with no build step and no engine installed — it stages `src/*.ts` in a temp directory
|
|
107
|
+
whose `package.json` says `"type": "module"` and runs them under Node's type stripping:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm run conformance # 652/652, all 26 sections
|
|
111
|
+
npm run conformance -- --failures
|
|
112
|
+
npm run conformance-gfm # 24/24, all five extensions
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The `// =>` assertions in this repo's Markdown are executed as tests
|
|
116
|
+
(`test/doc-examples.test.ts`, and `tools/check-doc-examples.mjs` for the engine-free
|
|
117
|
+
check), so a wrong expected value is a failing test.
|
|
118
|
+
|
|
119
|
+
Options are `gfm` (default `true`) and `breaks` (default `false`). `gfm` gates five
|
|
120
|
+
extensions together — tables, strikethrough, task list items, autolink literals (bare
|
|
121
|
+
`www.` / `https://` / `a@b.co`) and the disallowed-raw-HTML filter. Footnotes are not
|
|
122
|
+
implemented. With `gfm:false` the output is plain CommonMark.
|
|
123
|
+
|
|
124
|
+
Footnotes are a GitHub product feature rather than part of the GFM spec suite, and their
|
|
125
|
+
absence is quiet: `[^1]` is a valid CommonMark link label, so a footnote authored on
|
|
126
|
+
GitHub renders as a broken link instead of raising an error.
|
|
20
127
|
|
|
21
128
|
```js
|
|
22
|
-
import {
|
|
23
|
-
import { Markdown } from '@tabnas/markdown'
|
|
129
|
+
import { toHtml } from '@tabnas/markdown'
|
|
24
130
|
|
|
25
|
-
|
|
131
|
+
toHtml('Text[^1]\n\n[^1]: note') // => '<p>Text<a href="note">^1</a></p>\n'
|
|
132
|
+
```
|
|
26
133
|
|
|
27
|
-
|
|
28
|
-
|
|
134
|
+
Nothing outside CommonMark and GFM is implemented — no math, front matter, definition
|
|
135
|
+
lists, heading attributes, admonitions, wiki links, emoji shortcodes, highlight or
|
|
136
|
+
sub/superscript. Each would need its own opt-in flag; `gfm` is not going to grow to mean
|
|
137
|
+
"everything". Note one collision: GFM's single-tilde strikethrough takes the syntax other
|
|
138
|
+
dialects use for subscript, so `H~2~O` is a deletion under the default `gfm:true`.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
import { toHtml } from '@tabnas/markdown'
|
|
142
|
+
|
|
143
|
+
toHtml('H~2~O') // => '<p>H<del>2</del>O</p>\n'
|
|
29
144
|
```
|
|
30
145
|
|
|
31
146
|
## Documentation
|
|
32
147
|
|
|
33
|
-
- [Tutorial](doc/tutorial.md) — first parse
|
|
148
|
+
- [Tutorial](doc/tutorial.md) — first parse, start to finish.
|
|
34
149
|
- [How-to guide](doc/guide.md) — task recipes.
|
|
35
|
-
- [Reference](doc/reference.md) — API
|
|
36
|
-
- [Concepts](doc/concepts.md) — how it works.
|
|
150
|
+
- [Reference](doc/reference.md) — API, options, AST node types.
|
|
151
|
+
- [Concepts](doc/concepts.md) — how it works, and why.
|
|
152
|
+
|
|
153
|
+
Top-level [README](../README.md) · Go port: [go/README.md](../go/README.md).
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT. Copyright (c) Richard Rodger and other contributors.
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { MdNode } from './node.ts';
|
|
2
|
+
import type { TableAlign } from './node.ts';
|
|
3
|
+
import type { ParserOptions } from './options.ts';
|
|
4
|
+
export type DocumentNode = {
|
|
5
|
+
type: 'document';
|
|
6
|
+
children: Block[];
|
|
7
|
+
};
|
|
8
|
+
export type Block = HeadingNode | ParagraphNode | BlockquoteNode | ListNode | ListItemNode | CodeNode | HtmlNode | ThematicBreakNode | TableNode;
|
|
9
|
+
export type HeadingNode = {
|
|
10
|
+
type: 'heading';
|
|
11
|
+
depth: 1 | 2 | 3 | 4 | 5 | 6;
|
|
12
|
+
children: Inline[];
|
|
13
|
+
};
|
|
14
|
+
export type ParagraphNode = {
|
|
15
|
+
type: 'paragraph';
|
|
16
|
+
children: Inline[];
|
|
17
|
+
};
|
|
18
|
+
export type BlockquoteNode = {
|
|
19
|
+
type: 'blockquote';
|
|
20
|
+
children: Block[];
|
|
21
|
+
};
|
|
22
|
+
export type ListNode = {
|
|
23
|
+
type: 'list';
|
|
24
|
+
ordered: boolean;
|
|
25
|
+
start: number | null;
|
|
26
|
+
spread: boolean;
|
|
27
|
+
children: ListItemNode[];
|
|
28
|
+
};
|
|
29
|
+
export type ListItemNode = {
|
|
30
|
+
type: 'listItem';
|
|
31
|
+
spread: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* mdast's task list field: `true`/`false` for a GFM task list item
|
|
34
|
+
* (`- [x] foo`), `null` for an ordinary item — and therefore `null`
|
|
35
|
+
* everywhere when `gfm` is off.
|
|
36
|
+
*/
|
|
37
|
+
checked: boolean | null;
|
|
38
|
+
children: Block[];
|
|
39
|
+
};
|
|
40
|
+
export type CodeNode = {
|
|
41
|
+
type: 'code';
|
|
42
|
+
lang: string | null;
|
|
43
|
+
meta: string | null;
|
|
44
|
+
value: string;
|
|
45
|
+
};
|
|
46
|
+
export type HtmlNode = {
|
|
47
|
+
type: 'html';
|
|
48
|
+
value: string;
|
|
49
|
+
};
|
|
50
|
+
export type ThematicBreakNode = {
|
|
51
|
+
type: 'thematicBreak';
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* A GFM table, in mdast's shape.
|
|
55
|
+
*
|
|
56
|
+
* `align` has one entry per column — `null` where the delimiter row gave no
|
|
57
|
+
* colon — and every row has exactly that many cells, since the block phase
|
|
58
|
+
* pads short rows and truncates long ones.
|
|
59
|
+
*
|
|
60
|
+
* mdast has no header flag: the **first** row is the header row, by
|
|
61
|
+
* convention, and this projection preserves that ordering from the tree.
|
|
62
|
+
*/
|
|
63
|
+
export type TableNode = {
|
|
64
|
+
type: 'table';
|
|
65
|
+
align: TableAlign[];
|
|
66
|
+
children: TableRowNode[];
|
|
67
|
+
};
|
|
68
|
+
export type TableRowNode = {
|
|
69
|
+
type: 'tableRow';
|
|
70
|
+
children: TableCellNode[];
|
|
71
|
+
};
|
|
72
|
+
export type TableCellNode = {
|
|
73
|
+
type: 'tableCell';
|
|
74
|
+
children: Inline[];
|
|
75
|
+
};
|
|
76
|
+
export type Inline = TextNode | EmphasisNode | StrongNode | InlineCodeNode | LinkNode | ImageNode | BreakNode | DeleteNode | HtmlNode;
|
|
77
|
+
export type TextNode = {
|
|
78
|
+
type: 'text';
|
|
79
|
+
value: string;
|
|
80
|
+
};
|
|
81
|
+
export type EmphasisNode = {
|
|
82
|
+
type: 'emphasis';
|
|
83
|
+
children: Inline[];
|
|
84
|
+
};
|
|
85
|
+
export type StrongNode = {
|
|
86
|
+
type: 'strong';
|
|
87
|
+
children: Inline[];
|
|
88
|
+
};
|
|
89
|
+
export type InlineCodeNode = {
|
|
90
|
+
type: 'inlineCode';
|
|
91
|
+
value: string;
|
|
92
|
+
};
|
|
93
|
+
export type LinkNode = {
|
|
94
|
+
type: 'link';
|
|
95
|
+
url: string;
|
|
96
|
+
title: string | null;
|
|
97
|
+
children: Inline[];
|
|
98
|
+
};
|
|
99
|
+
export type ImageNode = {
|
|
100
|
+
type: 'image';
|
|
101
|
+
url: string;
|
|
102
|
+
title: string | null;
|
|
103
|
+
alt: string;
|
|
104
|
+
};
|
|
105
|
+
export type BreakNode = {
|
|
106
|
+
type: 'break';
|
|
107
|
+
};
|
|
108
|
+
export type DeleteNode = {
|
|
109
|
+
type: 'delete';
|
|
110
|
+
children: Inline[];
|
|
111
|
+
};
|
|
112
|
+
/** Project a parsed native tree into the public JSON AST. */
|
|
113
|
+
export declare function toAst(doc: MdNode, opts: ParserOptions): DocumentNode;
|
package/dist/ast.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2021-2026 Richard Rodger, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.toAst = toAst;
|
|
5
|
+
/** Plain-text flattening of an image's inline children, for `alt`. */
|
|
6
|
+
function collectAltText(node) {
|
|
7
|
+
let out = '';
|
|
8
|
+
let child = node.firstChild;
|
|
9
|
+
while (child) {
|
|
10
|
+
if ('text' === child.type || 'code' === child.type || 'html_inline' === child.type) {
|
|
11
|
+
out += child.literal ?? '';
|
|
12
|
+
}
|
|
13
|
+
else if ('softbreak' === child.type || 'linebreak' === child.type) {
|
|
14
|
+
out += '\n';
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
out += collectAltText(child);
|
|
18
|
+
}
|
|
19
|
+
child = child.next;
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* mdast semantics: an item is spread when two of its children are separated by
|
|
25
|
+
* a *blank line* — not merely when it has more than one child. `- a\n - b`
|
|
26
|
+
* holds a paragraph and a nested list with no blank line between them, and is
|
|
27
|
+
* not spread; `- a\n\n - b` is.
|
|
28
|
+
*
|
|
29
|
+
* Derived from the block parser's `sourcepos` rather than tracked separately:
|
|
30
|
+
* consecutive children whose line ranges are not adjacent must have had a
|
|
31
|
+
* blank line between them.
|
|
32
|
+
*/
|
|
33
|
+
function itemIsSpread(item) {
|
|
34
|
+
let child = item.firstChild;
|
|
35
|
+
while (child && child.next) {
|
|
36
|
+
const endLine = child.sourcepos[1][0];
|
|
37
|
+
const nextStartLine = child.next.sourcepos[0][0];
|
|
38
|
+
if (nextStartLine > endLine + 1)
|
|
39
|
+
return true;
|
|
40
|
+
child = child.next;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function inlineChildren(node, opts) {
|
|
45
|
+
const out = [];
|
|
46
|
+
const pushText = (value) => {
|
|
47
|
+
if ('' === value)
|
|
48
|
+
return;
|
|
49
|
+
const last = out[out.length - 1];
|
|
50
|
+
if (last && 'text' === last.type)
|
|
51
|
+
last.value += value;
|
|
52
|
+
else
|
|
53
|
+
out.push({ type: 'text', value });
|
|
54
|
+
};
|
|
55
|
+
let child = node.firstChild;
|
|
56
|
+
while (child) {
|
|
57
|
+
switch (child.type) {
|
|
58
|
+
case 'text':
|
|
59
|
+
pushText(child.literal ?? '');
|
|
60
|
+
break;
|
|
61
|
+
case 'softbreak':
|
|
62
|
+
// Documented behaviour: a soft break reads as a space in the AST.
|
|
63
|
+
if (opts.breaks)
|
|
64
|
+
out.push({ type: 'break' });
|
|
65
|
+
else
|
|
66
|
+
pushText(' ');
|
|
67
|
+
break;
|
|
68
|
+
case 'linebreak':
|
|
69
|
+
out.push({ type: 'break' });
|
|
70
|
+
break;
|
|
71
|
+
case 'code':
|
|
72
|
+
out.push({ type: 'inlineCode', value: child.literal ?? '' });
|
|
73
|
+
break;
|
|
74
|
+
case 'html_inline':
|
|
75
|
+
out.push({ type: 'html', value: child.literal ?? '' });
|
|
76
|
+
break;
|
|
77
|
+
case 'emph':
|
|
78
|
+
out.push({ type: 'emphasis', children: inlineChildren(child, opts) });
|
|
79
|
+
break;
|
|
80
|
+
case 'strong':
|
|
81
|
+
out.push({ type: 'strong', children: inlineChildren(child, opts) });
|
|
82
|
+
break;
|
|
83
|
+
case 'del':
|
|
84
|
+
out.push({ type: 'delete', children: inlineChildren(child, opts) });
|
|
85
|
+
break;
|
|
86
|
+
case 'link':
|
|
87
|
+
out.push({
|
|
88
|
+
type: 'link',
|
|
89
|
+
url: child.destination ?? '',
|
|
90
|
+
title: child.title ?? null,
|
|
91
|
+
children: inlineChildren(child, opts),
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
case 'image':
|
|
95
|
+
out.push({
|
|
96
|
+
type: 'image',
|
|
97
|
+
url: child.destination ?? '',
|
|
98
|
+
title: child.title ?? null,
|
|
99
|
+
alt: collectAltText(child),
|
|
100
|
+
});
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
// A block node cannot appear here in a well-formed tree; skipping is
|
|
104
|
+
// safer than emitting a node the published types do not allow.
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
child = child.next;
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** Containers whose children are blocks rather than inlines. */
|
|
112
|
+
const BLOCK_CONTAINERS = {
|
|
113
|
+
document: true,
|
|
114
|
+
block_quote: true,
|
|
115
|
+
list: true,
|
|
116
|
+
item: true,
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Project a container's block children.
|
|
120
|
+
*
|
|
121
|
+
* Iterative rather than recursive, because the recursion depth here is the
|
|
122
|
+
* document's container nesting depth, which untrusted input controls directly:
|
|
123
|
+
* `'> '.repeat(4000)` is 8 KB of Markdown that the block parser and the HTML
|
|
124
|
+
* renderer both handle, but that overflowed the stack in this projection —
|
|
125
|
+
* crashing the package's primary API on input the rest of the pipeline
|
|
126
|
+
* survives.
|
|
127
|
+
*
|
|
128
|
+
* Two passes. The first walks the block tree with an explicit stack, recording
|
|
129
|
+
* nodes in an order where every parent precedes its descendants. Building in
|
|
130
|
+
* reverse then guarantees a node's children are already built when it is
|
|
131
|
+
* reached, so `buildBlock` can look them up instead of recursing.
|
|
132
|
+
*
|
|
133
|
+
* The Go port keeps the recursive form: goroutine stacks grow on demand and it
|
|
134
|
+
* projects 100k-deep nesting without trouble, so the same defect does not
|
|
135
|
+
* arise there.
|
|
136
|
+
*/
|
|
137
|
+
function blockChildren(node, opts) {
|
|
138
|
+
const order = [];
|
|
139
|
+
const stack = [];
|
|
140
|
+
for (let c = node.lastChild; c; c = c.prev)
|
|
141
|
+
stack.push(c);
|
|
142
|
+
while (0 < stack.length) {
|
|
143
|
+
const n = stack.pop();
|
|
144
|
+
order.push(n);
|
|
145
|
+
if (true === BLOCK_CONTAINERS[n.type]) {
|
|
146
|
+
for (let c = n.lastChild; c; c = c.prev)
|
|
147
|
+
stack.push(c);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const built = new Map();
|
|
151
|
+
for (let i = order.length - 1; 0 <= i; i--) {
|
|
152
|
+
const n = order[i];
|
|
153
|
+
const block = buildBlock(n, opts, built);
|
|
154
|
+
if (null !== block)
|
|
155
|
+
built.set(n, block);
|
|
156
|
+
}
|
|
157
|
+
const out = [];
|
|
158
|
+
for (let c = node.firstChild; c; c = c.next) {
|
|
159
|
+
const b = built.get(c);
|
|
160
|
+
if (undefined !== b)
|
|
161
|
+
out.push(b);
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
/** Children of `n` that have already been built, in source order. */
|
|
166
|
+
function builtChildren(n, built) {
|
|
167
|
+
const out = [];
|
|
168
|
+
for (let c = n.firstChild; c; c = c.next) {
|
|
169
|
+
const b = built.get(c);
|
|
170
|
+
if (undefined !== b)
|
|
171
|
+
out.push(b);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
function buildBlock(node, opts, built) {
|
|
176
|
+
switch (node.type) {
|
|
177
|
+
case 'paragraph':
|
|
178
|
+
return { type: 'paragraph', children: inlineChildren(node, opts) };
|
|
179
|
+
case 'heading':
|
|
180
|
+
return {
|
|
181
|
+
type: 'heading',
|
|
182
|
+
depth: node.level,
|
|
183
|
+
children: inlineChildren(node, opts),
|
|
184
|
+
};
|
|
185
|
+
case 'thematic_break':
|
|
186
|
+
return { type: 'thematicBreak' };
|
|
187
|
+
case 'block_quote':
|
|
188
|
+
return { type: 'blockquote', children: builtChildren(node, built) };
|
|
189
|
+
case 'code_block': {
|
|
190
|
+
const info = (node.info ?? '').trim();
|
|
191
|
+
let lang = null;
|
|
192
|
+
let meta = null;
|
|
193
|
+
if ('' !== info) {
|
|
194
|
+
const sp = info.search(/\s/);
|
|
195
|
+
if (-1 === sp) {
|
|
196
|
+
lang = info;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
lang = info.slice(0, sp);
|
|
200
|
+
meta = info.slice(sp + 1).trim() || null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// The native tree keeps the trailing newline because the spec's HTML
|
|
204
|
+
// for `<pre><code>` includes it; mdast's `code.value` does not. Strip
|
|
205
|
+
// exactly one, not all, so a block that genuinely ends in a blank line
|
|
206
|
+
// keeps it.
|
|
207
|
+
const raw = node.literal ?? '';
|
|
208
|
+
const value = raw.endsWith('\n') ? raw.slice(0, -1) : raw;
|
|
209
|
+
return { type: 'code', lang, meta, value };
|
|
210
|
+
}
|
|
211
|
+
case 'html_block':
|
|
212
|
+
return { type: 'html', value: node.literal ?? '' };
|
|
213
|
+
case 'table': {
|
|
214
|
+
// Built here rather than through `built`, because a table's children are
|
|
215
|
+
// rows and cells rather than blocks — `blockChildren` never descends
|
|
216
|
+
// into one. The nesting is a fixed three levels deep, so unlike the
|
|
217
|
+
// block containers this cannot be driven past the stack by input.
|
|
218
|
+
const rows = [];
|
|
219
|
+
for (let row = node.firstChild; row; row = row.next) {
|
|
220
|
+
if ('table_row' !== row.type)
|
|
221
|
+
continue;
|
|
222
|
+
const cells = [];
|
|
223
|
+
for (let cell = row.firstChild; cell; cell = cell.next) {
|
|
224
|
+
if ('table_cell' !== cell.type)
|
|
225
|
+
continue;
|
|
226
|
+
cells.push({ type: 'tableCell', children: inlineChildren(cell, opts) });
|
|
227
|
+
}
|
|
228
|
+
rows.push({ type: 'tableRow', children: cells });
|
|
229
|
+
}
|
|
230
|
+
return { type: 'table', align: node.tableAlign ?? [], children: rows };
|
|
231
|
+
}
|
|
232
|
+
case 'list': {
|
|
233
|
+
const data = node.listData;
|
|
234
|
+
const ordered = 'ordered' === data?.type;
|
|
235
|
+
const items = [];
|
|
236
|
+
let child = node.firstChild;
|
|
237
|
+
while (child) {
|
|
238
|
+
if ('item' === child.type) {
|
|
239
|
+
items.push({
|
|
240
|
+
type: 'listItem',
|
|
241
|
+
spread: itemIsSpread(child),
|
|
242
|
+
checked: child.checked,
|
|
243
|
+
children: builtChildren(child, built),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
child = child.next;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
type: 'list',
|
|
250
|
+
ordered,
|
|
251
|
+
start: ordered ? (data?.start ?? 1) : null,
|
|
252
|
+
spread: !(data?.tight ?? true),
|
|
253
|
+
children: items,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
case 'item':
|
|
257
|
+
// Only reachable if an item is somehow detached from its list; a list
|
|
258
|
+
// builds its own items above.
|
|
259
|
+
return {
|
|
260
|
+
type: 'listItem',
|
|
261
|
+
spread: itemIsSpread(node),
|
|
262
|
+
checked: node.checked,
|
|
263
|
+
children: builtChildren(node, built),
|
|
264
|
+
};
|
|
265
|
+
default:
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/** Project a parsed native tree into the public JSON AST. */
|
|
270
|
+
function toAst(doc, opts) {
|
|
271
|
+
return { type: 'document', children: blockChildren(doc, opts) };
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=ast.js.map
|
package/dist/ast.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"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"}
|
package/dist/block.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MdNode } from './node.ts';
|
|
2
|
+
import type { ParserOptions, RefMap } from './options.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Phase 1: build the block tree and collect link reference definitions.
|
|
5
|
+
* Paragraph and heading text is left raw in `stringContent` for phase 2.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseBlocks(input: string, options: ParserOptions): {
|
|
8
|
+
doc: MdNode;
|
|
9
|
+
refmap: RefMap;
|
|
10
|
+
};
|