satteri 0.10.5 → 0.11.3

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.
Files changed (90) hide show
  1. package/README.md +11 -0
  2. package/dist/arena-reader.d.ts +13 -0
  3. package/dist/arena-reader.js +104 -0
  4. package/dist/binding.browser.d.ts +1 -1
  5. package/dist/binding.browser.js +1 -1
  6. package/dist/binding.d.ts +1 -1
  7. package/dist/binding.js +1 -1
  8. package/dist/byte-writer.d.ts +0 -18
  9. package/dist/byte-writer.js +6 -30
  10. package/dist/child-stub.d.ts +0 -17
  11. package/dist/child-stub.js +6 -22
  12. package/dist/command-buffer.d.ts +5 -26
  13. package/dist/command-buffer.js +28 -39
  14. package/dist/compile-options.d.ts +11 -0
  15. package/dist/compile-options.js +101 -0
  16. package/dist/compile-types.d.ts +342 -0
  17. package/dist/compile-types.js +1 -0
  18. package/dist/compile.d.ts +22 -328
  19. package/dist/compile.js +133 -383
  20. package/dist/directive-types.d.ts +1 -0
  21. package/dist/directive-types.js +1 -6
  22. package/dist/generated/arena-layout.d.ts +6 -4
  23. package/dist/generated/arena-layout.js +6 -7
  24. package/dist/generated/fused-wire.d.ts +3 -0
  25. package/dist/generated/fused-wire.js +229 -0
  26. package/dist/generated/parse-options.d.ts +1 -0
  27. package/dist/generated/parse-options.js +1 -5
  28. package/dist/generated/wire-constants.d.ts +4 -0
  29. package/dist/generated/wire-constants.js +34 -42
  30. package/dist/handles.d.ts +0 -7
  31. package/dist/hast/child-stub.d.ts +1 -8
  32. package/dist/hast/child-stub.js +14 -13
  33. package/dist/hast/element-props.d.ts +13 -0
  34. package/dist/hast/element-props.js +52 -6
  35. package/dist/hast/generated/node-types.d.ts +1 -9
  36. package/dist/hast/generated/node-types.js +1 -9
  37. package/dist/hast/generated/walk-decode.d.ts +10 -0
  38. package/dist/hast/generated/walk-decode.js +61 -0
  39. package/dist/hast/hast-materializer.d.ts +3 -10
  40. package/dist/hast/hast-materializer.js +73 -47
  41. package/dist/hast/hast-reader.d.ts +9 -38
  42. package/dist/hast/hast-reader.js +82 -271
  43. package/dist/hast/hast-visitor.d.ts +29 -16
  44. package/dist/hast/hast-visitor.js +200 -508
  45. package/dist/hast/hast-walk.d.ts +18 -0
  46. package/dist/hast/hast-walk.js +264 -0
  47. package/dist/index.d.ts +5 -5
  48. package/dist/index.js +4 -12
  49. package/dist/lazy-child-resolver.d.ts +1 -21
  50. package/dist/lazy-child-resolver.js +11 -32
  51. package/dist/materializer-cache.d.ts +5 -29
  52. package/dist/materializer-cache.js +29 -101
  53. package/dist/mdast/child-stub.d.ts +1 -12
  54. package/dist/mdast/child-stub.js +18 -28
  55. package/dist/mdast/column-align.d.ts +1 -1
  56. package/dist/mdast/column-align.js +0 -2
  57. package/dist/mdast/generated/layout.d.ts +0 -16
  58. package/dist/mdast/generated/layout.js +6 -47
  59. package/dist/mdast/generated/node-types.d.ts +1 -9
  60. package/dist/mdast/generated/node-types.js +3 -9
  61. package/dist/mdast/mdast-materializer.d.ts +3 -11
  62. package/dist/mdast/mdast-materializer.js +91 -63
  63. package/dist/mdast/mdast-reader.d.ts +15 -63
  64. package/dist/mdast/mdast-reader.js +132 -269
  65. package/dist/mdast/mdast-visitor.d.ts +23 -15
  66. package/dist/mdast/mdast-visitor.js +189 -294
  67. package/dist/mdast/mdast-walk.d.ts +13 -0
  68. package/dist/mdast/mdast-walk.js +144 -0
  69. package/dist/mdx-attr.js +0 -3
  70. package/dist/mdx-types.js +1 -6
  71. package/dist/op-stream.d.ts +4 -15
  72. package/dist/op-stream.js +31 -20
  73. package/dist/phantom.d.ts +0 -1
  74. package/dist/phantom.js +1 -9
  75. package/dist/plugin-pipeline.d.ts +32 -0
  76. package/dist/plugin-pipeline.js +177 -0
  77. package/dist/plugin.d.ts +14 -8
  78. package/dist/plugin.js +5 -10
  79. package/dist/types.d.ts +0 -1
  80. package/dist/visitor-node.d.ts +12 -0
  81. package/dist/visitor-node.js +23 -0
  82. package/dist/visitor-shared.d.ts +26 -30
  83. package/dist/visitor-shared.js +34 -36
  84. package/dist/wire-read.d.ts +0 -22
  85. package/dist/wire-read.js +3 -24
  86. package/index.d.ts +19 -10
  87. package/index.js +56 -53
  88. package/package.json +6 -12
  89. package/dist/string-pool.d.ts +0 -13
  90. package/dist/string-pool.js +0 -91
