satteri 0.10.4 → 0.11.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 +11 -0
- package/dist/arena-reader.d.ts +13 -0
- package/dist/arena-reader.js +104 -0
- package/dist/binding.browser.d.ts +1 -1
- package/dist/binding.browser.js +1 -1
- package/dist/binding.d.ts +1 -1
- package/dist/binding.js +1 -1
- package/dist/byte-writer.d.ts +0 -18
- package/dist/byte-writer.js +6 -30
- package/dist/child-stub.d.ts +0 -17
- package/dist/child-stub.js +6 -22
- package/dist/command-buffer.d.ts +5 -26
- package/dist/command-buffer.js +28 -39
- package/dist/compile-options.d.ts +11 -0
- package/dist/compile-options.js +99 -0
- package/dist/compile-types.d.ts +330 -0
- package/dist/compile-types.js +1 -0
- package/dist/compile.d.ts +22 -328
- package/dist/compile.js +129 -379
- package/dist/directive-types.d.ts +1 -0
- package/dist/directive-types.js +1 -6
- package/dist/generated/arena-layout.d.ts +6 -4
- package/dist/generated/arena-layout.js +6 -7
- package/dist/generated/fused-wire.d.ts +3 -0
- package/dist/generated/fused-wire.js +229 -0
- package/dist/generated/parse-options.js +0 -5
- package/dist/generated/wire-constants.d.ts +3 -0
- package/dist/generated/wire-constants.js +33 -42
- package/dist/handles.d.ts +0 -7
- package/dist/hast/child-stub.d.ts +1 -8
- package/dist/hast/child-stub.js +14 -13
- package/dist/hast/element-props.d.ts +13 -0
- package/dist/hast/element-props.js +52 -6
- package/dist/hast/generated/node-types.d.ts +1 -9
- package/dist/hast/generated/node-types.js +1 -9
- package/dist/hast/generated/walk-decode.d.ts +10 -0
- package/dist/hast/generated/walk-decode.js +61 -0
- package/dist/hast/hast-materializer.d.ts +3 -10
- package/dist/hast/hast-materializer.js +73 -47
- package/dist/hast/hast-reader.d.ts +9 -38
- package/dist/hast/hast-reader.js +82 -271
- package/dist/hast/hast-visitor.d.ts +29 -16
- package/dist/hast/hast-visitor.js +197 -508
- package/dist/hast/hast-walk.d.ts +18 -0
- package/dist/hast/hast-walk.js +264 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -12
- package/dist/lazy-child-resolver.d.ts +1 -21
- package/dist/lazy-child-resolver.js +11 -32
- package/dist/materializer-cache.d.ts +5 -29
- package/dist/materializer-cache.js +29 -101
- package/dist/mdast/child-stub.d.ts +1 -12
- package/dist/mdast/child-stub.js +18 -28
- package/dist/mdast/column-align.d.ts +1 -1
- package/dist/mdast/column-align.js +0 -2
- package/dist/mdast/generated/layout.d.ts +0 -16
- package/dist/mdast/generated/layout.js +6 -47
- package/dist/mdast/generated/node-types.d.ts +1 -9
- package/dist/mdast/generated/node-types.js +3 -9
- package/dist/mdast/mdast-materializer.d.ts +3 -11
- package/dist/mdast/mdast-materializer.js +91 -63
- package/dist/mdast/mdast-reader.d.ts +15 -63
- package/dist/mdast/mdast-reader.js +132 -269
- package/dist/mdast/mdast-visitor.d.ts +23 -15
- package/dist/mdast/mdast-visitor.js +188 -294
- package/dist/mdast/mdast-walk.d.ts +13 -0
- package/dist/mdast/mdast-walk.js +144 -0
- package/dist/mdx-attr.js +0 -3
- package/dist/mdx-types.js +1 -6
- package/dist/op-stream.d.ts +1 -15
- package/dist/op-stream.js +3 -19
- package/dist/phantom.d.ts +0 -1
- package/dist/phantom.js +1 -9
- package/dist/plugin-pipeline.d.ts +32 -0
- package/dist/plugin-pipeline.js +177 -0
- package/dist/plugin.d.ts +8 -7
- package/dist/plugin.js +3 -9
- package/dist/types.d.ts +0 -1
- package/dist/visitor-node.d.ts +12 -0
- package/dist/visitor-node.js +23 -0
- package/dist/visitor-shared.d.ts +26 -30
- package/dist/visitor-shared.js +34 -36
- package/dist/wire-read.d.ts +0 -22
- package/dist/wire-read.js +3 -24
- package/index.d.ts +19 -10
- package/index.js +56 -53
- package/package.json +3 -12
- package/dist/string-pool.d.ts +0 -13
- package/dist/string-pool.js +0 -91
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared materializer machinery for the HAST and MDAST flavors: per-reader
|
|
3
|
-
* node memo, lazy `children` descriptors, and the frozen-mode (plugin walk
|
|
4
|
-
* path) freeze rules.
|
|
5
|
-
*/
|
|
6
1
|
import { deepFreeze } from "./freeze.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
export function installNodeData(node, rawData, label, nodeId) {
|
|
3
|
+
if (rawData === null)
|
|
4
|
+
return;
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(rawData);
|
|
7
|
+
if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
|
|
8
|
+
node.data = parsed;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
if (process.env.NODE_ENV !== "production") {
|
|
13
|
+
console.warn(`${label}: malformed node_data for nodeId=${nodeId}`, err);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
16
17
|
export function createMaterializer(spec) {
|
|
17
18
|
const readerCaches = new WeakMap();
|
|
18
19
|
function materialize(reader, nodeId, frozen = false, refs) {
|
|
@@ -24,8 +25,7 @@ export function createMaterializer(spec) {
|
|
|
24
25
|
}
|
|
25
26
|
return node;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
* is frozen, so the accessor cannot self-replace with a data property. */
|
|
28
|
+
// A frozen node cannot replace its children getter, so cache the array separately.
|
|
29
29
|
function frozenChildrenDescriptor(reader, cache) {
|
|
30
30
|
return {
|
|
31
31
|
get() {
|
|
@@ -46,9 +46,7 @@ export function createMaterializer(spec) {
|
|
|
46
46
|
enumerable: true,
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
* first read. The id is captured rather than stored on the node, so a
|
|
51
|
-
* materialized tree carries no marker for `toEqual` or a spread to find. */
|
|
49
|
+
// Capture the ID so mutable trees expose no arena identity marker.
|
|
52
50
|
function mutableChildrenDescriptor(reader, nodeId) {
|
|
53
51
|
return {
|
|
54
52
|
get() {
|
|
@@ -88,16 +86,14 @@ export function createMaterializer(spec) {
|
|
|
88
86
|
}
|
|
89
87
|
return cache;
|
|
90
88
|
}
|
|
91
|
-
function buildNode(reader, cache, nodeId, nodeType
|
|
89
|
+
function buildNode(reader, cache, nodeId, nodeType) {
|
|
92
90
|
const typeName = spec.typeNames[nodeType] ?? `unknown(${nodeType})`;
|
|
93
|
-
//
|
|
91
|
+
// Unified's assertNode requires a plain-object prototype.
|
|
94
92
|
const node = { type: typeName };
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
node.position = position;
|
|
98
|
-
}
|
|
93
|
+
// Populate before _nodeId so both materialization paths share V8 hidden classes.
|
|
94
|
+
spec.populate(node, reader, nodeId, nodeType);
|
|
99
95
|
if (cache.frozen) {
|
|
100
|
-
// Non-enumerable
|
|
96
|
+
// Non-enumerable IDs prevent spread copies from impersonating arena nodes.
|
|
101
97
|
cache.refs?.set(node, nodeId);
|
|
102
98
|
Object.defineProperty(node, "_nodeId", {
|
|
103
99
|
value: nodeId,
|
|
@@ -106,87 +102,19 @@ export function createMaterializer(spec) {
|
|
|
106
102
|
enumerable: false,
|
|
107
103
|
});
|
|
108
104
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
const parsed = JSON.parse(rawData);
|
|
116
|
-
if (parsed && typeof parsed === "object" && Object.keys(parsed).length > 0) {
|
|
117
|
-
Object.defineProperty(node, "data", {
|
|
118
|
-
value: parsed,
|
|
119
|
-
writable: true,
|
|
120
|
-
configurable: true,
|
|
121
|
-
enumerable: true,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
if (process.env.NODE_ENV !== "production") {
|
|
127
|
-
console.warn(`${spec.label}: malformed node_data for nodeId=${nodeId}`, err);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
105
|
+
installNodeData(node, reader.getNodeData(nodeId), spec.label, nodeId);
|
|
106
|
+
if (cache.frozen) {
|
|
107
|
+
// All fields are eager until the children getter is installed below.
|
|
108
|
+
for (const value of Object.values(node))
|
|
109
|
+
deepFreeze(value);
|
|
130
110
|
}
|
|
131
|
-
if (
|
|
111
|
+
if (spec.hasChildren(nodeType, node, reader, nodeId)) {
|
|
132
112
|
Object.defineProperty(node, "children", cache.children ?? mutableChildrenDescriptor(reader, nodeId));
|
|
133
113
|
}
|
|
134
114
|
if (cache.frozen) {
|
|
135
|
-
// Deep-freeze the eager own values but not the lazy `children` accessor;
|
|
136
|
-
// freeze eagerly even for containers so nothing is writable while cached.
|
|
137
|
-
const descriptors = Object.getOwnPropertyDescriptors(node);
|
|
138
|
-
for (const key of Object.keys(descriptors)) {
|
|
139
|
-
const desc = descriptors[key];
|
|
140
|
-
if (desc !== undefined && "value" in desc) {
|
|
141
|
-
deepFreeze(desc.value);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
115
|
Object.freeze(node);
|
|
145
116
|
}
|
|
146
117
|
return node;
|
|
147
118
|
}
|
|
148
|
-
|
|
149
|
-
* Iterative on purpose: recursing to full document depth overflows on deeply
|
|
150
|
-
* nested input, and nothing else here descends more than one level.
|
|
151
|
-
*
|
|
152
|
-
* Breadth-first over the parents still to fill, so every node is built and
|
|
153
|
-
* every child list decoded exactly once, and a child is wired into its
|
|
154
|
-
* parent's array as it is built rather than in a second pass.
|
|
155
|
-
*/
|
|
156
|
-
function fillTree(reader, cache, rootId) {
|
|
157
|
-
const rootType = reader.getNodeType(rootId);
|
|
158
|
-
const root = buildNode(reader, cache, rootId, rootType, true);
|
|
159
|
-
if (!spec.hasChildren(rootType, root, reader, rootId))
|
|
160
|
-
return root;
|
|
161
|
-
const parents = [root];
|
|
162
|
-
const parentIds = [rootId];
|
|
163
|
-
for (let p = 0; p < parentIds.length; p++) {
|
|
164
|
-
const parent = parents[p];
|
|
165
|
-
const parentId = parentIds[p];
|
|
166
|
-
if (parent === undefined || parentId === undefined)
|
|
167
|
-
continue;
|
|
168
|
-
const ids = reader.getChildIds(parentId);
|
|
169
|
-
const kids = new Array(ids.length);
|
|
170
|
-
for (let i = 0; i < ids.length; i++) {
|
|
171
|
-
const childId = ids[i];
|
|
172
|
-
if (childId === undefined)
|
|
173
|
-
continue;
|
|
174
|
-
const childType = reader.getNodeType(childId);
|
|
175
|
-
const child = buildNode(reader, cache, childId, childType, true);
|
|
176
|
-
kids[i] = child;
|
|
177
|
-
if (spec.hasChildren(childType, child, reader, childId)) {
|
|
178
|
-
parents.push(child);
|
|
179
|
-
parentIds.push(childId);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
// Assignment beats defineProperty here; `eager` left `children` uninstalled.
|
|
183
|
-
parent.children = kids;
|
|
184
|
-
}
|
|
185
|
-
return root;
|
|
186
|
-
}
|
|
187
|
-
/** Whole tree at once: the caller will walk it, so lazy accessors cost more than they defer. */
|
|
188
|
-
function materializeTree(reader, rootId) {
|
|
189
|
-
return fillTree(reader, readerCache(reader, false, undefined), rootId);
|
|
190
|
-
}
|
|
191
|
-
return { node: materialize, tree: materializeTree };
|
|
119
|
+
return { node: materialize };
|
|
192
120
|
}
|
|
@@ -2,19 +2,8 @@ import type { LazyChildResolver } from "../lazy-child-resolver.js";
|
|
|
2
2
|
import type { MdastNode } from "../types.js";
|
|
3
3
|
import type { MdastReader } from "./mdast-reader.js";
|
|
4
4
|
type MdastResolver = LazyChildResolver<MdastReader, MdastNode>;
|
|
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). Spread/identity rules
|
|
9
|
-
* are enforced by `nid()` (authoritative doc in hast-visitor.ts).
|
|
10
|
-
*
|
|
11
|
-
* A user-defined node's `type` is the one exception: it lives in the arena,
|
|
12
|
-
* not the tag, so it joins the lazy fields rather than making every sibling
|
|
13
|
-
* list snapshot the arena up front.
|
|
14
|
-
*/
|
|
15
5
|
export declare class MdastChildStub {
|
|
16
|
-
|
|
17
|
-
_id: number;
|
|
6
|
+
#private;
|
|
18
7
|
type: string;
|
|
19
8
|
constructor(resolver: MdastResolver, id: number, nodeType: number);
|
|
20
9
|
}
|
package/dist/mdast/child-stub.js
CHANGED
|
@@ -3,8 +3,6 @@ import { MDAST_LAYOUT_KEYS } from "./generated/layout.js";
|
|
|
3
3
|
import { NAME_TO_TYPE, TYPE_NAMES } from "./generated/node-types.js";
|
|
4
4
|
import { LEAF_TYPES } from "./mdast-materializer.js";
|
|
5
5
|
const N = NAME_TO_TYPE;
|
|
6
|
-
/** Per-type stub fields for the types `addTypeProperties` hand-writes; the
|
|
7
|
-
* fixed-layout types come from the generated `MDAST_LAYOUT_KEYS`. */
|
|
8
6
|
const HAND_WRITTEN_FIELDS = {
|
|
9
7
|
[N.list]: ["ordered", "start", "spread"],
|
|
10
8
|
[N.listItem]: ["spread", "checked"],
|
|
@@ -17,9 +15,7 @@ const HAND_WRITTEN_FIELDS = {
|
|
|
17
15
|
[N.mdxJsxTextElement]: ["name", "attributes"],
|
|
18
16
|
};
|
|
19
17
|
const TYPE_NAME_BY_TAG = flatByTag(TYPE_NAMES);
|
|
20
|
-
|
|
21
|
-
* the open `node.type`, so the stub exposes `value` (leaf content) but no
|
|
22
|
-
* separate `name`. */
|
|
18
|
+
// Custom nodes expose their stored name as type, without a separate name field.
|
|
23
19
|
const MDAST_CUSTOM = NAME_TO_TYPE.custom;
|
|
24
20
|
const MDAST_STUB_DESCRIPTORS = [];
|
|
25
21
|
for (const tag of Object.keys(TYPE_NAMES)) {
|
|
@@ -32,25 +28,15 @@ for (const tag of Object.keys(TYPE_NAMES)) {
|
|
|
32
28
|
fields.push("children");
|
|
33
29
|
MDAST_STUB_DESCRIPTORS[nodeType] = stubDescriptors(fields);
|
|
34
30
|
}
|
|
35
|
-
/** Unknown node types still expose the prelude-backed lazy fields. */
|
|
36
31
|
const FALLBACK_DESCRIPTORS = stubDescriptors([]);
|
|
37
|
-
|
|
38
|
-
* Walk-path child stub: arena id + `type` eagerly, every other field a lazy
|
|
39
|
-
* forward to the materialized node (first read snapshots the arena via
|
|
40
|
-
* `materializeOne`, which enforces the handle epoch). Spread/identity rules
|
|
41
|
-
* are enforced by `nid()` (authoritative doc in hast-visitor.ts).
|
|
42
|
-
*
|
|
43
|
-
* A user-defined node's `type` is the one exception: it lives in the arena,
|
|
44
|
-
* not the tag, so it joins the lazy fields rather than making every sibling
|
|
45
|
-
* list snapshot the arena up front.
|
|
46
|
-
*/
|
|
32
|
+
// Custom type names live in the arena, so reading type must remain lazy too.
|
|
47
33
|
export class MdastChildStub {
|
|
48
|
-
|
|
49
|
-
|
|
34
|
+
#resolver;
|
|
35
|
+
#id;
|
|
50
36
|
type;
|
|
51
37
|
constructor(resolver, id, nodeType) {
|
|
52
|
-
this
|
|
53
|
-
this
|
|
38
|
+
this.#resolver = resolver;
|
|
39
|
+
this.#id = id;
|
|
54
40
|
if (nodeType === MDAST_CUSTOM) {
|
|
55
41
|
installLazyCustomType(this);
|
|
56
42
|
installLazyCustomChildren(this);
|
|
@@ -62,16 +48,22 @@ export class MdastChildStub {
|
|
|
62
48
|
}
|
|
63
49
|
/** @internal */
|
|
64
50
|
get _refs() {
|
|
65
|
-
return this.
|
|
51
|
+
return this.#resolver.refs;
|
|
52
|
+
}
|
|
53
|
+
/** @internal */
|
|
54
|
+
get _id() {
|
|
55
|
+
return this.#id;
|
|
56
|
+
}
|
|
57
|
+
/** @internal */
|
|
58
|
+
_materialize() {
|
|
59
|
+
return this.#resolver.materializeOne(this.#id);
|
|
66
60
|
}
|
|
67
61
|
}
|
|
68
|
-
|
|
69
|
-
* stub only knows the tag, so it cannot tell a leaf from a parent until the
|
|
70
|
-
* arena snapshot says which shape this node has. */
|
|
62
|
+
// A custom node’s leafness is unknown until materialization; leaf stubs must lose their children field.
|
|
71
63
|
function installLazyCustomChildren(stub) {
|
|
72
64
|
Object.defineProperty(stub, "children", {
|
|
73
65
|
get() {
|
|
74
|
-
const real = this.
|
|
66
|
+
const real = this._materialize();
|
|
75
67
|
const value = real.children;
|
|
76
68
|
if (value === undefined) {
|
|
77
69
|
delete this.children;
|
|
@@ -89,12 +81,10 @@ function installLazyCustomChildren(stub) {
|
|
|
89
81
|
configurable: true,
|
|
90
82
|
});
|
|
91
83
|
}
|
|
92
|
-
/** `type` as a self-replacing accessor: the materialized node folds the stored
|
|
93
|
-
* name into `type`. Enumerable so a spread copy still carries it. */
|
|
94
84
|
function installLazyCustomType(stub) {
|
|
95
85
|
Object.defineProperty(stub, "type", {
|
|
96
86
|
get() {
|
|
97
|
-
const value = this.
|
|
87
|
+
const value = this._materialize().type;
|
|
98
88
|
Object.defineProperty(this, "type", {
|
|
99
89
|
value,
|
|
100
90
|
writable: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function decodeColumnAlign(byte: number):
|
|
1
|
+
export declare function decodeColumnAlign(byte: number): "left" | "right" | "center" | null;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/** Decode a table column-alignment byte — shared by the generated walk decoder
|
|
2
|
-
* and the snapshot reader so the mapping lives in one place. */
|
|
3
1
|
const ALIGN_NAMES = [null, "left", "right", "center"];
|
|
4
2
|
export function decodeColumnAlign(byte) {
|
|
5
3
|
return ALIGN_NAMES[byte] ?? null;
|
|
@@ -1,18 +1,2 @@
|
|
|
1
|
-
import type { MdastReader } from "../mdast-reader.js";
|
|
2
|
-
/** Materialized property names per tag (the non-skip `js` names above),
|
|
3
|
-
* exported for the child-stub field tables. */
|
|
4
1
|
export declare const MDAST_LAYOUT_KEYS: Readonly<Record<number, readonly string[]>>;
|
|
5
|
-
/**
|
|
6
|
-
* Decode a node's type-specific `type_data` from the walk buffer onto `node`,
|
|
7
|
-
* driven by `MDAST_LAYOUTS` (fixed-field types) and `MDAST_TAILS` (counted
|
|
8
|
-
* attribute lists). Returns `false` for tags in neither, so the caller falls
|
|
9
|
-
* through to the remaining hand-written cases (list, listItem).
|
|
10
|
-
*/
|
|
11
2
|
export declare function decodeMdastTypeData(view: DataView, buf: Uint8Array, start: number, nodeType: number, node: Record<string, unknown>): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Attach a node's fixed `type_data` fields, materialized from the arena
|
|
14
|
-
* snapshot, driven by `MDAST_LAYOUTS`. Returns `false` for tags with no entry,
|
|
15
|
-
* so the materializer falls through to its hand-written cases (list, table,
|
|
16
|
-
* directives, MDX JSX). Fields are eager plain stores.
|
|
17
|
-
*/
|
|
18
|
-
export declare function materializeMdastFields(reader: MdastReader, node: object, nodeId: number, nodeType: number): boolean;
|
|
@@ -3,7 +3,6 @@ import { ru16, ru32, rstr } from "../../wire-read.js";
|
|
|
3
3
|
import { restorePhantomSpaces } from "../../phantom.js";
|
|
4
4
|
import { decodeMdxJsxAttr } from "../../mdx-attr.js";
|
|
5
5
|
import { decodeColumnAlign } from "../column-align.js";
|
|
6
|
-
/** Walk-wire fields per node-type tag (see Rust `write_mdast_type_data_inline`). */
|
|
7
6
|
const MDAST_LAYOUTS = {
|
|
8
7
|
2: [{ js: "depth", offset: 0, kind: "u8", default: 1 }],
|
|
9
8
|
7: [{ js: "value", offset: 0, kind: "str32" }],
|
|
@@ -64,8 +63,6 @@ const MDAST_LAYOUTS = {
|
|
|
64
63
|
103: [{ js: "value", offset: 0, kind: "str32", phantom: true }],
|
|
65
64
|
104: [{ js: "value", offset: 0, kind: "str32", phantom: true }],
|
|
66
65
|
};
|
|
67
|
-
/** Materialized property names per tag (the non-skip `js` names above),
|
|
68
|
-
* exported for the child-stub field tables. */
|
|
69
66
|
export const MDAST_LAYOUT_KEYS = {
|
|
70
67
|
2: ["depth"],
|
|
71
68
|
7: ["value"],
|
|
@@ -88,10 +85,6 @@ export const MDAST_LAYOUT_KEYS = {
|
|
|
88
85
|
103: ["value"],
|
|
89
86
|
104: ["value"],
|
|
90
87
|
};
|
|
91
|
-
/** Walk-wire tail descriptors (a name head, then a counted item list) for
|
|
92
|
-
* the variable-length attribute types the generic decoder below handles
|
|
93
|
-
* without a hand-written case: `map` is a string key/value object
|
|
94
|
-
* (directives), `jsx` a typed MDX-JSX attribute array. */
|
|
95
88
|
const MDAST_TAILS = {
|
|
96
89
|
21: { head: [], item: [{ js: "align", kind: "u8" }], bytes: { attrsKey: "align" } },
|
|
97
90
|
30: {
|
|
@@ -137,13 +130,12 @@ const MDAST_TAILS = {
|
|
|
137
130
|
jsx: { attrsKey: "attributes" },
|
|
138
131
|
},
|
|
139
132
|
};
|
|
140
|
-
/**
|
|
141
|
-
* Decode a node's type-specific `type_data` from the walk buffer onto `node`,
|
|
142
|
-
* driven by `MDAST_LAYOUTS` (fixed-field types) and `MDAST_TAILS` (counted
|
|
143
|
-
* attribute lists). Returns `false` for tags in neither, so the caller falls
|
|
144
|
-
* through to the remaining hand-written cases (list, listItem).
|
|
145
|
-
*/
|
|
146
133
|
export function decodeMdastTypeData(view, buf, start, nodeType, node) {
|
|
134
|
+
if (nodeType === 7 || nodeType === 10 || nodeType === 13 || nodeType === 25 || nodeType === 26) {
|
|
135
|
+
const len = ru32(view, start);
|
|
136
|
+
node.value = rstr(buf, start + 4, len);
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
147
139
|
const fields = MDAST_LAYOUTS[nodeType];
|
|
148
140
|
if (fields !== undefined) {
|
|
149
141
|
let pos = start;
|
|
@@ -170,9 +162,7 @@ export function decodeMdastTypeData(view, buf, start, nodeType, node) {
|
|
|
170
162
|
const tail = MDAST_TAILS[nodeType];
|
|
171
163
|
if (tail !== undefined) {
|
|
172
164
|
let pos = start;
|
|
173
|
-
//
|
|
174
|
-
// runs per attribute item in the matched-node decode path, and the
|
|
175
|
-
// unoptimized tiers CodSpeed measures won't elide the allocation.
|
|
165
|
+
// Inline reads avoid allocating a tuple per attribute field in unoptimized V8 tiers.
|
|
176
166
|
for (const f of tail.head) {
|
|
177
167
|
let value;
|
|
178
168
|
if (f.kind === "u8") {
|
|
@@ -186,7 +176,6 @@ export function decodeMdastTypeData(view, buf, start, nodeType, node) {
|
|
|
186
176
|
pos += len;
|
|
187
177
|
value = f.phantom ? restorePhantomSpaces(raw) : raw;
|
|
188
178
|
}
|
|
189
|
-
// MDX JSX elements carry a nullable name (empty → null); map heads keep it.
|
|
190
179
|
node[f.js] = tail.jsx !== undefined && value === "" ? null : value;
|
|
191
180
|
}
|
|
192
181
|
const count = ru16(view, pos);
|
|
@@ -236,33 +225,3 @@ export function decodeMdastTypeData(view, buf, start, nodeType, node) {
|
|
|
236
225
|
}
|
|
237
226
|
return false;
|
|
238
227
|
}
|
|
239
|
-
/**
|
|
240
|
-
* Attach a node's fixed `type_data` fields, materialized from the arena
|
|
241
|
-
* snapshot, driven by `MDAST_LAYOUTS`. Returns `false` for tags with no entry,
|
|
242
|
-
* so the materializer falls through to its hand-written cases (list, table,
|
|
243
|
-
* directives, MDX JSX). Fields are eager plain stores.
|
|
244
|
-
*/
|
|
245
|
-
export function materializeMdastFields(reader, node, nodeId, nodeType) {
|
|
246
|
-
const fields = MDAST_LAYOUTS[nodeType];
|
|
247
|
-
if (fields === undefined)
|
|
248
|
-
return false;
|
|
249
|
-
const out = node;
|
|
250
|
-
for (const f of fields) {
|
|
251
|
-
if (f.skip)
|
|
252
|
-
continue;
|
|
253
|
-
if (f.kind === "u8") {
|
|
254
|
-
// Short type_data falls back to the layout's declared default,
|
|
255
|
-
// matching the Rust walk serializer.
|
|
256
|
-
const b = reader.fieldU8(nodeId, f.offset, f.default ?? 0);
|
|
257
|
-
out[f.js] = f.values ? (f.values[b] ?? f.values[0]) : b;
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
// Short type_data (e.g. a 20-byte ReferenceData-only imageReference)
|
|
261
|
-
// reads as empty, mirroring the Rust decoders' bounds checks.
|
|
262
|
-
const raw = reader.fieldString(nodeId, f.offset);
|
|
263
|
-
const s = f.nullable && raw === "" ? null : raw;
|
|
264
|
-
out[f.js] = f.phantom && typeof s === "string" ? restorePhantomSpaces(s) : s;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return true;
|
|
268
|
-
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
/** Node-type tag -> canonical AST name. */
|
|
2
1
|
export declare const TYPE_NAMES: Readonly<Record<number, string>>;
|
|
3
|
-
/** Canonical AST name -> node-type tag. */
|
|
4
2
|
export declare const NAME_TO_TYPE: Readonly<Record<string, number>>;
|
|
5
3
|
/** Node-type tag by Rust enum variant name. */
|
|
6
4
|
export declare const NodeType: Readonly<{
|
|
@@ -50,13 +48,7 @@ export declare const NodeType: Readonly<{
|
|
|
50
48
|
}>;
|
|
51
49
|
/** Node-type tag -> Rust variant name (`typeName` diagnostics). */
|
|
52
50
|
export declare const NodeTypeName: Readonly<Record<number, string>>;
|
|
53
|
-
/** Names a plugin can subscribe to (every node except `root`). */
|
|
54
51
|
export declare const VISITOR_KEYS: ReadonlySet<string>;
|
|
55
|
-
/** Name -> tag for the types the op-stream can encode; one lookup gates AND
|
|
56
|
-
* resolves the emit-path tag. Excluded names (see `*_OPSTREAM_EXCLUDED` in
|
|
57
|
-
* schema.rs) have no encoding — the visitor throws for them. */
|
|
58
52
|
export declare const MDAST_OPSTREAM_TYPES: Readonly<Record<string, number>>;
|
|
59
|
-
/** Names of the variable-length `custom` node types (hand-written or
|
|
60
|
-
* `Tail`-generated codec). The op-stream round-trip oracle asserts it covers
|
|
61
|
-
* every one, so a forgotten or drifted encode/decode arm fails loudly. */
|
|
62
53
|
export declare const MDAST_CUSTOM_TYPES: readonly string[];
|
|
54
|
+
export declare const LEAF_TYPES: ReadonlySet<number>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// @generated by `cargo run -p satteri-layout-codegen`. Do not edit by hand.
|
|
2
|
-
/** Node-type tag -> canonical AST name. */
|
|
3
2
|
export const TYPE_NAMES = {
|
|
4
3
|
0: "root",
|
|
5
4
|
1: "paragraph",
|
|
@@ -45,7 +44,6 @@ export const TYPE_NAMES = {
|
|
|
45
44
|
103: "mdxTextExpression",
|
|
46
45
|
104: "mdxjsEsm",
|
|
47
46
|
};
|
|
48
|
-
/** Canonical AST name -> node-type tag. */
|
|
49
47
|
export const NAME_TO_TYPE = {
|
|
50
48
|
root: 0,
|
|
51
49
|
paragraph: 1,
|
|
@@ -183,7 +181,6 @@ export const NodeTypeName = {
|
|
|
183
181
|
103: "MdxTextExpression",
|
|
184
182
|
104: "MdxjsEsm",
|
|
185
183
|
};
|
|
186
|
-
/** Names a plugin can subscribe to (every node except `root`). */
|
|
187
184
|
export const VISITOR_KEYS = new Set([
|
|
188
185
|
"paragraph",
|
|
189
186
|
"heading",
|
|
@@ -228,9 +225,6 @@ export const VISITOR_KEYS = new Set([
|
|
|
228
225
|
"mdxTextExpression",
|
|
229
226
|
"mdxjsEsm",
|
|
230
227
|
]);
|
|
231
|
-
/** Name -> tag for the types the op-stream can encode; one lookup gates AND
|
|
232
|
-
* resolves the emit-path tag. Excluded names (see `*_OPSTREAM_EXCLUDED` in
|
|
233
|
-
* schema.rs) have no encoding — the visitor throws for them. */
|
|
234
228
|
export const MDAST_OPSTREAM_TYPES = {
|
|
235
229
|
paragraph: 1,
|
|
236
230
|
heading: 2,
|
|
@@ -275,9 +269,6 @@ export const MDAST_OPSTREAM_TYPES = {
|
|
|
275
269
|
mdxTextExpression: 103,
|
|
276
270
|
mdxjsEsm: 104,
|
|
277
271
|
};
|
|
278
|
-
/** Names of the variable-length `custom` node types (hand-written or
|
|
279
|
-
* `Tail`-generated codec). The op-stream round-trip oracle asserts it covers
|
|
280
|
-
* every one, so a forgotten or drifted encode/decode arm fails loudly. */
|
|
281
272
|
export const MDAST_CUSTOM_TYPES = [
|
|
282
273
|
"list",
|
|
283
274
|
"listItem",
|
|
@@ -289,3 +280,6 @@ export const MDAST_CUSTOM_TYPES = [
|
|
|
289
280
|
"mdxJsxFlowElement",
|
|
290
281
|
"mdxJsxTextElement",
|
|
291
282
|
];
|
|
283
|
+
export const LEAF_TYPES = new Set([
|
|
284
|
+
3, 7, 8, 9, 10, 13, 14, 16, 18, 20, 25, 26, 27, 28, 102, 103, 104,
|
|
285
|
+
]);
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import type { Root } from "mdast";
|
|
2
2
|
import type { MdastReader } from "./mdast-reader.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* `data.h*`. Leafness is per node there, not per type, so the read paths ask
|
|
6
|
-
* this instead of {@link LEAF_TYPES}.
|
|
7
|
-
* @see {@link Custom} */
|
|
3
|
+
import { LEAF_TYPES } from "./generated/node-types.js";
|
|
4
|
+
export { LEAF_TYPES };
|
|
8
5
|
export declare function isCustomLeaf(node: {
|
|
9
6
|
readonly value?: unknown;
|
|
10
7
|
readonly data?: unknown;
|
|
11
8
|
}, childCount: number): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Materialize a single MDAST node; scalars eager, `children` lazy, memoized
|
|
14
|
-
* per `(reader, id)`; `frozen` (the plugin walk path) deep-freezes so plugins
|
|
15
|
-
* cannot corrupt the shared cache.
|
|
16
|
-
*/
|
|
17
9
|
export declare const materializeNode: (reader: MdastReader, nodeId: number, frozen?: boolean, refs?: import("../visitor-shared.js").NodeRefs) => import("mdast").Nodes;
|
|
18
|
-
/** Materialize the full tree from root (nodeId=0). */
|
|
10
|
+
/** Materialize the full tree from root (nodeId=0) in one eager pass, breadth-first over the parents still to fill. */
|
|
19
11
|
export declare function materializeMdastTree(reader: MdastReader): Root;
|