satteri 0.6.3 → 0.7.0
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 +14 -1
- package/dist/compile.d.ts +86 -5
- package/dist/compile.js +97 -52
- package/dist/hast/hast-visitor.d.ts +7 -2
- package/dist/hast/hast-visitor.js +105 -76
- package/dist/mdast/mdast-visitor.d.ts +8 -3
- package/dist/mdast/mdast-visitor.js +41 -6
- package/index.d.ts +59 -8
- package/index.js +52 -52
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -163,6 +163,14 @@ heading(node) {
|
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
+
### How transforms compose
|
|
167
|
+
|
|
168
|
+
Unlike remark and rehype, which re-walk the tree until it stops changing, each Sätteri plugin walks the tree **once**. Within that single pass:
|
|
169
|
+
|
|
170
|
+
- **Passed-through children keep their identity.** When a visitor returns a replacement that reuses the original node's children (e.g. `{ ...node, children: [...node.children] }`), those children are spliced back unchanged — so a transform the same pass queues on a nested one still applies. This is what lets a `containerDirective` visitor turn both an outer `:::note` and a nested `:::tip` into asides in one go.
|
|
171
|
+
- **A plugin's own freshly-built nodes are not re-walked by that plugin.** If a visitor returns a brand-new node (one that didn't come from the tree), the same plugin won't visit it. Produce its final shape directly, or hand it off to a later plugin — every plugin runs over the fully materialized output of the ones before it.
|
|
172
|
+
- **Dropping a subtree drops transforms queued inside it.** If one visitor removes or replaces a node while another (in the same pass) had queued a transform on something inside that subtree, the orphaned transform is dropped and a warning is logged. This is usually intentional — you discarded that subtree on purpose — but the warning helps catch the cases where it isn't.
|
|
173
|
+
|
|
166
174
|
### Async plugins
|
|
167
175
|
|
|
168
176
|
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.
|
|
@@ -289,7 +297,8 @@ Type-safe wrapper for HAST plugin definitions.
|
|
|
289
297
|
interface CompileOptions {
|
|
290
298
|
mdastPlugins?: MdastPluginDefinition[];
|
|
291
299
|
hastPlugins?: HastPluginDefinition[];
|
|
292
|
-
|
|
300
|
+
features?: Features;
|
|
301
|
+
fileURL?: URL;
|
|
293
302
|
}
|
|
294
303
|
|
|
295
304
|
// mdxToJs accepts MdxCompileOptions, which extends CompileOptions
|
|
@@ -298,6 +307,10 @@ interface MdxCompileOptions extends CompileOptions {
|
|
|
298
307
|
}
|
|
299
308
|
```
|
|
300
309
|
|
|
310
|
+
`fileURL` is the `URL` of the document being processed, surfaced to plugins as `ctx.fileURL` (a `URL`, or `undefined` when omitted). Pass a file URL such as Astro's `fileURL`, or convert a filesystem path with Node's `pathToFileURL`; read it back with `fileURLToPath(ctx.fileURL)`.
|
|
311
|
+
|
|
312
|
+
`Features` controls the Markdown extensions Sätteri's parser recognizes: `gfm`, `frontmatter`, `math`, `directive`, `smartPunctuation`, etc. `gfm`, `math`, and `smartPunctuation` also accept granular options. For example, `math: { singleDollarTextMath: false }` keeps single `$` as literal text. See the [Features reference](https://satteri.dev/docs/features/) for the full list.
|
|
313
|
+
|
|
301
314
|
## License
|
|
302
315
|
|
|
303
316
|
MIT
|
package/dist/compile.d.ts
CHANGED
|
@@ -16,14 +16,90 @@ export interface SmartPunctuationOptions {
|
|
|
16
16
|
/** Replace `...` with ellipsis (`…`). Default: true. */
|
|
17
17
|
ellipses?: boolean;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Per-backref callback. Invoked once per anchor in the footnotes section
|
|
21
|
+
* with 1-based `referenceNumber` and `rerunIndex` (1 on the first backref
|
|
22
|
+
* to that definition, 2 on the second, and so on). Must return the final
|
|
23
|
+
* string used as the backref content or `aria-label`.
|
|
24
|
+
*/
|
|
25
|
+
export type FootnoteBackrefCallback = (referenceNumber: number, rerunIndex: number) => string;
|
|
26
|
+
/**
|
|
27
|
+
* i18n strings for the GFM footnotes section. Mirrors `footnoteLabel`,
|
|
28
|
+
* `footnoteBackLabel`, and `footnoteBackContent` from remark-rehype.
|
|
29
|
+
*
|
|
30
|
+
* `backContent` and `backLabel` each accept either a template string with
|
|
31
|
+
* the `{reference}` placeholder (substituted with `1` or `1-2` to match
|
|
32
|
+
* remark-rehype's default suffix), or a callback receiving the raw
|
|
33
|
+
* `(referenceNumber, rerunIndex)` pair.
|
|
34
|
+
*
|
|
35
|
+
* Passing this object enables footnotes. To turn them off, use
|
|
36
|
+
* `gfm: { footnotes: false }`.
|
|
37
|
+
*/
|
|
38
|
+
export interface FootnoteOptions {
|
|
39
|
+
/** `<h2>` label opening the footnotes section. Default: `"Footnotes"`. */
|
|
40
|
+
label?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Backref `<a>` content. Default: `"↩"`.
|
|
43
|
+
*
|
|
44
|
+
* Template form: the string is used as-is, and a `<sup>K</sup>` marker
|
|
45
|
+
* is auto-appended on reruns (k > 1). Callback form: returns the full
|
|
46
|
+
* content for each backref; no auto-sup is added.
|
|
47
|
+
*/
|
|
48
|
+
backContent?: string | FootnoteBackrefCallback;
|
|
49
|
+
/**
|
|
50
|
+
* Backref `aria-label`. Default: `"Back to reference {reference}"`.
|
|
51
|
+
*
|
|
52
|
+
* Template form: `{reference}` becomes `n` for the first backref, `n-K`
|
|
53
|
+
* for subsequent ones. Callback form: returns the `aria-label` string
|
|
54
|
+
* for each backref.
|
|
55
|
+
*/
|
|
56
|
+
backLabel?: string | FootnoteBackrefCallback;
|
|
57
|
+
}
|
|
58
|
+
/** Granular GFM toggles, nested under {@link Features.gfm}. */
|
|
59
|
+
export interface GfmOptions {
|
|
60
|
+
/**
|
|
61
|
+
* Enable GFM footnotes (`[^id]`). Default: true.
|
|
62
|
+
*
|
|
63
|
+
* Pass `false` to drop footnote parsing while keeping the rest of GFM;
|
|
64
|
+
* pass an object to enable footnotes with custom i18n strings (see
|
|
65
|
+
* {@link FootnoteOptions}).
|
|
66
|
+
*/
|
|
67
|
+
footnotes?: boolean | FootnoteOptions;
|
|
68
|
+
}
|
|
69
|
+
/** Granular math toggles, nested under {@link Features.math}. */
|
|
70
|
+
export interface MathOptions {
|
|
71
|
+
/**
|
|
72
|
+
* Treat single-dollar runs (`$ ... $`) as inline math. Default: true.
|
|
73
|
+
*
|
|
74
|
+
* Set `false` to keep single `$` as literal text while still parsing
|
|
75
|
+
* `$$ ... $$` display math. Mirrors `singleDollarTextMath` from
|
|
76
|
+
* remark-math.
|
|
77
|
+
*/
|
|
78
|
+
singleDollarTextMath?: boolean;
|
|
79
|
+
}
|
|
19
80
|
/** Parser feature toggles. All default to their documented value when omitted. */
|
|
20
81
|
export interface Features {
|
|
21
|
-
/**
|
|
22
|
-
|
|
82
|
+
/**
|
|
83
|
+
* GFM: tables, footnotes, strikethrough, task lists. Default: true.
|
|
84
|
+
*
|
|
85
|
+
* Pass an options object for granular control:
|
|
86
|
+
* ```ts
|
|
87
|
+
* gfm: { footnotes: false } // skip footnotes only
|
|
88
|
+
* gfm: { footnotes: { label: "Notes" } } // localize footnotes
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
gfm?: boolean | GfmOptions;
|
|
23
92
|
/** Frontmatter: YAML (`--- ... ---`) and TOML (`+++ ... +++`). Default: true. */
|
|
24
93
|
frontmatter?: boolean;
|
|
25
|
-
/**
|
|
26
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Math blocks and inline math. Default: true.
|
|
96
|
+
*
|
|
97
|
+
* Pass an options object for granular control:
|
|
98
|
+
* ```ts
|
|
99
|
+
* math: { singleDollarTextMath: false } // $$..$$ only, $..$ literal
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
math?: boolean | MathOptions;
|
|
27
103
|
/** Heading attributes (`# text { #id .class }`). Default: true. */
|
|
28
104
|
headingAttributes?: boolean;
|
|
29
105
|
/** Colon-delimited container directive blocks (`:::`). Default: false. */
|
|
@@ -48,7 +124,12 @@ export interface CompileOptions {
|
|
|
48
124
|
mdastPlugins?: MdastPluginInput[];
|
|
49
125
|
hastPlugins?: HastPluginInput[];
|
|
50
126
|
features?: Features;
|
|
51
|
-
|
|
127
|
+
/**
|
|
128
|
+
* The document being processed, surfaced to plugins as `ctx.fileURL`. Must
|
|
129
|
+
* be a `URL` (e.g. Astro's `fileURL`); convert a filesystem path with Node's
|
|
130
|
+
* `pathToFileURL` before passing it.
|
|
131
|
+
*/
|
|
132
|
+
fileURL?: URL;
|
|
52
133
|
}
|
|
53
134
|
/**
|
|
54
135
|
* MDX-only compile options.
|
package/dist/compile.js
CHANGED
|
@@ -5,16 +5,55 @@ import { MdastReader } from "./mdast/mdast-reader.js";
|
|
|
5
5
|
import { materializeMdastTree } from "./mdast/mdast-materializer.js";
|
|
6
6
|
import { HastReader } from "./hast/hast-reader.js";
|
|
7
7
|
import { materializeHastTree } from "./hast/hast-materializer.js";
|
|
8
|
+
/**
|
|
9
|
+
* Split the user-facing `Features` (with nested unions) into the flat napi
|
|
10
|
+
* `JsFeatures` shape plus the conversion-side `JsConvertOptions` carrying
|
|
11
|
+
* the footnote i18n strings. The public API only exposes `features`; the
|
|
12
|
+
* footnote strings are routed to napi internally.
|
|
13
|
+
*/
|
|
8
14
|
function featuresToNative(features) {
|
|
9
15
|
if (!features)
|
|
10
|
-
return undefined;
|
|
16
|
+
return { features: undefined, convertOptions: undefined };
|
|
11
17
|
const result = {};
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
let convertOptions;
|
|
19
|
+
if (features.gfm !== undefined) {
|
|
20
|
+
if (typeof features.gfm === "object") {
|
|
21
|
+
const g = features.gfm;
|
|
22
|
+
const gfmOpts = {};
|
|
23
|
+
if (g.footnotes !== undefined) {
|
|
24
|
+
if (typeof g.footnotes === "object") {
|
|
25
|
+
gfmOpts.footnotes = true;
|
|
26
|
+
convertOptions = convertOptions ?? {};
|
|
27
|
+
if (g.footnotes.label !== undefined)
|
|
28
|
+
convertOptions.footnoteLabel = g.footnotes.label;
|
|
29
|
+
if (g.footnotes.backContent !== undefined)
|
|
30
|
+
convertOptions.footnoteBackContent = g.footnotes.backContent;
|
|
31
|
+
if (g.footnotes.backLabel !== undefined)
|
|
32
|
+
convertOptions.footnoteBackLabel = g.footnotes.backLabel;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
gfmOpts.footnotes = g.footnotes;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
result.gfmOptions = gfmOpts;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
result.gfm = features.gfm;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
14
44
|
if (features.frontmatter !== undefined)
|
|
15
45
|
result.frontmatter = features.frontmatter;
|
|
16
|
-
if (features.math !== undefined)
|
|
17
|
-
|
|
46
|
+
if (features.math !== undefined) {
|
|
47
|
+
if (typeof features.math === "object") {
|
|
48
|
+
const mathOpts = {};
|
|
49
|
+
if (features.math.singleDollarTextMath !== undefined)
|
|
50
|
+
mathOpts.singleDollarTextMath = features.math.singleDollarTextMath;
|
|
51
|
+
result.mathOptions = mathOpts;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
result.math = features.math;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
18
57
|
if (features.headingAttributes !== undefined)
|
|
19
58
|
result.headingAttributes = features.headingAttributes;
|
|
20
59
|
if (features.directive !== undefined)
|
|
@@ -33,41 +72,46 @@ function featuresToNative(features) {
|
|
|
33
72
|
result.smartPunctuation = features.smartPunctuation;
|
|
34
73
|
}
|
|
35
74
|
}
|
|
36
|
-
return result;
|
|
75
|
+
return { features: result, convertOptions };
|
|
76
|
+
}
|
|
77
|
+
function warnDroppedTransforms(plugin, dropped) {
|
|
78
|
+
const name = plugin.name ?? "<anonymous>";
|
|
79
|
+
const noun = dropped === 1 ? "transform" : "transforms";
|
|
80
|
+
console.warn(`satteri: plugin "${name}" queued ${dropped} mdast ${noun} on node(s) that were removed or ` +
|
|
81
|
+
`replaced earlier in the same pass; ${dropped === 1 ? "it was" : "they were"} dropped.`);
|
|
37
82
|
}
|
|
38
|
-
function runMdastPluginsOnHandle(handle, plugins,
|
|
39
|
-
|
|
83
|
+
function runMdastPluginsOnHandle(handle, plugins, fileURL) {
|
|
84
|
+
// Each plugin runs once over the tree. A transform that passes a child
|
|
85
|
+
// through (returning it inside the replacement) keeps that child's identity,
|
|
86
|
+
// so a patch the same pass queued on it still applies — nesting composes in
|
|
87
|
+
// one pass. A plugin's own freshly-built nodes are not re-walked; transform
|
|
88
|
+
// them up front, or hand off to a later plugin that sees the materialized tree.
|
|
89
|
+
const runPlugin = (plugin) => {
|
|
90
|
+
const subs = resolveMdastSubscriptions(plugin);
|
|
91
|
+
const result = visitMdastHandle(handle, plugin, subs, () => getHandleSource(handle), fileURL);
|
|
92
|
+
const apply = (r) => {
|
|
93
|
+
if (!r.hasMutations)
|
|
94
|
+
return;
|
|
95
|
+
const dropped = applyCommandsToMdastHandle(handle, r.commandBuffer);
|
|
96
|
+
if (dropped)
|
|
97
|
+
warnDroppedTransforms(plugin, dropped);
|
|
98
|
+
};
|
|
99
|
+
return result instanceof Promise ? result.then(apply) : apply(result);
|
|
100
|
+
};
|
|
40
101
|
let i = 0;
|
|
41
102
|
const runNext = () => {
|
|
42
103
|
while (i < plugins.length) {
|
|
43
|
-
const
|
|
44
|
-
const raw = plugins[idx];
|
|
104
|
+
const raw = plugins[i++];
|
|
45
105
|
const plugin = typeof raw === "function" ? raw() : raw;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return result.then((r) => {
|
|
50
|
-
applyMdastResult(r, idx, plugins.length, handle);
|
|
51
|
-
return runNext();
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
applyMdastResult(result, idx, plugins.length, handle);
|
|
106
|
+
const r = runPlugin(plugin);
|
|
107
|
+
if (r instanceof Promise)
|
|
108
|
+
return r.then(runNext);
|
|
55
109
|
}
|
|
56
|
-
return { handle
|
|
110
|
+
return { handle };
|
|
57
111
|
};
|
|
58
|
-
function applyMdastResult(result, idx, total, h) {
|
|
59
|
-
if (result.hasMutations) {
|
|
60
|
-
if (idx === total - 1) {
|
|
61
|
-
pendingCommands = result.commandBuffer;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
applyCommandsToMdastHandle(h, result.commandBuffer);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
112
|
return runNext();
|
|
69
113
|
}
|
|
70
|
-
function runHastPluginsOnHandle(handle, plugins, source,
|
|
114
|
+
function runHastPluginsOnHandle(handle, plugins, source, fileURL) {
|
|
71
115
|
if (plugins.length === 0)
|
|
72
116
|
return;
|
|
73
117
|
let i = 0;
|
|
@@ -77,7 +121,7 @@ function runHastPluginsOnHandle(handle, plugins, source, filename) {
|
|
|
77
121
|
i++;
|
|
78
122
|
const plugin = typeof raw === "function" ? raw() : raw;
|
|
79
123
|
const subs = resolveSubscriptions(plugin);
|
|
80
|
-
const result = visitHastHandle(handle, plugin, subs, source,
|
|
124
|
+
const result = visitHastHandle(handle, plugin, subs, source, fileURL);
|
|
81
125
|
if (result instanceof Promise) {
|
|
82
126
|
return result.then(runNext);
|
|
83
127
|
}
|
|
@@ -129,9 +173,9 @@ function mdxOptionsToNative(opts) {
|
|
|
129
173
|
return result;
|
|
130
174
|
}
|
|
131
175
|
export function markdownToHtml(source, options = {}) {
|
|
132
|
-
const { mdastPlugins = [], hastPlugins = [], features,
|
|
133
|
-
const nativeFeatures = featuresToNative(features);
|
|
134
|
-
const result = createHastHandleFromMdast(source, mdastPlugins, false,
|
|
176
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL } = options;
|
|
177
|
+
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
178
|
+
const result = createHastHandleFromMdast(source, mdastPlugins, false, fileURL, nativeFeatures, nativeConvertOptions);
|
|
135
179
|
const renderAndDrop = (h, frontmatter) => {
|
|
136
180
|
try {
|
|
137
181
|
const html = renderHandle(h);
|
|
@@ -144,7 +188,7 @@ export function markdownToHtml(source, options = {}) {
|
|
|
144
188
|
const runHastThenRender = (r) => {
|
|
145
189
|
let hastResult;
|
|
146
190
|
try {
|
|
147
|
-
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source,
|
|
191
|
+
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL);
|
|
148
192
|
}
|
|
149
193
|
catch (err) {
|
|
150
194
|
dropHandle(r.hastHandle);
|
|
@@ -163,10 +207,10 @@ export function markdownToHtml(source, options = {}) {
|
|
|
163
207
|
return runHastThenRender(result);
|
|
164
208
|
}
|
|
165
209
|
export function mdxToJs(source, options = {}) {
|
|
166
|
-
const { mdastPlugins = [], hastPlugins = [], features,
|
|
210
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL, ...mdxFields } = options;
|
|
167
211
|
const mdxOptions = mdxOptionsToNative(mdxFields);
|
|
168
|
-
const nativeFeatures = featuresToNative(features);
|
|
169
|
-
const result = createHastHandleFromMdast(source, mdastPlugins, true,
|
|
212
|
+
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
213
|
+
const result = createHastHandleFromMdast(source, mdastPlugins, true, fileURL, nativeFeatures, nativeConvertOptions);
|
|
170
214
|
const compileAndDrop = (h, frontmatter) => {
|
|
171
215
|
try {
|
|
172
216
|
const code = compileHandle(h, mdxOptions);
|
|
@@ -179,7 +223,7 @@ export function mdxToJs(source, options = {}) {
|
|
|
179
223
|
const runHastThenCompile = (r) => {
|
|
180
224
|
let hastResult;
|
|
181
225
|
try {
|
|
182
|
-
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source,
|
|
226
|
+
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL);
|
|
183
227
|
}
|
|
184
228
|
catch (err) {
|
|
185
229
|
dropHandle(r.hastHandle);
|
|
@@ -224,9 +268,11 @@ function readFrontmatter(handle) {
|
|
|
224
268
|
/** Parse, run mdast plugins, capture frontmatter, then convert to HAST.
|
|
225
269
|
* Frontmatter is read from the post-plugin MDAST so visitor mutations to
|
|
226
270
|
* the yaml/toml node are reflected in the returned value. */
|
|
227
|
-
function createHastHandleFromMdast(source, mdastPlugins, mdx,
|
|
271
|
+
function createHastHandleFromMdast(source, mdastPlugins, mdx, fileURL,
|
|
228
272
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
229
|
-
nativeFeatures
|
|
273
|
+
nativeFeatures,
|
|
274
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
275
|
+
nativeConvertOptions) {
|
|
230
276
|
const mdastHandle = mdx
|
|
231
277
|
? createMdxMdastHandle(source, nativeFeatures)
|
|
232
278
|
: createMdastHandle(source, nativeFeatures);
|
|
@@ -234,11 +280,8 @@ nativeFeatures) {
|
|
|
234
280
|
// on success, but if any step here throws the handle would otherwise leak.
|
|
235
281
|
const finalize = (r) => {
|
|
236
282
|
try {
|
|
237
|
-
if (r.pendingCommands) {
|
|
238
|
-
applyCommandsToMdastHandle(r.handle, r.pendingCommands);
|
|
239
|
-
}
|
|
240
283
|
const frontmatter = readFrontmatter(r.handle);
|
|
241
|
-
const hastHandle = convertMdastToHastHandle(r.handle);
|
|
284
|
+
const hastHandle = convertMdastToHastHandle(r.handle, nativeConvertOptions);
|
|
242
285
|
return { hastHandle, frontmatter };
|
|
243
286
|
}
|
|
244
287
|
finally {
|
|
@@ -247,9 +290,9 @@ nativeFeatures) {
|
|
|
247
290
|
};
|
|
248
291
|
try {
|
|
249
292
|
if (mdastPlugins.length === 0) {
|
|
250
|
-
return finalize({ handle: mdastHandle
|
|
293
|
+
return finalize({ handle: mdastHandle });
|
|
251
294
|
}
|
|
252
|
-
const mdastResult = runMdastPluginsOnHandle(mdastHandle, mdastPlugins,
|
|
295
|
+
const mdastResult = runMdastPluginsOnHandle(mdastHandle, mdastPlugins, fileURL);
|
|
253
296
|
if (mdastResult instanceof Promise) {
|
|
254
297
|
return mdastResult.then(finalize, (err) => {
|
|
255
298
|
dropHandle(mdastHandle);
|
|
@@ -266,7 +309,7 @@ nativeFeatures) {
|
|
|
266
309
|
// Step-by-step API: individual pipeline stages with materialized trees
|
|
267
310
|
/** Parse Markdown source into a materialized mdast tree. */
|
|
268
311
|
export function markdownToMdast(source, options = {}) {
|
|
269
|
-
const handle = createMdastHandle(source, featuresToNative(options.features));
|
|
312
|
+
const handle = createMdastHandle(source, featuresToNative(options.features).features);
|
|
270
313
|
try {
|
|
271
314
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
272
315
|
}
|
|
@@ -276,7 +319,7 @@ export function markdownToMdast(source, options = {}) {
|
|
|
276
319
|
}
|
|
277
320
|
/** Parse MDX source into a materialized mdast tree. */
|
|
278
321
|
export function mdxToMdast(source, options = {}) {
|
|
279
|
-
const handle = createMdxMdastHandle(source, featuresToNative(options.features));
|
|
322
|
+
const handle = createMdxMdastHandle(source, featuresToNative(options.features).features);
|
|
280
323
|
try {
|
|
281
324
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
282
325
|
}
|
|
@@ -286,7 +329,8 @@ export function mdxToMdast(source, options = {}) {
|
|
|
286
329
|
}
|
|
287
330
|
/** Convert Markdown source to a materialized hast tree. */
|
|
288
331
|
export function markdownToHast(source, options = {}) {
|
|
289
|
-
const
|
|
332
|
+
const { features: nativeFeatures, convertOptions } = featuresToNative(options.features);
|
|
333
|
+
const handle = createHastHandle(source, nativeFeatures, convertOptions);
|
|
290
334
|
try {
|
|
291
335
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
292
336
|
}
|
|
@@ -296,7 +340,8 @@ export function markdownToHast(source, options = {}) {
|
|
|
296
340
|
}
|
|
297
341
|
/** Convert MDX source to a materialized hast tree. */
|
|
298
342
|
export function mdxToHast(source, options = {}) {
|
|
299
|
-
const
|
|
343
|
+
const { features: nativeFeatures, convertOptions } = featuresToNative(options.features);
|
|
344
|
+
const handle = createMdxHastHandle(source, nativeFeatures, convertOptions);
|
|
300
345
|
try {
|
|
301
346
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
302
347
|
}
|
|
@@ -15,7 +15,12 @@ export interface HastDiagnostic {
|
|
|
15
15
|
}
|
|
16
16
|
export interface HastVisitorContext {
|
|
17
17
|
readonly source: string;
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The URL of the document being processed (the compile `fileURL` option),
|
|
20
|
+
* or `undefined` when none was given. Use `fileURLToPath(ctx.fileURL)` for a
|
|
21
|
+
* decoded filesystem path.
|
|
22
|
+
*/
|
|
23
|
+
readonly fileURL: URL | undefined;
|
|
19
24
|
removeNode(node: Readonly<HastNode>): void;
|
|
20
25
|
replaceNode(node: Readonly<HastNode>, newNode: HastNode): void;
|
|
21
26
|
insertBefore(node: Readonly<HastNode>, newNode: HastNode): void;
|
|
@@ -70,5 +75,5 @@ export declare function resolveSubscriptions(plugin: HastVisitorInstance): Resol
|
|
|
70
75
|
*
|
|
71
76
|
* Returns void if all visitors are sync, or a Promise if any visitor is async.
|
|
72
77
|
*/
|
|
73
|
-
export declare function visitHastHandle(handle: HastHandle, plugin: HastVisitorInstance, subs: ResolvedSubscription[], source: string | (() => string),
|
|
78
|
+
export declare function visitHastHandle(handle: HastHandle, plugin: HastVisitorInstance, subs: ResolvedSubscription[], source: string | (() => string), fileURL: URL | undefined): void | Promise<void>;
|
|
74
79
|
export {};
|
|
@@ -21,24 +21,37 @@ function attachParseExpression(node, parseFn) {
|
|
|
21
21
|
configurable: true,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Serialize a HastNode for the command buffer. Marks each node `_hast: true`,
|
|
26
|
+
* and — except at the root, which is the new replacement content — emits a
|
|
27
|
+
* reused (materialized) node as a `{ _ref: id }` placeholder so the rebuild
|
|
28
|
+
* splices the original in place (preserving its id, applying any pending patch
|
|
29
|
+
* on it) instead of rebuilding it fresh.
|
|
30
|
+
*/
|
|
25
31
|
function markHast(node) {
|
|
26
|
-
|
|
32
|
+
return markHastNode(node, true);
|
|
33
|
+
}
|
|
34
|
+
function markHastNode(node, isRoot) {
|
|
35
|
+
if (!isRoot) {
|
|
36
|
+
const id = nodeIdMap.get(node) ?? node._nodeId;
|
|
37
|
+
if (typeof id === "number")
|
|
38
|
+
return { _ref: id };
|
|
39
|
+
}
|
|
27
40
|
const obj = { _hast: true, type: node.type };
|
|
28
41
|
if ("tagName" in node)
|
|
29
|
-
obj.tagName =
|
|
42
|
+
obj.tagName = node.tagName;
|
|
30
43
|
if ("properties" in node)
|
|
31
|
-
obj.properties =
|
|
44
|
+
obj.properties = node.properties;
|
|
32
45
|
if ("value" in node)
|
|
33
|
-
obj.value =
|
|
46
|
+
obj.value = node.value;
|
|
34
47
|
if ("name" in node)
|
|
35
|
-
obj.name =
|
|
48
|
+
obj.name = node.name;
|
|
36
49
|
if ("attributes" in node)
|
|
37
|
-
obj.attributes =
|
|
38
|
-
if ("data" in node &&
|
|
39
|
-
obj.data =
|
|
50
|
+
obj.attributes = node.attributes;
|
|
51
|
+
if ("data" in node && node.data != null)
|
|
52
|
+
obj.data = node.data;
|
|
40
53
|
if ("children" in node) {
|
|
41
|
-
obj.children =
|
|
54
|
+
obj.children = node.children.map((c) => markHastNode(c, false));
|
|
42
55
|
}
|
|
43
56
|
return obj;
|
|
44
57
|
}
|
|
@@ -52,11 +65,11 @@ class HastVisitorContextImpl {
|
|
|
52
65
|
#pendingNodes = new Map();
|
|
53
66
|
#handle;
|
|
54
67
|
#getSource;
|
|
55
|
-
|
|
56
|
-
constructor(handle, getSource,
|
|
68
|
+
fileURL;
|
|
69
|
+
constructor(handle, getSource, fileURL) {
|
|
57
70
|
this.#handle = handle;
|
|
58
71
|
this.#getSource = getSource;
|
|
59
|
-
this.
|
|
72
|
+
this.fileURL = fileURL;
|
|
60
73
|
}
|
|
61
74
|
get source() {
|
|
62
75
|
const value = this.#getSource();
|
|
@@ -99,7 +112,8 @@ class HastVisitorContextImpl {
|
|
|
99
112
|
}
|
|
100
113
|
if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
|
|
101
114
|
// MDX JSX nodes use `attributes`, not `properties`, keep replaceNode path
|
|
102
|
-
const
|
|
115
|
+
const pending = this.#pendingNodes.get(id);
|
|
116
|
+
const current = (pending ?? node);
|
|
103
117
|
const updated = { ...current };
|
|
104
118
|
const attrs = [...(updated.attributes ?? [])];
|
|
105
119
|
const idx = attrs.findIndex((a) => a.type === "mdxJsxAttribute" && a.name === key);
|
|
@@ -109,7 +123,7 @@ class HastVisitorContextImpl {
|
|
|
109
123
|
? null
|
|
110
124
|
: typeof value === "string"
|
|
111
125
|
? value
|
|
112
|
-
:
|
|
126
|
+
: String(value);
|
|
113
127
|
attrs.push({ type: "mdxJsxAttribute", name: key, value: attrValue });
|
|
114
128
|
updated.attributes = attrs;
|
|
115
129
|
this.replaceNode(node, updated);
|
|
@@ -213,6 +227,21 @@ function decodeProperties(view, buf, pos) {
|
|
|
213
227
|
}
|
|
214
228
|
return properties;
|
|
215
229
|
}
|
|
230
|
+
/** Decode the 24-byte position block written by `serialize_hast_node_inline`. */
|
|
231
|
+
function readPositionPrefix(view, offset) {
|
|
232
|
+
const startOffset = view.getUint32(offset, true);
|
|
233
|
+
const endOffset = view.getUint32(offset + 4, true);
|
|
234
|
+
const startLine = view.getUint32(offset + 8, true);
|
|
235
|
+
const startColumn = view.getUint32(offset + 12, true);
|
|
236
|
+
const endLine = view.getUint32(offset + 16, true);
|
|
237
|
+
const endColumn = view.getUint32(offset + 20, true);
|
|
238
|
+
if (startLine === 0 && startOffset === 0)
|
|
239
|
+
return undefined;
|
|
240
|
+
return {
|
|
241
|
+
start: { offset: startOffset, line: startLine, column: startColumn },
|
|
242
|
+
end: { offset: endOffset, line: endLine, column: endColumn },
|
|
243
|
+
};
|
|
244
|
+
}
|
|
216
245
|
/**
|
|
217
246
|
* Walk-path element node: uses prototype getters instead of per-instance
|
|
218
247
|
* Object.defineProperty. V8 optimises shared hidden classes far better,
|
|
@@ -228,8 +257,6 @@ class WalkElement {
|
|
|
228
257
|
/** @internal */ _propsPos;
|
|
229
258
|
/** @internal */ _childIds;
|
|
230
259
|
/** @internal */ _resolver;
|
|
231
|
-
/** @internal */ _dataPos;
|
|
232
|
-
/** @internal */ _dataLen;
|
|
233
260
|
get properties() {
|
|
234
261
|
const val = decodeProperties(this._view, this._buf, this._propsPos);
|
|
235
262
|
Object.defineProperty(this, "properties", {
|
|
@@ -250,59 +277,29 @@ class WalkElement {
|
|
|
250
277
|
});
|
|
251
278
|
return val;
|
|
252
279
|
}
|
|
253
|
-
get data() {
|
|
254
|
-
if (this._dataPos < 0)
|
|
255
|
-
return undefined;
|
|
256
|
-
const val = JSON.parse(textDecoder.decode(this._buf.subarray(this._dataPos, this._dataPos + this._dataLen)));
|
|
257
|
-
Object.defineProperty(this, "data", {
|
|
258
|
-
value: val,
|
|
259
|
-
writable: true,
|
|
260
|
-
enumerable: true,
|
|
261
|
-
configurable: true,
|
|
262
|
-
});
|
|
263
|
-
return val;
|
|
264
|
-
}
|
|
265
280
|
}
|
|
266
|
-
/** Read a matched element node
|
|
267
|
-
*
|
|
268
|
-
function readElementFromBinary(view, buf, offset, nodeId, resolver) {
|
|
281
|
+
/** Read the tail of a matched element node (tag + properties).
|
|
282
|
+
* Common prelude (data/position/children) is already consumed by `readMatchedNode`. */
|
|
283
|
+
function readElementFromBinary(view, buf, offset, nodeId, resolver, position, childIds, data) {
|
|
269
284
|
let pos = offset;
|
|
270
285
|
// Eager: tagName (almost always accessed by visitors)
|
|
271
286
|
const tagLen = view.getUint16(pos, true);
|
|
272
287
|
pos += 2;
|
|
273
288
|
const tagName = textDecoder.decode(buf.subarray(pos, pos + tagLen));
|
|
274
289
|
pos += tagLen;
|
|
275
|
-
// Pre-scan: find section byte offsets without decoding strings
|
|
276
290
|
const propsPos = pos;
|
|
277
|
-
const propCount = view.getUint16(pos, true);
|
|
278
|
-
pos += 2;
|
|
279
|
-
for (let i = 0; i < propCount; i++) {
|
|
280
|
-
const nLen = view.getUint16(pos, true);
|
|
281
|
-
pos += 2 + nLen + 1; // name + kind byte
|
|
282
|
-
const vLen = view.getUint16(pos, true);
|
|
283
|
-
pos += 2 + vLen; // value
|
|
284
|
-
}
|
|
285
|
-
const childCount = view.getUint16(pos, true);
|
|
286
|
-
pos += 2;
|
|
287
|
-
const childIdsPos = pos;
|
|
288
|
-
pos += childCount * 4;
|
|
289
|
-
const nodeDataLen = view.getUint32(pos, true);
|
|
290
|
-
pos += 4;
|
|
291
|
-
const nodeDataPos = nodeDataLen > 0 ? pos : -1;
|
|
292
|
-
// Collect child IDs for lazy materialization
|
|
293
|
-
const ids = [];
|
|
294
|
-
for (let i = 0; i < childCount; i++)
|
|
295
|
-
ids.push(view.getUint32(childIdsPos + i * 4, true));
|
|
296
291
|
// Build node using class (prototype getters, no per-instance defineProperty)
|
|
297
292
|
const node = new WalkElement();
|
|
298
293
|
node.tagName = tagName;
|
|
294
|
+
if (position !== undefined)
|
|
295
|
+
node.position = position;
|
|
296
|
+
if (data !== null)
|
|
297
|
+
node.data = data;
|
|
299
298
|
node._view = view;
|
|
300
299
|
node._buf = buf;
|
|
301
300
|
node._propsPos = propsPos;
|
|
302
|
-
node._childIds =
|
|
301
|
+
node._childIds = childIds;
|
|
303
302
|
node._resolver = resolver;
|
|
304
|
-
node._dataPos = nodeDataPos;
|
|
305
|
-
node._dataLen = nodeDataLen;
|
|
306
303
|
nodeIdMap.set(node, nodeId);
|
|
307
304
|
return node;
|
|
308
305
|
}
|
|
@@ -315,10 +312,15 @@ const TEXT_NODE_TYPES = {
|
|
|
315
312
|
[HAST_MDX_TEXT_EXPRESSION]: "mdxTextExpression",
|
|
316
313
|
[HAST_MDX_ESM]: "mdxjsEsm",
|
|
317
314
|
};
|
|
318
|
-
function readTextFromBinary(view, buf, offset, nodeId, nodeType) {
|
|
315
|
+
function readTextFromBinary(view, buf, offset, nodeId, nodeType, position, data) {
|
|
319
316
|
const valLen = view.getUint32(offset, true);
|
|
320
317
|
const value = textDecoder.decode(buf.subarray(offset + 4, offset + 4 + valLen));
|
|
321
|
-
const
|
|
318
|
+
const base = { type: TEXT_NODE_TYPES[nodeType], value };
|
|
319
|
+
if (position !== undefined)
|
|
320
|
+
base.position = position;
|
|
321
|
+
if (data !== null)
|
|
322
|
+
base.data = data;
|
|
323
|
+
const node = base;
|
|
322
324
|
nodeIdMap.set(node, nodeId);
|
|
323
325
|
if (nodeType === HAST_MDX_FLOW_EXPRESSION || nodeType === HAST_MDX_TEXT_EXPRESSION) {
|
|
324
326
|
attachParseExpression(node, napiParseExpression);
|
|
@@ -329,14 +331,14 @@ function readTextFromBinary(view, buf, offset, nodeId, nodeType) {
|
|
|
329
331
|
return node;
|
|
330
332
|
}
|
|
331
333
|
/** Read an MDX JSX element from the binary data section. */
|
|
332
|
-
function readMdxJsxFromBinary(view, buf, offset, nodeId, nodeType, resolver) {
|
|
334
|
+
function readMdxJsxFromBinary(view, buf, offset, nodeId, nodeType, resolver, position, childIds, data) {
|
|
333
335
|
let pos = offset;
|
|
334
336
|
// Name
|
|
335
337
|
const nameLen = view.getUint16(pos, true);
|
|
336
338
|
pos += 2;
|
|
337
339
|
const name = nameLen > 0 ? textDecoder.decode(buf.subarray(pos, pos + nameLen)) : null;
|
|
338
340
|
pos += nameLen;
|
|
339
|
-
// Attributes: [kind: u8][nameLen: u16][name][valLen:
|
|
341
|
+
// Attributes: [kind: u8][nameLen: u16][name][valLen: u32][val]
|
|
340
342
|
const attrCount = view.getUint16(pos, true);
|
|
341
343
|
pos += 2;
|
|
342
344
|
const attributes = [];
|
|
@@ -370,7 +372,36 @@ function readMdxJsxFromBinary(view, buf, offset, nodeId, nodeType, resolver) {
|
|
|
370
372
|
break;
|
|
371
373
|
}
|
|
372
374
|
}
|
|
373
|
-
|
|
375
|
+
const typeName = nodeType === HAST_MDX_JSX_ELEMENT ? "mdxJsxFlowElement" : "mdxJsxTextElement";
|
|
376
|
+
const base = { type: typeName, name, attributes };
|
|
377
|
+
if (position !== undefined)
|
|
378
|
+
base.position = position;
|
|
379
|
+
if (data !== null)
|
|
380
|
+
base.data = data;
|
|
381
|
+
nodeIdMap.set(base, nodeId);
|
|
382
|
+
makeLazyChildren(base, childIds, resolver);
|
|
383
|
+
return base;
|
|
384
|
+
}
|
|
385
|
+
function readMatchedNode(view, buf, offset, nodeId, nodeType, resolver) {
|
|
386
|
+
let pos = offset;
|
|
387
|
+
// Shared prelude (matches serialize_hast_node_inline / serialize_mdast_node_inline):
|
|
388
|
+
// [data_len: u32][data_bytes][position: 24B][child_count: u16][child_ids: N×u32]
|
|
389
|
+
// Data (JSON), eagerly parsed
|
|
390
|
+
const dataLen = view.getUint32(pos, true);
|
|
391
|
+
pos += 4;
|
|
392
|
+
let data = null;
|
|
393
|
+
if (dataLen > 0) {
|
|
394
|
+
const jsonStr = textDecoder.decode(buf.subarray(pos, pos + dataLen));
|
|
395
|
+
try {
|
|
396
|
+
data = JSON.parse(jsonStr);
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
/* ignore malformed JSON */
|
|
400
|
+
}
|
|
401
|
+
pos += dataLen;
|
|
402
|
+
}
|
|
403
|
+
const position = readPositionPrefix(view, pos);
|
|
404
|
+
pos += 24;
|
|
374
405
|
const childCount = view.getUint16(pos, true);
|
|
375
406
|
pos += 2;
|
|
376
407
|
const childIds = [];
|
|
@@ -378,16 +409,9 @@ function readMdxJsxFromBinary(view, buf, offset, nodeId, nodeType, resolver) {
|
|
|
378
409
|
childIds.push(view.getUint32(pos, true));
|
|
379
410
|
pos += 4;
|
|
380
411
|
}
|
|
381
|
-
|
|
382
|
-
const node = { type: typeName, name, attributes };
|
|
383
|
-
nodeIdMap.set(node, nodeId);
|
|
384
|
-
makeLazyChildren(node, childIds, resolver);
|
|
385
|
-
resolver.attachLazyData(node, nodeId);
|
|
386
|
-
return node;
|
|
387
|
-
}
|
|
388
|
-
function readMatchedNode(view, buf, offset, nodeId, nodeType, resolver) {
|
|
412
|
+
// Dispatch to type-specific tail (pos now sits at the type-specific section)
|
|
389
413
|
if (nodeType === HAST_ELEMENT) {
|
|
390
|
-
return readElementFromBinary(view, buf,
|
|
414
|
+
return readElementFromBinary(view, buf, pos, nodeId, resolver, position, childIds, data);
|
|
391
415
|
}
|
|
392
416
|
else if (nodeType === HAST_TEXT ||
|
|
393
417
|
nodeType === HAST_COMMENT ||
|
|
@@ -395,13 +419,18 @@ function readMatchedNode(view, buf, offset, nodeId, nodeType, resolver) {
|
|
|
395
419
|
nodeType === HAST_MDX_FLOW_EXPRESSION ||
|
|
396
420
|
nodeType === HAST_MDX_TEXT_EXPRESSION ||
|
|
397
421
|
nodeType === HAST_MDX_ESM) {
|
|
398
|
-
return readTextFromBinary(view, buf,
|
|
422
|
+
return readTextFromBinary(view, buf, pos, nodeId, nodeType, position, data);
|
|
399
423
|
}
|
|
400
424
|
else if (nodeType === HAST_MDX_JSX_ELEMENT || nodeType === HAST_MDX_JSX_TEXT_ELEMENT) {
|
|
401
|
-
return readMdxJsxFromBinary(view, buf,
|
|
402
|
-
}
|
|
403
|
-
// Fallback: minimal node
|
|
404
|
-
const
|
|
425
|
+
return readMdxJsxFromBinary(view, buf, pos, nodeId, nodeType, resolver, position, childIds, data);
|
|
426
|
+
}
|
|
427
|
+
// Fallback: minimal node carrying whatever prelude data we found
|
|
428
|
+
const base = { type: `unknown(${nodeType})` };
|
|
429
|
+
if (position !== undefined)
|
|
430
|
+
base.position = position;
|
|
431
|
+
if (data !== null)
|
|
432
|
+
base.data = data;
|
|
433
|
+
const node = base;
|
|
405
434
|
nodeIdMap.set(node, nodeId);
|
|
406
435
|
return node;
|
|
407
436
|
}
|
|
@@ -529,9 +558,9 @@ function mergeAndReset(returnBuffer, ctx) {
|
|
|
529
558
|
*
|
|
530
559
|
* Returns void if all visitors are sync, or a Promise if any visitor is async.
|
|
531
560
|
*/
|
|
532
|
-
export function visitHastHandle(handle, plugin, subs, source,
|
|
561
|
+
export function visitHastHandle(handle, plugin, subs, source, fileURL) {
|
|
533
562
|
const getSource = typeof source === "function" ? source : () => source;
|
|
534
|
-
const ctx = new HastVisitorContextImpl(handle, getSource,
|
|
563
|
+
const ctx = new HastVisitorContextImpl(handle, getSource, fileURL);
|
|
535
564
|
const returnBuffer = new CommandBuffer();
|
|
536
565
|
const resolver = new LazyChildResolver(handle);
|
|
537
566
|
const rustSubs = subs.map((s) => ({ nodeType: s.nodeType, tagFilter: s.tagFilter }));
|
|
@@ -13,8 +13,13 @@ export interface MdastDiagnostic {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class MdastVisitorContext {
|
|
15
15
|
#private;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The URL of the document being processed (the compile `fileURL` option),
|
|
18
|
+
* or `undefined` when none was given. Use `fileURLToPath(ctx.fileURL)` for a
|
|
19
|
+
* decoded filesystem path.
|
|
20
|
+
*/
|
|
21
|
+
readonly fileURL: URL | undefined;
|
|
22
|
+
constructor(handle: MdastHandle, getSource: () => string, fileURL: URL | undefined);
|
|
18
23
|
get source(): string;
|
|
19
24
|
removeNode(node: Readonly<MdastNode>): void;
|
|
20
25
|
insertBefore(node: Readonly<MdastNode>, newNode: MdastNode): void;
|
|
@@ -102,5 +107,5 @@ export declare function resolveMdastSubscriptions(plugin: MdastPluginInstance):
|
|
|
102
107
|
* Returns MdastVisitResult synchronously if all visitors are sync,
|
|
103
108
|
* or Promise<MdastVisitResult> if any visitor is async.
|
|
104
109
|
*/
|
|
105
|
-
export declare function visitMdastHandle(handle: MdastHandle, plugin: MdastPluginInstance, subs: MdastSubscription[], source: string | (() => string),
|
|
110
|
+
export declare function visitMdastHandle(handle: MdastHandle, plugin: MdastPluginInstance, subs: MdastSubscription[], source: string | (() => string), fileURL: URL | undefined): MdastVisitResult | Promise<MdastVisitResult>;
|
|
106
111
|
export {};
|
|
@@ -60,11 +60,16 @@ export class MdastVisitorContext {
|
|
|
60
60
|
#diagnostics = [];
|
|
61
61
|
#handle;
|
|
62
62
|
#getSource;
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
/**
|
|
64
|
+
* The URL of the document being processed (the compile `fileURL` option),
|
|
65
|
+
* or `undefined` when none was given. Use `fileURLToPath(ctx.fileURL)` for a
|
|
66
|
+
* decoded filesystem path.
|
|
67
|
+
*/
|
|
68
|
+
fileURL;
|
|
69
|
+
constructor(handle, getSource, fileURL) {
|
|
65
70
|
this.#handle = handle;
|
|
66
71
|
this.#getSource = getSource;
|
|
67
|
-
this.
|
|
72
|
+
this.fileURL = fileURL;
|
|
68
73
|
}
|
|
69
74
|
get source() {
|
|
70
75
|
const value = this.#getSource();
|
|
@@ -501,6 +506,36 @@ function readMdastMatchedNode(view, buf, dataOffset, nodeId, nodeType, resolver)
|
|
|
501
506
|
/** Apply a sync visitor result to the return buffer.
|
|
502
507
|
* If the result is the same object as the input node, treat it as a no-op
|
|
503
508
|
* so that context mutations (e.g. setProperty) are not clobbered. */
|
|
509
|
+
/** The arena id of a node if it is an existing (materialized) node, else
|
|
510
|
+
* undefined for a freshly-built one. */
|
|
511
|
+
function reusedId(node) {
|
|
512
|
+
if (node === null || typeof node !== "object")
|
|
513
|
+
return undefined;
|
|
514
|
+
const id = nid(node);
|
|
515
|
+
return typeof id === "number" ? id : undefined;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Rewrite a returned replacement tree so every *reused* node (one that came
|
|
519
|
+
* from the arena, at any depth) becomes a `{ _ref: id }` placeholder. The
|
|
520
|
+
* rebuild splices those originals back in place, preserving their ids — so a
|
|
521
|
+
* patch a nested visitor queued on a passed-through child still lands, in the
|
|
522
|
+
* same pass. Freshly-built nodes serialize as before. The root is never reffed:
|
|
523
|
+
* it is the new shape replacing the visited node.
|
|
524
|
+
*/
|
|
525
|
+
function refifyReusedNodes(node, isRoot) {
|
|
526
|
+
if (node === null || typeof node !== "object")
|
|
527
|
+
return node;
|
|
528
|
+
if (!isRoot) {
|
|
529
|
+
const id = reusedId(node);
|
|
530
|
+
if (id !== undefined)
|
|
531
|
+
return { _ref: id };
|
|
532
|
+
}
|
|
533
|
+
const children = node.children;
|
|
534
|
+
if (Array.isArray(children)) {
|
|
535
|
+
return { ...node, children: children.map((c) => refifyReusedNodes(c, false)) };
|
|
536
|
+
}
|
|
537
|
+
return node;
|
|
538
|
+
}
|
|
504
539
|
function applyMdastVisitResult(result, nodeId, returnBuffer, originalNode) {
|
|
505
540
|
if (result === undefined || result === null)
|
|
506
541
|
return;
|
|
@@ -515,7 +550,7 @@ function applyMdastVisitResult(result, nodeId, returnBuffer, originalNode) {
|
|
|
515
550
|
returnBuffer.replace(nodeId, result);
|
|
516
551
|
break;
|
|
517
552
|
case "structured_node":
|
|
518
|
-
returnBuffer.replace(nodeId, result);
|
|
553
|
+
returnBuffer.replace(nodeId, refifyReusedNodes(result, true));
|
|
519
554
|
break;
|
|
520
555
|
}
|
|
521
556
|
}
|
|
@@ -526,9 +561,9 @@ function applyMdastVisitResult(result, nodeId, returnBuffer, originalNode) {
|
|
|
526
561
|
* Returns MdastVisitResult synchronously if all visitors are sync,
|
|
527
562
|
* or Promise<MdastVisitResult> if any visitor is async.
|
|
528
563
|
*/
|
|
529
|
-
export function visitMdastHandle(handle, plugin, subs, source,
|
|
564
|
+
export function visitMdastHandle(handle, plugin, subs, source, fileURL) {
|
|
530
565
|
const getSource = typeof source === "function" ? source : () => source;
|
|
531
|
-
const context = new MdastVisitorContext(handle, getSource,
|
|
566
|
+
const context = new MdastVisitorContext(handle, getSource, fileURL);
|
|
532
567
|
const returnBuffer = new CommandBuffer();
|
|
533
568
|
const resolver = new MdastLazyChildResolver(handle);
|
|
534
569
|
const rustSubs = subs.map((s) => ({ nodeType: s.nodeType, tagFilter: [] }));
|
package/index.d.ts
CHANGED
|
@@ -4,34 +4,38 @@
|
|
|
4
4
|
* Apply MDAST commands and convert to HAST handle in one step.
|
|
5
5
|
* The MDAST handle is consumed (emptied).
|
|
6
6
|
*/
|
|
7
|
-
export declare function applyCommandsAndConvertToHastHandle(handle: MdastHandle, commandBuf: Uint8Array): HastHandle
|
|
7
|
+
export declare function applyCommandsAndConvertToHastHandle(handle: MdastHandle, commandBuf: Uint8Array, convertOptions?: JsConvertOptions | undefined | null): HastHandle
|
|
8
8
|
|
|
9
9
|
/** Apply a command buffer to a HAST handle's arena in-place. */
|
|
10
10
|
export declare function applyCommandsToHandle(handle: HastHandle, commandBuf: Uint8Array): void
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Apply a command buffer to an MDAST handle in-place. Returns how many patches
|
|
14
|
+
* were dropped because their target lived inside a subtree this pass removed or
|
|
15
|
+
* replaced (see the lenient note below); the JS pipeline warns when non-zero.
|
|
16
|
+
*/
|
|
17
|
+
export declare function applyCommandsToMdastHandle(handle: MdastHandle, commandBuf: Uint8Array): number
|
|
14
18
|
|
|
15
19
|
/** Compile a HAST handle's arena to MDX JavaScript. Does not consume the handle. */
|
|
16
20
|
export declare function compileHandle(handle: HastHandle, options?: JsMdxOptions | undefined | null): string
|
|
17
21
|
|
|
18
22
|
/** Compile MDX source directly to JavaScript. */
|
|
19
|
-
export declare function compileMdx(source: string, options?: JsMdxOptions | undefined | null, features?: JsFeatures | undefined | null): string
|
|
23
|
+
export declare function compileMdx(source: string, options?: JsMdxOptions | undefined | null, features?: JsFeatures | undefined | null, convertOptions?: JsConvertOptions | undefined | null): string
|
|
20
24
|
|
|
21
25
|
/** Convert an MDAST handle to a HAST handle. The MDAST handle is consumed (emptied). */
|
|
22
|
-
export declare function convertMdastToHastHandle(handle: MdastHandle): HastHandle
|
|
26
|
+
export declare function convertMdastToHastHandle(handle: MdastHandle, convertOptions?: JsConvertOptions | undefined | null): HastHandle
|
|
23
27
|
|
|
24
28
|
/**
|
|
25
29
|
* Parse markdown source and convert to HAST. Returns an opaque handle.
|
|
26
30
|
* The arena stays in Rust memory, no buffer is copied to JS.
|
|
27
31
|
*/
|
|
28
|
-
export declare function createHastHandle(source: string, features?: JsFeatures | undefined | null): HastHandle
|
|
32
|
+
export declare function createHastHandle(source: string, features?: JsFeatures | undefined | null, convertOptions?: JsConvertOptions | undefined | null): HastHandle
|
|
29
33
|
|
|
30
34
|
/** Parse markdown source into an MDAST arena handle. */
|
|
31
35
|
export declare function createMdastHandle(source: string, features?: JsFeatures | undefined | null): MdastHandle
|
|
32
36
|
|
|
33
37
|
/** Parse MDX source and convert to HAST. Returns an opaque handle. */
|
|
34
|
-
export declare function createMdxHastHandle(source: string, features?: JsFeatures | undefined | null): HastHandle
|
|
38
|
+
export declare function createMdxHastHandle(source: string, features?: JsFeatures | undefined | null, convertOptions?: JsConvertOptions | undefined | null): HastHandle
|
|
35
39
|
|
|
36
40
|
/** Parse MDX source into an MDAST arena handle. */
|
|
37
41
|
export declare function createMdxMdastHandle(source: string, features?: JsFeatures | undefined | null): MdastHandle
|
|
@@ -60,14 +64,37 @@ export declare function getMdastFrontmatter(handle: MdastHandle): JsFrontmatter
|
|
|
60
64
|
*/
|
|
61
65
|
export declare function getNodeData(handle: AnyHandle, nodeId: number): string | null
|
|
62
66
|
|
|
67
|
+
/**
|
|
68
|
+
* MDAST→HAST conversion options passed from JavaScript.
|
|
69
|
+
*
|
|
70
|
+
* Input-only: `object_to_js = false` because `FunctionRef` only crosses
|
|
71
|
+
* JS → Rust. A `JsConvertOptions` never gets serialized back to JS.
|
|
72
|
+
*/
|
|
73
|
+
export interface JsConvertOptions {
|
|
74
|
+
/** `<h2>` label opening the footnotes section. Default: `"Footnotes"`. */
|
|
75
|
+
footnoteLabel?: string
|
|
76
|
+
/** Backref `<a>` content. Default: `"\u{21a9}"` (↩). */
|
|
77
|
+
footnoteBackContent?: string | ((arg0: number, arg1: number) => string)
|
|
78
|
+
/**
|
|
79
|
+
* Backref `aria-label`. The token `{reference}` is replaced with the
|
|
80
|
+
* footnote number (`1`) or `number-K` (`1-2`) for repeated references.
|
|
81
|
+
* Default: `"Back to reference {reference}"`.
|
|
82
|
+
*/
|
|
83
|
+
footnoteBackLabel?: string | ((arg0: number, arg1: number) => string)
|
|
84
|
+
}
|
|
85
|
+
|
|
63
86
|
/** Feature toggles for the Markdown/MDX parser, passed from JavaScript. */
|
|
64
87
|
export interface JsFeatures {
|
|
65
88
|
/** GFM: tables, footnotes, strikethrough, task lists. Default: true. */
|
|
66
89
|
gfm?: boolean
|
|
90
|
+
/** Granular GFM control (overrides `gfm`). */
|
|
91
|
+
gfmOptions?: JsGfmOptions
|
|
67
92
|
/** Frontmatter: YAML (`--- ... ---`) and TOML (`+++ ... +++`). Default: true. */
|
|
68
93
|
frontmatter?: boolean
|
|
69
94
|
/** Math blocks and inline math (`$$ ... $$`, `$ ... $`). Default: true. */
|
|
70
95
|
math?: boolean
|
|
96
|
+
/** Granular math control (overrides `math`). */
|
|
97
|
+
mathOptions?: JsMathOptions
|
|
71
98
|
/** Heading attributes (`# text { #id .class }`). Default: true. */
|
|
72
99
|
headingAttributes?: boolean
|
|
73
100
|
/** Colon-delimited container directive blocks (`:::`). Default: false. */
|
|
@@ -92,6 +119,30 @@ export interface JsFrontmatter {
|
|
|
92
119
|
value: string
|
|
93
120
|
}
|
|
94
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Granular GFM toggles, nested under `features.gfm`. The footnote i18n
|
|
124
|
+
* strings (label, back-content, back-label) travel separately via the
|
|
125
|
+
* `JsConvertOptions` argument on conversion entry points; the JS package
|
|
126
|
+
* extracts them from `features.gfm.footnotes` before calling in.
|
|
127
|
+
*/
|
|
128
|
+
export interface JsGfmOptions {
|
|
129
|
+
/**
|
|
130
|
+
* Enable GFM footnotes (`[^id]`). Default: true. Set `false` to drop
|
|
131
|
+
* footnote parsing while keeping the rest of the GFM bundle.
|
|
132
|
+
*/
|
|
133
|
+
footnotes?: boolean
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Granular math toggles, nested under `features.math`. */
|
|
137
|
+
export interface JsMathOptions {
|
|
138
|
+
/**
|
|
139
|
+
* Treat single-dollar runs (`$ ... $`) as inline math. Default: true.
|
|
140
|
+
* Set `false` to keep single `$` as literal text (prose with currency)
|
|
141
|
+
* while still parsing double-dollar (`$$ ... $$`) display math.
|
|
142
|
+
*/
|
|
143
|
+
singleDollarTextMath?: boolean
|
|
144
|
+
}
|
|
145
|
+
|
|
95
146
|
/** MDX compile options passed from JavaScript. */
|
|
96
147
|
export interface JsMdxOptions {
|
|
97
148
|
/**
|
|
@@ -189,7 +240,7 @@ export declare function parseEsm(source: string): string | null
|
|
|
189
240
|
export declare function parseExpression(source: string): string | null
|
|
190
241
|
|
|
191
242
|
/** Parse Markdown source and return HTML string directly. */
|
|
192
|
-
export declare function parseToHtml(source: string, features?: JsFeatures | undefined | null): string
|
|
243
|
+
export declare function parseToHtml(source: string, features?: JsFeatures | undefined | null, convertOptions?: JsConvertOptions | undefined | null): string
|
|
193
244
|
|
|
194
245
|
/** Render a HAST handle's arena to HTML. Does not consume the handle. */
|
|
195
246
|
export declare function renderHandle(handle: HastHandle): string
|
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.6.
|
|
85
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
84
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
101
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
100
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
122
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
121
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
138
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
137
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
155
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
154
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
171
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
170
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
190
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
189
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
206
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
205
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
222
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
221
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
242
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
241
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
258
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
257
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
279
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
278
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
295
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
294
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
313
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
312
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
329
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
328
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
347
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
346
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
363
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
362
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
381
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
380
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
397
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
396
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
415
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
414
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
431
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
430
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
448
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
447
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
464
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
463
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
484
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
483
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
500
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
499
|
+
if (bindingPackageVersion !== '0.6.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.6.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.6.
|
|
516
|
-
throw new Error(`Native binding package version mismatch, expected 0.6.
|
|
515
|
+
if (bindingPackageVersion !== '0.6.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.6.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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "satteri",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "High-performance Markdown and MDX processing",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -80,17 +80,19 @@
|
|
|
80
80
|
]
|
|
81
81
|
},
|
|
82
82
|
"optionalDependencies": {
|
|
83
|
-
"@bruits/satteri-linux-x64-gnu": "0.
|
|
84
|
-
"@bruits/satteri-darwin-x64": "0.
|
|
85
|
-
"@bruits/satteri-darwin-arm64": "0.
|
|
86
|
-
"@bruits/satteri-win32-x64-msvc": "0.
|
|
87
|
-
"@bruits/satteri-wasm32-wasi": "0.
|
|
83
|
+
"@bruits/satteri-linux-x64-gnu": "0.7.0",
|
|
84
|
+
"@bruits/satteri-darwin-x64": "0.7.0",
|
|
85
|
+
"@bruits/satteri-darwin-arm64": "0.7.0",
|
|
86
|
+
"@bruits/satteri-win32-x64-msvc": "0.7.0",
|
|
87
|
+
"@bruits/satteri-wasm32-wasi": "0.7.0"
|
|
88
88
|
},
|
|
89
89
|
"scripts": {
|
|
90
90
|
"build:binary:wasm": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm --strip --target wasm32-wasip1-threads",
|
|
91
91
|
"postbuild:binary:wasm": "node patch-binding.js",
|
|
92
92
|
"build:binary:native": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm --strip",
|
|
93
93
|
"postbuild:binary:native": "node patch-binding.js",
|
|
94
|
+
"build:binary:native:lite": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm --strip -- --no-default-features",
|
|
95
|
+
"postbuild:binary:native:lite": "node patch-binding.js",
|
|
94
96
|
"build:binary:native:cross": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --release --esm --strip --cross-compile",
|
|
95
97
|
"postbuild:binary:native:cross": "node patch-binding.js",
|
|
96
98
|
"build:binary:native:debug": "napi build --manifest-path ../../crates/satteri-napi-binding/Cargo.toml --output-dir . --platform --esm",
|