@@ -1,13 +1,7 @@
1
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
2
  export const ARENA_MAGIC = 0x5241444d;
7
- /** `Arena<K>` kind tags carried in the header's `kind` field. */
8
3
  export const KIND_MDAST = 1;
9
4
  export const KIND_HAST = 2;
10
- /** `ArenaNode` `#[repr(C)]` field byte offsets (u32 fields; `node_type` is a u8). */
11
5
  export const FIELD = {
12
6
  id: 0,
13
7
  node_type: 4,
@@ -23,7 +17,12 @@ export const FIELD = {
23
17
  data_offset: 44,
24
18
  data_len: 48,
25
19
  };
26
- /** Raw-buffer header byte offsets (4-byte fields, u32 LE). */
20
+ export const W_PARENT = 2;
21
+ export const W_START_OFFSET = 3;
22
+ export const W_CHILDREN_START = 9;
23
+ export const W_CHILDREN_COUNT = 10;
24
+ export const W_DATA_OFFSET = 11;
25
+ export const W_DATA_LEN = 12;
27
26
  export const HEADER = {
28
27
  magic: 0,
29
28
  kind: 4,
@@ -0,0 +1,3 @@
1
+ import type { ArenaWire } from "../types.js";
2
+ export declare function readMdastWireNode(wire: ArenaWire, nodeId: number, nodeType: number, node: object): boolean;
3
+ export declare function readHastWireNode(wire: ArenaWire, nodeId: number, nodeType: number, node: object): boolean;
@@ -0,0 +1,229 @@
1
+ // @generated by `cargo run -p satteri-layout-codegen`. Do not edit by hand.
2
+ import { decodeElementProp } from "../hast/element-props.js";
3
+ import { restorePhantomSpaces } from "../phantom.js";
4
+ import { W_START_OFFSET, W_DATA_LEN, W_DATA_OFFSET } from "./arena-layout.js";
5
+ const FUSED_ENUM_0 = ["shortcut", "collapsed", "full"];
6
+ export function readMdastWireNode(wire, nodeId, nodeType, node) {
7
+ const { u8, u32, pool } = wire;
8
+ const w = wire.nodesW + nodeId * wire.strideW;
9
+ const wp = w + W_START_OFFSET;
10
+ const startLine = u32[wp + 2] ?? 0;
11
+ if (startLine !== 0) {
12
+ node.position = {
13
+ start: { offset: u32[wp] ?? 0, line: startLine, column: u32[wp + 3] ?? 0 },
14
+ end: { offset: u32[wp + 1] ?? 0, line: u32[wp + 4] ?? 0, column: u32[wp + 5] ?? 0 },
15
+ };
16
+ }
17
+ const n = node;
18
+ switch (nodeType) {
19
+ case 7:
20
+ case 10:
21
+ case 13:
22
+ case 25:
23
+ case 26: {
24
+ const dl = u32[w + W_DATA_LEN] ?? 0;
25
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
26
+ const o0 = u32[db] ?? 0;
27
+ n.value = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
28
+ return true;
29
+ }
30
+ case 2: {
31
+ const dl = u32[w + W_DATA_LEN] ?? 0;
32
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
33
+ n.depth = dl > 0 ? (u8[(db << 2) + 0] ?? 1) : 1;
34
+ return true;
35
+ }
36
+ case 8: {
37
+ const dl = u32[w + W_DATA_LEN] ?? 0;
38
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
39
+ const o0 = u32[db] ?? 0;
40
+ const s0 = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
41
+ n.lang = s0 === "" ? null : s0;
42
+ const o1 = u32[db + 2] ?? 0;
43
+ const s1 = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
44
+ n.meta = s1 === "" ? null : s1;
45
+ const o2 = u32[db + 4] ?? 0;
46
+ n.value = dl >= 24 ? pool.substring(o2, o2 + (u32[db + 5] ?? 0)) : "";
47
+ return true;
48
+ }
49
+ case 9: {
50
+ const dl = u32[w + W_DATA_LEN] ?? 0;
51
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
52
+ const o0 = u32[db] ?? 0;
53
+ n.url = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
54
+ const o1 = u32[db + 2] ?? 0;
55
+ const s1 = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
56
+ n.title = s1 === "" ? null : s1;
57
+ const o2 = u32[db + 4] ?? 0;
58
+ n.identifier = dl >= 24 ? pool.substring(o2, o2 + (u32[db + 5] ?? 0)) : "";
59
+ const o3 = u32[db + 6] ?? 0;
60
+ n.label = dl >= 32 ? pool.substring(o3, o3 + (u32[db + 7] ?? 0)) : "";
61
+ return true;
62
+ }
63
+ case 15: {
64
+ const dl = u32[w + W_DATA_LEN] ?? 0;
65
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
66
+ const o0 = u32[db] ?? 0;
67
+ n.url = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
68
+ const o1 = u32[db + 2] ?? 0;
69
+ const s1 = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
70
+ n.title = s1 === "" ? null : s1;
71
+ return true;
72
+ }
73
+ case 16: {
74
+ const dl = u32[w + W_DATA_LEN] ?? 0;
75
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
76
+ const o0 = u32[db] ?? 0;
77
+ n.url = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
78
+ const o1 = u32[db + 2] ?? 0;
79
+ n.alt = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
80
+ const o2 = u32[db + 4] ?? 0;
81
+ const s2 = dl >= 24 ? pool.substring(o2, o2 + (u32[db + 5] ?? 0)) : "";
82
+ n.title = s2 === "" ? null : s2;
83
+ return true;
84
+ }
85
+ case 17: {
86
+ const dl = u32[w + W_DATA_LEN] ?? 0;
87
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
88
+ const o0 = u32[db] ?? 0;
89
+ n.identifier = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
90
+ const o1 = u32[db + 2] ?? 0;
91
+ n.label = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
92
+ const b2 = dl > 16 ? (u8[(db << 2) + 16] ?? 0) : 0;
93
+ n.referenceType = FUSED_ENUM_0[b2] ?? FUSED_ENUM_0[0];
94
+ return true;
95
+ }
96
+ case 18: {
97
+ const dl = u32[w + W_DATA_LEN] ?? 0;
98
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
99
+ const o0 = u32[db] ?? 0;
100
+ n.identifier = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
101
+ const o1 = u32[db + 2] ?? 0;
102
+ n.label = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
103
+ const b2 = dl > 16 ? (u8[(db << 2) + 16] ?? 0) : 0;
104
+ n.referenceType = FUSED_ENUM_0[b2] ?? FUSED_ENUM_0[0];
105
+ const o3 = u32[db + 5] ?? 0;
106
+ n.alt = dl >= 28 ? pool.substring(o3, o3 + (u32[db + 6] ?? 0)) : "";
107
+ return true;
108
+ }
109
+ case 19: {
110
+ const dl = u32[w + W_DATA_LEN] ?? 0;
111
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
112
+ const o0 = u32[db] ?? 0;
113
+ n.identifier = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
114
+ const o1 = u32[db + 2] ?? 0;
115
+ n.label = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
116
+ return true;
117
+ }
118
+ case 20: {
119
+ const dl = u32[w + W_DATA_LEN] ?? 0;
120
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
121
+ const o0 = u32[db] ?? 0;
122
+ n.identifier = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
123
+ const o1 = u32[db + 2] ?? 0;
124
+ n.label = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
125
+ return true;
126
+ }
127
+ case 27: {
128
+ const dl = u32[w + W_DATA_LEN] ?? 0;
129
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
130
+ const o0 = u32[db] ?? 0;
131
+ const s0 = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
132
+ n.meta = s0 === "" ? null : s0;
133
+ const o1 = u32[db + 2] ?? 0;
134
+ n.value = dl >= 16 ? pool.substring(o1, o1 + (u32[db + 3] ?? 0)) : "";
135
+ return true;
136
+ }
137
+ case 28: {
138
+ const dl = u32[w + W_DATA_LEN] ?? 0;
139
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
140
+ const o0 = u32[db + 2] ?? 0;
141
+ n.value = dl >= 16 ? pool.substring(o0, o0 + (u32[db + 3] ?? 0)) : "";
142
+ return true;
143
+ }
144
+ case 102:
145
+ case 103:
146
+ case 104: {
147
+ const dl = u32[w + W_DATA_LEN] ?? 0;
148
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
149
+ const o0 = u32[db] ?? 0;
150
+ n.value = restorePhantomSpaces(dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "");
151
+ return true;
152
+ }
153
+ case 0:
154
+ case 1:
155
+ case 3:
156
+ case 4:
157
+ case 11:
158
+ case 12:
159
+ case 14:
160
+ case 22:
161
+ case 23:
162
+ case 24:
163
+ case 33:
164
+ case 34:
165
+ case 35:
166
+ case 36:
167
+ return true;
168
+ default:
169
+ return false;
170
+ }
171
+ }
172
+ export function readHastWireNode(wire, nodeId, nodeType, node) {
173
+ const { u8, u32, pool } = wire;
174
+ const w = wire.nodesW + nodeId * wire.strideW;
175
+ const wp = w + W_START_OFFSET;
176
+ const startLine = u32[wp + 2] ?? 0;
177
+ if (startLine !== 0) {
178
+ node.position = {
179
+ start: { offset: u32[wp] ?? 0, line: startLine, column: u32[wp + 3] ?? 0 },
180
+ end: { offset: u32[wp + 1] ?? 0, line: u32[wp + 4] ?? 0, column: u32[wp + 5] ?? 0 },
181
+ };
182
+ }
183
+ const n = node;
184
+ switch (nodeType) {
185
+ case 2:
186
+ case 3:
187
+ case 5:
188
+ case 13: {
189
+ const dl = u32[w + W_DATA_LEN] ?? 0;
190
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
191
+ const o0 = u32[db] ?? 0;
192
+ n.value = dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "";
193
+ return true;
194
+ }
195
+ case 12:
196
+ case 14: {
197
+ const dl = u32[w + W_DATA_LEN] ?? 0;
198
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
199
+ const o0 = u32[db] ?? 0;
200
+ n.value = restorePhantomSpaces(dl >= 8 ? pool.substring(o0, o0 + (u32[db + 1] ?? 0)) : "");
201
+ return true;
202
+ }
203
+ case 1: {
204
+ const dl = u32[w + W_DATA_LEN] ?? 0;
205
+ const db = (wire.typeDataB + (u32[w + W_DATA_OFFSET] ?? 0)) >> 2;
206
+ let tagName = "";
207
+ const properties = {};
208
+ if (dl >= 16) {
209
+ const toff = u32[db] ?? 0;
210
+ tagName = pool.substring(toff, toff + (u32[db + 1] ?? 0));
211
+ const count = u32[db + 2] ?? 0;
212
+ for (let i = 0; i < count; i++) {
213
+ const base = db + 4 + i * 5;
214
+ const noff = u32[base] ?? 0;
215
+ const voff = u32[base + 3] ?? 0;
216
+ properties[pool.substring(noff, noff + (u32[base + 1] ?? 0))] = decodeElementProp(u8[(base << 2) + 8] ?? 0, pool.substring(voff, voff + (u32[base + 4] ?? 0)));
217
+ }
218
+ }
219
+ n.tagName = tagName;
220
+ n.properties = properties;
221
+ return true;
222
+ }
223
+ case 0:
224
+ case 4:
225
+ return true;
226
+ default:
227
+ return false;
228
+ }
229
+ }
@@ -17,3 +17,4 @@ export declare const ENABLE_SMART_QUOTES: number;
17
17
  export declare const ENABLE_SMART_DASHES: number;
18
18
  export declare const ENABLE_SMART_ELLIPSES: number;
19
19
  export declare const ENABLE_MATH_MULTI_DOLLAR: number;
20
+ export declare const ENABLE_ATTRIBUTES: number;
@@ -1,9 +1,4 @@
1
1
  // @generated by `cargo run -p satteri-layout-codegen`. Do not edit by hand.
2
- // Parser option bits, declared once in `satteri-layout-codegen/src/schema.rs`.
3
- // `featuresToNative` packs them into the `parseOptions` integer the NAPI entry
4
- // points take; the compile-time asserts in
5
- // `satteri-napi-binding/src/generated/parse_options.rs` pin them to the real
6
- // `satteri_pulldown_cmark::Options` flags.
7
2
  export const ENABLE_TABLES = 1 << 1;
8
3
  export const ENABLE_FOOTNOTES = 1 << 2;
9
4
  export const ENABLE_STRIKETHROUGH = 1 << 3;
@@ -23,3 +18,4 @@ export const ENABLE_SMART_QUOTES = 1 << 18;
23
18
  export const ENABLE_SMART_DASHES = 1 << 19;
24
19
  export const ENABLE_SMART_ELLIPSES = 1 << 20;
25
20
  export const ENABLE_MATH_MULTI_DOLLAR = 1 << 23;
21
+ export const ENABLE_ATTRIBUTES = 1 << 24;
@@ -9,6 +9,7 @@ export declare const OP_BOOL = 8;
9
9
  export declare const OP_DATA = 9;
10
10
  export declare const OP_PROP = 10;
11
11
  export declare const OP_ALIGN = 11;
12
+ export declare const OP_POSITION = 12;
12
13
  export declare const OF_VALUE = 0;
13
14
  export declare const OF_URL = 1;
14
15
  export declare const OF_TITLE = 2;
@@ -35,6 +36,8 @@ export declare const CMD_WRAP = 9;
35
36
  export declare const CMD_REPLACE = 11;
36
37
  export declare const CMD_SET_PROPERTY = 12;
37
38
  export declare const CMD_SET_CHILDREN = 13;
39
+ export declare const CMD_SET_FIELD = 14;
40
+ export declare const CMD_SET_ATTRIBUTE = 15;
38
41
  export declare const PAYLOAD_RAW = 16;
39
42
  export declare const PAYLOAD_OPSTREAM = 20;
40
43
  export declare const RAW_LITERAL_BRACES = 1;
@@ -46,6 +49,7 @@ export declare const PROP_COMMA_SEP = 4;
46
49
  export declare const PROP_INT = 5;
47
50
  export declare const PROP_NULL = 6;
48
51
  export declare const PROP_COMMA_SEP_NUM = 7;
52
+ export declare const PROP_TOKEN_LIST = 8;
49
53
  export declare const MDX_ATTR_BOOLEAN_PROP = 0;
50
54
  export declare const MDX_ATTR_LITERAL_PROP = 1;
51
55
  export declare const MDX_ATTR_EXPRESSION_PROP = 2;
@@ -1,21 +1,16 @@
1
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]
2
+ export const OP_OPEN = 0x01;
8
3
  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).
