@tanstack/markdown 0.0.6 → 0.0.8
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 +57 -20
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +5 -3
- package/dist/inline.js +77 -32
- package/dist/octane.d.ts +15 -0
- package/dist/octane.d.ts.map +1 -0
- package/dist/octane.js +189 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +19 -7
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +3 -1
- package/package.json +25 -12
package/README.md
CHANGED
|
@@ -1,36 +1,73 @@
|
|
|
1
1
|
# TanStack Markdown
|
|
2
2
|
|
|
3
|
-
A tiny deterministic
|
|
3
|
+
A tiny, fast, deterministic Markdown parser and renderer for blogs and documentation.
|
|
4
|
+
|
|
5
|
+
- 4.6 KB gzip parser
|
|
6
|
+
- 6.4 KB gzip HTML renderer
|
|
7
|
+
- 6.3 KB gzip React adapter
|
|
8
|
+
- 6.3 KB gzip Octane adapter
|
|
9
|
+
- zero runtime dependencies
|
|
10
|
+
- serializable AST
|
|
11
|
+
- safe defaults for raw HTML and executable URLs
|
|
12
|
+
- optional docs extensions and external syntax highlighting
|
|
4
13
|
|
|
5
14
|
```bash
|
|
6
15
|
pnpm add @tanstack/markdown
|
|
7
16
|
```
|
|
8
17
|
|
|
9
|
-
|
|
18
|
+
```ts
|
|
19
|
+
import { renderHtml } from '@tanstack/markdown/html'
|
|
20
|
+
|
|
21
|
+
const html = renderHtml('# Fast by default')
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Markdown } from '@tanstack/markdown/react'
|
|
26
|
+
|
|
27
|
+
export function Article({ source }: { source: string }) {
|
|
28
|
+
return <Markdown>{source}</Markdown>
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```tsrx
|
|
33
|
+
import { Markdown } from '@tanstack/markdown/octane'
|
|
34
|
+
|
|
35
|
+
export function Article({ source }: { source: string }) @{
|
|
36
|
+
<Markdown>{source}</Markdown>
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
TanStack Markdown targets controlled technical content. It supports the Markdown used by blogs and docs, then spends its remaining complexity budget on deterministic output, renderer parity, malformed-input resilience, and small entry points. It is intentionally not a complete CommonMark, GFM, MDX, or general content-processing implementation.
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
- [Overview](./docs/overview.md)
|
|
45
|
+
- [Installation](./docs/installation.md)
|
|
46
|
+
- [Quick Start](./docs/quick-start.md)
|
|
47
|
+
- [Comparison](./docs/comparison.md)
|
|
48
|
+
- [Syntax Profile](./docs/core-concepts/syntax-profile.md)
|
|
49
|
+
- [React Guide](./docs/guides/react.md)
|
|
50
|
+
- [Octane Guide](./docs/guides/octane.md)
|
|
51
|
+
- [Syntax Highlighting](./docs/guides/syntax-highlighting.md)
|
|
52
|
+
- [Extensions](./docs/guides/extensions.md)
|
|
53
|
+
- [API Reference](./docs/reference/index.md)
|
|
54
|
+
- [Architecture](./docs/project/architecture.md)
|
|
55
|
+
|
|
56
|
+
## Verification
|
|
10
57
|
|
|
11
58
|
```bash
|
|
12
|
-
pnpm
|
|
13
|
-
pnpm run typecheck
|
|
14
|
-
pnpm run build
|
|
15
|
-
pnpm run research
|
|
59
|
+
pnpm run verify
|
|
16
60
|
```
|
|
17
61
|
|
|
18
|
-
|
|
62
|
+
To include downstream content in the corpus gate:
|
|
19
63
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- `scripts/measure-size.ts`: bundle size matrix
|
|
25
|
-
- `scripts/bench.ts`: CPU benchmark matrix
|
|
64
|
+
```bash
|
|
65
|
+
MARKDOWN_CORPUS_DIRS=../tanstack.com/src/blog:../tanstack.com/docs \
|
|
66
|
+
pnpm run test:corpus
|
|
67
|
+
```
|
|
26
68
|
|
|
27
|
-
|
|
69
|
+
Generated reports:
|
|
28
70
|
|
|
29
71
|
- [Bundle sizes](./reports/sizes.md)
|
|
30
72
|
- [Benchmarks](./reports/benchmarks.md)
|
|
31
|
-
- [
|
|
32
|
-
- [Spec and API](./docs/spec.md)
|
|
33
|
-
- [Goal and coverage map](./docs/goal.md)
|
|
34
|
-
- [Bundle strategy](./docs/bundle-strategy.md)
|
|
35
|
-
- [Extensions](./docs/extensions.md)
|
|
36
|
-
- [Recommendation](./docs/recommendation.md)
|
|
73
|
+
- [CommonMark compatibility accounting](./reports/conformance.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':
|
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);
|
|
@@ -185,13 +200,13 @@ function parseFootnoteReference(value, open, options) {
|
|
|
185
200
|
end: close + 1,
|
|
186
201
|
};
|
|
187
202
|
}
|
|
188
|
-
function parseLinkish(value, open, options) {
|
|
189
|
-
const closeBracket = findBalanced(value, open, '[', ']');
|
|
203
|
+
function parseLinkish(value, open, options, budget) {
|
|
204
|
+
const closeBracket = findBalanced(value, open, '[', ']', budget);
|
|
190
205
|
if (closeBracket === -1)
|
|
191
206
|
return undefined;
|
|
192
207
|
const label = value.slice(open + 1, closeBracket);
|
|
193
208
|
if (value[closeBracket + 1] === '(') {
|
|
194
|
-
const closeParen = findBalanced(value, closeBracket + 1, '(', ')');
|
|
209
|
+
const closeParen = findBalanced(value, closeBracket + 1, '(', ')', budget);
|
|
195
210
|
if (closeParen === -1)
|
|
196
211
|
return undefined;
|
|
197
212
|
const destination = value.slice(closeBracket + 2, closeParen).trim();
|
|
@@ -206,7 +221,7 @@ function parseLinkish(value, open, options) {
|
|
|
206
221
|
};
|
|
207
222
|
}
|
|
208
223
|
if (value[closeBracket + 1] === '[') {
|
|
209
|
-
const closeReference = findBalanced(value, closeBracket + 1, '[', ']');
|
|
224
|
+
const closeReference = findBalanced(value, closeBracket + 1, '[', ']', budget);
|
|
210
225
|
if (closeReference === -1)
|
|
211
226
|
return undefined;
|
|
212
227
|
const definition = options.references?.[normalizeReferenceLabel(value.slice(closeBracket + 2, closeReference))];
|
|
@@ -230,9 +245,11 @@ function parseDestination(value) {
|
|
|
230
245
|
...(match[2] ? { title: match[2] } : {}),
|
|
231
246
|
};
|
|
232
247
|
}
|
|
233
|
-
function findBalanced(value, openIndex, open, close) {
|
|
248
|
+
function findBalanced(value, openIndex, open, close, budget) {
|
|
234
249
|
let depth = 0;
|
|
235
250
|
for (let index = openIndex; index < value.length; index++) {
|
|
251
|
+
if (!takeScan(budget))
|
|
252
|
+
return -1;
|
|
236
253
|
if (value[index - 1] === '\\')
|
|
237
254
|
continue;
|
|
238
255
|
if (value[index] === open)
|
|
@@ -245,38 +262,51 @@ function findBalanced(value, openIndex, open, close) {
|
|
|
245
262
|
}
|
|
246
263
|
return -1;
|
|
247
264
|
}
|
|
248
|
-
function countRun(value, index, char) {
|
|
265
|
+
function countRun(value, index, char, budget) {
|
|
249
266
|
let count = 0;
|
|
250
|
-
while (value[index + count] === char)
|
|
267
|
+
while (value[index + count] === char) {
|
|
268
|
+
if (budget && !takeScan(budget))
|
|
269
|
+
break;
|
|
251
270
|
count++;
|
|
271
|
+
}
|
|
252
272
|
return count;
|
|
253
273
|
}
|
|
254
|
-
function findClosingRun(value, start, char, count) {
|
|
274
|
+
function findClosingRun(value, start, char, count, budget) {
|
|
255
275
|
for (let index = start; index < value.length; index++) {
|
|
276
|
+
if (!takeScan(budget))
|
|
277
|
+
return -1;
|
|
256
278
|
if (value[index] !== char)
|
|
257
279
|
continue;
|
|
258
|
-
if (countRun(value, index, char) >= count)
|
|
280
|
+
if (countRun(value, index, char, budget) >= count)
|
|
259
281
|
return index;
|
|
260
282
|
}
|
|
261
283
|
return -1;
|
|
262
284
|
}
|
|
263
|
-
function findDelimiter(value, start, delimiter) {
|
|
285
|
+
function findDelimiter(value, start, delimiter, budget) {
|
|
264
286
|
for (let index = start; index < value.length; index++) {
|
|
287
|
+
if (!takeScan(budget))
|
|
288
|
+
return -1;
|
|
265
289
|
if (value[index - 1] === '\\')
|
|
266
290
|
continue;
|
|
291
|
+
if (delimiter === '~~' && (value[index - 1] === '~' || value[index + 2] === '~'))
|
|
292
|
+
continue;
|
|
267
293
|
if (value.startsWith(delimiter, index))
|
|
268
294
|
return index;
|
|
269
295
|
}
|
|
270
296
|
return -1;
|
|
271
297
|
}
|
|
272
|
-
function findSingleTildeDelimiter(value, start) {
|
|
298
|
+
function findSingleTildeDelimiter(value, start, budget) {
|
|
273
299
|
if (isWhitespace(value[start] ?? ''))
|
|
274
300
|
return -1;
|
|
275
301
|
for (let index = start; index < value.length; index++) {
|
|
302
|
+
if (!takeScan(budget))
|
|
303
|
+
return -1;
|
|
276
304
|
if (value[index - 1] === '\\')
|
|
277
305
|
continue;
|
|
278
306
|
if (value[index] !== '~')
|
|
279
307
|
continue;
|
|
308
|
+
if (value[index - 1] === '~')
|
|
309
|
+
continue;
|
|
280
310
|
if (value[index + 1] === '~')
|
|
281
311
|
continue;
|
|
282
312
|
if (isWhitespace(value[index - 1] ?? ''))
|
|
@@ -285,6 +315,21 @@ function findSingleTildeDelimiter(value, start) {
|
|
|
285
315
|
}
|
|
286
316
|
return -1;
|
|
287
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
|
+
}
|
|
288
333
|
function isIntrawordUnderscore(value, open, close, delimiter) {
|
|
289
334
|
if (delimiter !== '_')
|
|
290
335
|
return false;
|
|
@@ -293,8 +338,8 @@ function isIntrawordUnderscore(value, open, close, delimiter) {
|
|
|
293
338
|
function isWhitespace(value) {
|
|
294
339
|
return /\s/.test(value);
|
|
295
340
|
}
|
|
296
|
-
function textFromMarkdown(value) {
|
|
297
|
-
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('');
|
|
298
343
|
}
|
|
299
344
|
function mergeText(nodes) {
|
|
300
345
|
const result = [];
|
package/dist/octane.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ComponentBody, ElementDescriptor, OctaneNode } from 'octane';
|
|
2
|
+
import type { BlockNode, InlineNode, MarkdownInput, RenderOptions } from './types.js';
|
|
3
|
+
type ComponentMap = Partial<Record<string, string | ComponentBody<any>>>;
|
|
4
|
+
export interface MarkdownOctaneOptions extends RenderOptions {
|
|
5
|
+
components?: ComponentMap;
|
|
6
|
+
}
|
|
7
|
+
export interface MarkdownProps extends MarkdownOctaneOptions {
|
|
8
|
+
children: MarkdownInput;
|
|
9
|
+
}
|
|
10
|
+
export declare function Markdown({ children, ...options }: MarkdownProps): ElementDescriptor;
|
|
11
|
+
export declare function renderMarkdownOctane(input: MarkdownInput, options?: MarkdownOctaneOptions): OctaneNode[];
|
|
12
|
+
export declare function renderBlockOctane(node: BlockNode, options?: MarkdownOctaneOptions, key?: string): ElementDescriptor;
|
|
13
|
+
export declare function renderInlineOctane(node: InlineNode, options?: MarkdownOctaneOptions, key?: string): OctaneNode;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=octane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"octane.d.ts","sourceRoot":"","sources":["../src/octane.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAE1E,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,qBAAsB,SAAQ,aAAa;IAC1D,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,qBAAqB;IAC1D,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,iBAAiB,CAEnF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,qBAA0B,GAAG,UAAU,EAAE,CAG5G;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,qBAA0B,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,iBAAiB,CA+DvH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,qBAA0B,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAwClH"}
|
package/dist/octane.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Fragment, createElement } from 'octane';
|
|
2
|
+
import { parseMarkdown } from './parser.js';
|
|
3
|
+
export function Markdown({ children, ...options }) {
|
|
4
|
+
return createElement(Fragment, null, ...renderMarkdownOctane(children, options));
|
|
5
|
+
}
|
|
6
|
+
export function renderMarkdownOctane(input, options = {}) {
|
|
7
|
+
const document = typeof input === 'string' ? parseMarkdown(input, options) : input;
|
|
8
|
+
return document.children.map((node, index) => renderBlockOctane(node, options, `b:${index}`));
|
|
9
|
+
}
|
|
10
|
+
export function renderBlockOctane(node, options = {}, key) {
|
|
11
|
+
switch (node.type) {
|
|
12
|
+
case 'heading':
|
|
13
|
+
return h(options, `h${node.depth}`, { key, ...(node.id ? { id: node.id } : {}), ...(node.framework ? { 'data-framework': node.framework } : {}) }, renderInlines(node.children, options), renderHeadingAnchorOctane(node.id, options));
|
|
14
|
+
case 'paragraph':
|
|
15
|
+
return h(options, 'p', { key }, renderInlines(node.children, options));
|
|
16
|
+
case 'code':
|
|
17
|
+
return renderCodeBlockOctane(node, options, key);
|
|
18
|
+
case 'list': {
|
|
19
|
+
const tag = node.ordered ? 'ol' : 'ul';
|
|
20
|
+
return h(options, tag, { key, ...(node.ordered && node.start && node.start !== 1 ? { start: node.start } : {}) }, node.items.map((item, index) => h(options, 'li', { key: index }, renderListItemChildrenOctane(item.children, item.checked, node.loose, options, `${index}`))));
|
|
21
|
+
}
|
|
22
|
+
case 'blockquote':
|
|
23
|
+
return h(options, 'blockquote', { key }, node.children.map((child, index) => renderBlockOctane(child, options, `${key}:${index}`)));
|
|
24
|
+
case 'table':
|
|
25
|
+
return h(options, 'table', { key }, h(options, 'thead', null, h(options, 'tr', null, node.header.map((cell, index) => renderTableCellOctane('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) => renderTableCellOctane('td', cell, node.align[index], options, index)))))
|
|
27
|
+
: null);
|
|
28
|
+
case 'footnotes':
|
|
29
|
+
return renderFootnotesOctane(node.items, options, key);
|
|
30
|
+
case 'thematicBreak':
|
|
31
|
+
return h(options, 'hr', { key });
|
|
32
|
+
case 'html':
|
|
33
|
+
return options.allowHtml
|
|
34
|
+
? h(options, 'div', { key, dangerouslySetInnerHTML: { __html: node.value } })
|
|
35
|
+
: h(options, 'p', { key }, node.value);
|
|
36
|
+
case 'callout':
|
|
37
|
+
return h(options, 'div', { key, className: `markdown-alert markdown-alert-${node.kind.toLowerCase()}` }, h(options, 'p', { className: 'markdown-alert-title' }, node.title), h(options, 'div', { className: 'markdown-alert-content' }, node.children.map((child, index) => renderBlockOctane(child, options, `${key}:${index}`))));
|
|
38
|
+
case 'component':
|
|
39
|
+
return renderComponentOctane(node, options, key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function renderInlineOctane(node, options = {}, key) {
|
|
43
|
+
switch (node.type) {
|
|
44
|
+
case 'text':
|
|
45
|
+
return node.value;
|
|
46
|
+
case 'inlineCode':
|
|
47
|
+
return h(options, 'code', { key }, node.value);
|
|
48
|
+
case 'strong':
|
|
49
|
+
return h(options, 'strong', { key }, renderInlines(node.children, options));
|
|
50
|
+
case 'emphasis':
|
|
51
|
+
return h(options, 'em', { key }, renderInlines(node.children, options));
|
|
52
|
+
case 'strike':
|
|
53
|
+
return h(options, 'del', { key }, renderInlines(node.children, options));
|
|
54
|
+
case 'footnoteReference':
|
|
55
|
+
return h(options, 'sup', { key }, h(options, 'a', {
|
|
56
|
+
id: `user-content-fnref-${footnoteReferenceId(node)}`,
|
|
57
|
+
'data-footnote-ref': '',
|
|
58
|
+
'aria-describedby': 'footnote-label',
|
|
59
|
+
href: `#user-content-fn-${node.id}`,
|
|
60
|
+
}, node.number));
|
|
61
|
+
case 'link':
|
|
62
|
+
return h(options, 'a', { key, href: node.href, ...(node.title ? { title: node.title } : {}) }, renderInlines(node.children, options));
|
|
63
|
+
case 'image':
|
|
64
|
+
return h(options, 'img', { key, src: node.src, alt: node.alt, ...(node.title ? { title: node.title } : {}) });
|
|
65
|
+
case 'break':
|
|
66
|
+
return h(options, 'br', { key });
|
|
67
|
+
case 'inlineHtml':
|
|
68
|
+
return options.allowHtml
|
|
69
|
+
? h(options, 'span', { key, dangerouslySetInnerHTML: { __html: node.value } })
|
|
70
|
+
: node.value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function renderInlines(nodes, options) {
|
|
74
|
+
return nodes.map((node, index) => renderInlineOctane(node, options, `i:${index}`));
|
|
75
|
+
}
|
|
76
|
+
function renderCodeBlockOctane(node, options, key) {
|
|
77
|
+
const lang = node.lang ?? 'plaintext';
|
|
78
|
+
const highlighter = options.highlighter;
|
|
79
|
+
const content = highlighter ? undefined : node.value;
|
|
80
|
+
const highlighted = highlighter
|
|
81
|
+
? {
|
|
82
|
+
dangerouslySetInnerHTML: {
|
|
83
|
+
__html: highlighter(node.value, lang, {
|
|
84
|
+
...(node.highlightLines && { highlightLines: node.highlightLines }),
|
|
85
|
+
...(options.codeLineNumbers !== undefined && { lineNumbers: options.codeLineNumbers }),
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
: undefined;
|
|
90
|
+
const pre = h(options, 'pre', {
|
|
91
|
+
className: 'tm-code',
|
|
92
|
+
'data-lang': lang,
|
|
93
|
+
...(node.title ? { 'data-code-title': node.title } : {}),
|
|
94
|
+
...(node.file ? { 'data-filename': node.file } : {}),
|
|
95
|
+
...(node.framework ? { 'data-framework': node.framework } : {}),
|
|
96
|
+
}, h(options, 'code', { className: `language-${lang}`, ...highlighted }, content));
|
|
97
|
+
if (!node.title)
|
|
98
|
+
return h(options, Fragment, { key }, pre);
|
|
99
|
+
return h(options, 'figure', { key, className: 'tm-code-frame', 'data-lang': lang }, h(options, 'figcaption', null, node.title), pre);
|
|
100
|
+
}
|
|
101
|
+
function renderListItemChildrenOctane(children, checked, loose, options, key) {
|
|
102
|
+
const [first, ...rest] = children;
|
|
103
|
+
const task = checked === undefined
|
|
104
|
+
? []
|
|
105
|
+
: [
|
|
106
|
+
h(options, 'input', {
|
|
107
|
+
key: `${key}:checkbox`,
|
|
108
|
+
type: 'checkbox',
|
|
109
|
+
disabled: true,
|
|
110
|
+
checked,
|
|
111
|
+
readOnly: true,
|
|
112
|
+
}),
|
|
113
|
+
' ',
|
|
114
|
+
];
|
|
115
|
+
if (first?.type === 'paragraph') {
|
|
116
|
+
const content = [...task, ...renderInlines(first.children, options)];
|
|
117
|
+
return [
|
|
118
|
+
...(loose ? [h(options, 'p', { key: `${key}:paragraph` }, content)] : content),
|
|
119
|
+
...rest.flatMap((child, childIndex) => renderListChildOctane(child, loose, options, `${key}:${childIndex + 1}`)),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
return [...task, ...children.flatMap((child, childIndex) => renderListChildOctane(child, loose, options, `${key}:${childIndex}`))];
|
|
123
|
+
}
|
|
124
|
+
function renderListChildOctane(child, loose, options, key) {
|
|
125
|
+
return !loose && child.type === 'paragraph' ? renderInlines(child.children, options) : [renderBlockOctane(child, options, key)];
|
|
126
|
+
}
|
|
127
|
+
function renderTableCellOctane(tag, cell, align, options, key) {
|
|
128
|
+
return h(options, tag, { key, ...(align ? { style: { textAlign: align } } : {}) }, renderInlines(cell.children, options));
|
|
129
|
+
}
|
|
130
|
+
function renderFootnotesOctane(items, options, key) {
|
|
131
|
+
return h(options, 'section', { key, 'data-footnotes': '', className: 'footnotes' }, h(options, 'h2', { id: 'footnote-label', className: 'sr-only' }, 'Footnotes', renderHeadingAnchorOctane('footnote-label', options)), h(options, 'ol', null, items.map(item => h(options, 'li', { key: item.id, id: `user-content-fn-${item.id}` }, renderFootnoteItemOctane(item, options)))));
|
|
132
|
+
}
|
|
133
|
+
function renderFootnoteItemOctane(item, options) {
|
|
134
|
+
const lastIndex = item.children.length - 1;
|
|
135
|
+
const backrefs = renderFootnoteBackrefsOctane(item, options);
|
|
136
|
+
if (lastIndex < 0)
|
|
137
|
+
return [h(options, 'p', { key: 'backref-wrapper' }, backrefs.slice(1))];
|
|
138
|
+
return item.children.map((child, index) => {
|
|
139
|
+
if (index === lastIndex && child.type === 'paragraph') {
|
|
140
|
+
return h(options, 'p', { key: index }, renderInlines(child.children, options), backrefs);
|
|
141
|
+
}
|
|
142
|
+
return renderBlockOctane(child, options, `${index}`);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function renderFootnoteBackrefsOctane(item, options) {
|
|
146
|
+
const result = [];
|
|
147
|
+
for (let index = 1; index <= (item.referenceCount ?? 1); index++) {
|
|
148
|
+
const referenceId = index === 1 ? item.id : `${item.id}-${index}`;
|
|
149
|
+
const label = index === 1 ? `${item.number}` : `${item.number}-${index}`;
|
|
150
|
+
result.push(' ', h(options, 'a', {
|
|
151
|
+
key: index,
|
|
152
|
+
'data-footnote-backref': '',
|
|
153
|
+
'aria-label': `Back to reference ${label}`,
|
|
154
|
+
className: 'data-footnote-backref',
|
|
155
|
+
href: `#user-content-fnref-${referenceId}`,
|
|
156
|
+
}, '\u21a9'));
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
function footnoteReferenceId(node) {
|
|
161
|
+
return node.referenceIndex && node.referenceIndex > 1 ? `${node.id}-${node.referenceIndex}` : node.id;
|
|
162
|
+
}
|
|
163
|
+
function h(options, tag, props, ...children) {
|
|
164
|
+
const component = typeof tag === 'string' ? options.components?.[tag] ?? tag : tag;
|
|
165
|
+
return createElement(component, props ?? undefined, ...children);
|
|
166
|
+
}
|
|
167
|
+
function renderComponentOctane(node, options, key) {
|
|
168
|
+
const tag = node.tagName ?? 'md-comment-component';
|
|
169
|
+
const props = {
|
|
170
|
+
...(node.properties ?? {}),
|
|
171
|
+
};
|
|
172
|
+
if (!node.tagName) {
|
|
173
|
+
props['data-component'] = node.name;
|
|
174
|
+
if (!props['data-attributes'])
|
|
175
|
+
props['data-attributes'] = JSON.stringify(node.attributes);
|
|
176
|
+
}
|
|
177
|
+
return h(options, tag, { key, ...props }, node.children.map((child, index) => renderBlockOctane(child, options, `${key}:${index}`)));
|
|
178
|
+
}
|
|
179
|
+
function renderHeadingAnchorOctane(id, options) {
|
|
180
|
+
if (!id || !options.headingAnchors)
|
|
181
|
+
return null;
|
|
182
|
+
const anchorOptions = typeof options.headingAnchors === 'object' ? options.headingAnchors : {};
|
|
183
|
+
return h(options, 'a', {
|
|
184
|
+
href: `#${id}`,
|
|
185
|
+
'aria-hidden': anchorOptions.ariaHidden ?? true,
|
|
186
|
+
className: anchorOptions.className ?? 'anchor-heading anchor-heading-link',
|
|
187
|
+
tabIndex: anchorOptions.tabIndex ?? -1,
|
|
188
|
+
}, anchorOptions.content ?? '#');
|
|
189
|
+
}
|
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,EAQV,gBAAgB,EAChB,YAAY,EAGb,MAAM,YAAY,CAAA;
|
|
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;
|
|
@@ -40,13 +41,21 @@ class BlockParser {
|
|
|
40
41
|
lines;
|
|
41
42
|
options;
|
|
42
43
|
slugger;
|
|
44
|
+
budget;
|
|
43
45
|
index = 0;
|
|
44
|
-
constructor(lines, options, slugger) {
|
|
46
|
+
constructor(lines, options, slugger, budget = { depth: 0 }) {
|
|
45
47
|
this.lines = lines;
|
|
46
48
|
this.options = options;
|
|
47
49
|
this.slugger = slugger;
|
|
50
|
+
this.budget = budget;
|
|
48
51
|
}
|
|
49
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++;
|
|
50
59
|
const nodes = [];
|
|
51
60
|
while (this.index < this.lines.length) {
|
|
52
61
|
if (isBlank(this.current())) {
|
|
@@ -68,6 +77,7 @@ class BlockParser {
|
|
|
68
77
|
this.parseParagraph();
|
|
69
78
|
nodes.push(node);
|
|
70
79
|
}
|
|
80
|
+
this.budget.depth--;
|
|
71
81
|
return nodes;
|
|
72
82
|
}
|
|
73
83
|
parseExtensionBlock() {
|
|
@@ -78,7 +88,7 @@ class BlockParser {
|
|
|
78
88
|
index: this.index,
|
|
79
89
|
options: this.options,
|
|
80
90
|
parseInline: value => parseInline(value, this.options),
|
|
81
|
-
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(),
|
|
82
92
|
consume: lines => {
|
|
83
93
|
consumed = lines;
|
|
84
94
|
},
|
|
@@ -151,7 +161,7 @@ class BlockParser {
|
|
|
151
161
|
}
|
|
152
162
|
return {
|
|
153
163
|
type: 'blockquote',
|
|
154
|
-
children: new BlockParser(quoted, this.options, this.slugger).parse(),
|
|
164
|
+
children: new BlockParser(quoted, this.options, this.slugger, this.budget).parse(),
|
|
155
165
|
};
|
|
156
166
|
}
|
|
157
167
|
parseList() {
|
|
@@ -211,7 +221,7 @@ class BlockParser {
|
|
|
211
221
|
itemLines.push(line.trimStart());
|
|
212
222
|
this.index++;
|
|
213
223
|
}
|
|
214
|
-
const children = new BlockParser(itemLines, this.options, this.slugger).parse();
|
|
224
|
+
const children = new BlockParser(itemLines, this.options, this.slugger, this.budget).parse();
|
|
215
225
|
const item = { type: 'listItem', children };
|
|
216
226
|
if (checked !== undefined)
|
|
217
227
|
item.checked = checked;
|
|
@@ -232,13 +242,15 @@ class BlockParser {
|
|
|
232
242
|
return undefined;
|
|
233
243
|
const headerCells = splitTableRow(header);
|
|
234
244
|
const align = splitTableRow(delimiter).map(parseAlign);
|
|
245
|
+
const columns = headerCells.length;
|
|
235
246
|
const rows = [];
|
|
236
247
|
this.index += 2;
|
|
237
248
|
while (this.index < this.lines.length) {
|
|
238
249
|
const line = this.current();
|
|
239
|
-
if (isBlank(line) ||
|
|
250
|
+
if (isBlank(line) || isBlockStart(line, this.next()))
|
|
240
251
|
break;
|
|
241
|
-
|
|
252
|
+
const values = splitTableRow(line);
|
|
253
|
+
rows.push(Array.from({ length: columns }, (_, index) => cell(values[index] ?? '', this.options)));
|
|
242
254
|
this.index++;
|
|
243
255
|
}
|
|
244
256
|
return {
|
|
@@ -434,7 +446,7 @@ function looksLikeTableHeader(header, delimiter) {
|
|
|
434
446
|
if (!header.includes('|'))
|
|
435
447
|
return false;
|
|
436
448
|
const cells = splitTableRow(delimiter);
|
|
437
|
-
return cells.length
|
|
449
|
+
return cells.length === splitTableRow(header).length && cells.every(cell => /^:?-+:?$/.test(cell.trim()));
|
|
438
450
|
}
|
|
439
451
|
function splitTableRow(value) {
|
|
440
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':
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/markdown",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
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",
|
|
@@ -28,6 +27,10 @@
|
|
|
28
27
|
"types": "./dist/react.d.ts",
|
|
29
28
|
"import": "./dist/react.js"
|
|
30
29
|
},
|
|
30
|
+
"./octane": {
|
|
31
|
+
"types": "./dist/octane.d.ts",
|
|
32
|
+
"import": "./dist/octane.js"
|
|
33
|
+
},
|
|
31
34
|
"./extensions/callouts": {
|
|
32
35
|
"types": "./dist/extensions/callouts.d.ts",
|
|
33
36
|
"import": "./dist/extensions/callouts.js"
|
|
@@ -53,21 +56,17 @@
|
|
|
53
56
|
"import": "./dist/extensions/tabs.js"
|
|
54
57
|
}
|
|
55
58
|
},
|
|
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
59
|
"publishConfig": {
|
|
65
60
|
"access": "public"
|
|
66
61
|
},
|
|
67
62
|
"peerDependencies": {
|
|
63
|
+
"octane": ">=0.1.12",
|
|
68
64
|
"react": ">=18"
|
|
69
65
|
},
|
|
70
66
|
"peerDependenciesMeta": {
|
|
67
|
+
"octane": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
71
70
|
"react": {
|
|
72
71
|
"optional": true
|
|
73
72
|
}
|
|
@@ -77,11 +76,13 @@
|
|
|
77
76
|
"@types/react": "^19.0.0",
|
|
78
77
|
"@types/react-dom": "^19.0.0",
|
|
79
78
|
"commonmark": "^0.31.2",
|
|
79
|
+
"commonmark-spec": "0.31.2",
|
|
80
80
|
"esbuild": "^0.25.0",
|
|
81
81
|
"markdown-it": "^14.2.0",
|
|
82
82
|
"markdown-wasm": "^1.2.0",
|
|
83
83
|
"marked": "^18.0.5",
|
|
84
84
|
"micromark": "^4.0.2",
|
|
85
|
+
"octane": "0.1.12",
|
|
85
86
|
"react": "^19.0.0",
|
|
86
87
|
"react-dom": "^19.0.0",
|
|
87
88
|
"rehype-stringify": "^10.0.1",
|
|
@@ -91,5 +92,17 @@
|
|
|
91
92
|
"typescript": "^5.8.0",
|
|
92
93
|
"unified": "^11.0.5",
|
|
93
94
|
"vitest": "^3.2.0"
|
|
95
|
+
},
|
|
96
|
+
"scripts": {
|
|
97
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
98
|
+
"typecheck": "tsc --noEmit",
|
|
99
|
+
"test": "vitest run",
|
|
100
|
+
"test:corpus": "vitest run tests/corpus.test.tsx",
|
|
101
|
+
"docs:verify": "node scripts/verify-docs.mjs",
|
|
102
|
+
"conformance": "tsx scripts/conformance.ts",
|
|
103
|
+
"bench": "tsx scripts/bench.ts",
|
|
104
|
+
"size": "tsx scripts/measure-size.ts",
|
|
105
|
+
"research": "pnpm run conformance && pnpm run size && pnpm run bench",
|
|
106
|
+
"verify": "pnpm test && pnpm run typecheck && pnpm run build && pnpm run docs:verify && pnpm run research && pnpm pack --dry-run"
|
|
94
107
|
}
|
|
95
|
-
}
|
|
108
|
+
}
|