@tanstack/markdown 0.0.5 → 0.0.7
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 +32 -16
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +24 -7
- package/dist/inline.js +82 -33
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +66 -21
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +27 -16
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -12
package/README.md
CHANGED
|
@@ -1,36 +1,52 @@
|
|
|
1
1
|
# TanStack Markdown
|
|
2
2
|
|
|
3
|
-
A tiny deterministic
|
|
3
|
+
A tiny, fast, deterministic Markdown renderer for blogs and documentation.
|
|
4
|
+
|
|
5
|
+
The current browser bundles are 4.6 KB gzip for the parser, 6.4 KB for HTML rendering, and 6.3 KB for the React adapter. The package has no runtime dependencies and does not bundle syntax highlighting.
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
8
|
pnpm add @tanstack/markdown
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
```ts
|
|
12
|
+
import { renderHtml } from '@tanstack/markdown/html'
|
|
13
|
+
|
|
14
|
+
const html = renderHtml('# Fast by default')
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Markdown } from '@tanstack/markdown/react'
|
|
19
|
+
|
|
20
|
+
export function Article({ source }: { source: string }) {
|
|
21
|
+
return <Markdown>{source}</Markdown>
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Raw HTML is escaped and executable link protocols are removed by default. `allowHtml` and highlighter output are explicit trusted-content boundaries.
|
|
26
|
+
|
|
27
|
+
## Scope
|
|
28
|
+
|
|
29
|
+
This is deliberately not a complete CommonMark, GFM, MDX, or content-processing implementation. It implements the syntax used by technical blogs and documentation, then spends its complexity budget on deterministic output, safe defaults, React/HTML parity, malformed-input resilience, and small entry points.
|
|
30
|
+
|
|
31
|
+
See the [docs Markdown profile](./docs/profile.md) for the supported contract and deliberate non-goals.
|
|
32
|
+
|
|
33
|
+
## Verification
|
|
10
34
|
|
|
11
35
|
```bash
|
|
12
|
-
pnpm
|
|
13
|
-
pnpm run typecheck
|
|
14
|
-
pnpm run build
|
|
15
|
-
pnpm run research
|
|
36
|
+
pnpm run verify
|
|
16
37
|
```
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
To include downstream repositories in the corpus gate:
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- `src/extensions/*`: optional docs-site extension functions
|
|
24
|
-
- `scripts/measure-size.ts`: bundle size matrix
|
|
25
|
-
- `scripts/bench.ts`: CPU benchmark matrix
|
|
41
|
+
```bash
|
|
42
|
+
MARKDOWN_CORPUS_DIRS=../tanstack.com/src/blog:../tanstack.com/docs pnpm run test:corpus
|
|
43
|
+
```
|
|
26
44
|
|
|
27
45
|
## Reports
|
|
28
46
|
|
|
29
47
|
- [Bundle sizes](./reports/sizes.md)
|
|
30
48
|
- [Benchmarks](./reports/benchmarks.md)
|
|
49
|
+
- [CommonMark compatibility accounting](./reports/conformance.md)
|
|
31
50
|
- [Audit](./docs/audit.md)
|
|
32
51
|
- [Spec and API](./docs/spec.md)
|
|
33
|
-
- [Goal and coverage map](./docs/goal.md)
|
|
34
|
-
- [Bundle strategy](./docs/bundle-strategy.md)
|
|
35
52
|
- [Extensions](./docs/extensions.md)
|
|
36
|
-
- [Recommendation](./docs/recommendation.md)
|
package/dist/html.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAyD,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAG7K,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAGpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAyD,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAG7K,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAGpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA0ChF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA0BlF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE9F"}
|
package/dist/html.js
CHANGED
|
@@ -28,9 +28,11 @@ export function renderBlock(node, options = {}) {
|
|
|
28
28
|
return `<blockquote>\n${node.children.map(child => renderBlock(child, options)).join('\n')}\n</blockquote>`;
|
|
29
29
|
case 'table': {
|
|
30
30
|
const header = `<thead><tr>${node.header.map((cell, index) => renderTableCell('th', cell, node.align[index], options)).join('')}</tr></thead>`;
|
|
31
|
-
const body =
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const body = node.rows.length
|
|
32
|
+
? `<tbody>${node.rows
|
|
33
|
+
.map(row => `<tr>${row.map((cell, index) => renderTableCell('td', cell, node.align[index], options)).join('')}</tr>`)
|
|
34
|
+
.join('')}</tbody>`
|
|
35
|
+
: '';
|
|
34
36
|
return `<table>${header}${body}</table>`;
|
|
35
37
|
}
|
|
36
38
|
case 'footnotes':
|
|
@@ -61,7 +63,7 @@ export function renderInline(node, options = {}) {
|
|
|
61
63
|
case 'strike':
|
|
62
64
|
return `<del>${renderInlines(node.children, options)}</del>`;
|
|
63
65
|
case 'footnoteReference':
|
|
64
|
-
return `<sup><a id="user-content-fnref-${escapeAttr(node
|
|
66
|
+
return `<sup><a id="user-content-fnref-${escapeAttr(footnoteReferenceId(node))}" data-footnote-ref="" aria-describedby="footnote-label" href="#user-content-fn-${escapeAttr(node.id)}">${node.number}</a></sup>`;
|
|
65
67
|
case 'link':
|
|
66
68
|
return `<a href="${escapeAttr(node.href)}"${node.title ? ` title="${escapeAttr(node.title)}"` : ''}>${renderInlines(node.children, options)}</a>`;
|
|
67
69
|
case 'image':
|
|
@@ -101,8 +103,11 @@ function renderCodeBlock(node, options) {
|
|
|
101
103
|
function renderListItemChildren(children, checked, loose, options) {
|
|
102
104
|
const first = children[0];
|
|
103
105
|
const task = checked === undefined ? '' : `<input type="checkbox" disabled${checked ? ' checked' : ''}> `;
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
+
if (first?.type === 'paragraph') {
|
|
107
|
+
const content = `${task}${renderInlines(first.children, options)}`;
|
|
108
|
+
const rest = children.length > 1 ? `\n${children.slice(1).map(child => renderBlock(child, options)).join('\n')}` : '';
|
|
109
|
+
return `${loose ? `<p>${content}</p>` : content}${rest}`;
|
|
110
|
+
}
|
|
106
111
|
return `${task}${children.map(child => renderBlock(child, options)).join('\n')}`;
|
|
107
112
|
}
|
|
108
113
|
function renderCallout(node, options) {
|
|
@@ -115,7 +120,7 @@ function renderFootnotes(items, options) {
|
|
|
115
120
|
return `<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes${renderHeadingAnchor('footnote-label', options)}</h2>\n<ol>\n${renderedItems}\n</ol>\n</section>`;
|
|
116
121
|
}
|
|
117
122
|
function renderFootnoteItem(item, options) {
|
|
118
|
-
const backref =
|
|
123
|
+
const backref = renderFootnoteBackrefs(item);
|
|
119
124
|
const lastIndex = item.children.length - 1;
|
|
120
125
|
if (lastIndex < 0)
|
|
121
126
|
return `<p>${backref.trimStart()}</p>`;
|
|
@@ -128,6 +133,18 @@ function renderFootnoteItem(item, options) {
|
|
|
128
133
|
})
|
|
129
134
|
.join('\n');
|
|
130
135
|
}
|
|
136
|
+
function renderFootnoteBackrefs(item) {
|
|
137
|
+
let result = '';
|
|
138
|
+
for (let index = 1; index <= (item.referenceCount ?? 1); index++) {
|
|
139
|
+
const referenceId = index === 1 ? item.id : `${item.id}-${index}`;
|
|
140
|
+
const label = index === 1 ? `${item.number}` : `${item.number}-${index}`;
|
|
141
|
+
result += ` <a data-footnote-backref="" aria-label="Back to reference ${label}" class="data-footnote-backref" href="#user-content-fnref-${escapeAttr(referenceId)}">↩</a>`;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
function footnoteReferenceId(node) {
|
|
146
|
+
return node.referenceIndex && node.referenceIndex > 1 ? `${node.id}-${node.referenceIndex}` : node.id;
|
|
147
|
+
}
|
|
131
148
|
function renderComponent(node, options) {
|
|
132
149
|
const tag = node.tagName ?? 'md-comment-component';
|
|
133
150
|
const attrs = renderComponentAttrs(node);
|
package/dist/inline.js
CHANGED
|
@@ -7,7 +7,12 @@ export function parseInline(value, options = {}) {
|
|
|
7
7
|
}
|
|
8
8
|
return result;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
const maxInlineDepth = 32;
|
|
11
|
+
const scansPerCharacter = 16;
|
|
12
|
+
function parseInlineRaw(value, options, budget = { scans: Math.max(value.length * scansPerCharacter, 1024), depth: 0 }) {
|
|
13
|
+
if (budget.depth >= maxInlineDepth)
|
|
14
|
+
return value ? [{ type: 'text', value }] : [];
|
|
15
|
+
budget.depth++;
|
|
11
16
|
const nodes = [];
|
|
12
17
|
let index = 0;
|
|
13
18
|
let text = '';
|
|
@@ -35,7 +40,7 @@ function parseInlineRaw(value, options) {
|
|
|
35
40
|
}
|
|
36
41
|
if (char === '`') {
|
|
37
42
|
const tickCount = countRun(value, index, '`');
|
|
38
|
-
const close = findClosingRun(value, index + tickCount, '`', tickCount);
|
|
43
|
+
const close = findClosingRun(value, index + tickCount, '`', tickCount, budget);
|
|
39
44
|
if (close !== -1) {
|
|
40
45
|
pushText();
|
|
41
46
|
nodes.push({
|
|
@@ -45,15 +50,18 @@ function parseInlineRaw(value, options) {
|
|
|
45
50
|
index = close + tickCount;
|
|
46
51
|
continue;
|
|
47
52
|
}
|
|
53
|
+
text += value.slice(index, index + tickCount);
|
|
54
|
+
index += tickCount;
|
|
55
|
+
continue;
|
|
48
56
|
}
|
|
49
57
|
if (char === '!' && next === '[') {
|
|
50
|
-
const parsed = parseLinkish(value, index + 1, options);
|
|
58
|
+
const parsed = parseLinkish(value, index + 1, options, budget);
|
|
51
59
|
if (parsed) {
|
|
52
60
|
pushText();
|
|
53
61
|
nodes.push({
|
|
54
62
|
type: 'image',
|
|
55
63
|
src: sanitizeUrl(parsed.href),
|
|
56
|
-
alt: textFromMarkdown(parsed.label),
|
|
64
|
+
alt: textFromMarkdown(parsed.label, budget),
|
|
57
65
|
...(parsed.title ? { title: parsed.title } : {}),
|
|
58
66
|
});
|
|
59
67
|
index = parsed.end;
|
|
@@ -61,14 +69,14 @@ function parseInlineRaw(value, options) {
|
|
|
61
69
|
}
|
|
62
70
|
}
|
|
63
71
|
if (char === '[') {
|
|
64
|
-
const footnote = parseFootnoteReference(value, index, options);
|
|
72
|
+
const footnote = parseFootnoteReference(value, index, options, budget);
|
|
65
73
|
if (footnote) {
|
|
66
74
|
pushText();
|
|
67
75
|
nodes.push(footnote.node);
|
|
68
76
|
index = footnote.end;
|
|
69
77
|
continue;
|
|
70
78
|
}
|
|
71
|
-
const parsed = parseLinkish(value, index, options);
|
|
79
|
+
const parsed = parseLinkish(value, index, options, budget);
|
|
72
80
|
if (parsed) {
|
|
73
81
|
const href = sanitizeUrl(parsed.href);
|
|
74
82
|
pushText();
|
|
@@ -77,23 +85,23 @@ function parseInlineRaw(value, options) {
|
|
|
77
85
|
type: 'link',
|
|
78
86
|
href,
|
|
79
87
|
...(parsed.title ? { title: parsed.title } : {}),
|
|
80
|
-
children: parseInlineRaw(parsed.label, options),
|
|
88
|
+
children: parseInlineRaw(parsed.label, options, budget),
|
|
81
89
|
});
|
|
82
90
|
}
|
|
83
91
|
else {
|
|
84
|
-
nodes.push(...parseInlineRaw(parsed.label, options));
|
|
92
|
+
nodes.push(...parseInlineRaw(parsed.label, options, budget));
|
|
85
93
|
}
|
|
86
94
|
index = parsed.end;
|
|
87
95
|
continue;
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
98
|
if ((char === '*' && next === '*') || (char === '_' && next === '_')) {
|
|
91
|
-
const close = findDelimiter(value, index + 2, char + char);
|
|
99
|
+
const close = findDelimiter(value, index + 2, char + char, budget);
|
|
92
100
|
if (close !== -1) {
|
|
93
101
|
pushText();
|
|
94
102
|
nodes.push({
|
|
95
103
|
type: 'strong',
|
|
96
|
-
children: parseInlineRaw(value.slice(index + 2, close), options),
|
|
104
|
+
children: parseInlineRaw(value.slice(index + 2, close), options, budget),
|
|
97
105
|
});
|
|
98
106
|
index = close + 2;
|
|
99
107
|
continue;
|
|
@@ -102,13 +110,19 @@ function parseInlineRaw(value, options) {
|
|
|
102
110
|
index += 2;
|
|
103
111
|
continue;
|
|
104
112
|
}
|
|
113
|
+
if (char === '~' && next === '~' && value[index + 2] === '~') {
|
|
114
|
+
const run = countRun(value, index, '~');
|
|
115
|
+
text += value.slice(index, index + run);
|
|
116
|
+
index += run;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
105
119
|
if (char === '~' && next === '~') {
|
|
106
|
-
const close = findDelimiter(value, index + 2, '~~');
|
|
120
|
+
const close = findDelimiter(value, index + 2, '~~', budget);
|
|
107
121
|
if (close !== -1) {
|
|
108
122
|
pushText();
|
|
109
123
|
nodes.push({
|
|
110
124
|
type: 'strike',
|
|
111
|
-
children: parseInlineRaw(value.slice(index + 2, close), options),
|
|
125
|
+
children: parseInlineRaw(value.slice(index + 2, close), options, budget),
|
|
112
126
|
});
|
|
113
127
|
index = close + 2;
|
|
114
128
|
continue;
|
|
@@ -118,31 +132,31 @@ function parseInlineRaw(value, options) {
|
|
|
118
132
|
continue;
|
|
119
133
|
}
|
|
120
134
|
if (char === '~') {
|
|
121
|
-
const close = findSingleTildeDelimiter(value, index + 1);
|
|
135
|
+
const close = findSingleTildeDelimiter(value, index + 1, budget);
|
|
122
136
|
if (close !== -1) {
|
|
123
137
|
pushText();
|
|
124
138
|
nodes.push({
|
|
125
139
|
type: 'strike',
|
|
126
|
-
children: parseInlineRaw(value.slice(index + 1, close), options),
|
|
140
|
+
children: parseInlineRaw(value.slice(index + 1, close), options, budget),
|
|
127
141
|
});
|
|
128
142
|
index = close + 1;
|
|
129
143
|
continue;
|
|
130
144
|
}
|
|
131
145
|
}
|
|
132
146
|
if (char === '*' || char === '_') {
|
|
133
|
-
const close = findDelimiter(value, index + 1, char);
|
|
147
|
+
const close = findDelimiter(value, index + 1, char, budget);
|
|
134
148
|
if (close !== -1 && !isIntrawordUnderscore(value, index, close, char)) {
|
|
135
149
|
pushText();
|
|
136
150
|
nodes.push({
|
|
137
151
|
type: 'emphasis',
|
|
138
|
-
children: parseInlineRaw(value.slice(index + 1, close), options),
|
|
152
|
+
children: parseInlineRaw(value.slice(index + 1, close), options, budget),
|
|
139
153
|
});
|
|
140
154
|
index = close + 1;
|
|
141
155
|
continue;
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
if (char === '<' && options.allowHtml) {
|
|
145
|
-
const close = value
|
|
159
|
+
const close = findCharacter(value, index + 1, '>', budget);
|
|
146
160
|
if (close !== -1) {
|
|
147
161
|
pushText();
|
|
148
162
|
nodes.push({ type: 'inlineHtml', value: value.slice(index, close + 1) });
|
|
@@ -154,12 +168,13 @@ function parseInlineRaw(value, options) {
|
|
|
154
168
|
index++;
|
|
155
169
|
}
|
|
156
170
|
pushText();
|
|
171
|
+
budget.depth--;
|
|
157
172
|
return nodes;
|
|
158
173
|
}
|
|
159
|
-
function parseFootnoteReference(value, open, options) {
|
|
174
|
+
function parseFootnoteReference(value, open, options, budget) {
|
|
160
175
|
if (value[open + 1] !== '^')
|
|
161
176
|
return undefined;
|
|
162
|
-
const close = value
|
|
177
|
+
const close = findCharacter(value, open + 2, ']', budget);
|
|
163
178
|
if (close === -1)
|
|
164
179
|
return undefined;
|
|
165
180
|
const label = value.slice(open + 2, close);
|
|
@@ -172,22 +187,26 @@ function parseFootnoteReference(value, open, options) {
|
|
|
172
187
|
options.footnoteOrder.push(key);
|
|
173
188
|
orderIndex = options.footnoteOrder.length - 1;
|
|
174
189
|
}
|
|
190
|
+
const referenceIndex = (options.footnoteCounts?.[key] ?? 0) + 1;
|
|
191
|
+
if (options.footnoteCounts)
|
|
192
|
+
options.footnoteCounts[key] = referenceIndex;
|
|
175
193
|
return {
|
|
176
194
|
node: {
|
|
177
195
|
type: 'footnoteReference',
|
|
178
|
-
id: footnoteId(definition.label),
|
|
196
|
+
id: definition.id ?? (footnoteId(definition.label) || 'footnote'),
|
|
179
197
|
number: orderIndex + 1,
|
|
198
|
+
...(referenceIndex > 1 ? { referenceIndex } : {}),
|
|
180
199
|
},
|
|
181
200
|
end: close + 1,
|
|
182
201
|
};
|
|
183
202
|
}
|
|
184
|
-
function parseLinkish(value, open, options) {
|
|
185
|
-
const closeBracket = findBalanced(value, open, '[', ']');
|
|
203
|
+
function parseLinkish(value, open, options, budget) {
|
|
204
|
+
const closeBracket = findBalanced(value, open, '[', ']', budget);
|
|
186
205
|
if (closeBracket === -1)
|
|
187
206
|
return undefined;
|
|
188
207
|
const label = value.slice(open + 1, closeBracket);
|
|
189
208
|
if (value[closeBracket + 1] === '(') {
|
|
190
|
-
const closeParen = findBalanced(value, closeBracket + 1, '(', ')');
|
|
209
|
+
const closeParen = findBalanced(value, closeBracket + 1, '(', ')', budget);
|
|
191
210
|
if (closeParen === -1)
|
|
192
211
|
return undefined;
|
|
193
212
|
const destination = value.slice(closeBracket + 2, closeParen).trim();
|
|
@@ -202,7 +221,7 @@ function parseLinkish(value, open, options) {
|
|
|
202
221
|
};
|
|
203
222
|
}
|
|
204
223
|
if (value[closeBracket + 1] === '[') {
|
|
205
|
-
const closeReference = findBalanced(value, closeBracket + 1, '[', ']');
|
|
224
|
+
const closeReference = findBalanced(value, closeBracket + 1, '[', ']', budget);
|
|
206
225
|
if (closeReference === -1)
|
|
207
226
|
return undefined;
|
|
208
227
|
const definition = options.references?.[normalizeReferenceLabel(value.slice(closeBracket + 2, closeReference))];
|
|
@@ -226,9 +245,11 @@ function parseDestination(value) {
|
|
|
226
245
|
...(match[2] ? { title: match[2] } : {}),
|
|
227
246
|
};
|
|
228
247
|
}
|
|
229
|
-
function findBalanced(value, openIndex, open, close) {
|
|
248
|
+
function findBalanced(value, openIndex, open, close, budget) {
|
|
230
249
|
let depth = 0;
|
|
231
250
|
for (let index = openIndex; index < value.length; index++) {
|
|
251
|
+
if (!takeScan(budget))
|
|
252
|
+
return -1;
|
|
232
253
|
if (value[index - 1] === '\\')
|
|
233
254
|
continue;
|
|
234
255
|
if (value[index] === open)
|
|
@@ -241,38 +262,51 @@ function findBalanced(value, openIndex, open, close) {
|
|
|
241
262
|
}
|
|
242
263
|
return -1;
|
|
243
264
|
}
|
|
244
|
-
function countRun(value, index, char) {
|
|
265
|
+
function countRun(value, index, char, budget) {
|
|
245
266
|
let count = 0;
|
|
246
|
-
while (value[index + count] === char)
|
|
267
|
+
while (value[index + count] === char) {
|
|
268
|
+
if (budget && !takeScan(budget))
|
|
269
|
+
break;
|
|
247
270
|
count++;
|
|
271
|
+
}
|
|
248
272
|
return count;
|
|
249
273
|
}
|
|
250
|
-
function findClosingRun(value, start, char, count) {
|
|
274
|
+
function findClosingRun(value, start, char, count, budget) {
|
|
251
275
|
for (let index = start; index < value.length; index++) {
|
|
276
|
+
if (!takeScan(budget))
|
|
277
|
+
return -1;
|
|
252
278
|
if (value[index] !== char)
|
|
253
279
|
continue;
|
|
254
|
-
if (countRun(value, index, char) >= count)
|
|
280
|
+
if (countRun(value, index, char, budget) >= count)
|
|
255
281
|
return index;
|
|
256
282
|
}
|
|
257
283
|
return -1;
|
|
258
284
|
}
|
|
259
|
-
function findDelimiter(value, start, delimiter) {
|
|
285
|
+
function findDelimiter(value, start, delimiter, budget) {
|
|
260
286
|
for (let index = start; index < value.length; index++) {
|
|
287
|
+
if (!takeScan(budget))
|
|
288
|
+
return -1;
|
|
261
289
|
if (value[index - 1] === '\\')
|
|
262
290
|
continue;
|
|
291
|
+
if (delimiter === '~~' && (value[index - 1] === '~' || value[index + 2] === '~'))
|
|
292
|
+
continue;
|
|
263
293
|
if (value.startsWith(delimiter, index))
|
|
264
294
|
return index;
|
|
265
295
|
}
|
|
266
296
|
return -1;
|
|
267
297
|
}
|
|
268
|
-
function findSingleTildeDelimiter(value, start) {
|
|
298
|
+
function findSingleTildeDelimiter(value, start, budget) {
|
|
269
299
|
if (isWhitespace(value[start] ?? ''))
|
|
270
300
|
return -1;
|
|
271
301
|
for (let index = start; index < value.length; index++) {
|
|
302
|
+
if (!takeScan(budget))
|
|
303
|
+
return -1;
|
|
272
304
|
if (value[index - 1] === '\\')
|
|
273
305
|
continue;
|
|
274
306
|
if (value[index] !== '~')
|
|
275
307
|
continue;
|
|
308
|
+
if (value[index - 1] === '~')
|
|
309
|
+
continue;
|
|
276
310
|
if (value[index + 1] === '~')
|
|
277
311
|
continue;
|
|
278
312
|
if (isWhitespace(value[index - 1] ?? ''))
|
|
@@ -281,6 +315,21 @@ function findSingleTildeDelimiter(value, start) {
|
|
|
281
315
|
}
|
|
282
316
|
return -1;
|
|
283
317
|
}
|
|
318
|
+
function findCharacter(value, start, character, budget) {
|
|
319
|
+
for (let index = start; index < value.length; index++) {
|
|
320
|
+
if (!takeScan(budget))
|
|
321
|
+
return -1;
|
|
322
|
+
if (value[index] === character)
|
|
323
|
+
return index;
|
|
324
|
+
}
|
|
325
|
+
return -1;
|
|
326
|
+
}
|
|
327
|
+
function takeScan(budget) {
|
|
328
|
+
if (budget.scans <= 0)
|
|
329
|
+
return false;
|
|
330
|
+
budget.scans--;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
284
333
|
function isIntrawordUnderscore(value, open, close, delimiter) {
|
|
285
334
|
if (delimiter !== '_')
|
|
286
335
|
return false;
|
|
@@ -289,8 +338,8 @@ function isIntrawordUnderscore(value, open, close, delimiter) {
|
|
|
289
338
|
function isWhitespace(value) {
|
|
290
339
|
return /\s/.test(value);
|
|
291
340
|
}
|
|
292
|
-
function textFromMarkdown(value) {
|
|
293
|
-
return parseInlineRaw(value, {}).map(node => (node.type === 'text' || node.type === 'inlineCode' ? node.value : '')).join('');
|
|
341
|
+
function textFromMarkdown(value, budget) {
|
|
342
|
+
return parseInlineRaw(value, {}, budget).map(node => (node.type === 'text' || node.type === 'inlineCode' ? node.value : '')).join('');
|
|
294
343
|
}
|
|
295
344
|
function mergeText(nodes) {
|
|
296
345
|
const result = [];
|
package/dist/parser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAQV,gBAAgB,EAChB,YAAY,EAGb,MAAM,YAAY,CAAA;AAWnB,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,gBAAgB,CAyC5F"}
|
package/dist/parser.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseInline } from './inline.js';
|
|
2
2
|
import { createSlugger, footnoteId, isBlank, normalizeInput, normalizeReferenceLabel, plainText, stripIndent } from './utils.js';
|
|
3
|
+
const maxBlockDepth = 64;
|
|
3
4
|
export function parseMarkdown(markdown, options = {}) {
|
|
4
5
|
const normalized = normalizeInput(markdown);
|
|
5
6
|
const frontmatterEnabled = options.frontmatter !== false;
|
|
@@ -15,13 +16,14 @@ export function parseMarkdown(markdown, options = {}) {
|
|
|
15
16
|
const definitions = extractDefinitions(lines);
|
|
16
17
|
lines = definitions.lines;
|
|
17
18
|
const footnoteOrder = [];
|
|
19
|
+
const footnoteCounts = Object.create(null);
|
|
18
20
|
const hasReferences = Object.keys(definitions.references).length > 0;
|
|
19
21
|
const hasFootnotes = Object.keys(definitions.footnotes).length > 0;
|
|
20
22
|
const parseOptions = hasReferences || hasFootnotes
|
|
21
23
|
? {
|
|
22
24
|
...options,
|
|
23
25
|
...(hasReferences ? { references: definitions.references } : {}),
|
|
24
|
-
...(hasFootnotes ? { footnotes: definitions.footnotes, footnoteOrder } : {}),
|
|
26
|
+
...(hasFootnotes ? { footnotes: definitions.footnotes, footnoteOrder, footnoteCounts } : {}),
|
|
25
27
|
}
|
|
26
28
|
: options;
|
|
27
29
|
const parser = new BlockParser(lines, parseOptions, createSlugger());
|
|
@@ -39,13 +41,21 @@ class BlockParser {
|
|
|
39
41
|
lines;
|
|
40
42
|
options;
|
|
41
43
|
slugger;
|
|
44
|
+
budget;
|
|
42
45
|
index = 0;
|
|
43
|
-
constructor(lines, options, slugger) {
|
|
46
|
+
constructor(lines, options, slugger, budget = { depth: 0 }) {
|
|
44
47
|
this.lines = lines;
|
|
45
48
|
this.options = options;
|
|
46
49
|
this.slugger = slugger;
|
|
50
|
+
this.budget = budget;
|
|
47
51
|
}
|
|
48
52
|
parse() {
|
|
53
|
+
if (this.budget.depth >= maxBlockDepth) {
|
|
54
|
+
const value = this.lines.slice(this.index).join('\n');
|
|
55
|
+
this.index = this.lines.length;
|
|
56
|
+
return value ? [{ type: 'paragraph', children: parseInline(value, this.options) }] : [];
|
|
57
|
+
}
|
|
58
|
+
this.budget.depth++;
|
|
49
59
|
const nodes = [];
|
|
50
60
|
while (this.index < this.lines.length) {
|
|
51
61
|
if (isBlank(this.current())) {
|
|
@@ -67,6 +77,7 @@ class BlockParser {
|
|
|
67
77
|
this.parseParagraph();
|
|
68
78
|
nodes.push(node);
|
|
69
79
|
}
|
|
80
|
+
this.budget.depth--;
|
|
70
81
|
return nodes;
|
|
71
82
|
}
|
|
72
83
|
parseExtensionBlock() {
|
|
@@ -77,7 +88,7 @@ class BlockParser {
|
|
|
77
88
|
index: this.index,
|
|
78
89
|
options: this.options,
|
|
79
90
|
parseInline: value => parseInline(value, this.options),
|
|
80
|
-
parseBlocks: value => new BlockParser(normalizeInput(value).split('\n'), this.options, this.slugger).parse(),
|
|
91
|
+
parseBlocks: value => new BlockParser(normalizeInput(value).split('\n'), this.options, this.slugger, this.budget).parse(),
|
|
81
92
|
consume: lines => {
|
|
82
93
|
consumed = lines;
|
|
83
94
|
},
|
|
@@ -150,7 +161,7 @@ class BlockParser {
|
|
|
150
161
|
}
|
|
151
162
|
return {
|
|
152
163
|
type: 'blockquote',
|
|
153
|
-
children: new BlockParser(quoted, this.options, this.slugger).parse(),
|
|
164
|
+
children: new BlockParser(quoted, this.options, this.slugger, this.budget).parse(),
|
|
154
165
|
};
|
|
155
166
|
}
|
|
156
167
|
parseList() {
|
|
@@ -164,7 +175,7 @@ class BlockParser {
|
|
|
164
175
|
let loose = false;
|
|
165
176
|
while (this.index < this.lines.length) {
|
|
166
177
|
const marker = listMarker(this.current());
|
|
167
|
-
if (!marker || marker
|
|
178
|
+
if (!marker || !sameListType(marker, first) || marker.indent !== baseIndent)
|
|
168
179
|
break;
|
|
169
180
|
let firstLine = marker.content;
|
|
170
181
|
const task = firstLine.match(/^\[([ xX])\]\s+(.*)$/);
|
|
@@ -176,18 +187,32 @@ class BlockParser {
|
|
|
176
187
|
while (this.index < this.lines.length) {
|
|
177
188
|
const line = this.current();
|
|
178
189
|
const nextMarker = listMarker(line);
|
|
179
|
-
if (nextMarker && nextMarker.indent === baseIndent
|
|
190
|
+
if (nextMarker && nextMarker.indent === baseIndent)
|
|
180
191
|
break;
|
|
181
192
|
if (isBlank(line)) {
|
|
182
|
-
|
|
193
|
+
let nextIndex = this.index;
|
|
194
|
+
while (nextIndex < this.lines.length && isBlank(this.lines[nextIndex]))
|
|
195
|
+
nextIndex++;
|
|
196
|
+
const following = this.lines[nextIndex];
|
|
197
|
+
if (following === undefined)
|
|
198
|
+
break;
|
|
199
|
+
const followingMarker = listMarker(following);
|
|
200
|
+
if (followingMarker?.indent === baseIndent) {
|
|
201
|
+
if (!sameListType(followingMarker, first))
|
|
202
|
+
break;
|
|
203
|
+
loose = true;
|
|
204
|
+
this.index = nextIndex;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
if (leadingSpaces(following) < marker.contentIndent)
|
|
183
208
|
break;
|
|
184
209
|
loose = true;
|
|
185
210
|
itemLines.push('');
|
|
186
|
-
this.index
|
|
211
|
+
this.index = nextIndex;
|
|
187
212
|
continue;
|
|
188
213
|
}
|
|
189
|
-
if (leadingSpaces(line)
|
|
190
|
-
itemLines.push(stripIndent(line,
|
|
214
|
+
if (leadingSpaces(line) >= marker.contentIndent) {
|
|
215
|
+
itemLines.push(stripIndent(line, marker.contentIndent));
|
|
191
216
|
this.index++;
|
|
192
217
|
continue;
|
|
193
218
|
}
|
|
@@ -196,7 +221,7 @@ class BlockParser {
|
|
|
196
221
|
itemLines.push(line.trimStart());
|
|
197
222
|
this.index++;
|
|
198
223
|
}
|
|
199
|
-
const children = new BlockParser(itemLines, this.options, this.slugger).parse();
|
|
224
|
+
const children = new BlockParser(itemLines, this.options, this.slugger, this.budget).parse();
|
|
200
225
|
const item = { type: 'listItem', children };
|
|
201
226
|
if (checked !== undefined)
|
|
202
227
|
item.checked = checked;
|
|
@@ -217,13 +242,15 @@ class BlockParser {
|
|
|
217
242
|
return undefined;
|
|
218
243
|
const headerCells = splitTableRow(header);
|
|
219
244
|
const align = splitTableRow(delimiter).map(parseAlign);
|
|
245
|
+
const columns = headerCells.length;
|
|
220
246
|
const rows = [];
|
|
221
247
|
this.index += 2;
|
|
222
248
|
while (this.index < this.lines.length) {
|
|
223
249
|
const line = this.current();
|
|
224
|
-
if (isBlank(line) ||
|
|
250
|
+
if (isBlank(line) || isBlockStart(line, this.next()))
|
|
225
251
|
break;
|
|
226
|
-
|
|
252
|
+
const values = splitTableRow(line);
|
|
253
|
+
rows.push(Array.from({ length: columns }, (_, index) => cell(values[index] ?? '', this.options)));
|
|
227
254
|
this.index++;
|
|
228
255
|
}
|
|
229
256
|
return {
|
|
@@ -295,8 +322,9 @@ function parseCodeInfo(info) {
|
|
|
295
322
|
};
|
|
296
323
|
}
|
|
297
324
|
function extractDefinitions(lines) {
|
|
298
|
-
const references =
|
|
299
|
-
const footnotes =
|
|
325
|
+
const references = Object.create(null);
|
|
326
|
+
const footnotes = Object.create(null);
|
|
327
|
+
const footnoteIds = new Map();
|
|
300
328
|
const remaining = [];
|
|
301
329
|
let fenceMarker;
|
|
302
330
|
let fenceSize = 0;
|
|
@@ -331,7 +359,13 @@ function extractDefinitions(lines) {
|
|
|
331
359
|
content.push(continuation.replace(/^(?: {4}|\t)/, ''));
|
|
332
360
|
index++;
|
|
333
361
|
}
|
|
334
|
-
|
|
362
|
+
const key = normalizeReferenceLabel(label);
|
|
363
|
+
if (!footnotes[key]) {
|
|
364
|
+
const baseId = footnoteId(label) || 'footnote';
|
|
365
|
+
const count = (footnoteIds.get(baseId) ?? 0) + 1;
|
|
366
|
+
footnoteIds.set(baseId, count);
|
|
367
|
+
footnotes[key] = { label, content: content.join('\n'), id: count === 1 ? baseId : `${baseId}-${count}` };
|
|
368
|
+
}
|
|
335
369
|
continue;
|
|
336
370
|
}
|
|
337
371
|
const definition = line.match(/^ {0,3}\[([^\]\n]+)\]:[ \t]*(\S+)[ \t]*$/);
|
|
@@ -349,15 +383,21 @@ function extractDefinitions(lines) {
|
|
|
349
383
|
function createFootnotesBlock(footnotes, footnoteOrder, options) {
|
|
350
384
|
const items = [];
|
|
351
385
|
for (let index = 0; index < footnoteOrder.length; index++) {
|
|
352
|
-
const
|
|
386
|
+
const key = footnoteOrder[index];
|
|
387
|
+
const definition = footnotes[key];
|
|
353
388
|
if (!definition)
|
|
354
389
|
continue;
|
|
355
390
|
items.push({
|
|
356
|
-
id: footnoteId(definition.label),
|
|
391
|
+
id: definition.id ?? (footnoteId(definition.label) || 'footnote'),
|
|
357
392
|
number: index + 1,
|
|
358
393
|
children: new BlockParser(normalizeInput(definition.content).split('\n'), options, createSlugger()).parse(),
|
|
359
394
|
});
|
|
360
395
|
}
|
|
396
|
+
for (const item of items) {
|
|
397
|
+
const count = options.footnoteCounts?.[footnoteOrder[item.number - 1]] ?? 1;
|
|
398
|
+
if (count > 1)
|
|
399
|
+
item.referenceCount = count;
|
|
400
|
+
}
|
|
361
401
|
return { type: 'footnotes', items };
|
|
362
402
|
}
|
|
363
403
|
function parseLineRanges(value) {
|
|
@@ -374,7 +414,7 @@ function parseLineRanges(value) {
|
|
|
374
414
|
return [...lines].sort((a, b) => a - b);
|
|
375
415
|
}
|
|
376
416
|
function listMarker(line) {
|
|
377
|
-
const match = line.match(/^(\s{0,8})([-+*]|\d{1,9}[.)])\
|
|
417
|
+
const match = line.match(/^(\s{0,8})([-+*]|\d{1,9}[.)])(?:([ \t]+)(.*))?$/);
|
|
378
418
|
if (!match)
|
|
379
419
|
return undefined;
|
|
380
420
|
const marker = match[2];
|
|
@@ -383,9 +423,14 @@ function listMarker(line) {
|
|
|
383
423
|
ordered,
|
|
384
424
|
...(ordered ? { number: Number.parseInt(marker, 10) } : {}),
|
|
385
425
|
indent: match[1].length,
|
|
386
|
-
|
|
426
|
+
marker: ordered ? marker.at(-1) : marker,
|
|
427
|
+
contentIndent: match[1].length + marker.length + (match[3]?.length ?? 1),
|
|
428
|
+
content: match[4] ?? '',
|
|
387
429
|
};
|
|
388
430
|
}
|
|
431
|
+
function sameListType(left, right) {
|
|
432
|
+
return left.ordered === right.ordered && left.marker === right.marker;
|
|
433
|
+
}
|
|
389
434
|
function leadingSpaces(line) {
|
|
390
435
|
return line.match(/^ */)?.[0].length ?? 0;
|
|
391
436
|
}
|
|
@@ -401,7 +446,7 @@ function looksLikeTableHeader(header, delimiter) {
|
|
|
401
446
|
if (!header.includes('|'))
|
|
402
447
|
return false;
|
|
403
448
|
const cells = splitTableRow(delimiter);
|
|
404
|
-
return cells.length
|
|
449
|
+
return cells.length === splitTableRow(header).length && cells.every(cell => /^:?-+:?$/.test(cell.trim()));
|
|
405
450
|
}
|
|
406
451
|
function splitTableRow(value) {
|
|
407
452
|
let row = value.trim();
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAmC,UAAU,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAErI,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAExE,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CAGvG;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAmC,UAAU,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAErI,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAExE,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CAGvG;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CA+DhH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAwC/G"}
|
package/dist/react.js
CHANGED
|
@@ -22,7 +22,9 @@ export function renderBlockReact(node, options = {}, key) {
|
|
|
22
22
|
case 'blockquote':
|
|
23
23
|
return h(options, 'blockquote', { key }, node.children.map((child, index) => renderBlockReact(child, options, `${key}:${index}`)));
|
|
24
24
|
case 'table':
|
|
25
|
-
return h(options, 'table', { key }, h(options, 'thead', null, h(options, 'tr', null, node.header.map((cell, index) => renderTableCellReact('th', cell, node.align[index], options, index)))),
|
|
25
|
+
return h(options, 'table', { key }, h(options, 'thead', null, h(options, 'tr', null, node.header.map((cell, index) => renderTableCellReact('th', cell, node.align[index], options, index)))), node.rows.length
|
|
26
|
+
? h(options, 'tbody', null, node.rows.map((row, rowIndex) => h(options, 'tr', { key: rowIndex }, row.map((cell, index) => renderTableCellReact('td', cell, node.align[index], options, index)))))
|
|
27
|
+
: null);
|
|
26
28
|
case 'footnotes':
|
|
27
29
|
return renderFootnotesReact(node.items, options, key);
|
|
28
30
|
case 'thematicBreak':
|
|
@@ -51,7 +53,7 @@ export function renderInlineReact(node, options = {}, key) {
|
|
|
51
53
|
return h(options, 'del', { key }, renderInlines(node.children, options));
|
|
52
54
|
case 'footnoteReference':
|
|
53
55
|
return h(options, 'sup', { key }, h(options, 'a', {
|
|
54
|
-
id: `user-content-fnref-${node
|
|
56
|
+
id: `user-content-fnref-${footnoteReferenceId(node)}`,
|
|
55
57
|
'data-footnote-ref': '',
|
|
56
58
|
'aria-describedby': 'footnote-label',
|
|
57
59
|
href: `#user-content-fn-${node.id}`,
|
|
@@ -113,10 +115,10 @@ function renderListItemChildrenReact(children, checked, loose, options, key) {
|
|
|
113
115
|
}),
|
|
114
116
|
' ',
|
|
115
117
|
];
|
|
116
|
-
if (
|
|
118
|
+
if (first?.type === 'paragraph') {
|
|
119
|
+
const content = [...task, ...renderInlines(first.children, options)];
|
|
117
120
|
return [
|
|
118
|
-
...
|
|
119
|
-
...renderInlines(first.children, options),
|
|
121
|
+
...(loose ? [h(options, 'p', { key: `${key}:paragraph` }, content)] : content),
|
|
120
122
|
...rest.flatMap((child, childIndex) => renderListChildReact(child, loose, options, `${key}:${childIndex + 1}`)),
|
|
121
123
|
];
|
|
122
124
|
}
|
|
@@ -133,24 +135,33 @@ function renderFootnotesReact(items, options, key) {
|
|
|
133
135
|
}
|
|
134
136
|
function renderFootnoteItemReact(item, options) {
|
|
135
137
|
const lastIndex = item.children.length - 1;
|
|
136
|
-
const
|
|
138
|
+
const backrefs = renderFootnoteBackrefsReact(item, options);
|
|
137
139
|
if (lastIndex < 0)
|
|
138
|
-
return [h(options, 'p', { key: 'backref-wrapper' },
|
|
140
|
+
return [h(options, 'p', { key: 'backref-wrapper' }, backrefs.slice(1))];
|
|
139
141
|
return item.children.map((child, index) => {
|
|
140
142
|
if (index === lastIndex && child.type === 'paragraph') {
|
|
141
|
-
return h(options, 'p', { key: index }, renderInlines(child.children, options),
|
|
143
|
+
return h(options, 'p', { key: index }, renderInlines(child.children, options), backrefs);
|
|
142
144
|
}
|
|
143
145
|
return renderBlockReact(child, options, `${index}`);
|
|
144
146
|
});
|
|
145
147
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
function renderFootnoteBackrefsReact(item, options) {
|
|
149
|
+
const result = [];
|
|
150
|
+
for (let index = 1; index <= (item.referenceCount ?? 1); index++) {
|
|
151
|
+
const referenceId = index === 1 ? item.id : `${item.id}-${index}`;
|
|
152
|
+
const label = index === 1 ? `${item.number}` : `${item.number}-${index}`;
|
|
153
|
+
result.push(' ', h(options, 'a', {
|
|
154
|
+
key: index,
|
|
155
|
+
'data-footnote-backref': '',
|
|
156
|
+
'aria-label': `Back to reference ${label}`,
|
|
157
|
+
className: 'data-footnote-backref',
|
|
158
|
+
href: `#user-content-fnref-${referenceId}`,
|
|
159
|
+
}, '\u21a9'));
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
function footnoteReferenceId(node) {
|
|
164
|
+
return node.referenceIndex && node.referenceIndex > 1 ? `${node.id}-${node.referenceIndex}` : node.id;
|
|
154
165
|
}
|
|
155
166
|
function h(options, tag, props, ...children) {
|
|
156
167
|
const component = typeof tag === 'string' ? options.components?.[tag] ?? tag : tag;
|
package/dist/types.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export interface FootnotesNode {
|
|
|
60
60
|
export interface FootnoteItemNode {
|
|
61
61
|
id: string;
|
|
62
62
|
number: number;
|
|
63
|
+
referenceCount?: number;
|
|
63
64
|
children: BlockNode[];
|
|
64
65
|
}
|
|
65
66
|
export interface ThematicBreakNode {
|
|
@@ -108,6 +109,7 @@ export interface FootnoteReferenceNode {
|
|
|
108
109
|
type: 'footnoteReference';
|
|
109
110
|
id: string;
|
|
110
111
|
number: number;
|
|
112
|
+
referenceIndex?: number;
|
|
111
113
|
}
|
|
112
114
|
export interface LinkNode {
|
|
113
115
|
type: 'link';
|
|
@@ -162,6 +164,7 @@ export interface ParseOptions {
|
|
|
162
164
|
references?: Record<string, LinkReferenceDefinition>;
|
|
163
165
|
footnotes?: Record<string, FootnoteDefinition>;
|
|
164
166
|
footnoteOrder?: string[];
|
|
167
|
+
footnoteCounts?: Record<string, number>;
|
|
165
168
|
}
|
|
166
169
|
export interface RenderOptions extends ParseOptions {
|
|
167
170
|
highlighter?: CodeHighlighter;
|
|
@@ -194,5 +197,6 @@ export interface LinkReferenceDefinition {
|
|
|
194
197
|
export interface FootnoteDefinition {
|
|
195
198
|
label: string;
|
|
196
199
|
content: string;
|
|
200
|
+
id?: string;
|
|
197
201
|
}
|
|
198
202
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,gBAAgB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,EAAE,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAA;CAC7B;AAED,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,aAAa,GACb,aAAa,GACb,QAAQ,GACR,cAAc,GACd,SAAS,GACT,aAAa,GACb,iBAAiB,GACjB,aAAa,GACb,WAAW,GACX,aAAa,CAAA;AAEjB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,YAAY,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IACrD,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,IAAI,EAAE,aAAa,EAAE,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,QAAQ,EAAE,SAAS,EAAE,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAED,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,UAAU,GACV,qBAAqB,GACrB,QAAQ,GACR,SAAS,GACT,SAAS,GACT,cAAc,CAAA;AAElB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAA;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/markdown",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "A tiny deterministic
|
|
5
|
+
"description": "A tiny, fast, deterministic Markdown renderer for blogs and documentation.",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"packageManager": "pnpm@11.4.0",
|
|
8
7
|
"sideEffects": false,
|
|
9
8
|
"files": [
|
|
10
9
|
"dist",
|
|
@@ -53,14 +52,6 @@
|
|
|
53
52
|
"import": "./dist/extensions/tabs.js"
|
|
54
53
|
}
|
|
55
54
|
},
|
|
56
|
-
"scripts": {
|
|
57
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
58
|
-
"typecheck": "tsc --noEmit",
|
|
59
|
-
"test": "vitest run",
|
|
60
|
-
"bench": "tsx scripts/bench.ts",
|
|
61
|
-
"size": "tsx scripts/measure-size.ts",
|
|
62
|
-
"research": "pnpm run size && pnpm run bench"
|
|
63
|
-
},
|
|
64
55
|
"publishConfig": {
|
|
65
56
|
"access": "public"
|
|
66
57
|
},
|
|
@@ -77,6 +68,7 @@
|
|
|
77
68
|
"@types/react": "^19.0.0",
|
|
78
69
|
"@types/react-dom": "^19.0.0",
|
|
79
70
|
"commonmark": "^0.31.2",
|
|
71
|
+
"commonmark-spec": "0.31.2",
|
|
80
72
|
"esbuild": "^0.25.0",
|
|
81
73
|
"markdown-it": "^14.2.0",
|
|
82
74
|
"markdown-wasm": "^1.2.0",
|
|
@@ -91,5 +83,16 @@
|
|
|
91
83
|
"typescript": "^5.8.0",
|
|
92
84
|
"unified": "^11.0.5",
|
|
93
85
|
"vitest": "^3.2.0"
|
|
86
|
+
},
|
|
87
|
+
"scripts": {
|
|
88
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
89
|
+
"typecheck": "tsc --noEmit",
|
|
90
|
+
"test": "vitest run",
|
|
91
|
+
"test:corpus": "vitest run tests/corpus.test.tsx",
|
|
92
|
+
"conformance": "tsx scripts/conformance.ts",
|
|
93
|
+
"bench": "tsx scripts/bench.ts",
|
|
94
|
+
"size": "tsx scripts/measure-size.ts",
|
|
95
|
+
"research": "pnpm run conformance && pnpm run size && pnpm run bench",
|
|
96
|
+
"verify": "pnpm test && pnpm run typecheck && pnpm run build && pnpm run research && pnpm pack --dry-run"
|
|
94
97
|
}
|
|
95
|
-
}
|
|
98
|
+
}
|