4
+ export const OP_REF = 0x03;
5
+ export const OP_KEEP_CHILDREN = 0x04;
6
+ export const OP_STR = 0x05;
7
+ export const OP_U8 = 0x06;
8
+ export const OP_U32 = 0x07;
9
+ export const OP_BOOL = 0x08;
10
+ export const OP_DATA = 0x09;
11
+ export const OP_PROP = 0x0a;
12
+ export const OP_ALIGN = 0x0b;
13
+ export const OP_POSITION = 0x0c;
19
14
  export const OF_VALUE = 0;
20
15
  export const OF_URL = 1;
21
16
  export const OF_TITLE = 2;
@@ -24,17 +19,15 @@ export const OF_LANG = 4;
24
19
  export const OF_META = 5;
25
20
  export const OF_IDENTIFIER = 6;
26
21
  export const OF_LABEL = 7;
27
- export const OF_NAME = 8; // directive / MDX JSX element name
22
+ export const OF_NAME = 8;
28
23
  export const OF_REFERENCE_TYPE = 9;
29
24
  export const OF_DEPTH = 10;
30
25
  export const OF_CHECKED = 11;
31
26
  export const OF_START = 12;
32
27
  export const OF_ORDERED = 13;
33
28
  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…].
29
+ export const OF_TAGNAME = 15;
30
+ export const OF_EXPLICIT = 16;
38
31
  export const CMD_REMOVE = 0x01;
