satteri 0.8.1 → 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 +54 -0
- package/dist/byte-writer.d.ts +31 -0
- package/dist/byte-writer.js +106 -0
- package/dist/child-stub.d.ts +17 -0
- package/dist/child-stub.js +57 -0
- package/dist/command-buffer.d.ts +23 -26
- package/dist/command-buffer.js +64 -132
- package/dist/compile.d.ts +13 -1
- package/dist/compile.js +44 -28
- package/dist/directive-types.d.ts +4 -2
- package/dist/generated/arena-layout.d.ts +37 -0
- package/dist/generated/arena-layout.js +41 -0
- package/dist/generated/wire-constants.d.ts +51 -0
- package/dist/generated/wire-constants.js +63 -0
- package/dist/handles.d.ts +21 -0
- package/dist/handles.js +1 -0
- package/dist/hast/child-stub.d.ts +18 -0
- package/dist/hast/child-stub.js +43 -0
- package/dist/hast/element-props.d.ts +2 -0
- package/dist/hast/element-props.js +23 -0
- package/dist/hast/generated/node-types.d.ts +14 -0
- package/dist/hast/generated/node-types.js +64 -0
- package/dist/hast/hast-materializer.d.ts +2 -1
- package/dist/hast/hast-materializer.js +9 -45
- package/dist/hast/hast-reader.d.ts +18 -23
- package/dist/hast/hast-reader.js +48 -115
- package/dist/hast/hast-visitor.d.ts +35 -13
- package/dist/hast/hast-visitor.js +395 -302
- package/dist/index.d.ts +10 -4
- package/dist/index.js +23 -1
- package/dist/lazy-child-resolver.d.ts +36 -0
- package/dist/lazy-child-resolver.js +95 -0
- package/dist/lazy-props.d.ts +1 -1
- package/dist/mdast/child-stub.d.ts +18 -0
- package/dist/mdast/child-stub.js +46 -0
- package/dist/mdast/column-align.d.ts +1 -0
- package/dist/mdast/column-align.js +6 -0
- package/dist/mdast/generated/layout.d.ts +19 -0
- package/dist/mdast/generated/layout.js +272 -0
- package/dist/mdast/generated/node-types.d.ts +58 -0
- package/dist/mdast/generated/node-types.js +266 -0
- package/dist/mdast/mdast-materializer.d.ts +3 -2
- package/dist/mdast/mdast-materializer.js +9 -93
- package/dist/mdast/mdast-reader.d.ts +4 -120
- package/dist/mdast/mdast-reader.js +45 -272
- package/dist/mdast/mdast-visitor.d.ts +52 -14
- package/dist/mdast/mdast-visitor.js +348 -427
- package/dist/mdx-attr.d.ts +2 -0
- package/dist/mdx-attr.js +20 -0
- package/dist/op-stream.d.ts +38 -0
- package/dist/op-stream.js +125 -0
- package/dist/phantom.d.ts +2 -0
- package/dist/phantom.js +13 -0
- package/dist/types.d.ts +34 -4
- package/dist/visitor-shared.d.ts +28 -0
- package/dist/visitor-shared.js +52 -0
- package/dist/wire-read.d.ts +27 -0
- package/dist/wire-read.js +59 -0
- package/index.js +52 -52
- package/package.json +6 -6
package/dist/compile.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MdastPluginInput, HastPluginInput } from "./plugin.js";
|
|
2
|
-
import type { MdastNode, HastNode } from "./types.js";
|
|
2
|
+
import type { MdastNode, HastNode, Data } from "./types.js";
|
|
3
3
|
/** Configuration for static subtree collapsing during MDX compilation. */
|
|
4
4
|
export interface OptimizeStaticConfig {
|
|
5
5
|
component: string;
|
|
@@ -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,6 +208,8 @@ 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;
|
|
211
|
+
/** Document-level data bag shared with plugins via `ctx.data`; the seeded `data` option if provided, else a fresh `{}`. */
|
|
212
|
+
data: Data;
|
|
203
213
|
}
|
|
204
214
|
/** Result of {@link mdxToJs}. */
|
|
205
215
|
export interface MdxToJsResult {
|
|
@@ -207,6 +217,8 @@ export interface MdxToJsResult {
|
|
|
207
217
|
code: string;
|
|
208
218
|
/** Frontmatter block at the start of the document, or `null` if none. */
|
|
209
219
|
frontmatter: Frontmatter | null;
|
|
220
|
+
/** Document-level data bag shared with plugins via `ctx.data`; the seeded `data` option if provided, else a fresh `{}`. */
|
|
221
|
+
data: Data;
|
|
210
222
|
}
|
|
211
223
|
type AnyFn = (...args: any[]) => unknown;
|
|
212
224
|
type ReturnsPromise<F> = F extends AnyFn ? Extract<ReturnType<F>, Promise<unknown>> extends never ? false : true : false;
|
package/dist/compile.js
CHANGED
|
@@ -3,6 +3,7 @@ import { visitMdastHandle, resolveMdastSubscriptions, } from "./mdast/mdast-visi
|
|
|
3
3
|
import { createHastHandle, createMdxHastHandle, renderHandle, compileHandle, dropHandle, createMdastHandle, createMdxMdastHandle, applyCommandsToMdastHandle, convertMdastToHastHandle, getHandleSource, getMdastFrontmatter, serializeHandle, } from "#binding";
|
|
4
4
|
import { MdastReader } from "./mdast/mdast-reader.js";
|
|
5
5
|
import { materializeMdastTree } from "./mdast/mdast-materializer.js";
|
|
6
|
+
import { markHandleMutated } from "./lazy-child-resolver.js";
|
|
6
7
|
import { HastReader } from "./hast/hast-reader.js";
|
|
7
8
|
import { materializeHastTree } from "./hast/hast-materializer.js";
|
|
8
9
|
/**
|
|
@@ -74,13 +75,21 @@ function featuresToNative(features) {
|
|
|
74
75
|
}
|
|
75
76
|
return { features: result, convertOptions };
|
|
76
77
|
}
|
|
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);
|
|
84
|
+
dropHandle(handle);
|
|
85
|
+
}
|
|
77
86
|
function warnDroppedTransforms(plugin, dropped, kind) {
|
|
78
87
|
const name = plugin.name ?? "<anonymous>";
|
|
79
88
|
const noun = dropped === 1 ? "transform" : "transforms";
|
|
80
89
|
console.warn(`satteri: plugin "${name}" queued ${dropped} ${kind} ${noun} on node(s) that were removed or ` +
|
|
81
90
|
`replaced earlier in the same pass; ${dropped === 1 ? "it was" : "they were"} dropped.`);
|
|
82
91
|
}
|
|
83
|
-
function runMdastPluginsOnHandle(handle, plugins, fileURL) {
|
|
92
|
+
function runMdastPluginsOnHandle(handle, plugins, fileURL, data) {
|
|
84
93
|
// Each plugin runs once over the tree. A transform that passes a child
|
|
85
94
|
// through (returning it inside the replacement) keeps that child's identity,
|
|
86
95
|
// so a patch the same pass queued on it still applies — nesting composes in
|
|
@@ -88,10 +97,11 @@ function runMdastPluginsOnHandle(handle, plugins, fileURL) {
|
|
|
88
97
|
// them up front, or hand off to a later plugin that sees the materialized tree.
|
|
89
98
|
const runPlugin = (plugin) => {
|
|
90
99
|
const subs = resolveMdastSubscriptions(plugin);
|
|
91
|
-
const result = visitMdastHandle(handle, plugin, subs, () => getHandleSource(handle), fileURL);
|
|
100
|
+
const result = visitMdastHandle(handle, plugin, subs, () => getHandleSource(handle), fileURL, data);
|
|
92
101
|
const apply = (r) => {
|
|
93
102
|
if (!r.hasMutations)
|
|
94
103
|
return;
|
|
104
|
+
markHandleMutated(handle);
|
|
95
105
|
const dropped = applyCommandsToMdastHandle(handle, r.commandBuffer);
|
|
96
106
|
if (dropped)
|
|
97
107
|
warnDroppedTransforms(plugin, dropped, "mdast");
|
|
@@ -111,7 +121,7 @@ function runMdastPluginsOnHandle(handle, plugins, fileURL) {
|
|
|
111
121
|
};
|
|
112
122
|
return runNext();
|
|
113
123
|
}
|
|
114
|
-
function runHastPluginsOnHandle(handle, plugins, source, fileURL) {
|
|
124
|
+
function runHastPluginsOnHandle(handle, plugins, source, fileURL, data) {
|
|
115
125
|
if (plugins.length === 0)
|
|
116
126
|
return;
|
|
117
127
|
let i = 0;
|
|
@@ -121,7 +131,7 @@ function runHastPluginsOnHandle(handle, plugins, source, fileURL) {
|
|
|
121
131
|
i++;
|
|
122
132
|
const plugin = typeof raw === "function" ? raw() : raw;
|
|
123
133
|
const subs = resolveSubscriptions(plugin);
|
|
124
|
-
const result = visitHastHandle(handle, plugin, subs, source, fileURL);
|
|
134
|
+
const result = visitHastHandle(handle, plugin, subs, source, fileURL, data);
|
|
125
135
|
const warnIfDropped = (dropped) => {
|
|
126
136
|
if (dropped)
|
|
127
137
|
warnDroppedTransforms(plugin, dropped, "hast");
|
|
@@ -181,30 +191,31 @@ function mdxOptionsToNative(opts) {
|
|
|
181
191
|
return result;
|
|
182
192
|
}
|
|
183
193
|
export function markdownToHtml(source, options = {}) {
|
|
184
|
-
const { mdastPlugins = [], hastPlugins = [], features, fileURL } = options;
|
|
194
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL, data = {} } = options;
|
|
195
|
+
const hastMayHaveStubs = hastPlugins.length > 0;
|
|
185
196
|
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
186
|
-
const result = createHastHandleFromMdast(source, mdastPlugins, false, fileURL, nativeFeatures, nativeConvertOptions);
|
|
197
|
+
const result = createHastHandleFromMdast(source, mdastPlugins, false, fileURL, nativeFeatures, nativeConvertOptions, data);
|
|
187
198
|
const renderAndDrop = (h, frontmatter) => {
|
|
188
199
|
try {
|
|
189
200
|
const html = renderHandle(h);
|
|
190
|
-
return { html, frontmatter };
|
|
201
|
+
return { html, frontmatter, data };
|
|
191
202
|
}
|
|
192
203
|
finally {
|
|
193
|
-
|
|
204
|
+
releaseHandle(h, hastMayHaveStubs);
|
|
194
205
|
}
|
|
195
206
|
};
|
|
196
207
|
const runHastThenRender = (r) => {
|
|
197
208
|
let hastResult;
|
|
198
209
|
try {
|
|
199
|
-
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL);
|
|
210
|
+
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL, data);
|
|
200
211
|
}
|
|
201
212
|
catch (err) {
|
|
202
|
-
|
|
213
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
203
214
|
throw err;
|
|
204
215
|
}
|
|
205
216
|
if (hastResult instanceof Promise) {
|
|
206
217
|
return hastResult.then(() => renderAndDrop(r.hastHandle, r.frontmatter), (err) => {
|
|
207
|
-
|
|
218
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
208
219
|
throw err;
|
|
209
220
|
});
|
|
210
221
|
}
|
|
@@ -215,31 +226,32 @@ export function markdownToHtml(source, options = {}) {
|
|
|
215
226
|
return runHastThenRender(result);
|
|
216
227
|
}
|
|
217
228
|
export function mdxToJs(source, options = {}) {
|
|
218
|
-
const { mdastPlugins = [], hastPlugins = [], features, fileURL, ...mdxFields } = options;
|
|
229
|
+
const { mdastPlugins = [], hastPlugins = [], features, fileURL, data = {}, ...mdxFields } = options;
|
|
230
|
+
const hastMayHaveStubs = hastPlugins.length > 0;
|
|
219
231
|
const mdxOptions = mdxOptionsToNative(mdxFields);
|
|
220
232
|
const { features: nativeFeatures, convertOptions: nativeConvertOptions } = featuresToNative(features);
|
|
221
|
-
const result = createHastHandleFromMdast(source, mdastPlugins, true, fileURL, nativeFeatures, nativeConvertOptions);
|
|
233
|
+
const result = createHastHandleFromMdast(source, mdastPlugins, true, fileURL, nativeFeatures, nativeConvertOptions, data);
|
|
222
234
|
const compileAndDrop = (h, frontmatter) => {
|
|
223
235
|
try {
|
|
224
236
|
const code = compileHandle(h, mdxOptions);
|
|
225
|
-
return { code, frontmatter };
|
|
237
|
+
return { code, frontmatter, data };
|
|
226
238
|
}
|
|
227
239
|
finally {
|
|
228
|
-
|
|
240
|
+
releaseHandle(h, hastMayHaveStubs);
|
|
229
241
|
}
|
|
230
242
|
};
|
|
231
243
|
const runHastThenCompile = (r) => {
|
|
232
244
|
let hastResult;
|
|
233
245
|
try {
|
|
234
|
-
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL);
|
|
246
|
+
hastResult = runHastPluginsOnHandle(r.hastHandle, hastPlugins, source, fileURL, data);
|
|
235
247
|
}
|
|
236
248
|
catch (err) {
|
|
237
|
-
|
|
249
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
238
250
|
throw err;
|
|
239
251
|
}
|
|
240
252
|
if (hastResult instanceof Promise) {
|
|
241
253
|
return hastResult.then(() => compileAndDrop(r.hastHandle, r.frontmatter), (err) => {
|
|
242
|
-
|
|
254
|
+
releaseHandle(r.hastHandle, hastMayHaveStubs);
|
|
243
255
|
throw err;
|
|
244
256
|
});
|
|
245
257
|
}
|
|
@@ -280,37 +292,41 @@ function createHastHandleFromMdast(source, mdastPlugins, mdx, fileURL,
|
|
|
280
292
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
281
293
|
nativeFeatures,
|
|
282
294
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
283
|
-
nativeConvertOptions) {
|
|
295
|
+
nativeConvertOptions, data) {
|
|
284
296
|
const mdastHandle = mdx
|
|
285
297
|
? createMdxMdastHandle(source, nativeFeatures)
|
|
286
298
|
: createMdastHandle(source, nativeFeatures);
|
|
287
|
-
|
|
299
|
+
const mdastMayHaveStubs = mdastPlugins.length > 0;
|
|
300
|
+
// finally{release} is intentional: convertMdastToHastHandle empties the arena
|
|
288
301
|
// on success, but if any step here throws the handle would otherwise leak.
|
|
289
302
|
const finalize = (r) => {
|
|
290
303
|
try {
|
|
291
304
|
const frontmatter = readFrontmatter(r.handle);
|
|
305
|
+
// convert empties the mdast arena, so invalidate any stub held past this point.
|
|
306
|
+
if (mdastMayHaveStubs)
|
|
307
|
+
markHandleMutated(r.handle);
|
|
292
308
|
const hastHandle = convertMdastToHastHandle(r.handle, nativeConvertOptions);
|
|
293
309
|
return { hastHandle, frontmatter };
|
|
294
310
|
}
|
|
295
311
|
finally {
|
|
296
|
-
|
|
312
|
+
releaseHandle(r.handle, mdastMayHaveStubs);
|
|
297
313
|
}
|
|
298
314
|
};
|
|
299
315
|
try {
|
|
300
316
|
if (mdastPlugins.length === 0) {
|
|
301
317
|
return finalize({ handle: mdastHandle });
|
|
302
318
|
}
|
|
303
|
-
const mdastResult = runMdastPluginsOnHandle(mdastHandle, mdastPlugins, fileURL);
|
|
319
|
+
const mdastResult = runMdastPluginsOnHandle(mdastHandle, mdastPlugins, fileURL, data);
|
|
304
320
|
if (mdastResult instanceof Promise) {
|
|
305
321
|
return mdastResult.then(finalize, (err) => {
|
|
306
|
-
|
|
322
|
+
releaseHandle(mdastHandle, mdastMayHaveStubs);
|
|
307
323
|
throw err;
|
|
308
324
|
});
|
|
309
325
|
}
|
|
310
326
|
return finalize(mdastResult);
|
|
311
327
|
}
|
|
312
328
|
catch (err) {
|
|
313
|
-
|
|
329
|
+
releaseHandle(mdastHandle, mdastMayHaveStubs);
|
|
314
330
|
throw err;
|
|
315
331
|
}
|
|
316
332
|
}
|
|
@@ -322,7 +338,7 @@ export function markdownToMdast(source, options = {}) {
|
|
|
322
338
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
323
339
|
}
|
|
324
340
|
finally {
|
|
325
|
-
|
|
341
|
+
releaseHandle(handle, true);
|
|
326
342
|
}
|
|
327
343
|
}
|
|
328
344
|
/** Parse MDX source into a materialized mdast tree. */
|
|
@@ -332,7 +348,7 @@ export function mdxToMdast(source, options = {}) {
|
|
|
332
348
|
return materializeMdastTree(new MdastReader(serializeHandle(handle)));
|
|
333
349
|
}
|
|
334
350
|
finally {
|
|
335
|
-
|
|
351
|
+
releaseHandle(handle, true);
|
|
336
352
|
}
|
|
337
353
|
}
|
|
338
354
|
/** Convert Markdown source to a materialized hast tree. */
|
|
@@ -343,7 +359,7 @@ export function markdownToHast(source, options = {}) {
|
|
|
343
359
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
344
360
|
}
|
|
345
361
|
finally {
|
|
346
|
-
|
|
362
|
+
releaseHandle(handle, true);
|
|
347
363
|
}
|
|
348
364
|
}
|
|
349
365
|
/** Convert MDX source to a materialized hast tree. */
|
|
@@ -354,6 +370,6 @@ export function mdxToHast(source, options = {}) {
|
|
|
354
370
|
return materializeHastTree(new HastReader(serializeHandle(handle)));
|
|
355
371
|
}
|
|
356
372
|
finally {
|
|
357
|
-
|
|
373
|
+
releaseHandle(handle, true);
|
|
358
374
|
}
|
|
359
375
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BlockContent, Data as MdastData, DefinitionContent, Parent as MdastParent, PhrasingContent } from "mdast";
|
|
2
|
-
export type DirectiveAttributes = Record<string, string>;
|
|
2
|
+
export type DirectiveAttributes = Record<string, string | null | undefined>;
|
|
3
3
|
export interface ContainerDirective extends MdastParent {
|
|
4
4
|
type: "containerDirective";
|
|
5
5
|
name: string;
|
|
@@ -8,7 +8,6 @@ export interface ContainerDirective extends MdastParent {
|
|
|
8
8
|
data?: ContainerDirectiveData | undefined;
|
|
9
9
|
}
|
|
10
10
|
export interface ContainerDirectiveData extends MdastData {
|
|
11
|
-
directiveLabel?: boolean | undefined;
|
|
12
11
|
}
|
|
13
12
|
export interface LeafDirective extends MdastParent {
|
|
14
13
|
type: "leafDirective";
|
|
@@ -33,6 +32,9 @@ declare module "mdast" {
|
|
|
33
32
|
containerDirective: ContainerDirective;
|
|
34
33
|
leafDirective: LeafDirective;
|
|
35
34
|
}
|
|
35
|
+
interface ParagraphData {
|
|
36
|
+
directiveLabel?: boolean | null | undefined;
|
|
37
|
+
}
|
|
36
38
|
interface PhrasingContentMap {
|
|
37
39
|
textDirective: TextDirective;
|
|
38
40
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** `b"MDAR"` magic, read as a little-endian u32. */
|
|
2
|
+
export declare const ARENA_MAGIC = 1380009037;
|
|
3
|
+
/** `Arena<K>` kind tags carried in the header's `kind` field. */
|
|
4
|
+
export declare const KIND_MDAST = 1;
|
|
5
|
+
export declare const KIND_HAST = 2;
|
|
6
|
+
/** `ArenaNode` `#[repr(C)]` field byte offsets (u32 fields; `node_type` is a u8). */
|
|
7
|
+
export declare const FIELD: {
|
|
8
|
+
readonly id: 0;
|
|
9
|
+
readonly node_type: 4;
|
|
10
|
+
readonly parent: 8;
|
|
11
|
+
readonly start_offset: 12;
|
|
12
|
+
readonly end_offset: 16;
|
|
13
|
+
readonly start_line: 20;
|
|
14
|
+
readonly start_column: 24;
|
|
15
|
+
readonly end_line: 28;
|
|
16
|
+
readonly end_column: 32;
|
|
17
|
+
readonly children_start: 36;
|
|
18
|
+
readonly children_count: 40;
|
|
19
|
+
readonly data_offset: 44;
|
|
20
|
+
readonly data_len: 48;
|
|
21
|
+
};
|
|
22
|
+
/** Raw-buffer header byte offsets (4-byte fields, u32 LE). */
|
|
23
|
+
export declare const HEADER: {
|
|
24
|
+
readonly magic: 0;
|
|
25
|
+
readonly kind: 4;
|
|
26
|
+
readonly node_struct_size: 8;
|
|
27
|
+
readonly node_count: 12;
|
|
28
|
+
readonly nodes_offset: 16;
|
|
29
|
+
readonly children_count: 20;
|
|
30
|
+
readonly children_offset: 24;
|
|
31
|
+
readonly type_data_len: 28;
|
|
32
|
+
readonly type_data_offset: 32;
|
|
33
|
+
readonly source_len: 36;
|
|
34
|
+
readonly source_offset: 40;
|
|
35
|
+
readonly node_data_count: 44;
|
|
36
|
+
readonly node_data_offset: 48;
|
|
37
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// @generated by `cargo run -p satteri-layout-codegen`. Do not edit by hand.
|
|
2
|
+
// Arena raw-buffer layout, declared once in `satteri-layout-codegen/src/schema.rs`.
|
|
3
|
+
// The Rust side is pinned to these offsets by the compile-time asserts in
|
|
4
|
+
// `satteri-arena/src/generated/layout.rs`.
|
|
5
|
+
/** `b"MDAR"` magic, read as a little-endian u32. */
|
|
6
|
+
export const ARENA_MAGIC = 0x5241444d;
|
|
7
|
+
/** `Arena<K>` kind tags carried in the header's `kind` field. */
|
|
8
|
+
export const KIND_MDAST = 1;
|
|
9
|
+
export const KIND_HAST = 2;
|
|
10
|
+
/** `ArenaNode` `#[repr(C)]` field byte offsets (u32 fields; `node_type` is a u8). */
|
|
11
|
+
export const FIELD = {
|
|
12
|
+
id: 0,
|
|
13
|
+
node_type: 4,
|
|
14
|
+
parent: 8,
|
|
15
|
+
start_offset: 12,
|
|
16
|
+
end_offset: 16,
|
|
17
|
+
start_line: 20,
|
|
18
|
+
start_column: 24,
|
|
19
|
+
end_line: 28,
|
|
20
|
+
end_column: 32,
|
|
21
|
+
children_start: 36,
|
|
22
|
+
children_count: 40,
|
|
23
|
+
data_offset: 44,
|
|
24
|
+
data_len: 48,
|
|
25
|
+
};
|
|
26
|
+
/** Raw-buffer header byte offsets (4-byte fields, u32 LE). */
|
|
27
|
+
export const HEADER = {
|
|
28
|
+
magic: 0,
|
|
29
|
+
kind: 4,
|
|
30
|
+
node_struct_size: 8,
|
|
31
|
+
node_count: 12,
|
|
32
|
+
nodes_offset: 16,
|
|
33
|
+
children_count: 20,
|
|
34
|
+
children_offset: 24,
|
|
35
|
+
type_data_len: 28,
|
|
36
|
+
type_data_offset: 32,
|
|
37
|
+
source_len: 36,
|
|
38
|
+
source_offset: 40,
|
|
39
|
+
node_data_count: 44,
|
|
40
|
+
node_data_offset: 48,
|
|
41
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare const OP_OPEN = 1;
|
|
2
|
+
export declare const OP_CLOSE = 2;
|
|
3
|
+
export declare const OP_REF = 3;
|
|
4
|
+
export declare const OP_KEEP_CHILDREN = 4;
|
|
5
|
+
export declare const OP_STR = 5;
|
|
6
|
+
export declare const OP_U8 = 6;
|
|
7
|
+
export declare const OP_U32 = 7;
|
|
8
|
+
export declare const OP_BOOL = 8;
|
|
9
|
+
export declare const OP_DATA = 9;
|
|
10
|
+
export declare const OP_PROP = 10;
|
|
11
|
+
export declare const OP_ALIGN = 11;
|
|
12
|
+
export declare const OF_VALUE = 0;
|
|
13
|
+
export declare const OF_URL = 1;
|
|
14
|
+
export declare const OF_TITLE = 2;
|
|
15
|
+
export declare const OF_ALT = 3;
|
|
16
|
+
export declare const OF_LANG = 4;
|
|
17
|
+
export declare const OF_META = 5;
|
|
18
|
+
export declare const OF_IDENTIFIER = 6;
|
|
19
|
+
export declare const OF_LABEL = 7;
|
|
20
|
+
export declare const OF_NAME = 8;
|
|
21
|
+
export declare const OF_REFERENCE_TYPE = 9;
|
|
22
|
+
export declare const OF_DEPTH = 10;
|
|
23
|
+
export declare const OF_CHECKED = 11;
|
|
24
|
+
export declare const OF_START = 12;
|
|
25
|
+
export declare const OF_ORDERED = 13;
|
|
26
|
+
export declare const OF_SPREAD = 14;
|
|
27
|
+
export declare const OF_TAGNAME = 15;
|
|
28
|
+
export declare const OF_EXPLICIT = 16;
|
|
29
|
+
export declare const CMD_REMOVE = 1;
|
|
30
|
+
export declare const CMD_INSERT_BEFORE = 5;
|
|
31
|
+
export declare const CMD_INSERT_AFTER = 6;
|
|
32
|
+
export declare const CMD_PREPEND_CHILD = 7;
|
|
33
|
+
export declare const CMD_APPEND_CHILD = 8;
|
|
34
|
+
export declare const CMD_WRAP = 9;
|
|
35
|
+
export declare const CMD_REPLACE = 11;
|
|
36
|
+
export declare const CMD_SET_PROPERTY = 12;
|
|
37
|
+
export declare const CMD_SET_CHILDREN = 13;
|
|
38
|
+
export declare const PAYLOAD_RAW_MARKDOWN = 16;
|
|
39
|
+
export declare const PAYLOAD_RAW_HTML = 17;
|
|
40
|
+
export declare const PAYLOAD_OPSTREAM = 20;
|
|
41
|
+
export declare const PROP_STRING = 0;
|
|
42
|
+
export declare const PROP_BOOL_TRUE = 1;
|
|
43
|
+
export declare const PROP_BOOL_FALSE = 2;
|
|
44
|
+
export declare const PROP_SPACE_SEP = 3;
|
|
45
|
+
export declare const PROP_COMMA_SEP = 4;
|
|
46
|
+
export declare const PROP_INT = 5;
|
|
47
|
+
export declare const PROP_NULL = 6;
|
|
48
|
+
export declare const MDX_ATTR_BOOLEAN_PROP = 0;
|
|
49
|
+
export declare const MDX_ATTR_LITERAL_PROP = 1;
|
|
50
|
+
export declare const MDX_ATTR_EXPRESSION_PROP = 2;
|
|
51
|
+
export declare const MDX_ATTR_SPREAD = 3;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// @generated by `cargo run -p satteri-layout-codegen`. Do not edit by hand.
|
|
2
|
+
// JS<->Rust wire-protocol byte values, declared once in
|
|
3
|
+
// `satteri-layout-codegen/src/schema.rs`. Rust twins live in
|
|
4
|
+
// `satteri-plugin-api/src/generated/wire_constants.rs` and
|
|
5
|
+
// `satteri-ast/src/generated/wire_constants.rs`.
|
|
6
|
+
// Op-stream op codes (JS `OpWriter` -> Rust `replay_opstream`).
|
|
7
|
+
export const OP_OPEN = 0x01; // [type: u8]
|
|
8
|
+
export const OP_CLOSE = 0x02;
|
|
9
|
+
export const OP_REF = 0x03; // [id: u32 LE] — splice an existing node
|
|
10
|
+
export const OP_KEEP_CHILDREN = 0x04; // splice the anchor node's original children
|
|
11
|
+
export const OP_STR = 0x05; // [field: u8][len: u32 LE][utf8]
|
|
12
|
+
export const OP_U8 = 0x06; // [field: u8][value: u8]
|
|
13
|
+
export const OP_U32 = 0x07; // [field: u8][value: u32 LE]
|
|
14
|
+
export const OP_BOOL = 0x08; // [field: u8][0|1]
|
|
15
|
+
export const OP_DATA = 0x09; // [len: u32 LE][json utf8]
|
|
16
|
+
export const OP_PROP = 0x0a; // [name str][kind: u8][value str] — HAST element property
|
|
17
|
+
export const OP_ALIGN = 0x0b; // [len: u32 LE][ColumnAlign bytes] — table column alignment
|
|
18
|
+
// Op-stream field ids (single namespace across OP_STR/OP_U8/OP_U32/OP_BOOL).
|
|
19
|
+
export const OF_VALUE = 0;
|
|
20
|
+
export const OF_URL = 1;
|
|
21
|
+
export const OF_TITLE = 2;
|
|
22
|
+
export const OF_ALT = 3;
|
|
23
|
+
export const OF_LANG = 4;
|
|
24
|
+
export const OF_META = 5;
|
|
25
|
+
export const OF_IDENTIFIER = 6;
|
|
26
|
+
export const OF_LABEL = 7;
|
|
27
|
+
export const OF_NAME = 8; // directive / MDX JSX element name
|
|
28
|
+
export const OF_REFERENCE_TYPE = 9;
|
|
29
|
+
export const OF_DEPTH = 10;
|
|
30
|
+
export const OF_CHECKED = 11;
|
|
31
|
+
export const OF_START = 12;
|
|
32
|
+
export const OF_ORDERED = 13;
|
|
33
|
+
export const OF_SPREAD = 14;
|
|
34
|
+
export const OF_TAGNAME = 15; // HAST element tag name
|
|
35
|
+
export const OF_EXPLICIT = 16; // MDX JSX `_mdxExplicitJsx` flag
|
|
36
|
+
// Command bytes (0x01–0x0F range). Each is followed by [nodeId: u32 LE];
|
|
37
|
+
// structural commands then carry [payloadType: u8][payload…].
|
|
38
|
+
export const CMD_REMOVE = 0x01;
|
|
39
|
+
export const CMD_INSERT_BEFORE = 0x05;
|
|
40
|
+
export const CMD_INSERT_AFTER = 0x06;
|
|
41
|
+
export const CMD_PREPEND_CHILD = 0x07;
|
|
42
|
+
export const CMD_APPEND_CHILD = 0x08;
|
|
43
|
+
export const CMD_WRAP = 0x09;
|
|
44
|
+
export const CMD_REPLACE = 0x0b;
|
|
45
|
+
export const CMD_SET_PROPERTY = 0x0c; // [valueType: u8][name str][value str], PROP_* value kinds
|
|
46
|
+
export const CMD_SET_CHILDREN = 0x0d; // payload is a Root-wrapped child list
|
|
47
|
+
// Structural-command payload types (0x10+, a range distinct from commands).
|
|
48
|
+
export const PAYLOAD_RAW_MARKDOWN = 0x10; // [len: u32 LE][utf8] — re-parsed as markdown
|
|
49
|
+
export const PAYLOAD_RAW_HTML = 0x11; // [len: u32 LE][utf8] — re-parsed as HTML/MDX
|
|
50
|
+
export const PAYLOAD_OPSTREAM = 0x14; // [len: u32 LE][op bytes] — replayed straight into the arena
|
|
51
|
+
// Property value kinds (HAST element properties and SET_PROPERTY commands).
|
|
52
|
+
export const PROP_STRING = 0; // UTF-8 value
|
|
53
|
+
export const PROP_BOOL_TRUE = 1; // no value bytes
|
|
54
|
+
export const PROP_BOOL_FALSE = 2; // no value bytes
|
|
55
|
+
export const PROP_SPACE_SEP = 3; // space-separated list (UTF-8)
|
|
56
|
+
export const PROP_COMMA_SEP = 4; // comma-separated list (UTF-8)
|
|
57
|
+
export const PROP_INT = 5; // decimal string, parsed to i64
|
|
58
|
+
export const PROP_NULL = 6; // no value bytes
|
|
59
|
+
// MDX JSX attribute kinds (MDAST and HAST MDX JSX element type_data).
|
|
60
|
+
export const MDX_ATTR_BOOLEAN_PROP = 0; // name only, no value
|
|
61
|
+
export const MDX_ATTR_LITERAL_PROP = 1; // name="literal"
|
|
62
|
+
export const MDX_ATTR_EXPRESSION_PROP = 2; // name={expr}
|
|
63
|
+
export const MDX_ATTR_SPREAD = 3; // {...expr}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opaque handles to Rust-owned arenas. The napi-generated `index.d.ts` refers
|
|
3
|
+
* to `MdastHandle`/`HastHandle`/`AnyHandle` as bare, undeclared names; these
|
|
4
|
+
* global declarations give those signatures real types. The kind brand makes
|
|
5
|
+
* passing a hast handle to an mdast entry point (a runtime error in Rust) a
|
|
6
|
+
* compile error in TS.
|
|
7
|
+
*/
|
|
8
|
+
declare global {
|
|
9
|
+
interface MdastHandle {
|
|
10
|
+
readonly __satteriHandleKind: "mdast";
|
|
11
|
+
}
|
|
12
|
+
interface HastHandle {
|
|
13
|
+
readonly __satteriHandleKind: "hast";
|
|
14
|
+
}
|
|
15
|
+
/** Handle accepted by kind-agnostic entry points (drop, serialize, …). */
|
|
16
|
+
type AnyHandle = MdastHandle | HastHandle;
|
|
17
|
+
}
|
|
18
|
+
type MdastHandleAlias = MdastHandle;
|
|
19
|
+
type HastHandleAlias = HastHandle;
|
|
20
|
+
type AnyHandleAlias = AnyHandle;
|
|
21
|
+
export type { MdastHandleAlias as MdastHandle, HastHandleAlias as HastHandle, AnyHandleAlias as AnyHandle, };
|
package/dist/handles.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LazyChildResolver } from "../lazy-child-resolver.js";
|
|
2
|
+
import type { HastNode } from "../types.js";
|
|
3
|
+
import type { HastReader } from "./hast-reader.js";
|
|
4
|
+
type HastResolver = LazyChildResolver<HastReader, HastNode>;
|
|
5
|
+
/**
|
|
6
|
+
* Walk-path child stub: arena id + `type` eagerly, every other field a lazy
|
|
7
|
+
* forward to the materialized node (first read snapshots the arena via
|
|
8
|
+
* `materializeOne`, which enforces the handle epoch — the pass seal is checked
|
|
9
|
+
* where the stubs are built). Spread/identity rules are enforced by `nid()`
|
|
10
|
+
* in hast-visitor.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare class HastChildStub {
|
|
13
|
+
_resolver: HastResolver;
|
|
14
|
+
_id: number;
|
|
15
|
+
type: string;
|
|
16
|
+
constructor(resolver: HastResolver, id: number, nodeType: number);
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { flatByTag, stubDescriptors } from "../child-stub.js";
|
|
2
|
+
import { NAME_TO_TYPE, TYPE_NAMES } from "./generated/node-types.js";
|
|
3
|
+
const N = NAME_TO_TYPE;
|
|
4
|
+
/** Per-type stub fields, mirroring `materializeHastNode`'s switch. */
|
|
5
|
+
const HAST_STUB_FIELDS = {
|
|
6
|
+
[N.root]: ["children"],
|
|
7
|
+
[N.element]: ["tagName", "properties", "children"],
|
|
8
|
+
[N.text]: ["value"],
|
|
9
|
+
[N.comment]: ["value"],
|
|
10
|
+
[N.doctype]: [],
|
|
11
|
+
[N.raw]: ["value"],
|
|
12
|
+
[N.mdxJsxFlowElement]: ["name", "attributes", "children"],
|
|
13
|
+
[N.mdxJsxTextElement]: ["name", "attributes", "children"],
|
|
14
|
+
[N.mdxFlowExpression]: ["value"],
|
|
15
|
+
[N.mdxTextExpression]: ["value"],
|
|
16
|
+
[N.mdxjsEsm]: ["value"],
|
|
17
|
+
};
|
|
18
|
+
const TYPE_NAME_BY_TAG = flatByTag(TYPE_NAMES);
|
|
19
|
+
const HAST_STUB_DESCRIPTORS = [];
|
|
20
|
+
for (const tag of Object.keys(HAST_STUB_FIELDS)) {
|
|
21
|
+
const nodeType = Number(tag);
|
|
22
|
+
HAST_STUB_DESCRIPTORS[nodeType] = stubDescriptors(HAST_STUB_FIELDS[nodeType]);
|
|
23
|
+
}
|
|
24
|
+
/** Unknown node types still expose the prelude-backed lazy fields. */
|
|
25
|
+
const FALLBACK_DESCRIPTORS = stubDescriptors([]);
|
|
26
|
+
/**
|
|
27
|
+
* Walk-path child stub: arena id + `type` eagerly, every other field a lazy
|
|
28
|
+
* forward to the materialized node (first read snapshots the arena via
|
|
29
|
+
* `materializeOne`, which enforces the handle epoch — the pass seal is checked
|
|
30
|
+
* where the stubs are built). Spread/identity rules are enforced by `nid()`
|
|
31
|
+
* in hast-visitor.ts.
|
|
32
|
+
*/
|
|
33
|
+
export class HastChildStub {
|
|
34
|
+
_resolver;
|
|
35
|
+
_id;
|
|
36
|
+
type;
|
|
37
|
+
constructor(resolver, id, nodeType) {
|
|
38
|
+
this._resolver = resolver;
|
|
39
|
+
this._id = id;
|
|
40
|
+
this.type = TYPE_NAME_BY_TAG[nodeType] ?? `unknown(${nodeType})`;
|
|
41
|
+
Object.defineProperties(this, HAST_STUB_DESCRIPTORS[nodeType] ?? FALLBACK_DESCRIPTORS);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Decode a HAST element property value from its wire `(kind, value)` — shared
|
|
2
|
+
* by the walk decoder and the snapshot reader so the kind dispatch lives once.
|
|
3
|
+
* The bool kinds carry no value string (callers pass `""`). */
|
|
4
|
+
import { PROP_BOOL_TRUE, PROP_BOOL_FALSE, PROP_SPACE_SEP, PROP_COMMA_SEP, PROP_INT, } from "../generated/wire-constants.js";
|
|
5
|
+
export function decodeElementProp(kind, value) {
|
|
6
|
+
switch (kind) {
|
|
7
|
+
case PROP_BOOL_TRUE:
|
|
8
|
+
return true;
|
|
9
|
+
case PROP_BOOL_FALSE:
|
|
10
|
+
return false;
|
|
11
|
+
case PROP_SPACE_SEP:
|
|
12
|
+
return value.split(" ").filter((s) => s.length > 0);
|
|
13
|
+
case PROP_COMMA_SEP:
|
|
14
|
+
return value
|
|
15
|
+
.split(",")
|
|
16
|
+
.map((s) => s.trim())
|
|
17
|
+
.filter((s) => s.length > 0);
|
|
18
|
+
case PROP_INT:
|
|
19
|
+
return Number(value);
|
|
20
|
+
default:
|
|
21
|
+
return value; // PROP_STRING
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Node-type tag -> canonical AST name. */
|
|
2
|
+
export declare const TYPE_NAMES: Readonly<Record<number, string>>;
|
|
3
|
+
/** Canonical AST name -> node-type tag. */
|
|
4
|
+
export declare const NAME_TO_TYPE: Readonly<Record<string, number>>;
|
|
5
|
+
/** Names a plugin can subscribe to (every node except `root`). */
|
|
6
|
+
export declare const VISITOR_KEYS: ReadonlySet<string>;
|
|
7
|
+
/** Name -> tag for the types the op-stream can encode; one lookup gates AND
|
|
8
|
+
* resolves the emit-path tag. Excluded names (see `*_OPSTREAM_EXCLUDED` in
|
|
9
|
+
* schema.rs) have no encoding — the visitor throws for them. */
|
|
10
|
+
export declare const HAST_OPSTREAM_TYPES: Readonly<Record<string, number>>;
|
|
11
|
+
/** Names of the variable-length `custom` node types (hand-written or
|
|
12
|
+
* `Tail`-generated codec). The op-stream round-trip oracle asserts it covers
|
|
13
|
+
* every one, so a forgotten or drifted encode/decode arm fails loudly. */
|
|
14
|
+
export declare const HAST_CUSTOM_TYPES: readonly string[];
|