satteri 0.9.0 → 0.9.1
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 +21 -2
- package/dist/compile.d.ts +10 -2
- package/dist/compile.js +28 -26
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -182,9 +182,25 @@ const { html, data } = markdownToHtml("# A\n\n# B", { mdastPlugins: [collectHead
|
|
|
182
182
|
console.log(data?.headings); // ["A", "B"]
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
The bag lives entirely on the JS side, so any value is allowed, including functions, class instances, and `Map`/`Set`. References are preserved across plugins and across the mdast→hast boundary. A fresh, empty bag is created for every compile.
|
|
185
|
+
The bag lives entirely on the JS side, so any value is allowed, including functions, class instances, and `Map`/`Set`. References are preserved across plugins and across the mdast→hast boundary. A fresh, empty bag is created for every compile unless you seed one with the `data` option.
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
To seed data into the bag before plugins run, pass an object to the `data` option. The same object is available in all plugins and returned as `result.data` after compilation, so you can pre-populate it with values or methods that plugins can read and update.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const data = { title: "Hello" };
|
|
191
|
+
const rewriteTitle = defineMdastPlugin({
|
|
192
|
+
name: "rewrite-title",
|
|
193
|
+
heading(_node, ctx) {
|
|
194
|
+
ctx.data.title = "Updated";
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const result = markdownToHtml("# A", { mdastPlugins: [rewriteTitle], data });
|
|
199
|
+
console.log(result.data === data); // true, the seeded object is returned
|
|
200
|
+
console.log(data.title); // "Updated"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
By default keys are typed as `unknown`. To give a key a type, augment the `DataMap` interface:
|
|
188
204
|
|
|
189
205
|
```ts
|
|
190
206
|
declare module "satteri" {
|
|
@@ -334,6 +350,7 @@ interface CompileOptions {
|
|
|
334
350
|
hastPlugins?: HastPluginDefinition[];
|
|
335
351
|
features?: Features;
|
|
336
352
|
fileURL?: URL;
|
|
353
|
+
data?: Data;
|
|
337
354
|
}
|
|
338
355
|
|
|
339
356
|
// mdxToJs accepts MdxCompileOptions, which extends CompileOptions
|
|
@@ -344,6 +361,8 @@ interface MdxCompileOptions extends CompileOptions {
|
|
|
344
361
|
|
|
345
362
|
`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)`.
|
|
346
363
|
|
|
364
|
+
`data` seeds the document-level data bag before plugins run, surfaced as `ctx.data` and returned as `result.data`. See [Sharing data between plugins](#sharing-data-between-plugins).
|
|
365
|
+
|
|
347
366
|
`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.
|
|
348
367
|
|
|
349
368
|
## License
|
package/dist/compile.d.ts
CHANGED
|
@@ -130,6 +130,14 @@ export interface CompileOptions {
|
|
|
130
130
|
* `pathToFileURL` before passing it.
|
|
131
131
|
*/
|
|
132
132
|
fileURL?: URL;
|
|
133
|
+
/**
|
|
134
|
+
* Initial document-level data bag, seeding `ctx.data` before any plugin runs.
|
|
135
|
+
* It is the same object plugins mutate and the caller reads back as
|
|
136
|
+
* `result.data`, so values flow both into and out of a compile. Defaults to a
|
|
137
|
+
* fresh empty object. Used by reference and mutated in place, so pass a
|
|
138
|
+
* throwaway object per compile rather than a shared one.
|
|
139
|
+
*/
|
|
140
|
+
data?: Data;
|
|
133
141
|
}
|
|
134
142
|
/**
|
|
135
143
|
* MDX-only compile options.
|
|
@@ -200,7 +208,7 @@ export interface MarkdownToHtmlResult {
|
|
|
200
208
|
html: string;
|
|
201
209
|
/** Frontmatter block at the start of the document, or `null` if none. */
|
|
202
210
|
frontmatter: Frontmatter | null;
|
|
203
|
-
/** Document-level data bag
|
|
211
|
+
/** Document-level data bag shared with plugins via `ctx.data`; the seeded `data` option if provided, else a fresh `{}`. */
|
|
204
212
|
data: Data;
|
|
205
213
|
}
|
|
206
214
|
/** Result of {@link mdxToJs}. */
|
|
@@ -209,7 +217,7 @@ export interface MdxToJsResult {
|
|
|
209
217
|
code: string;
|
|
210
218
|
/** Frontmatter block at the start of the document, or `null` if none. */
|
|
211
219
|
frontmatter: Frontmatter | null;
|
|
212
|
-
/** Document-level data bag
|
|
220
|
+
/** Document-level data bag shared with plugins via `ctx.data`; the seeded `data` option if provided, else a fresh `{}`. */
|
|
213
221
|
data: Data;
|
|
214
222
|
}
|
|
215
223
|
type AnyFn = (...args: any[]) => unknown;
|
package/dist/compile.js
CHANGED
|
@@ -75,11 +75,12 @@ function featuresToNative(features) {
|
|
|
75
75
|
}
|
|
76
76
|
return { features: result, convertOptions };
|
|
77
77
|
}
|
|
78
|
-
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
function
|
|
82
|
-
|
|
78
|
+
/** Free a handle's arena. A plugin's visitor can hand child stubs to user code;
|
|
79
|
+
* pass `invalidateStubs` so the epoch bump makes any stub retained past this
|
|
80
|
+
* point hit the designed retention error instead of snapshotting the freed arena. */
|
|
81
|
+
function releaseHandle(handle, invalidateStubs) {
|
|
82
|
+
if (invalidateStubs)
|
|
83
|
+
markHandleMutated(handle);
|
|
83
84
|
dropHandle(handle);
|
|
84
85
|
}
|
|
85
86
|
function warnDroppedTransforms(plugin, dropped, kind) {
|
|
@@ -190,9 +191,9 @@ function mdxOptionsToNative(opts) {
|
|
|
190
191
|
return result;
|
|
191
192
|
}
|
|
192
193
|
export function markdownToHtml(source, options = {}) {
|
|
193
|
-
const { mdastPlugins = [], hastPlugins = [], features, fileURL } = options;
|
|
194
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL, data = {} } = options;
|
|
195
|
+
const hastMayHaveStubs = hastPlugins.length > 0;
|
|
194
196
|
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
195
|
-
const data = {};
|
|
196
197
|
const result = createHastHandleFromMdast(source, mdastPlugins, false, fileURL, nativeFeatures, nativeConvertOptions, data);
|
|
197
198
|
const renderAndDrop = (h, frontmatter) => {
|
|
198
199
|
try {
|
|
@@ -200,7 +201,7 @@ export function markdownToHtml(source, options = {}) {
|
|
|
200
201
|
return { html, frontmatter, data };
|
|
201
202
|
}
|
|
202
203
|
finally {
|
|
203
|
-
|
|
204
|
+
releaseHandle(h, hastMayHaveStubs);
|
|
204
205
|
}
|
|
205
206
|
};
|
|
206
207
|
const runHastThenRender = (r) => {
|
|
@@ -209,12 +210,12 @@ export function markdownToHtml(source, options = {}) {
|
|
|
209
210
|
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL, data);
|
|
210
211
|
}
|
|
211
212
|
catch (err) {
|
|
212
|
-
|
|
213
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
213
214
|
throw err;
|
|
214
215
|
}
|
|
215
216
|
if (hastResult instanceof Promise) {
|
|
216
217
|
return hastResult.then(() => renderAndDrop(r.hastHandle, r.frontmatter), (err) => {
|
|
217
|
-
|
|
218
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
218
219
|
throw err;
|
|
219
220
|
});
|
|
220
221
|
}
|
|
@@ -225,10 +226,10 @@ export function markdownToHtml(source, options = {}) {
|
|
|
225
226
|
return runHastThenRender(result);
|
|
226
227
|
}
|
|
227
228
|
export function mdxToJs(source, options = {}) {
|
|
228
|
-
const { mdastPlugins = [], hastPlugins = [], features, fileURL, ...mdxFields } = options;
|
|
229
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL, data = {}, ...mdxFields } = options;
|
|
230
|
+
const hastMayHaveStubs = hastPlugins.length > 0;
|
|
229
231
|
const mdxOptions = mdxOptionsToNative(mdxFields);
|
|
230
232
|
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
231
|
-
const data = {};
|
|
232
233
|
const result = createHastHandleFromMdast(source, mdastPlugins, true, fileURL, nativeFeatures, nativeConvertOptions, data);
|
|
233
234
|
const compileAndDrop = (h, frontmatter) => {
|
|
234
235
|
try {
|
|
@@ -236,7 +237,7 @@ export function mdxToJs(source, options = {}) {
|
|
|
236
237
|
return { code, frontmatter, data };
|
|
237
238
|
}
|
|
238
239
|
finally {
|
|
239
|
-
|
|
240
|
+
releaseHandle(h, hastMayHaveStubs);
|
|
240
241
|
}
|
|
241
242
|
};
|
|
242
243
|
const runHastThenCompile = (r) => {
|
|
@@ -245,12 +246,12 @@ export function mdxToJs(source, options = {}) {
|
|
|
245
246
|
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL, data);
|
|
246
247
|
}
|
|
247
248
|
catch (err) {
|
|
248
|
-
|
|
249
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
249
250
|
throw err;
|
|
250
251
|
}
|
|
251
252
|
if (hastResult instanceof Promise) {
|
|
252
253
|
return hastResult.then(() => compileAndDrop(r.hastHandle, r.frontmatter), (err) => {
|
|
253
|
-
|
|
254
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
254
255
|
throw err;
|
|
255
256
|
});
|
|
256
257
|
}
|
|
@@ -295,19 +296,20 @@ nativeConvertOptions, data) {
|
|
|
295
296
|
const mdastHandle = mdx
|
|
296
297
|
? createMdxMdastHandle(source, nativeFeatures)
|
|
297
298
|
: createMdastHandle(source, nativeFeatures);
|
|
298
|
-
|
|
299
|
+
const mdastMayHaveStubs = mdastPlugins.length > 0;
|
|
300
|
+
// finally{release} is intentional: convertMdastToHastHandle empties the arena
|
|
299
301
|
// on success, but if any step here throws the handle would otherwise leak.
|
|
300
302
|
const finalize = (r) => {
|
|
301
303
|
try {
|
|
302
304
|
const frontmatter = readFrontmatter(r.handle);
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
// convert empties the mdast arena, so invalidate any stub held past this point.
|
|
306
|
+
if (mdastMayHaveStubs)
|
|
307
|
+
markHandleMutated(r.handle);
|
|
306
308
|
const hastHandle = convertMdastToHastHandle(r.handle, nativeConvertOptions);
|
|
307
309
|
return { hastHandle, frontmatter };
|
|
308
310
|
}
|
|
309
311
|
finally {
|
|
310
|
-
|
|
312
|
+
releaseHandle(r.handle, mdastMayHaveStubs);
|
|
311
313
|
}
|
|
312
314
|
};
|
|
313
315
|
try {
|
|
@@ -317,14 +319,14 @@ nativeConvertOptions, data) {
|
|
|
317
319
|
const mdastResult = runMdastPluginsOnHandle(mdastHandle, mdastPlugins, fileURL, data);
|
|
318
320
|
if (mdastResult instanceof Promise) {
|
|
319
321
|
return mdastResult.then(finalize, (err) => {
|
|
320
|
-
|
|
322
|
+
releaseHandle(mdastHandle, mdastMayHaveStubs);
|
|
321
323
|
throw err;
|
|
322
324
|
});
|
|
323
325
|
}
|
|
324
326
|
return finalize(mdastResult);
|
|
325
327
|
}
|
|
326
328
|
catch (err) {
|
|
327
|
-
|
|
329
|
+
releaseHandle(mdastHandle, mdastMayHaveStubs);
|
|
328
330
|
throw err;
|
|
329
331
|
}
|
|
330
332
|
}
|
|
@@ -336,7 +338,7 @@ export function markdownToMdast(source, options = {}) {
|
|
|
336
338
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
337
339
|
}
|
|
338
340
|
finally {
|
|
339
|
-
|
|
341
|
+
releaseHandle(handle, true);
|
|
340
342
|
}
|
|
341
343
|
}
|
|
342
344
|
/** Parse MDX source into a materialized mdast tree. */
|
|
@@ -346,7 +348,7 @@ export function mdxToMdast(source, options = {}) {
|
|
|
346
348
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
347
349
|
}
|
|
348
350
|
finally {
|
|
349
|
-
|
|
351
|
+
releaseHandle(handle, true);
|
|
350
352
|
}
|
|
351
353
|
}
|
|
352
354
|
/** Convert Markdown source to a materialized hast tree. */
|
|
@@ -357,7 +359,7 @@ export function markdownToHast(source, options = {}) {
|
|
|
357
359
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
358
360
|
}
|
|
359
361
|
finally {
|
|
360
|
-
|
|
362
|
+
releaseHandle(handle, true);
|
|
361
363
|
}
|
|
362
364
|
}
|
|
363
365
|
/** Convert MDX source to a materialized hast tree. */
|
|
@@ -368,6 +370,6 @@ export function mdxToHast(source, options = {}) {
|
|
|
368
370
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
369
371
|
}
|
|
370
372
|
finally {
|
|
371
|
-
|
|
373
|
+
releaseHandle(handle, true);
|
|
372
374
|
}
|
|
373
375
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "satteri",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "High-performance Markdown and MDX processing",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
]
|
|
81
81
|
},
|
|
82
82
|
"optionalDependencies": {
|
|
83
|
-
"@bruits/satteri-linux-x64-gnu": "0.9.
|
|
84
|
-
"@bruits/satteri-darwin-x64": "0.9.
|
|
85
|
-
"@bruits/satteri-darwin-arm64": "0.9.
|
|
86
|
-
"@bruits/satteri-win32-x64-msvc": "0.9.
|
|
87
|
-
"@bruits/satteri-wasm32-wasi": "0.9.
|
|
83
|
+
"@bruits/satteri-linux-x64-gnu": "0.9.1",
|
|
84
|
+
"@bruits/satteri-darwin-x64": "0.9.1",
|
|
85
|
+
"@bruits/satteri-darwin-arm64": "0.9.1",
|
|
86
|
+
"@bruits/satteri-win32-x64-msvc": "0.9.1",
|
|
87
|
+
"@bruits/satteri-wasm32-wasi": "0.9.1"
|
|
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",
|