39
32
  export const CMD_INSERT_BEFORE = 0x05;
40
33
  export const CMD_INSERT_AFTER = 0x06;
@@ -42,24 +35,23 @@ export const CMD_PREPEND_CHILD = 0x07;
42
35
  export const CMD_APPEND_CHILD = 0x08;
43
36
  export const CMD_WRAP = 0x09;
44
37
  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 = 0x10; // [flags: u8][len: u32 LE][utf8] — re-parsed as markdown; see RAW_* flags
49
- export const PAYLOAD_OPSTREAM = 0x14; // [len: u32 LE][op bytes] — replayed straight into the arena
50
- // Flag bits for the `PAYLOAD_RAW` payload.
51
- export const RAW_LITERAL_BRACES = 0x01; // keep MDX `{…}` as literal text (only affects MDX output)
52
- // Property value kinds (HAST element properties and SET_PROPERTY commands).
53
- export const PROP_STRING = 0; // UTF-8 value
54
- export const PROP_BOOL_TRUE = 1; // no value bytes
55
- export const PROP_BOOL_FALSE = 2; // no value bytes
56
- export const PROP_SPACE_SEP = 3; // space-separated list (UTF-8)
57
- export const PROP_COMMA_SEP = 4; // comma-separated list (UTF-8)
58
- export const PROP_INT = 5; // decimal string, parsed to i64
59
- export const PROP_NULL = 6; // no value bytes
60
- export const PROP_COMMA_SEP_NUM = 7; // comma-separated list, numeric items parsed to numbers
61
- // MDX JSX attribute kinds (MDAST and HAST MDX JSX element type_data).
62
- export const MDX_ATTR_BOOLEAN_PROP = 0; // name only, no value
63
- export const MDX_ATTR_LITERAL_PROP = 1; // name="literal"
64
- export const MDX_ATTR_EXPRESSION_PROP = 2; // name={expr}
65
- export const MDX_ATTR_SPREAD = 3; // {...expr}
38
+ export const CMD_SET_PROPERTY = 0x0c;
39
+ export const CMD_SET_CHILDREN = 0x0d;
40
+ export const CMD_SET_FIELD = 0x0e;
41
+ export const CMD_SET_ATTRIBUTE = 0x0f;
42
+ export const PAYLOAD_RAW = 0x10;
43
+ export const PAYLOAD_OPSTREAM = 0x14;
44
+ export const RAW_LITERAL_BRACES = 0x01;
45
+ export const PROP_STRING = 0;
46
+ export const PROP_BOOL_TRUE = 1;
47
+ export const PROP_BOOL_FALSE = 2;
48
+ export const PROP_SPACE_SEP = 3;
49
+ export const PROP_COMMA_SEP = 4;
50
+ export const PROP_INT = 5;
51
+ export const PROP_NULL = 6;
52
+ export const PROP_COMMA_SEP_NUM = 7;
53
+ export const PROP_TOKEN_LIST = 8;
54
+ export const MDX_ATTR_BOOLEAN_PROP = 0;
55
+ export const MDX_ATTR_LITERAL_PROP = 1;
56
+ export const MDX_ATTR_EXPRESSION_PROP = 2;
57
+ export const MDX_ATTR_SPREAD = 3;
package/dist/handles.d.ts CHANGED
@@ -1,10 +1,3 @@
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
1
  declare global {
9
2
  interface MdastHandle {
10
3
  readonly __satteriHandleKind: "mdast";
@@ -2,15 +2,8 @@ import type { LazyChildResolver } from "../lazy-child-resolver.js";
2
2
  import type { HastNode } from "../types.js";
3
3
  import type { HastReader } from "./hast-reader.js";
4
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). Spread/identity rules
9
- * are enforced by `nid()` in hast-visitor.ts.
10
- */
11
5
  export declare class HastChildStub {
12
- _resolver: HastResolver;
13
- _id: number;
6
+ #private;
14
7
  type: string;
15
8
  constructor(resolver: HastResolver, id: number, nodeType: number);
16
9
  }
@@ -2,7 +2,7 @@ import { flatByTag, installStubDescriptors, stubDescriptors, } from "../child-st
2
2
  import { NAME_TO_TYPE, TYPE_NAMES } from "./generated/node-types.js";
3
3
  import { HAST_CONTAINER_TYPES } from "./hast-materializer.js";
4
4
  const N = NAME_TO_TYPE;
5
- /** Per-type stub fields; must mirror `materializeHastNode`'s populate switch. */
5
+ // Stub fields must match the fields populated by materializeHastNode.
6
6
  const HAST_STUB_FIELDS = {
7
7
  [N.root]: [],
8
8
  [N.element]: ["tagName", "properties"],
@@ -25,26 +25,27 @@ for (const tag of Object.keys(HAST_STUB_FIELDS)) {
25
25
  fields.push("children");
26
26
  HAST_STUB_DESCRIPTORS[nodeType] = stubDescriptors(fields);
27
27
  }
28
- /** Unknown node types still expose the prelude-backed lazy fields. */
29
28
  const FALLBACK_DESCRIPTORS = stubDescriptors([]);
30
- /**
31
- * Walk-path child stub: arena id + `type` eagerly, every other field a lazy
32
- * forward to the materialized node (first read snapshots the arena via
33
- * `materializeOne`, which enforces the handle epoch). Spread/identity rules
34
- * are enforced by `nid()` in hast-visitor.ts.
35
- */
36
29
  export class HastChildStub {
37
- _resolver;
38
- _id;
30
+ #resolver;
31
+ #id;
39
32
  type;
40
33
  constructor(resolver, id, nodeType) {
41
- this._resolver = resolver;
42
- this._id = id;
34
+ this.#resolver = resolver;
35
+ this.#id = id;
43
36
  this.type = TYPE_NAME_BY_TAG[nodeType] ?? `unknown(${nodeType})`;
44
37
  installStubDescriptors(this, HAST_STUB_DESCRIPTORS[nodeType] ?? FALLBACK_DESCRIPTORS);
45
38
  }
46
39
  /** @internal */
47
40
  get _refs() {
48
- return this._resolver.refs;
41
+ return this.#resolver.refs;
42
+ }
43
+ /** @internal */
44
+ get _id() {
45
+ return this.#id;
46
+ }
47
+ /** @internal */
48
+ _materialize() {
49
+ return this.#resolver.materializeOne(this.#id);
49
50
  }
50
51
  }
@@ -1,2 +1,15 @@
1
1
  export type HastPropertyValue = string | number | boolean | (string | number)[];
2
+ /** Encode an array property value as `PROP_TOKEN_LIST`: whether it serializes
3
+ * comma- or space-separated depends on the element's schema, which is only
4
+ * known at render (a subtree may still be detached here). A leading `1`/`0`
5
+ * records whether comma joining needs trailing padding. Each NUL-terminated
6
+ * token starts with `n` (number) or `s` (string), preserving numeric items
7
+ * when a later plugin reads the property.
8
+ *
9
+ * A list *ending* in an empty string gets another appended, mirroring
10
+ * `comma-separated-tokens`, which pads so the value parses back to the same
11
+ * list. Only `""` pads: `null` joins to the same empty token but does not.
12
+ * Keep padding separate from the items so materializing and re-encoding
13
+ * a property never adds phantom tokens. */
14
+ export declare function encodeTokenList(items: readonly unknown[]): string;
2
15
  export declare function decodeElementProp(kind: number, value: string): HastPropertyValue;
@@ -1,7 +1,52 @@
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_COMMA_SEP_NUM, PROP_INT, } from "../generated/wire-constants.js";
1
+ // Boolean property kinds carry no value string in the wire protocol.
2
+ import { PROP_BOOL_TRUE, PROP_BOOL_FALSE, PROP_SPACE_SEP, PROP_COMMA_SEP, PROP_COMMA_SEP_NUM, PROP_INT, PROP_TOKEN_LIST, } from "../generated/wire-constants.js";
3
+ /** Encode an array property value as `PROP_TOKEN_LIST`: whether it serializes
4
+ * comma- or space-separated depends on the element's schema, which is only
5
+ * known at render (a subtree may still be detached here). A leading `1`/`0`
6
+ * records whether comma joining needs trailing padding. Each NUL-terminated
7
+ * token starts with `n` (number) or `s` (string), preserving numeric items
8
+ * when a later plugin reads the property.
9
+ *
10
+ * A list *ending* in an empty string gets another appended, mirroring
11
+ * `comma-separated-tokens`, which pads so the value parses back to the same
12
+ * list. Only `""` pads: `null` joins to the same empty token but does not.
13
+ * Keep padding separate from the items so materializing and re-encoding
14
+ * a property never adds phantom tokens. */
15
+ export function encodeTokenList(items) {
16
+ if (items.length === 0)
17
+ return "";
18
+ let tokens = items[items.length - 1] === "" ? "1" : "0";
19
+ for (const item of items)
20
+ tokens += `${tokenToWire(item)}\0`;
21
+ return tokens;
22
+ }
23
+ /** U+0001 introduces an escape so a token carrying a NUL of its own does not
24
+ * read as two tokens: `\u00010` is a NUL, `\u00011` the escape itself. */
25
+ const ESCAPE = "\u0001";
26
+ // eslint-disable-next-line no-control-regex -- U+0001 introduces the wire protocol's escape sequences.
27
+ const TOKEN_ESCAPE = /\u0001([01])/g;
28
+ /** `join` renders null and undefined as an empty token; keep that. */
29
+ function tokenToWire(item) {
30
+ const token = item === null || item === undefined ? "" : String(item);
31
+ const escaped = token.includes("\0") || token.includes(ESCAPE)
32
+ ? token.replaceAll(ESCAPE, `${ESCAPE}1`).replaceAll("\0", `${ESCAPE}0`)
33
+ : token;
34
+ return `${typeof item === "number" ? "n" : "s"}${escaped}`;
35
+ }
36
+ function decodeTokenList(value) {
37
+ if (value === "")
38
+ return [];
39
+ const body = value.slice(1);
40
+ const tokens = (body.endsWith("\0") ? body.slice(0, -1) : body).split("\0");
41
+ return tokens.map((entry) => {
42
+ const token = entry.slice(1);
43
+ if (entry[0] === "n")
44
+ return Number(token);
45
+ return token.includes(ESCAPE)
46
+ ? token.replace(TOKEN_ESCAPE, (_, digit) => (digit === "0" ? "\0" : ESCAPE))
47
+ : token;
48
+ });
49
+ }
5
50
  export function decodeElementProp(kind, value) {
6
51
  switch (kind) {
7
52
  case PROP_BOOL_TRUE:
@@ -11,7 +56,6 @@ export function decodeElementProp(kind, value) {
11
56
  case PROP_SPACE_SEP:
12
57
  return value.split(" ").filter((s) => s.length > 0);
13
58
  case PROP_COMMA_SEP: {
14
- // Interior empty items are kept; only a trailing empty is dropped.
15
59
  const items = value.split(",").map((s) => s.trim());
16
60
  if (items[items.length - 1] === "")
17
61
  items.pop();
@@ -23,9 +67,11 @@ export function decodeElementProp(kind, value) {
23
67
  items.pop();
24
68
  return items.map((s) => (s !== "" && !Number.isNaN(Number(s)) ? Number(s) : s));
25
69
  }
70
+ case PROP_TOKEN_LIST:
71
+ return decodeTokenList(value);
26
72
  case PROP_INT:
27
73
  return Number(value);
28
74
  default:
29
- return value; // PROP_STRING
75
+ return value;
30
76
  }
31
77
  }
@@ -1,14 +1,6 @@
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
- /** Names a plugin can subscribe to (every node except `root`). */
6
3
  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
4
  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
5
  export declare const HAST_CUSTOM_TYPES: readonly string[];
6
+ export declare const CONTAINER_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: "element",
@@ -13,7 +12,6 @@ export const TYPE_NAMES = {
13
12
  13: "mdxjsEsm",
14
13
  14: "mdxTextExpression",
15
14
  };
16
- /** Canonical AST name -> node-type tag. */
17
15
  export const NAME_TO_TYPE = {
18
16
  root: 0,
19
17
  element: 1,
@@ -27,7 +25,6 @@ export const NAME_TO_TYPE = {
27
25
  mdxjsEsm: 13,
28
26
  mdxTextExpression: 14,
29
27
  };
30
- /** Names a plugin can subscribe to (every node except `root`). */
31
28
  export const VISITOR_KEYS = new Set([
32
29
  "element",
33
30
  "text",
@@ -40,9 +37,6 @@ export const VISITOR_KEYS = new Set([
40
37
  "mdxjsEsm",
41
38
  "mdxTextExpression",
42
39
  ]);
43
- /** Name -> tag for the types the op-stream can encode; one lookup gates AND
44
- * resolves the emit-path tag. Excluded names (see `*_OPSTREAM_EXCLUDED` in
45
- * schema.rs) have no encoding — the visitor throws for them. */
46
40
  export const HAST_OPSTREAM_TYPES = {
47
41
  element: 1,
48
42
  text: 2,
@@ -54,11 +48,9 @@ export const HAST_OPSTREAM_TYPES = {
54
48
  mdxjsEsm: 13,
55
49
  mdxTextExpression: 14,
56
50
  };
57
- /** Names of the variable-length `custom` node types (hand-written or
58
- * `Tail`-generated codec). The op-stream round-trip oracle asserts it covers
59
- * every one, so a forgotten or drifted encode/decode arm fails loudly. */
60
51
  export const HAST_CUSTOM_TYPES = [
61
52
  "element",
62
53
  "mdxJsxFlowElement",
63
54
  "mdxJsxTextElement",
64
55
  ];
56
+ export const CONTAINER_TYPES = new Set([0, 1, 10, 11]);
@@ -0,0 +1,10 @@
1
+ import type { MdxJsxAttributeUnion } from "../../types.js";
2
+ export declare function readWalkElementTag(view: DataView, buf: Uint8Array, pos: number): string;
3
+ export declare function walkElementPropsAt(view: DataView, pos: number): number;
4
+ export declare function walkElementPropCount(view: DataView, propsAt: number): number;
5
+ export declare function decodeWalkElementProps(view: DataView, buf: Uint8Array, pos: number): Record<string, string | number | boolean | (string | number)[]>;
6
+ export declare function readWalkHastValue(view: DataView, buf: Uint8Array, offset: number, nodeType: number): string;
7
+ export declare function readWalkMdxJsx(view: DataView, buf: Uint8Array, pos: number): {
8
+ name: string | null;
9
+ attributes: MdxJsxAttributeUnion[];
10
+ };