satteri 0.1.1 → 0.1.3

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 CHANGED
@@ -1,7 +1,301 @@
1
1
  # satteri
2
2
 
3
- TypeScript layer with readers, visitors, materializers, and plugin system for Sätteri, a high-performance Markdown and MDX processor.
3
+ Native-enhanced Markdown parsing and processing for JavaScript. Parse and compile in Rust, create flexible plugins in JavaScript.
4
4
 
5
- > [!NOTE]
6
- > **Work in progress** — this package is under active development.
7
- > See the [Contributing Guide](../../CONTRIBUTING.md) if you want to get involved!
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install satteri
9
+ yarn add satteri
10
+ pnpm add satteri
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Markdown to HTML
16
+
17
+ ```ts
18
+ import { markdownToHtml } from "satteri";
19
+
20
+ const html = markdownToHtml("# Hello\n\nWorld");
21
+ // <h1>Hello</h1>\n<p>World</p>
22
+ ```
23
+
24
+ ### MDX to JS
25
+
26
+ ```ts
27
+ import { mdxToJs } from "satteri";
28
+
29
+ const js = mdxToJs("# Hello\n\n<MyComponent />");
30
+ ```
31
+
32
+ ### With plugins
33
+
34
+ Both functions accept `mdastPlugins` (operate on the Markdown AST before conversion to HAST) and `hastPlugins` (operate on the HAST before output).
35
+
36
+ ```ts
37
+ import { markdownToHtml } from "satteri";
38
+ import { removeHeadings } from "./my-mdast-plugins.js";
39
+ import { addLinkClasses } from "./my-hast-plugins.js";
40
+
41
+ const html = markdownToHtml("# Hello\n\n[link](https://example.com)", {
42
+ mdastPlugins: [removeHeadings],
43
+ hastPlugins: [addLinkClasses],
44
+ });
45
+ ```
46
+
47
+ If you're familiar with the unified ecosystem, mdast and hast plugins would be similar to remark and rehype plugins, respectively, and re-uses the same AST shape for both. This project does not currently have an equivalent of micromark or recma plugins.
48
+
49
+ ## Plugins
50
+
51
+ ### MDAST plugins
52
+
53
+ MDAST plugins run on the Markdown syntax tree, allowing you to do things like replace emoji shortcodes, unwrap images from paragraphs, or collect headings for a table of contents before Markdown is transformed to HTML / JS. Define visitor methods named after node types (`heading`, `code`, `link`, `image`, etc.). Each visitor receives the node and a context object for mutations.
54
+
55
+ ```ts
56
+ const emojis = defineMdastPlugin({
57
+ name: "emojis",
58
+ text(node, ctx) {
59
+ if (node.value.includes(":wave:")) {
60
+ ctx.setProperty(node, "value", node.value.replaceAll(":wave:", "\u{1F44B}"));
61
+ }
62
+ },
63
+ });
64
+ ```
65
+
66
+ Visitors can alternatively return a replacement node, raw Markdown, or raw HTML. This is useful when the replacement can't be expressed as property changes on the original node:
67
+
68
+ ```ts
69
+ const highlightCode = defineMdastPlugin({
70
+ name: "highlight-code",
71
+ code(node) {
72
+ return { rawHtml: `<pre class="highlighted">${escape(node.value)}</pre>` };
73
+ },
74
+ });
75
+ ```
76
+
77
+ All standard mdast node types are supported, plus GFM extensions (`table`, `tableRow`, `tableCell`, `delete`, `footnoteDefinition`, `footnoteReference`) and MDX nodes (`mdxJsxFlowElement`, `mdxJsxTextElement`, `mdxFlowExpression`, `mdxTextExpression`, `mdxjsEsm`) if enabled. For more information on the AST shape and node types, see the [mdast spec](https://github.com/syntax-tree/mdast).
78
+
79
+ ### HAST plugins
80
+
81
+ HAST plugins run on the HTML syntax tree after mdast-to-hast conversion, allowing you to do things like add classes to elements, set attributes on links, or wrap HTML elements with other elements, etc. Element visitors use a `filter` array to specify which tag names (or component names for MDX) to match.
82
+
83
+ ```ts
84
+ const addLinkClasses = defineHastPlugin({
85
+ name: "add-link-classes",
86
+ element: {
87
+ filter: ["a"],
88
+ visit(node, ctx) {
89
+ ctx.setProperty(node, "class", "link");
90
+ ctx.setProperty(node, "target", "_blank");
91
+ },
92
+ },
93
+ });
94
+ ```
95
+
96
+ Multiple filter groups on the same node type:
97
+
98
+ ```ts
99
+ const multiFilter = defineHastPlugin({
100
+ name: "multi-filter",
101
+ element: [
102
+ {
103
+ filter: ["h1", "h2", "h3"],
104
+ visit(node, ctx) {
105
+ ctx.setProperty(node, "class", "heading");
106
+ },
107
+ },
108
+ {
109
+ filter: ["a"],
110
+ visit(node, ctx) {
111
+ ctx.setProperty(node, "target", "_blank");
112
+ },
113
+ },
114
+ ],
115
+ });
116
+ ```
117
+
118
+ An empty filter matches all elements, but can quickly become expensive when used on large documents, so use with caution:
119
+
120
+ ```ts
121
+ const allElements = defineHastPlugin({
122
+ name: "all-elements",
123
+ element: {
124
+ filter: [],
125
+ visit(node, ctx) {
126
+ ctx.setProperty(node, "data-visited", "true");
127
+ },
128
+ },
129
+ });
130
+ ```
131
+
132
+ Non-element visitors (`text`, `comment`, `raw`, `doctype`, MDX expression types) use bare functions instead of filter objects:
133
+
134
+ ```ts
135
+ const uppercaseText = defineHastPlugin({
136
+ name: "uppercase-text",
137
+ text(node, ctx) {
138
+ ctx.setProperty(node, "value", node.value.toUpperCase());
139
+ },
140
+ });
141
+ ```
142
+
143
+ For more information on the AST shape and node types, see the [hast spec](https://github.com/syntax-tree/hast).
144
+
145
+ ### Mutating nodes
146
+
147
+ Unlike remark and rehype plugins, nodes in Sätteri inside plugins are read-only. The AST lives in Rust memory and JavaScript only has a "view" over the different nodes, so direct mutations like `node.value = "new text"` have no effect. Use the context methods (`ctx.setProperty`, `ctx.removeNode`, `ctx.replaceNode`, etc.) instead, which send changes back to Rust in an efficient way.
148
+
149
+ ```ts
150
+ // Won't work
151
+ heading(node, ctx) {
152
+ node.depth = 2; // no effect, TypeScript will also complain that the node is readonly
153
+ }
154
+
155
+ // Do this instead
156
+ heading(node, ctx) {
157
+ ctx.setProperty(node, "depth", 2);
158
+ }
159
+
160
+ // Or return a new node to replace it entirely, but this is less efficient and generally not recommended
161
+ heading(node) {
162
+ return { ..node, depth: 2 };
163
+ }
164
+ ```
165
+
166
+ ### Async plugins
167
+
168
+ Visitors can optionally be async. When any visitor is async, `markdownToHtml` and `mdxToJs` return a `Promise<string>` instead of `string`. For performance reasons, it is typically best to avoid async visitors, especially if your visitor matches a large number of nodes.
169
+
170
+ ````ts
171
+ const highlighter = await createHighlighter({ themes: ["github-dark"], langs: ["js", "ts"] });
172
+
173
+ const asyncHighlight = defineMdastPlugin({
174
+ name: "async-highlight",
175
+ async code(node) {
176
+ const html = await highlighter.codeToHtml(node.value, {
177
+ lang: node.lang,
178
+ theme: "github-dark",
179
+ });
180
+ return { rawHtml: html };
181
+ },
182
+ });
183
+
184
+ // Returns Promise<string> when async plugins are used
185
+ const html = await markdownToHtml("```js\ncode\n```", {
186
+ mdastPlugins: [asyncHighlight],
187
+ });
188
+ ````
189
+
190
+ ## API
191
+
192
+ ### `markdownToHtml(source: string, options?: CompileOptions)`
193
+
194
+ Parse Markdown and compile to HTML. Returns `string` if all plugins are sync, `Promise<string>` if any are async.
195
+
196
+ ```ts
197
+ const html = markdownToHtml("# Hello\n\nWorld");
198
+ // <h1>Hello</h1>\n<p>World</p>
199
+ ```
200
+
201
+ ### `mdxToJs(source: string, options?: MdxCompileOptions)`
202
+
203
+ Parse MDX and compile to JavaScript module code. Same sync/async return behavior.
204
+
205
+ ```ts
206
+ const js = mdxToJs("# Hello\n\n<MyComponent />");
207
+ ```
208
+
209
+ #### Static optimization
210
+
211
+ The `optimizeStatic` option for MDX collapses static subtrees into pre-rendered HTML strings, reducing the number of JSX element calls in the output and increasing rendering performance. Dynamic content (JSX components, expressions) is preserved as normal JSX calls.
212
+
213
+ ```ts
214
+ // Astro-style: wraps static HTML in <Fragment set:html="...">
215
+ const js = mdxToJs("# Hello\n\nWorld", {
216
+ optimizeStatic: {
217
+ component: "Fragment",
218
+ prop: "set:html",
219
+ },
220
+ });
221
+
222
+ // React-style: wraps in <div dangerouslySetInnerHTML={{ __html: "..." }}>
223
+ const js = mdxToJs("# Hello\n\nWorld", {
224
+ optimizeStatic: {
225
+ component: "div",
226
+ prop: "dangerouslySetInnerHTML",
227
+ wrapPropValue: true,
228
+ },
229
+ });
230
+ ```
231
+
232
+ The `ignoreElements` option can be used to exclude specific elements from collapsing.
233
+
234
+ ### `markdownToMdast(source: string)`
235
+
236
+ Parse Markdown and return a complete mdast tree. This can be useful if you wanted to benefit from the fast native parsing of Sätteri, but ultimately wanted another pipeline to handle transformations and compilation, e.g. using remark plugins and `remark-stringify` to convert back to Markdown after processing.
237
+
238
+ ```ts
239
+ import { markdownToMdast } from "satteri";
240
+
241
+ const tree = markdownToMdast("# Hello\n\nWorld");
242
+ // tree.children[0].type === "heading"
243
+ // tree.children[0].depth === 1
244
+ ```
245
+
246
+ ### `mdxToMdast(source: string)`
247
+
248
+ Parse MDX and return a complete mdast tree.
249
+
250
+ ```ts
251
+ const tree = mdxToMdast('<Component foo="bar" />');
252
+ // tree.children[0].type === "mdxJsxFlowElement"
253
+ // tree.children[0].name === "Component"
254
+ ```
255
+
256
+ ### `markdownToHast(source: string)`
257
+
258
+ Parse Markdown, convert to hast, and return a complete hast tree.
259
+
260
+ ```ts
261
+ const tree = markdownToHast("# Hello\n\nWorld");
262
+ // tree.children[0].type === "element"
263
+ // tree.children[0].tagName === "h1"
264
+ ```
265
+
266
+ ### `mdxToHast(source: string)`
267
+
268
+ Parse MDX, convert to hast, and return a complete hast tree.
269
+
270
+ ```ts
271
+ const tree = mdxToHast("<MyComponent />");
272
+ // tree.children[0].type === "mdxJsxFlowElement"
273
+ // tree.children[0].name === "MyComponent"
274
+ ```
275
+
276
+ ### `defineMdastPlugin(definition: MdastPluginDefinition)`
277
+
278
+ Type-safe wrapper for MDAST plugin definitions.
279
+
280
+ ### `defineHastPlugin(definition: HastPluginDefinition)`
281
+
282
+ Type-safe wrapper for HAST plugin definitions.
283
+
284
+ ### `CompileOptions`
285
+
286
+ ```ts
287
+ interface CompileOptions {
288
+ mdastPlugins?: MdastPluginDefinition[];
289
+ hastPlugins?: HastPluginDefinition[];
290
+ filename?: string;
291
+ }
292
+
293
+ // mdxToJs accepts MdxCompileOptions, which extends CompileOptions
294
+ interface MdxCompileOptions extends CompileOptions {
295
+ optimizeStatic?: OptimizeStaticConfig;
296
+ }
297
+ ```
298
+
299
+ ## License
300
+
301
+ MIT
@@ -40,7 +40,6 @@ export function classifyReturn(value) {
40
40
  return "structured_node";
41
41
  throw new Error("Invalid return value from visitor: must have raw, rawHtml, or type");
42
42
  }
43
- // CommandBuffer
44
43
  const INITIAL_SIZE = 4096;
45
44
  const encoder = new TextEncoder();
46
45
  const EMPTY_U8 = new Uint8Array(0);
package/dist/compile.d.ts CHANGED
@@ -1,10 +1,5 @@
1
- /**
2
- * Top-level compile functions, the primary public API.
3
- *
4
- * Both MDAST and HAST arenas stay in Rust memory via opaque handles.
5
- * Only matched nodes and mutation commands cross the NAPI boundary.
6
- */
7
1
  import type { MdastPluginDefinition, HastPluginDefinition } from "./plugin.js";
2
+ import type { MdastNode, HastNode } from "./types.js";
8
3
  /** Configuration for static subtree collapsing during MDX compilation. */
9
4
  export interface OptimizeStaticConfig {
10
5
  component: string;
@@ -15,8 +10,18 @@ export interface OptimizeStaticConfig {
15
10
  export interface CompileOptions {
16
11
  mdastPlugins?: MdastPluginDefinition[];
17
12
  hastPlugins?: HastPluginDefinition[];
18
- optimizeStatic?: OptimizeStaticConfig;
19
13
  filename?: string;
20
14
  }
21
- export declare function compileMarkdownToHtml(source: string, options?: CompileOptions): string | Promise<string>;
22
- export declare function compileMdxToJs(source: string, options?: CompileOptions): string | Promise<string>;
15
+ export interface MdxCompileOptions extends CompileOptions {
16
+ optimizeStatic?: OptimizeStaticConfig;
17
+ }
18
+ export declare function markdownToHtml(source: string, options?: CompileOptions): string | Promise<string>;
19
+ export declare function mdxToJs(source: string, options?: MdxCompileOptions): string | Promise<string>;
20
+ /** Parse Markdown source into a materialized mdast tree. */
21
+ export declare function markdownToMdast(source: string): MdastNode;
22
+ /** Parse MDX source into a materialized mdast tree. */
23
+ export declare function mdxToMdast(source: string): MdastNode;
24
+ /** Convert Markdown source to a materialized hast tree. */
25
+ export declare function markdownToHast(source: string): HastNode;
26
+ /** Convert MDX source to a materialized hast tree. */
27
+ export declare function mdxToHast(source: string): HastNode;
package/dist/compile.js CHANGED
@@ -1,37 +1,27 @@
1
- /**
2
- * Top-level compile functions, the primary public API.
3
- *
4
- * Both MDAST and HAST arenas stay in Rust memory via opaque handles.
5
- * Only matched nodes and mutation commands cross the NAPI boundary.
6
- */
7
1
  import { visitHastHandle, resolveSubscriptions } from "./hast/hast-visitor.js";
8
2
  import { visitMdastHandle, resolveMdastSubscriptions, } from "./mdast/mdast-visitor.js";
9
- import { parseToHtml, compileMdx, createHastHandle, createMdxHastHandle, renderHandle, compileHandle, applyCommandsToHandle, dropHandle, createMdastHandle, createMdxMdastHandle, applyCommandsToMdastHandle, convertMdastToHastHandle, applyCommandsAndConvertToHastHandle, getHandleSource, } from "../index.js";
10
- // Helpers
11
- function initPlugins(plugins) {
12
- return plugins.map((def) => ({
13
- instance: def.createOnce(),
14
- name: def.name,
15
- }));
16
- }
3
+ import { parseToHtml, compileMdx, createHastHandle, createMdxHastHandle, renderHandle, compileHandle, applyCommandsToHandle, dropHandle, createMdastHandle, createMdxMdastHandle, applyCommandsToMdastHandle, convertMdastToHastHandle, applyCommandsAndConvertToHastHandle, getHandleSource, serializeHandle, serializeMdastHandle, } from "../index.js";
4
+ import { ArenaReader } from "./mdast/mdast-reader.js";
5
+ import { materializeTree } from "./mdast/mdast-materializer.js";
6
+ import { HastReader } from "./hast/hast-reader.js";
7
+ import { materializeHastTree } from "./hast/hast-materializer.js";
17
8
  function runMdastPluginsOnHandle(handle, plugins, filename) {
18
- const instances = initPlugins(plugins);
19
9
  let pendingCommands = null;
20
10
  const source = getHandleSource(handle);
21
11
  let i = 0;
22
12
  const runNext = () => {
23
- while (i < instances.length) {
13
+ while (i < plugins.length) {
24
14
  const idx = i++;
25
- const { instance } = instances[idx];
26
- const subs = resolveMdastSubscriptions(instance);
27
- const result = visitMdastHandle(handle, instance, subs, source, filename);
15
+ const plugin = plugins[idx];
16
+ const subs = resolveMdastSubscriptions(plugin);
17
+ const result = visitMdastHandle(handle, plugin, subs, source, filename);
28
18
  if (result instanceof Promise) {
29
19
  return result.then((r) => {
30
- applyMdastResult(r, idx, instances.length, handle);
20
+ applyMdastResult(r, idx, plugins.length, handle);
31
21
  return runNext();
32
22
  });
33
23
  }
34
- applyMdastResult(result, idx, instances.length, handle);
24
+ applyMdastResult(result, idx, plugins.length, handle);
35
25
  }
36
26
  return { handle, pendingCommands };
37
27
  };
@@ -47,18 +37,16 @@ function runMdastPluginsOnHandle(handle, plugins, filename) {
47
37
  }
48
38
  return runNext();
49
39
  }
50
- // HAST plugin runner (handle-based)
51
40
  function runHastPluginsOnHandle(handle, plugins, source, filename) {
52
41
  if (plugins.length === 0)
53
42
  return;
54
- const instances = initPlugins(plugins);
55
43
  let i = 0;
56
44
  const runNext = () => {
57
- while (i < instances.length) {
58
- const { instance } = instances[i];
45
+ while (i < plugins.length) {
46
+ const plugin = plugins[i];
59
47
  i++;
60
- const subs = resolveSubscriptions(instance);
61
- const result = visitHastHandle(handle, instance, subs, source, filename);
48
+ const subs = resolveSubscriptions(plugin);
49
+ const result = visitHastHandle(handle, plugin, subs, source, filename);
62
50
  if (result instanceof Promise) {
63
51
  return result.then(runNext);
64
52
  }
@@ -66,7 +54,7 @@ function runHastPluginsOnHandle(handle, plugins, source, filename) {
66
54
  };
67
55
  return runNext();
68
56
  }
69
- export function compileMarkdownToHtml(source, options = {}) {
57
+ export function markdownToHtml(source, options = {}) {
70
58
  const { mdastPlugins = [], hastPlugins = [], filename = "<unknown>" } = options;
71
59
  if (mdastPlugins.length === 0 && hastPlugins.length === 0) {
72
60
  return parseToHtml(source);
@@ -90,7 +78,7 @@ export function compileMarkdownToHtml(source, options = {}) {
90
78
  }
91
79
  return finish(handleResult);
92
80
  }
93
- export function compileMdxToJs(source, options = {}) {
81
+ export function mdxToJs(source, options = {}) {
94
82
  const { mdastPlugins = [], hastPlugins = [], optimizeStatic, filename = "<unknown>" } = options;
95
83
  const mdxOptions = optimizeStatic ? { optimizeStatic } : undefined;
96
84
  if (mdastPlugins.length === 0 && hastPlugins.length === 0) {
@@ -135,3 +123,30 @@ function createHastHandleFromMdast(source, mdastPlugins, mdx, filename) {
135
123
  }
136
124
  return convert(mdastResult);
137
125
  }
126
+ // Step-by-step API: individual pipeline stages with materialized trees
127
+ /** Parse Markdown source into a materialized mdast tree. */
128
+ export function markdownToMdast(source) {
129
+ const handle = createMdastHandle(source);
130
+ const buf = serializeMdastHandle(handle);
131
+ return materializeTree(new ArenaReader(buf));
132
+ }
133
+ /** Parse MDX source into a materialized mdast tree. */
134
+ export function mdxToMdast(source) {
135
+ const handle = createMdxMdastHandle(source);
136
+ const buf = serializeMdastHandle(handle);
137
+ return materializeTree(new ArenaReader(buf));
138
+ }
139
+ /** Convert Markdown source to a materialized hast tree. */
140
+ export function markdownToHast(source) {
141
+ const handle = createHastHandle(source);
142
+ const buf = serializeHandle(handle);
143
+ dropHandle(handle);
144
+ return materializeHastTree(new HastReader(buf));
145
+ }
146
+ /** Convert MDX source to a materialized hast tree. */
147
+ export function mdxToHast(source) {
148
+ const handle = createMdxHastHandle(source);
149
+ const buf = serializeHandle(handle);
150
+ dropHandle(handle);
151
+ return materializeHastTree(new HastReader(buf));
152
+ }
@@ -15,19 +15,19 @@ export interface HastDiagnostic {
15
15
  export interface HastVisitorContext {
16
16
  readonly source: string;
17
17
  readonly filename: string;
18
- removeNode(node: HastNode): void;
19
- replaceNode(node: HastNode, newNode: HastNode): void;
20
- insertBefore(node: HastNode, newNode: HastNode): void;
21
- insertAfter(node: HastNode, newNode: HastNode): void;
22
- wrapNode(node: HastNode, parentNode: HastNode): void;
23
- prependChild(node: HastNode, childNode: HastNode): void;
24
- appendChild(node: HastNode, childNode: HastNode): void;
25
- setProperty(node: HastNode, key: string, value: unknown): void;
18
+ removeNode(node: Readonly<HastNode>): void;
19
+ replaceNode(node: Readonly<HastNode>, newNode: HastNode): void;
20
+ insertBefore(node: Readonly<HastNode>, newNode: HastNode): void;
21
+ insertAfter(node: Readonly<HastNode>, newNode: HastNode): void;
22
+ wrapNode(node: Readonly<HastNode>, parentNode: HastNode): void;
23
+ prependChild(node: Readonly<HastNode>, childNode: HastNode): void;
24
+ appendChild(node: Readonly<HastNode>, childNode: HastNode): void;
25
+ setProperty(node: Readonly<HastNode>, key: string, value: unknown): void;
26
26
  /** Collect the concatenated text of all descendant text nodes (like DOM textContent). */
27
- textContent(node: HastNode): string;
27
+ textContent(node: Readonly<HastNode>): string;
28
28
  report(opts: {
29
29
  message: string;
30
- node?: HastNode;
30
+ node?: Readonly<HastNode>;
31
31
  severity?: "error" | "warning" | "info";
32
32
  }): void;
33
33
  getDiagnostics(): HastDiagnostic[];
@@ -35,9 +35,9 @@ export interface HastVisitorContext {
35
35
  /** A filtered visitor: Rust filters by tag/component name, only matched nodes cross the boundary. */
36
36
  export interface HastFilteredVisitor<N extends HastNode = HastNode> {
37
37
  filter: string[];
38
- visit(node: N, ctx: HastVisitorContext): HastNode | void | Promise<HastNode | void>;
38
+ visit(node: Readonly<N>, ctx: HastVisitorContext): HastNode | void | Promise<HastNode | void>;
39
39
  }
40
- type HastVisitorFn<N extends HastNode = HastNode> = (node: N, ctx: HastVisitorContext) => HastNode | void | Promise<HastNode | void>;
40
+ type HastVisitorFn<N extends HastNode = HastNode> = (node: Readonly<N>, ctx: HastVisitorContext) => HastNode | void | Promise<HastNode | void>;
41
41
  export interface HastVisitorInstance {
42
42
  element?: HastFilteredVisitor<Element> | HastFilteredVisitor<Element>[];
43
43
  mdxJsxFlowElement?: HastFilteredVisitor<MdxJsxFlowElementHast> | HastFilteredVisitor<MdxJsxFlowElementHast>[];
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { compileMarkdownToHtml, compileMdxToJs } from "./compile.js";
2
- export type { CompileOptions, OptimizeStaticConfig } from "./compile.js";
1
+ export { markdownToHtml, mdxToJs, markdownToMdast, mdxToMdast, markdownToHast, mdxToHast, } from "./compile.js";
2
+ export type { CompileOptions, MdxCompileOptions, OptimizeStaticConfig } from "./compile.js";
3
3
  export { defineMdastPlugin, defineHastPlugin } from "./plugin.js";
4
4
  export type { MdastPluginDefinition, HastPluginDefinition } from "./plugin.js";
5
5
  export type { HastVisitorInstance, HastVisitorContext, HastFilteredVisitor, EstreeProgram, } from "./hast/hast-visitor.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // Public API: compile functions
2
- export { compileMarkdownToHtml, compileMdxToJs } from "./compile.js";
2
+ export { markdownToHtml, mdxToJs, markdownToMdast, mdxToMdast, markdownToHast, mdxToHast, } from "./compile.js";
3
3
  // Plugin definitions
4
4
  export { defineMdastPlugin, defineHastPlugin } from "./plugin.js";
@@ -15,22 +15,22 @@ export declare class MdastVisitorContext {
15
15
  readonly source: string;
16
16
  readonly filename: string;
17
17
  constructor(handle: MdastHandle, source: string, filename: string);
18
- removeNode(node: MdastNode): void;
19
- insertBefore(node: MdastNode, newNode: MdastNode): void;
20
- insertAfter(node: MdastNode, newNode: MdastNode): void;
21
- wrapNode(node: MdastNode, parentNode: MdastNode): void;
22
- prependChild(node: MdastNode, childNode: MdastNode): void;
23
- appendChild(node: MdastNode, childNode: MdastNode): void;
24
- replaceNode(node: MdastNode, newNode: MdastNode): void;
25
- setProperty(node: MdastNode, key: string, value: unknown): void;
18
+ removeNode(node: Readonly<MdastNode>): void;
19
+ insertBefore(node: Readonly<MdastNode>, newNode: MdastNode): void;
20
+ insertAfter(node: Readonly<MdastNode>, newNode: MdastNode): void;
21
+ wrapNode(node: Readonly<MdastNode>, parentNode: MdastNode): void;
22
+ prependChild(node: Readonly<MdastNode>, childNode: MdastNode): void;
23
+ appendChild(node: Readonly<MdastNode>, childNode: MdastNode): void;
24
+ replaceNode(node: Readonly<MdastNode>, newNode: MdastNode): void;
25
+ setProperty<N extends MdastNode, K extends keyof N & string>(node: Readonly<N>, key: K, value: N[K]): void;
26
26
  /** Collect the concatenated text of all descendant text nodes (like mdast-util-to-string). */
27
- textContent(node: MdastNode, options?: {
27
+ textContent(node: Readonly<MdastNode>, options?: {
28
28
  includeImageAlt?: boolean;
29
29
  includeHtml?: boolean;
30
30
  }): string;
31
31
  report({ message, node, severity, }: {
32
32
  message: string;
33
- node?: MdastNode;
33
+ node?: Readonly<MdastNode>;
34
34
  severity?: "error" | "warning" | "info";
35
35
  }): void;
36
36
  /** Get the binary command buffer for all mutations recorded via context methods. */
@@ -42,7 +42,7 @@ type MdastVisitorResult = MdastNode | {
42
42
  } | {
43
43
  rawHtml: string;
44
44
  } | undefined | null | void;
45
- type MdastVisitorFn<N extends MdastNode = MdastNode> = (node: N, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
45
+ type MdastVisitorFn<N extends MdastNode = MdastNode> = (node: Readonly<N>, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
46
46
  export interface MdastPluginInstance {
47
47
  root?: MdastVisitorFn<Root>;
48
48
  paragraph?: MdastVisitorFn<Paragraph>;
@@ -1,7 +1,7 @@
1
1
  import { materializeNode, TYPE_NAMES } from "./mdast-materializer.js";
2
2
  import { ArenaReader } from "./mdast-reader.js";
3
3
  import { CommandBuffer, classifyReturn } from "../command-buffer.js";
4
- import { walkMdastHandle, serializeMdastHandle, getNodeData as napiGetNodeData, setNodeData, mdastTextContentHandle, } from "../../index.js";
4
+ import { walkMdastHandle, serializeMdastHandle, getNodeData as napiGetNodeData, mdastTextContentHandle, } from "../../index.js";
5
5
  const MutationType = {
6
6
  Replace: "replace",
7
7
  Remove: "remove",
@@ -86,6 +86,11 @@ export class MdastVisitorContext {
86
86
  this.#commandBuffer.replace(nid(node), newNode);
87
87
  }
88
88
  setProperty(node, key, value) {
89
+ if (key === "data") {
90
+ // data is stored as JSON in the arena, serialize it for the command buffer
91
+ this.#commandBuffer.setProperty(nid(node), key, value != null ? JSON.stringify(value) : null);
92
+ return;
93
+ }
89
94
  this.#commandBuffer.setProperty(nid(node), key, value);
90
95
  }
91
96
  /** Collect the concatenated text of all descendant text nodes (like mdast-util-to-string). */
@@ -209,7 +214,7 @@ class MdastLazyChildResolver {
209
214
  * [node_data: u32+bytes][position: 6×u32 = 24B][child_count: u16][child_ids: N×u32][type-specific data]
210
215
  */
211
216
  const encoder = new TextEncoder();
212
- function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, dirtyData, resolver) {
217
+ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, resolver) {
213
218
  let pos = dataOffset;
214
219
  // Node data (JSON bytes), always first
215
220
  const dataJsonLen = ru32(view, pos);
@@ -452,26 +457,9 @@ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, dirtyData
452
457
  // strong(12), break(14), tableRow(22), tableCell(23), delete(24): no extra data
453
458
  }
454
459
  mdastNodeIdMap.set(node, nodeId);
455
- // Read inline node_data JSON from the end of the data section.
456
- // The Rust serializer always appends [json_len: u32][json_bytes...] at the end.
457
- // We need to find it by reading from dataEnd backwards.
458
- // Actually, we read it at `dataOffset + dataLen - (4 + jsonDataLen)` but we don't
459
- // know jsonDataLen yet. Instead, the data section ends with [len: u32][bytes...],
460
- // so we scan from the current end of type-specific data.
461
- // For simplicity, we'll handle this in the caller which knows the full data_len.
462
- // Set up data getter/setter that tracks dirty entries
463
- let currentData = initialData;
464
- Object.defineProperty(node, "data", {
465
- get() {
466
- return currentData;
467
- },
468
- set(value) {
469
- currentData = value;
470
- dirtyData.set(nodeId, value);
471
- },
472
- configurable: true,
473
- enumerable: true,
474
- });
460
+ if (initialData) {
461
+ node.data = initialData;
462
+ }
475
463
  return node;
476
464
  }
477
465
  /** Apply a sync visitor result to the return buffer.
@@ -505,7 +493,6 @@ function applyMdastVisitResult(result, nodeId, returnBuffer, originalNode) {
505
493
  export function visitMdastHandle(handle, plugin, subs, source, filename) {
506
494
  const context = new MdastVisitorContext(handle, source, filename);
507
495
  const returnBuffer = new CommandBuffer();
508
- const dirtyData = new Map();
509
496
  const resolver = new MdastLazyChildResolver(handle);
510
497
  const rustSubs = subs.map((s) => ({ nodeType: s.nodeType, tagFilter: [] }));
511
498
  const matchBuf = walkMdastHandle(handle, rustSubs);
@@ -518,7 +505,7 @@ export function visitMdastHandle(handle, plugin, subs, source, filename) {
518
505
  const subIndex = matchBuf[indexBase + 4];
519
506
  const dataOffset = ru32(matchView, indexBase + 6);
520
507
  const sub = subs[subIndex];
521
- const node = readMdastMatchedNode(matchView, matchBuf, dataOffset, nodeId, sub.nodeType, dirtyData, resolver);
508
+ const node = readMdastMatchedNode(matchView, matchBuf, dataOffset, nodeId, sub.nodeType, resolver);
522
509
  const result = sub.visitFn.call(plugin, node, context);
523
510
  if (result instanceof Promise) {
524
511
  deferred ??= [];
@@ -533,16 +520,12 @@ export function visitMdastHandle(handle, plugin, subs, source, filename) {
533
520
  for (const { nodeId, result, originalNode } of results) {
534
521
  applyMdastVisitResult(result, nodeId, returnBuffer, originalNode);
535
522
  }
536
- return finalizeMdastVisit(handle, context, returnBuffer, dirtyData);
523
+ return finalizeMdastVisit(handle, context, returnBuffer);
537
524
  });
538
525
  }
539
- return finalizeMdastVisit(handle, context, returnBuffer, dirtyData);
526
+ return finalizeMdastVisit(handle, context, returnBuffer);
540
527
  }
541
- function finalizeMdastVisit(handle, context, returnBuffer, dirtyData) {
542
- for (const [id, value] of dirtyData) {
543
- const json = value ? JSON.stringify(value) : "";
544
- setNodeData(handle, id, encoder.encode(json));
545
- }
528
+ function finalizeMdastVisit(handle, context, returnBuffer) {
546
529
  const { merged, hasMutations } = mergeAndReset(returnBuffer, context);
547
530
  return { commandBuffer: merged, diagnostics: context.getDiagnostics(), hasMutations };
548
531
  }
package/dist/plugin.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  import type { MdastPluginInstance } from "./mdast/mdast-visitor.js";
2
2
  import type { HastVisitorInstance } from "./hast/hast-visitor.js";
3
- export interface MdastPluginDefinition {
3
+ export type MdastPluginDefinition = MdastPluginInstance & {
4
4
  name: string;
5
- createOnce(): MdastPluginInstance;
6
- }
7
- export interface HastPluginDefinition {
5
+ };
6
+ export type HastPluginDefinition = HastVisitorInstance & {
8
7
  name: string;
9
- createOnce(): HastVisitorInstance;
10
- }
8
+ };
11
9
  export declare function defineMdastPlugin(definition: MdastPluginDefinition): MdastPluginDefinition;
12
10
  export declare function defineHastPlugin(definition: HastPluginDefinition): HastPluginDefinition;
package/dist/plugin.js CHANGED
@@ -2,17 +2,11 @@ export function defineMdastPlugin(definition) {
2
2
  if (!definition.name) {
3
3
  throw new Error("Plugin definition must have a name");
4
4
  }
5
- if (typeof definition.createOnce !== "function") {
6
- throw new Error("Plugin definition must have a createOnce function");
7
- }
8
5
  return definition;
9
6
  }
10
7
  export function defineHastPlugin(definition) {
11
8
  if (!definition.name) {
12
9
  throw new Error("Plugin definition must have a name");
13
10
  }
14
- if (typeof definition.createOnce !== "function") {
15
- throw new Error("Plugin definition must have a createOnce function");
16
- }
17
11
  return definition;
18
12
  }
package/dist/types.js CHANGED
@@ -1,5 +1 @@
1
- // Shared types for the satteri JS layer.
2
- //
3
- // Uses standard @types/mdast, @types/hast, and mdast-util-mdx-* packages
4
- // for AST node types. Extension types (toml, math, raw) are augmented here.
5
1
  export {};
package/index.js CHANGED
@@ -81,8 +81,8 @@ function requireNative() {
81
81
  try {
82
82
  const binding = require('@bruits/satteri-android-arm64')
83
83
  const bindingPackageVersion = require('@bruits/satteri-android-arm64/package.json').version
84
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
85
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
84
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
85
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
86
86
  }
87
87
  return binding
88
88
  } catch (e) {
@@ -97,8 +97,8 @@ function requireNative() {
97
97
  try {
98
98
  const binding = require('@bruits/satteri-android-arm-eabi')
99
99
  const bindingPackageVersion = require('@bruits/satteri-android-arm-eabi/package.json').version
100
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
101
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
100
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
101
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
102
102
  }
103
103
  return binding
104
104
  } catch (e) {
@@ -118,8 +118,8 @@ function requireNative() {
118
118
  try {
119
119
  const binding = require('@bruits/satteri-win32-x64-gnu')
120
120
  const bindingPackageVersion = require('@bruits/satteri-win32-x64-gnu/package.json').version
121
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
122
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
121
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
122
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
123
123
  }
124
124
  return binding
125
125
  } catch (e) {
@@ -134,8 +134,8 @@ function requireNative() {
134
134
  try {
135
135
  const binding = require('@bruits/satteri-win32-x64-msvc')
136
136
  const bindingPackageVersion = require('@bruits/satteri-win32-x64-msvc/package.json').version
137
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
138
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
137
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
138
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
139
139
  }
140
140
  return binding
141
141
  } catch (e) {
@@ -151,8 +151,8 @@ function requireNative() {
151
151
  try {
152
152
  const binding = require('@bruits/satteri-win32-ia32-msvc')
153
153
  const bindingPackageVersion = require('@bruits/satteri-win32-ia32-msvc/package.json').version
154
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
155
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
154
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
155
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
156
156
  }
157
157
  return binding
158
158
  } catch (e) {
@@ -167,8 +167,8 @@ function requireNative() {
167
167
  try {
168
168
  const binding = require('@bruits/satteri-win32-arm64-msvc')
169
169
  const bindingPackageVersion = require('@bruits/satteri-win32-arm64-msvc/package.json').version
170
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
171
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
170
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
171
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
172
172
  }
173
173
  return binding
174
174
  } catch (e) {
@@ -186,8 +186,8 @@ function requireNative() {
186
186
  try {
187
187
  const binding = require('@bruits/satteri-darwin-universal')
188
188
  const bindingPackageVersion = require('@bruits/satteri-darwin-universal/package.json').version
189
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
190
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
189
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
190
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
191
191
  }
192
192
  return binding
193
193
  } catch (e) {
@@ -202,8 +202,8 @@ function requireNative() {
202
202
  try {
203
203
  const binding = require('@bruits/satteri-darwin-x64')
204
204
  const bindingPackageVersion = require('@bruits/satteri-darwin-x64/package.json').version
205
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
206
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
205
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
206
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
207
207
  }
208
208
  return binding
209
209
  } catch (e) {
@@ -218,8 +218,8 @@ function requireNative() {
218
218
  try {
219
219
  const binding = require('@bruits/satteri-darwin-arm64')
220
220
  const bindingPackageVersion = require('@bruits/satteri-darwin-arm64/package.json').version
221
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
222
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
221
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
222
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
223
223
  }
224
224
  return binding
225
225
  } catch (e) {
@@ -238,8 +238,8 @@ function requireNative() {
238
238
  try {
239
239
  const binding = require('@bruits/satteri-freebsd-x64')
240
240
  const bindingPackageVersion = require('@bruits/satteri-freebsd-x64/package.json').version
241
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
242
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
241
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
242
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
243
243
  }
244
244
  return binding
245
245
  } catch (e) {
@@ -254,8 +254,8 @@ function requireNative() {
254
254
  try {
255
255
  const binding = require('@bruits/satteri-freebsd-arm64')
256
256
  const bindingPackageVersion = require('@bruits/satteri-freebsd-arm64/package.json').version
257
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
258
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
257
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
258
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
259
259
  }
260
260
  return binding
261
261
  } catch (e) {
@@ -275,8 +275,8 @@ function requireNative() {
275
275
  try {
276
276
  const binding = require('@bruits/satteri-linux-x64-musl')
277
277
  const bindingPackageVersion = require('@bruits/satteri-linux-x64-musl/package.json').version
278
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
279
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
278
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
279
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
280
280
  }
281
281
  return binding
282
282
  } catch (e) {
@@ -291,8 +291,8 @@ function requireNative() {
291
291
  try {
292
292
  const binding = require('@bruits/satteri-linux-x64-gnu')
293
293
  const bindingPackageVersion = require('@bruits/satteri-linux-x64-gnu/package.json').version
294
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
295
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
294
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
295
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
296
296
  }
297
297
  return binding
298
298
  } catch (e) {
@@ -309,8 +309,8 @@ function requireNative() {
309
309
  try {
310
310
  const binding = require('@bruits/satteri-linux-arm64-musl')
311
311
  const bindingPackageVersion = require('@bruits/satteri-linux-arm64-musl/package.json').version
312
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
313
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
312
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
313
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
314
314
  }
315
315
  return binding
316
316
  } catch (e) {
@@ -325,8 +325,8 @@ function requireNative() {
325
325
  try {
326
326
  const binding = require('@bruits/satteri-linux-arm64-gnu')
327
327
  const bindingPackageVersion = require('@bruits/satteri-linux-arm64-gnu/package.json').version
328
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
329
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
328
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
329
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
330
330
  }
331
331
  return binding
332
332
  } catch (e) {
@@ -343,8 +343,8 @@ function requireNative() {
343
343
  try {
344
344
  const binding = require('@bruits/satteri-linux-arm-musleabihf')
345
345
  const bindingPackageVersion = require('@bruits/satteri-linux-arm-musleabihf/package.json').version
346
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
347
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
346
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
347
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
348
348
  }
349
349
  return binding
350
350
  } catch (e) {
@@ -359,8 +359,8 @@ function requireNative() {
359
359
  try {
360
360
  const binding = require('@bruits/satteri-linux-arm-gnueabihf')
361
361
  const bindingPackageVersion = require('@bruits/satteri-linux-arm-gnueabihf/package.json').version
362
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
363
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
362
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
363
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
364
364
  }
365
365
  return binding
366
366
  } catch (e) {
@@ -377,8 +377,8 @@ function requireNative() {
377
377
  try {
378
378
  const binding = require('@bruits/satteri-linux-loong64-musl')
379
379
  const bindingPackageVersion = require('@bruits/satteri-linux-loong64-musl/package.json').version
380
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
381
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
380
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
381
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
382
382
  }
383
383
  return binding
384
384
  } catch (e) {
@@ -393,8 +393,8 @@ function requireNative() {
393
393
  try {
394
394
  const binding = require('@bruits/satteri-linux-loong64-gnu')
395
395
  const bindingPackageVersion = require('@bruits/satteri-linux-loong64-gnu/package.json').version
396
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
397
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
396
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
397
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
398
398
  }
399
399
  return binding
400
400
  } catch (e) {
@@ -411,8 +411,8 @@ function requireNative() {
411
411
  try {
412
412
  const binding = require('@bruits/satteri-linux-riscv64-musl')
413
413
  const bindingPackageVersion = require('@bruits/satteri-linux-riscv64-musl/package.json').version
414
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
415
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
414
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
415
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
416
416
  }
417
417
  return binding
418
418
  } catch (e) {
@@ -427,8 +427,8 @@ function requireNative() {
427
427
  try {
428
428
  const binding = require('@bruits/satteri-linux-riscv64-gnu')
429
429
  const bindingPackageVersion = require('@bruits/satteri-linux-riscv64-gnu/package.json').version
430
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
431
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
430
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
431
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
432
432
  }
433
433
  return binding
434
434
  } catch (e) {
@@ -444,8 +444,8 @@ function requireNative() {
444
444
  try {
445
445
  const binding = require('@bruits/satteri-linux-ppc64-gnu')
446
446
  const bindingPackageVersion = require('@bruits/satteri-linux-ppc64-gnu/package.json').version
447
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
448
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
447
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
448
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
449
449
  }
450
450
  return binding
451
451
  } catch (e) {
@@ -460,8 +460,8 @@ function requireNative() {
460
460
  try {
461
461
  const binding = require('@bruits/satteri-linux-s390x-gnu')
462
462
  const bindingPackageVersion = require('@bruits/satteri-linux-s390x-gnu/package.json').version
463
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
464
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
463
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
464
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
465
465
  }
466
466
  return binding
467
467
  } catch (e) {
@@ -480,8 +480,8 @@ function requireNative() {
480
480
  try {
481
481
  const binding = require('@bruits/satteri-openharmony-arm64')
482
482
  const bindingPackageVersion = require('@bruits/satteri-openharmony-arm64/package.json').version
483
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
484
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
483
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
484
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
485
485
  }
486
486
  return binding
487
487
  } catch (e) {
@@ -496,8 +496,8 @@ function requireNative() {
496
496
  try {
497
497
  const binding = require('@bruits/satteri-openharmony-x64')
498
498
  const bindingPackageVersion = require('@bruits/satteri-openharmony-x64/package.json').version
499
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
500
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
499
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
500
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
501
501
  }
502
502
  return binding
503
503
  } catch (e) {
@@ -512,8 +512,8 @@ function requireNative() {
512
512
  try {
513
513
  const binding = require('@bruits/satteri-openharmony-arm')
514
514
  const bindingPackageVersion = require('@bruits/satteri-openharmony-arm/package.json').version
515
- if (bindingPackageVersion !== '0.1.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
516
- throw new Error(`Native binding package version mismatch, expected 0.1.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
515
+ if (bindingPackageVersion !== '0.1.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
516
+ throw new Error(`Native binding package version mismatch, expected 0.1.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
517
517
  }
518
518
  return binding
519
519
  } catch (e) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "satteri",
3
- "version": "0.1.1",
4
- "description": "High-performance Markdown processing",
3
+ "version": "0.1.3",
4
+ "description": "High-performance Markdown and MDX processing",
5
5
  "files": [
6
6
  "dist",
7
7
  "browser.js",
@@ -10,22 +10,19 @@
10
10
  "satteri_napi.wasi.cjs",
11
11
  "satteri_napi.wasi-browser.js",
12
12
  "wasi-worker.mjs",
13
- "wasi-worker-browser.js",
14
- "satteri_napi.linux-x64-gnu.node"
13
+ "wasi-worker-browser.js"
15
14
  ],
16
15
  "type": "module",
17
16
  "main": "./dist/index.js",
18
17
  "exports": {
19
- ".": "./dist/index.js",
20
- "./hast": "./dist/hast-types.js",
21
- "./mdast": "./dist/mdast-types.js"
18
+ ".": "./dist/index.js"
22
19
  },
23
20
  "scripts": {
24
- "build:native": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm",
21
+ "build:native": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm --strip",
25
22
  "build:native:debug": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --esm",
26
23
  "build:ts": "tsc --project tsconfig.build.json",
27
24
  "build": "pnpm build:native && pnpm build:ts",
28
- "artifacts": "napi create-npm-dirs && napi artifacts && napi version",
25
+ "artifacts": "napi create-npm-dirs && napi artifacts",
29
26
  "dev": "tsc --watch",
30
27
  "vitest": "vitest",
31
28
  "test": "vitest run",
@@ -41,6 +38,7 @@
41
38
  "@emnapi/runtime": "^1.9.1",
42
39
  "@napi-rs/wasm-runtime": "^1.1.2",
43
40
  "@types/node": "^25.5.0",
41
+ "shiki": "^4.0.2",
44
42
  "vitest": "^4"
45
43
  },
46
44
  "napi": {
@@ -53,5 +51,12 @@
53
51
  "x86_64-pc-windows-msvc",
54
52
  "wasm32-wasip1-threads"
55
53
  ]
54
+ },
55
+ "optionalDependencies": {
56
+ "@bruits/satteri-linux-x64-gnu": "0.1.3",
57
+ "@bruits/satteri-darwin-x64": "0.1.3",
58
+ "@bruits/satteri-darwin-arm64": "0.1.3",
59
+ "@bruits/satteri-win32-x64-msvc": "0.1.3",
60
+ "@bruits/satteri-wasm32-wasi": "0.1.3"
56
61
  }
57
62
  }
Binary file