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,356 +1,222 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ArenaReader } from "../arena-reader.js";
|
|
2
|
+
import { FIELD, KIND_MDAST, W_CHILDREN_COUNT, W_CHILDREN_START, W_DATA_LEN, W_DATA_OFFSET, W_PARENT, W_START_OFFSET, } from "../generated/arena-layout.js";
|
|
3
|
+
import { decodeMdxJsxAttr } from "../mdx-attr.js";
|
|
3
4
|
import { decodeColumnAlign } from "./column-align.js";
|
|
4
|
-
import { PoolOffsets } from "../string-pool.js";
|
|
5
5
|
import { NodeTypeName } from "./generated/node-types.js";
|
|
6
|
-
import { ARENA_MAGIC, KIND_MDAST, FIELD, HEADER } from "../generated/arena-layout.js";
|
|
7
6
|
export { NodeType, NodeTypeName } from "./generated/node-types.js";
|
|
8
7
|
export class MdastReader {
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
8
|
+
#arena;
|
|
9
|
+
// Typed arrays avoid DataView getter overhead in unoptimized V8 tiers.
|
|
10
|
+
#u8;
|
|
11
|
+
#u32;
|
|
12
|
+
#nodesB;
|
|
13
|
+
#nodesW;
|
|
14
|
+
#strideB;
|
|
15
|
+
#strideW;
|
|
16
|
+
#childrenW;
|
|
17
|
+
#typeDataB;
|
|
15
18
|
constructor(buffer) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.#
|
|
23
|
-
this.#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
throw new Error(`MdastReader was handed a buffer of kind ${kind} (expected ${KIND_MDAST}). ` +
|
|
34
|
-
`MDAST and HAST node types overlap; reading the wrong kind decodes garbage.`);
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
nodeStructSize: v.getUint32(HEADER.node_struct_size, true),
|
|
38
|
-
nodeCount: v.getUint32(HEADER.node_count, true),
|
|
39
|
-
nodesOffset: v.getUint32(HEADER.nodes_offset, true),
|
|
40
|
-
childrenCount: v.getUint32(HEADER.children_count, true),
|
|
41
|
-
childrenOffset: v.getUint32(HEADER.children_offset, true),
|
|
42
|
-
typeDataLen: v.getUint32(HEADER.type_data_len, true),
|
|
43
|
-
typeDataOffset: v.getUint32(HEADER.type_data_offset, true),
|
|
44
|
-
stringPoolLen: v.getUint32(HEADER.string_pool_len, true),
|
|
45
|
-
stringPoolOffset: v.getUint32(HEADER.string_pool_offset, true),
|
|
46
|
-
nodeDataCount: v.getUint32(HEADER.node_data_count, true),
|
|
47
|
-
nodeDataOffset: v.getUint32(HEADER.node_data_offset, true),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
#nodeDataTable = null;
|
|
51
|
-
/** Per-node JSON `data` blob (set via `Arena::set_node_data` on the Rust
|
|
52
|
-
* side). Lazy-builds a `Map<id, string>` on first call so materialization
|
|
53
|
-
* of a data-heavy tree stays O(nodes) rather than O(nodes × entries). */
|
|
19
|
+
const arena = new ArenaReader(buffer, KIND_MDAST);
|
|
20
|
+
this.#arena = arena;
|
|
21
|
+
this.#u8 = arena.u8;
|
|
22
|
+
this.#u32 = arena.u32;
|
|
23
|
+
const header = arena.header;
|
|
24
|
+
this.#nodesB = header.nodesOffset;
|
|
25
|
+
this.#nodesW = header.nodesOffset >> 2;
|
|
26
|
+
this.#strideB = header.nodeStructSize;
|
|
27
|
+
this.#strideW = header.nodeStructSize >> 2;
|
|
28
|
+
this.#childrenW = header.childrenOffset >> 2;
|
|
29
|
+
this.#typeDataB = header.typeDataOffset;
|
|
30
|
+
}
|
|
31
|
+
/** @internal Memoized wire view for the fused decoder. */
|
|
32
|
+
getWire() {
|
|
33
|
+
return this.#arena.getWire();
|
|
34
|
+
}
|
|
35
|
+
/** Per-node JSON data, or null when absent. */
|
|
54
36
|
getNodeData(nodeId) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let pos = this.#header.nodeDataOffset;
|
|
61
|
-
for (let i = 0; i < this.#header.nodeDataCount; i++) {
|
|
62
|
-
const id = v.getUint32(pos, true);
|
|
63
|
-
pos += 4;
|
|
64
|
-
const len = v.getUint32(pos, true);
|
|
65
|
-
pos += 4;
|
|
66
|
-
const slice = new Uint8Array(this.#view.buffer, this.#view.byteOffset + pos, len);
|
|
67
|
-
this.#nodeDataTable.set(id, this.#textDecoder.decode(slice));
|
|
68
|
-
pos += len;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return this.#nodeDataTable.get(nodeId) ?? null;
|
|
37
|
+
return this.#arena.getNodeData(nodeId);
|
|
38
|
+
}
|
|
39
|
+
/** @internal null when no node carries data. */
|
|
40
|
+
getNodeDataTable() {
|
|
41
|
+
return this.#arena.getNodeDataTable();
|
|
72
42
|
}
|
|
73
43
|
get nodeCount() {
|
|
74
|
-
return this.#header.nodeCount;
|
|
44
|
+
return this.#arena.header.nodeCount;
|
|
75
45
|
}
|
|
76
46
|
get header() {
|
|
77
|
-
return { ...this.#header };
|
|
47
|
+
return { ...this.#arena.header };
|
|
78
48
|
}
|
|
79
|
-
/**
|
|
80
|
-
* source as written; for that, read `ctx.source` from a plugin. */
|
|
49
|
+
/** Full string pool, including interned strings; use ctx.source for the original document. */
|
|
81
50
|
getStringPool() {
|
|
82
|
-
|
|
83
|
-
const { stringPoolOffset, stringPoolLen } = this.#header;
|
|
84
|
-
const bytes = new Uint8Array(this.#view.buffer, this.#view.byteOffset + stringPoolOffset, stringPoolLen);
|
|
85
|
-
this.#stringPoolCache = this.#textDecoder.decode(bytes);
|
|
86
|
-
}
|
|
87
|
-
return this.#stringPoolCache;
|
|
51
|
+
return this.#arena.getStringPool();
|
|
88
52
|
}
|
|
53
|
+
/** Wire string refs use UTF-16 units, so substring preserves their offsets. */
|
|
89
54
|
getString(offset, len) {
|
|
90
|
-
|
|
91
|
-
return "";
|
|
92
|
-
const pool = this.getStringPool();
|
|
93
|
-
if (!this.#poolChecked) {
|
|
94
|
-
this.#poolChecked = true;
|
|
95
|
-
const { stringPoolOffset, stringPoolLen } = this.#header;
|
|
96
|
-
const extraBytes = stringPoolLen - pool.length;
|
|
97
|
-
if (extraBytes > 0) {
|
|
98
|
-
const bytes = new Uint8Array(this.#view.buffer, this.#view.byteOffset + stringPoolOffset, stringPoolLen);
|
|
99
|
-
this.#poolOffsets = new PoolOffsets(bytes, extraBytes);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// An all-ASCII pool has byte offsets equal to its UTF-16 indices.
|
|
103
|
-
const offsets = this.#poolOffsets;
|
|
104
|
-
return offsets === null
|
|
105
|
-
? pool.substring(offset, offset + len)
|
|
106
|
-
: offsets.slice(pool, offset, len);
|
|
55
|
+
return this.#arena.getString(offset, len);
|
|
107
56
|
}
|
|
108
57
|
getNode(nodeId) {
|
|
109
|
-
const
|
|
58
|
+
const nodeCount = this.nodeCount;
|
|
110
59
|
if (nodeId >= nodeCount) {
|
|
111
60
|
throw new RangeError(`Node ID ${nodeId} out of range (count: ${nodeCount})`);
|
|
112
61
|
}
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
const type =
|
|
116
|
-
const position = readPosition(v, base + FIELD.start_offset);
|
|
62
|
+
const u32 = this.#u32;
|
|
63
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
64
|
+
const type = this.#u8[this.#nodesB + nodeId * this.#strideB + FIELD.node_type] ?? 0;
|
|
117
65
|
return {
|
|
118
|
-
id:
|
|
66
|
+
id: u32[w] ?? 0,
|
|
119
67
|
type,
|
|
120
68
|
typeName: NodeTypeName[type] ?? `Unknown(${type})`,
|
|
121
|
-
parent:
|
|
122
|
-
position,
|
|
123
|
-
childrenStart:
|
|
124
|
-
childrenCount:
|
|
125
|
-
dataOffset:
|
|
126
|
-
dataLen:
|
|
69
|
+
parent: u32[w + W_PARENT] ?? 0,
|
|
70
|
+
position: this.getPosition(nodeId),
|
|
71
|
+
childrenStart: u32[w + W_CHILDREN_START] ?? 0,
|
|
72
|
+
childrenCount: u32[w + W_CHILDREN_COUNT] ?? 0,
|
|
73
|
+
dataOffset: u32[w + W_DATA_OFFSET] ?? 0,
|
|
74
|
+
dataLen: u32[w + W_DATA_LEN] ?? 0,
|
|
127
75
|
};
|
|
128
76
|
}
|
|
129
77
|
/** Fast path: read only the type byte for a node. */
|
|
130
78
|
getNodeType(nodeId) {
|
|
131
|
-
|
|
132
|
-
return this.#view.getUint8(nodesOffset + nodeId * nodeStructSize + FIELD.node_type);
|
|
79
|
+
return this.#u8[this.#nodesB + nodeId * this.#strideB + FIELD.node_type] ?? 0;
|
|
133
80
|
}
|
|
81
|
+
/** A zero start line marks a synthesized node with no source range (unist
|
|
82
|
+
* lines are 1-based), surfaced as `undefined`. */
|
|
134
83
|
getPosition(nodeId) {
|
|
135
|
-
const
|
|
136
|
-
|
|
84
|
+
const u32 = this.#u32;
|
|
85
|
+
const b = this.#nodesW + nodeId * this.#strideW + W_START_OFFSET;
|
|
86
|
+
const startLine = u32[b + 2] ?? 0;
|
|
87
|
+
if (startLine === 0)
|
|
88
|
+
return undefined;
|
|
89
|
+
return {
|
|
90
|
+
start: { offset: u32[b] ?? 0, line: startLine, column: u32[b + 3] ?? 0 },
|
|
91
|
+
end: { offset: u32[b + 1] ?? 0, line: u32[b + 4] ?? 0, column: u32[b + 5] ?? 0 },
|
|
92
|
+
};
|
|
137
93
|
}
|
|
138
94
|
/** Fast path: read only the parent id for a node (0xffffffff at the root). */
|
|
139
95
|
getParentId(nodeId) {
|
|
140
|
-
|
|
141
|
-
|
|
96
|
+
return this.#u32[this.#nodesW + nodeId * this.#strideW + W_PARENT] ?? 0;
|
|
97
|
+
}
|
|
98
|
+
getChildrenCount(nodeId) {
|
|
99
|
+
return this.#u32[this.#nodesW + nodeId * this.#strideW + W_CHILDREN_COUNT] ?? 0;
|
|
142
100
|
}
|
|
143
101
|
getChildIds(nodeId) {
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
const childrenCount = v.getUint32(base + FIELD.children_count, true);
|
|
102
|
+
const u32 = this.#u32;
|
|
103
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
104
|
+
const childrenStart = u32[w + W_CHILDREN_START] ?? 0;
|
|
105
|
+
const childrenCount = u32[w + W_CHILDREN_COUNT] ?? 0;
|
|
149
106
|
if (childrenCount === 0)
|
|
150
107
|
return [];
|
|
108
|
+
const base = this.#childrenW + childrenStart;
|
|
151
109
|
const ids = [];
|
|
152
110
|
for (let i = 0; i < childrenCount; i++) {
|
|
153
|
-
ids.push(
|
|
111
|
+
ids.push(u32[base + i] ?? 0);
|
|
154
112
|
}
|
|
155
113
|
return ids;
|
|
156
114
|
}
|
|
157
115
|
/** Push child node IDs directly onto a stack array (reverse order for depth-first). */
|
|
158
116
|
pushChildIds(nodeId, stack) {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
if (childrenCount === 0)
|
|
165
|
-
return;
|
|
117
|
+
const u32 = this.#u32;
|
|
118
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
119
|
+
const childrenStart = u32[w + W_CHILDREN_START] ?? 0;
|
|
120
|
+
const childrenCount = u32[w + W_CHILDREN_COUNT] ?? 0;
|
|
121
|
+
const base = this.#childrenW + childrenStart;
|
|
166
122
|
for (let i = childrenCount - 1; i >= 0; i--) {
|
|
167
|
-
stack.push(
|
|
123
|
+
stack.push(u32[base + i] ?? 0);
|
|
168
124
|
}
|
|
169
125
|
}
|
|
170
|
-
|
|
171
|
-
* decoder runs once per node, so an intermediate view or ref object here
|
|
172
|
-
* costs an allocation per field. */
|
|
126
|
+
// Read fields directly to avoid allocating an intermediate view or reference per field.
|
|
173
127
|
fieldU8(nodeId, offset, fallback) {
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
if (offset >=
|
|
128
|
+
const u32 = this.#u32;
|
|
129
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
130
|
+
if (offset >= (u32[w + W_DATA_LEN] ?? 0))
|
|
131
|
+
return fallback;
|
|
132
|
+
return this.#u8[this.#typeDataB + (u32[w + W_DATA_OFFSET] ?? 0) + offset] ?? fallback;
|
|
133
|
+
}
|
|
134
|
+
fieldU32(nodeId, offset, fallback) {
|
|
135
|
+
const u32 = this.#u32;
|
|
136
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
137
|
+
if (offset + 4 > (u32[w + W_DATA_LEN] ?? 0))
|
|
177
138
|
return fallback;
|
|
178
|
-
|
|
179
|
-
return v.getUint8(at + offset);
|
|
139
|
+
return u32[(this.#typeDataB + (u32[w + W_DATA_OFFSET] ?? 0) + offset) >> 2] ?? fallback;
|
|
180
140
|
}
|
|
181
141
|
/** `""` when the field is absent or empty; callers map that to `null` for
|
|
182
142
|
* nullable fields, matching the Rust decoders' bounds checks. */
|
|
183
143
|
fieldString(nodeId, offset) {
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
if (offset + 8 >
|
|
144
|
+
const u32 = this.#u32;
|
|
145
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
146
|
+
if (offset + 8 > (u32[w + W_DATA_LEN] ?? 0))
|
|
187
147
|
return "";
|
|
188
|
-
const at = this.#
|
|
189
|
-
return this.getString(
|
|
148
|
+
const at = (this.#typeDataB + (u32[w + W_DATA_OFFSET] ?? 0) + offset) >> 2;
|
|
149
|
+
return this.getString(u32[at] ?? 0, u32[at + 1] ?? 0);
|
|
190
150
|
}
|
|
191
151
|
getTypeData(nodeId) {
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const dataOffset =
|
|
195
|
-
const dataLen =
|
|
152
|
+
const u32 = this.#u32;
|
|
153
|
+
const w = this.#nodesW + nodeId * this.#strideW;
|
|
154
|
+
const dataOffset = u32[w + W_DATA_OFFSET] ?? 0;
|
|
155
|
+
const dataLen = u32[w + W_DATA_LEN] ?? 0;
|
|
196
156
|
if (dataLen === 0)
|
|
197
157
|
return new Uint8Array(0);
|
|
198
|
-
|
|
158
|
+
const start = this.#typeDataB + dataOffset;
|
|
159
|
+
return this.#u8.subarray(start, start + dataLen);
|
|
199
160
|
}
|
|
200
161
|
/** Read a StringRef (offset: u32 LE, len: u32 LE) from type data. */
|
|
201
162
|
readStringRef(typeData, byteOffset = 0) {
|
|
202
|
-
const at = typeData.byteOffset - this.#
|
|
163
|
+
const at = (typeData.byteOffset - this.#u8.byteOffset + byteOffset) >> 2;
|
|
203
164
|
return {
|
|
204
|
-
offset: this.#
|
|
205
|
-
len: this.#
|
|
165
|
+
offset: this.#u32[at] ?? 0,
|
|
166
|
+
len: this.#u32[at + 1] ?? 0,
|
|
206
167
|
};
|
|
207
168
|
}
|
|
208
|
-
/**
|
|
209
|
-
* StringRef value. Valid for Text, InlineCode, Html, Yaml, Toml nodes.
|
|
210
|
-
* These store a single StringRef as their type data.
|
|
211
|
-
*/
|
|
212
|
-
getTextValue(nodeId) {
|
|
213
|
-
return this.fieldString(nodeId, 0);
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* ListData #[repr(C)]: start(0..4), ordered(4), spread(5), _pad(6..8).
|
|
217
|
-
* Valid for List nodes.
|
|
218
|
-
*/
|
|
219
|
-
getListData(nodeId) {
|
|
220
|
-
const data = this.getTypeData(nodeId);
|
|
221
|
-
const view = new DataView(data.buffer, data.byteOffset);
|
|
222
|
-
return {
|
|
223
|
-
start: view.getUint32(0, true),
|
|
224
|
-
ordered: data[4] !== 0,
|
|
225
|
-
spread: data[5] !== 0,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* ListItemData #[repr(C)]: checked(0), spread(1).
|
|
230
|
-
* checked: 0=unchecked, 1=checked, 2=not-a-task-item.
|
|
231
|
-
*/
|
|
232
|
-
getListItemData(nodeId) {
|
|
233
|
-
const data = this.getTypeData(nodeId);
|
|
234
|
-
const checkedByte = data[0];
|
|
235
|
-
return {
|
|
236
|
-
checked: checkedByte === 2 ? null : checkedByte === 1,
|
|
237
|
-
spread: data[1] !== 0,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* DescriptionDetailsData #[repr(C)]: spread(0). Valid for descriptionDetails.
|
|
242
|
-
*/
|
|
243
|
-
getDescriptionDetailsData(nodeId) {
|
|
244
|
-
const data = this.getTypeData(nodeId);
|
|
245
|
-
return { spread: data.length > 0 && data[0] !== 0 };
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* TableData #[repr(C)]: align_count(0..4), then align_count bytes.
|
|
249
|
-
* Alignment bytes: 0=none, 1=left, 2=right, 3=center.
|
|
250
|
-
*/
|
|
169
|
+
/** Alignment bytes follow a u32 count: 0=none, 1=left, 2=right, 3=center. */
|
|
251
170
|
getTableAlign(nodeId) {
|
|
252
171
|
const data = this.getTypeData(nodeId);
|
|
253
172
|
if (data.length < 4)
|
|
254
173
|
return [];
|
|
255
|
-
const
|
|
256
|
-
const count = view.getUint32(0, true);
|
|
174
|
+
const count = this.#u32[(data.byteOffset - this.#u8.byteOffset) >> 2] ?? 0;
|
|
257
175
|
const result = [];
|
|
258
176
|
for (let i = 0; i < count; i++) {
|
|
259
|
-
result.push(decodeColumnAlign(data[4 + i]));
|
|
177
|
+
result.push(decodeColumnAlign(data[4 + i] ?? 0));
|
|
260
178
|
}
|
|
261
179
|
return result;
|
|
262
180
|
}
|
|
263
|
-
/**
|
|
264
|
-
* MdxJsxElementData: name StringRef (0..8). len===0 means fragment.
|
|
265
|
-
*/
|
|
181
|
+
/** A zero-length element name represents an MDX fragment. */
|
|
266
182
|
getMdxJsxElementName(nodeId) {
|
|
267
183
|
const data = this.getTypeData(nodeId);
|
|
268
184
|
const nameRef = this.readStringRef(data, 0);
|
|
269
185
|
return nameRef.len > 0 ? this.getString(nameRef.offset, nameRef.len) : null;
|
|
270
186
|
}
|
|
271
|
-
/**
|
|
272
|
-
* MDX JSX element data: name + attributes.
|
|
273
|
-
*
|
|
274
|
-
* Layout:
|
|
275
|
-
* [name: StringRef(8B)][attr_count: u32(4B)][_pad: u32(4B)] = 16-byte header
|
|
276
|
-
* then attr_count * 20 bytes:
|
|
277
|
-
* [kind: u8(1B)][_pad: [u8;3](3B)][name: StringRef(8B)][value: StringRef(8B)]
|
|
278
|
-
*
|
|
279
|
-
* Attribute kinds: 0=boolean, 1=literal, 2=expression, 3=spread
|
|
280
|
-
*/
|
|
187
|
+
/** Attribute kinds: 0=boolean, 1=literal, 2=expression, 3=spread. */
|
|
281
188
|
getMdxJsxElementData(nodeId) {
|
|
282
|
-
const
|
|
283
|
-
|
|
189
|
+
const u32 = this.#u32;
|
|
190
|
+
const nw = this.#nodesW + nodeId * this.#strideW;
|
|
191
|
+
const dataLen = u32[nw + W_DATA_LEN] ?? 0;
|
|
192
|
+
if (dataLen < 16) {
|
|
284
193
|
return { name: this.getMdxJsxElementName(nodeId), attributes: [] };
|
|
285
194
|
}
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
const
|
|
289
|
-
const attrCount =
|
|
195
|
+
const w = (this.#typeDataB + (u32[nw + W_DATA_OFFSET] ?? 0)) >> 2;
|
|
196
|
+
const nameLen = u32[w + 1] ?? 0;
|
|
197
|
+
const name = nameLen > 0 ? this.getString(u32[w] ?? 0, nameLen) : null;
|
|
198
|
+
const attrCount = u32[w + 2] ?? 0;
|
|
290
199
|
const attributes = [];
|
|
291
200
|
for (let i = 0; i < attrCount; i++) {
|
|
292
|
-
const base =
|
|
293
|
-
|
|
294
|
-
const attrNameRef = this.readStringRef(data, base + 4);
|
|
295
|
-
const attrValueRef = this.readStringRef(data, base + 12);
|
|
296
|
-
switch (kind) {
|
|
297
|
-
case 0: // BooleanProp
|
|
298
|
-
attributes.push({
|
|
299
|
-
type: "mdxJsxAttribute",
|
|
300
|
-
name: this.getString(attrNameRef.offset, attrNameRef.len),
|
|
301
|
-
value: null,
|
|
302
|
-
});
|
|
303
|
-
break;
|
|
304
|
-
case 1: // LiteralProp
|
|
305
|
-
attributes.push({
|
|
306
|
-
type: "mdxJsxAttribute",
|
|
307
|
-
name: this.getString(attrNameRef.offset, attrNameRef.len),
|
|
308
|
-
value: this.getString(attrValueRef.offset, attrValueRef.len),
|
|
309
|
-
});
|
|
310
|
-
break;
|
|
311
|
-
case 2: // ExpressionProp
|
|
312
|
-
attributes.push({
|
|
313
|
-
type: "mdxJsxAttribute",
|
|
314
|
-
name: this.getString(attrNameRef.offset, attrNameRef.len),
|
|
315
|
-
value: {
|
|
316
|
-
type: "mdxJsxAttributeValueExpression",
|
|
317
|
-
value: restorePhantomSpaces(this.getString(attrValueRef.offset, attrValueRef.len)),
|
|
318
|
-
},
|
|
319
|
-
});
|
|
320
|
-
break;
|
|
321
|
-
case 3: // Spread
|
|
322
|
-
attributes.push({
|
|
323
|
-
type: "mdxJsxExpressionAttribute",
|
|
324
|
-
value: restorePhantomSpaces(this.getString(attrValueRef.offset, attrValueRef.len)),
|
|
325
|
-
});
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
201
|
+
const base = w + 4 + i * 5;
|
|
202
|
+
attributes.push(decodeMdxJsxAttr(this.#u8[base << 2] ?? 0, this.getString(u32[base + 1] ?? 0, u32[base + 2] ?? 0), this.getString(u32[base + 3] ?? 0, u32[base + 4] ?? 0)));
|
|
328
203
|
}
|
|
329
204
|
return { name, attributes };
|
|
330
205
|
}
|
|
331
|
-
/**
|
|
332
|
-
* DirectiveData layout:
|
|
333
|
-
* [name: StringRef(8B)][attr_count: u32(4B)][_pad: u32(4B)] = 16-byte header
|
|
334
|
-
* then attr_count × 16 bytes:
|
|
335
|
-
* [key: StringRef(8B)][value: StringRef(8B)]
|
|
336
|
-
*/
|
|
337
206
|
getDirectiveData(nodeId) {
|
|
338
|
-
const
|
|
339
|
-
|
|
207
|
+
const u32 = this.#u32;
|
|
208
|
+
const nw = this.#nodesW + nodeId * this.#strideW;
|
|
209
|
+
if ((u32[nw + W_DATA_LEN] ?? 0) < 16) {
|
|
340
210
|
return { name: "", attributes: {} };
|
|
341
211
|
}
|
|
342
|
-
const
|
|
343
|
-
const name = this.getString(
|
|
344
|
-
const
|
|
345
|
-
const attrCount = view.getUint32(0, true);
|
|
212
|
+
const w = (this.#typeDataB + (u32[nw + W_DATA_OFFSET] ?? 0)) >> 2;
|
|
213
|
+
const name = this.getString(u32[w] ?? 0, u32[w + 1] ?? 0);
|
|
214
|
+
const attrCount = u32[w + 2] ?? 0;
|
|
346
215
|
const attributes = {};
|
|
347
216
|
for (let i = 0; i < attrCount; i++) {
|
|
348
|
-
const base =
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
const key = this.getString(keyRef.offset, keyRef.len);
|
|
352
|
-
const val = this.getString(valRef.offset, valRef.len);
|
|
353
|
-
attributes[key] = val;
|
|
217
|
+
const base = w + 4 + i * 4;
|
|
218
|
+
const key = this.getString(u32[base] ?? 0, u32[base + 1] ?? 0);
|
|
219
|
+
attributes[key] = this.getString(u32[base + 2] ?? 0, u32[base + 3] ?? 0);
|
|
354
220
|
}
|
|
355
221
|
return { name, attributes };
|
|
356
222
|
}
|
|
@@ -360,14 +226,11 @@ export class MdastReader {
|
|
|
360
226
|
walk(visitor, rootId = 0) {
|
|
361
227
|
const stack = [rootId];
|
|
362
228
|
while (stack.length > 0) {
|
|
363
|
-
const nodeId = stack.pop();
|
|
229
|
+
const nodeId = stack.pop() ?? 0;
|
|
364
230
|
const nodeType = this.getNodeType(nodeId);
|
|
365
231
|
const result = visitor(nodeId, nodeType);
|
|
366
232
|
if (result !== false) {
|
|
367
|
-
|
|
368
|
-
for (let i = childIds.length - 1; i >= 0; i--) {
|
|
369
|
-
stack.push(childIds[i]);
|
|
370
|
-
}
|
|
233
|
+
this.pushChildIds(nodeId, stack);
|
|
371
234
|
}
|
|
372
235
|
}
|
|
373
236
|
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Blockquote, Break, Code, Definition, Delete, Emphasis, FootnoteDefinition, FootnoteReference, Heading, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListItem, Parents as MdastParents, Root as MdastRoot, Paragraph, Strong, Table, TableCell, TableRow, Text, ThematicBreak, Yaml } from "mdast";
|
|
2
2
|
import { CommandBuffer } from "../command-buffer.js";
|
|
3
|
-
import type { MdastNode, Toml, MathNode, InlineMath, Superscript, Subscript, DescriptionList, DescriptionTerm, DescriptionDetails, Custom, Data, SourceFormat } from "../types.js";
|
|
4
|
-
import { type PluginOptions } from "../visitor-shared.js";
|
|
5
|
-
import { LazyChildResolver } from "../lazy-child-resolver.js";
|
|
6
|
-
import type { MdastHandle } from "../handles.js";
|
|
7
|
-
import type { Blockquote, Break, Code, Definition, Delete, Emphasis, FootnoteDefinition, FootnoteReference, Heading, Html, Image, ImageReference, InlineCode, Link, LinkReference, List, ListItem, Paragraph, Strong, Table, TableRow, TableCell, Text, ThematicBreak, Yaml, Parents as MdastParents, Root as MdastRoot } from "mdast";
|
|
8
|
-
import type { MdxJsxFlowElement, MdxJsxTextElement } from "../mdx-types.js";
|
|
9
|
-
import type { MdxFlowExpression, MdxTextExpression } from "../mdx-types.js";
|
|
10
|
-
import type { MdxjsEsm } from "../mdx-types.js";
|
|
11
3
|
import type { ContainerDirective, LeafDirective, TextDirective } from "../directive-types.js";
|
|
4
|
+
import type { MdastHandle } from "../handles.js";
|
|
5
|
+
import { LazyChildResolver } from "../lazy-child-resolver.js";
|
|
6
|
+
import type { MdxFlowExpression, MdxjsEsm, MdxJsxFlowElement, MdxJsxTextElement, MdxTextExpression } from "../mdx-types.js";
|
|
7
|
+
import type { Custom, Data, DescriptionDetails, DescriptionList, DescriptionTerm, InlineMath, MathNode, MdastNode, SourceFormat, Subscript, Superscript, Toml } from "../types.js";
|
|
8
|
+
import { type PluginOptions, type SettableFieldKey } from "../visitor-shared.js";
|
|
9
|
+
import { MdastReader } from "./mdast-reader.js";
|
|
12
10
|
/** A string spliced into the tree, re-parsed as Markdown. Set `mdxExpressions:
|
|
13
11
|
* false` to keep MDX `{…}` literal, needed when injecting generated HTML
|
|
14
12
|
* (KaTeX, highlighters, diagrams) whose braces aren't expressions. Default true. */
|
|
@@ -89,6 +87,18 @@ export declare class MdastVisitorContext {
|
|
|
89
87
|
* content, or a raw string, which parses to a root of its own.
|
|
90
88
|
*/
|
|
91
89
|
replaceNode(node: Readonly<MdastTarget>, newNode: MdastContent | MdastContent[]): void;
|
|
90
|
+
setField<N extends MdastTarget, K extends SettableFieldKey<N, true>>(node: Readonly<N>, key: K, value: Exclude<N[K], undefined>): void;
|
|
91
|
+
/** Table alignment is an array stored in the table's typed data. */
|
|
92
|
+
setField(node: Readonly<Table>, key: "align", value: Table["align"]): void;
|
|
93
|
+
/** `children` is structural and every parent accepts it, including node-type unions. */
|
|
94
|
+
setField(node: Readonly<MdastTarget>, key: "children", value: readonly MdastTarget[]): void;
|
|
95
|
+
/** `data` is an open per-node bag serialized to JSON. `null` clears it. */
|
|
96
|
+
setField(node: Readonly<MdastTarget>, key: "data", value: Record<string, unknown> | null): void;
|
|
97
|
+
/** Set one string entry in a directive's `attributes`. */
|
|
98
|
+
setAttribute(node: Readonly<ContainerDirective | LeafDirective | TextDirective>, name: string, value: string): void;
|
|
99
|
+
/** Set one entry in an MDX JSX element's `attributes`. */
|
|
100
|
+
setAttribute(node: Readonly<MdxJsxFlowElement | MdxJsxTextElement>, name: string, value: unknown): void;
|
|
101
|
+
/** @deprecated MDAST has no property container; use `setField`. */
|
|
92
102
|
setProperty<N extends MdastTarget, K extends keyof N & string>(node: Readonly<N>, key: K, value: N[K]): void;
|
|
93
103
|
/** `children` is structural and every parent accepts it, so the key also
|
|
94
104
|
* works on node-type unions (e.g. a node returned by `parent()`). */
|
|
@@ -119,12 +129,11 @@ export declare class MdastVisitorContext {
|
|
|
119
129
|
node?: Readonly<MdastTarget>;
|
|
120
130
|
severity?: "error" | "warning" | "info";
|
|
121
131
|
}): void;
|
|
122
|
-
/** Get the binary command buffer for all mutations recorded via context methods. */
|
|
123
132
|
getCommandBuffer(): CommandBuffer;
|
|
124
133
|
getDiagnostics(): MdastDiagnostic[];
|
|
125
134
|
}
|
|
126
135
|
type MdastVisitorResult = MdastNode | RawMdastContent | RawHtmlMdastContent | undefined | null | void;
|
|
127
|
-
type MdastVisitorFn<N extends MdastNode | Custom = MdastNode> = (node: Readonly<N>, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
|
|
136
|
+
export type MdastVisitorFn<N extends MdastNode | Custom = MdastNode> = (node: Readonly<N>, context: MdastVisitorContext) => MdastVisitorResult | Promise<MdastVisitorResult>;
|
|
128
137
|
export type MdastHookFn = (root: Readonly<MdastRoot>, context: MdastVisitorContext) => void | Promise<void>;
|
|
129
138
|
export interface MdastPluginInstance {
|
|
130
139
|
/** Plugin-level configuration (e.g. `{ position: true }` to read positions). */
|
|
@@ -188,17 +197,16 @@ interface MdastVisitResult {
|
|
|
188
197
|
export type { MdastHandle };
|
|
189
198
|
interface MdastSubscription {
|
|
190
199
|
nodeType: number;
|
|
191
|
-
visitFn:
|
|
200
|
+
visitFn: MdastVisitorFn;
|
|
192
201
|
}
|
|
193
202
|
export declare function resolveMdastSubscriptions(plugin: MdastPluginInstance): MdastSubscription[];
|
|
194
203
|
/**
|
|
195
204
|
* Walk an MDAST handle in Rust, dispatch matched nodes to JS visitor functions,
|
|
196
|
-
* and
|
|
205
|
+
* and collect mutations for the caller to apply. No arena buffers cross NAPI.
|
|
197
206
|
*
|
|
198
207
|
* Returns MdastVisitResult synchronously if all visitors are sync,
|
|
199
208
|
* or Promise<MdastVisitResult> if any visitor is async.
|
|
200
209
|
*/
|
|
201
210
|
export declare function visitMdastHandle(handle: MdastHandle, plugin: MdastPluginInstance, subs: MdastSubscription[], source: string | (() => string), fileURL: URL | undefined, data?: Data, sourceFormat?: SourceFormat, diagnostics?: MdastDiagnostic[]): MdastVisitResult | Promise<MdastVisitResult>;
|
|
202
|
-
/**
|
|
203
|
-
* visitors walk, and the visitors' mutations before `after` reads the tree. */
|
|
211
|
+
/** Hooks run in separate passes so each sees mutations from the preceding pass. */
|
|
204
212
|
export declare function visitMdastHook(handle: MdastHandle, plugin: MdastPluginInstance, hook: MdastHookFn, source: string | (() => string), fileURL: URL | undefined, data?: Data, sourceFormat?: SourceFormat, diagnostics?: MdastDiagnostic[]): MdastVisitResult | Promise<MdastVisitResult>;
|