@tanstack/markdown 0.0.7 → 0.0.9
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 +33 -12
- package/dist/octane.d.ts +15 -0
- package/dist/octane.d.ts.map +1 -0
- package/dist/octane.js +189 -0
- package/dist/parser.js +6 -2
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
# TanStack Markdown
|
|
2
2
|
|
|
3
|
-
A tiny, fast, deterministic Markdown renderer for blogs and documentation.
|
|
3
|
+
A tiny, fast, deterministic Markdown parser and renderer for blogs and documentation.
|
|
4
4
|
|
|
5
|
-
|
|
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
|
|
6
13
|
|
|
7
14
|
```bash
|
|
8
15
|
pnpm add @tanstack/markdown
|
|
@@ -22,13 +29,29 @@ export function Article({ source }: { source: string }) {
|
|
|
22
29
|
}
|
|
23
30
|
```
|
|
24
31
|
|
|
25
|
-
|
|
32
|
+
```tsrx
|
|
33
|
+
import { Markdown } from '@tanstack/markdown/octane'
|
|
26
34
|
|
|
27
|
-
|
|
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.
|
|
28
41
|
|
|
29
|
-
|
|
42
|
+
## Documentation
|
|
30
43
|
|
|
31
|
-
|
|
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)
|
|
32
55
|
|
|
33
56
|
## Verification
|
|
34
57
|
|
|
@@ -36,17 +59,15 @@ See the [docs Markdown profile](./docs/profile.md) for the supported contract an
|
|
|
36
59
|
pnpm run verify
|
|
37
60
|
```
|
|
38
61
|
|
|
39
|
-
To include downstream
|
|
62
|
+
To include downstream content in the corpus gate:
|
|
40
63
|
|
|
41
64
|
```bash
|
|
42
|
-
MARKDOWN_CORPUS_DIRS=../tanstack.com/src/blog:../tanstack.com/docs
|
|
65
|
+
MARKDOWN_CORPUS_DIRS=../tanstack.com/src/blog:../tanstack.com/docs \
|
|
66
|
+
pnpm run test:corpus
|
|
43
67
|
```
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
Generated reports:
|
|
46
70
|
|
|
47
71
|
- [Bundle sizes](./reports/sizes.md)
|
|
48
72
|
- [Benchmarks](./reports/benchmarks.md)
|
|
49
73
|
- [CommonMark compatibility accounting](./reports/conformance.md)
|
|
50
|
-
- [Audit](./docs/audit.md)
|
|
51
|
-
- [Spec and API](./docs/spec.md)
|
|
52
|
-
- [Extensions](./docs/extensions.md)
|
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.js
CHANGED
|
@@ -368,9 +368,13 @@ function extractDefinitions(lines) {
|
|
|
368
368
|
}
|
|
369
369
|
continue;
|
|
370
370
|
}
|
|
371
|
-
const definition = line.match(/^ {0,3}\[([^\]\n]+)\]:[ \t]*(\S+)[ \t]*$/);
|
|
371
|
+
const definition = line.match(/^ {0,3}\[([^\]\n]+)\]:[ \t]*(\S+)(?:[ \t]+(?:"([^"]*)"|'([^']*)'|\(([^)]*)\)))?[ \t]*$/);
|
|
372
372
|
if (definition) {
|
|
373
|
-
|
|
373
|
+
const title = definition[3] ?? definition[4] ?? definition[5];
|
|
374
|
+
references[normalizeReferenceLabel(definition[1])] = {
|
|
375
|
+
href: definition[2].replace(/^<|>$/g, ''),
|
|
376
|
+
...(title !== undefined ? { title } : {}),
|
|
377
|
+
};
|
|
374
378
|
index++;
|
|
375
379
|
continue;
|
|
376
380
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/markdown",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A tiny, fast, deterministic Markdown renderer for blogs and documentation.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"types": "./dist/react.d.ts",
|
|
28
28
|
"import": "./dist/react.js"
|
|
29
29
|
},
|
|
30
|
+
"./octane": {
|
|
31
|
+
"types": "./dist/octane.d.ts",
|
|
32
|
+
"import": "./dist/octane.js"
|
|
33
|
+
},
|
|
30
34
|
"./extensions/callouts": {
|
|
31
35
|
"types": "./dist/extensions/callouts.d.ts",
|
|
32
36
|
"import": "./dist/extensions/callouts.js"
|
|
@@ -56,9 +60,13 @@
|
|
|
56
60
|
"access": "public"
|
|
57
61
|
},
|
|
58
62
|
"peerDependencies": {
|
|
63
|
+
"octane": ">=0.1.12",
|
|
59
64
|
"react": ">=18"
|
|
60
65
|
},
|
|
61
66
|
"peerDependenciesMeta": {
|
|
67
|
+
"octane": {
|
|
68
|
+
"optional": true
|
|
69
|
+
},
|
|
62
70
|
"react": {
|
|
63
71
|
"optional": true
|
|
64
72
|
}
|
|
@@ -74,6 +82,7 @@
|
|
|
74
82
|
"markdown-wasm": "^1.2.0",
|
|
75
83
|
"marked": "^18.0.5",
|
|
76
84
|
"micromark": "^4.0.2",
|
|
85
|
+
"octane": "0.1.12",
|
|
77
86
|
"react": "^19.0.0",
|
|
78
87
|
"react-dom": "^19.0.0",
|
|
79
88
|
"rehype-stringify": "^10.0.1",
|
|
@@ -89,10 +98,11 @@
|
|
|
89
98
|
"typecheck": "tsc --noEmit",
|
|
90
99
|
"test": "vitest run",
|
|
91
100
|
"test:corpus": "vitest run tests/corpus.test.tsx",
|
|
101
|
+
"docs:verify": "node scripts/verify-docs.mjs",
|
|
92
102
|
"conformance": "tsx scripts/conformance.ts",
|
|
93
103
|
"bench": "tsx scripts/bench.ts",
|
|
94
104
|
"size": "tsx scripts/measure-size.ts",
|
|
95
105
|
"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"
|
|
106
|
+
"verify": "pnpm test && pnpm run typecheck && pnpm run build && pnpm run docs:verify && pnpm run research && pnpm pack --dry-run"
|
|
97
107
|
}
|
|
98
108
|
}
|