@fuzdev/fuz_ui 0.198.0 → 0.199.0
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 +5 -3
- package/dist/ApiIndex.svelte +2 -2
- package/dist/ApiModule.svelte +1 -1
- package/dist/LibraryDetail.svelte +14 -16
- package/dist/LibraryDetail.svelte.d.ts.map +1 -1
- package/dist/LibrarySummary.svelte +12 -12
- package/dist/Mdz.svelte +2 -2
- package/dist/MdzNodeView.svelte +8 -6
- package/dist/MdzNodeView.svelte.d.ts.map +1 -1
- package/dist/MdzRoot.svelte +30 -0
- package/dist/MdzRoot.svelte.d.ts +12 -0
- package/dist/MdzRoot.svelte.d.ts.map +1 -0
- package/dist/MdzStream.svelte +32 -0
- package/dist/MdzStream.svelte.d.ts +12 -0
- package/dist/MdzStream.svelte.d.ts.map +1 -0
- package/dist/MdzStreamNodeView.svelte +106 -0
- package/dist/MdzStreamNodeView.svelte.d.ts +9 -0
- package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -0
- package/dist/ProjectLinks.svelte +2 -0
- package/dist/ProjectLinks.svelte.d.ts.map +1 -1
- package/dist/declaration.svelte.js +2 -2
- package/dist/library.svelte.d.ts +9 -70
- package/dist/library.svelte.d.ts.map +1 -1
- package/dist/library.svelte.js +24 -18
- package/dist/library_helpers.d.ts +3 -3
- package/dist/library_helpers.js +3 -3
- package/dist/logos.d.ts +7 -0
- package/dist/logos.d.ts.map +1 -1
- package/dist/logos.js +9 -0
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +37 -29
- package/dist/mdz_components.d.ts +37 -23
- package/dist/mdz_components.d.ts.map +1 -1
- package/dist/mdz_components.js +16 -4
- package/dist/mdz_helpers.d.ts +46 -14
- package/dist/mdz_helpers.d.ts.map +1 -1
- package/dist/mdz_helpers.js +189 -56
- package/dist/mdz_lexer.d.ts.map +1 -1
- package/dist/mdz_lexer.js +18 -22
- package/dist/mdz_opcodes.d.ts +174 -0
- package/dist/mdz_opcodes.d.ts.map +1 -0
- package/dist/mdz_opcodes.js +14 -0
- package/dist/mdz_opcodes_to_nodes.d.ts +20 -0
- package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -0
- package/dist/mdz_opcodes_to_nodes.js +332 -0
- package/dist/mdz_stream_parser.d.ts +80 -0
- package/dist/mdz_stream_parser.d.ts.map +1 -0
- package/dist/mdz_stream_parser.js +354 -0
- package/dist/mdz_stream_parser_block.d.ts +76 -0
- package/dist/mdz_stream_parser_block.d.ts.map +1 -0
- package/dist/mdz_stream_parser_block.js +458 -0
- package/dist/mdz_stream_parser_inline.d.ts +52 -0
- package/dist/mdz_stream_parser_inline.d.ts.map +1 -0
- package/dist/mdz_stream_parser_inline.js +378 -0
- package/dist/mdz_stream_parser_link.d.ts +22 -0
- package/dist/mdz_stream_parser_link.d.ts.map +1 -0
- package/dist/mdz_stream_parser_link.js +215 -0
- package/dist/mdz_stream_parser_state.d.ts +187 -0
- package/dist/mdz_stream_parser_state.d.ts.map +1 -0
- package/dist/mdz_stream_parser_state.js +398 -0
- package/dist/mdz_stream_parser_text.d.ts +14 -0
- package/dist/mdz_stream_parser_text.d.ts.map +1 -0
- package/dist/mdz_stream_parser_text.js +50 -0
- package/dist/mdz_stream_parser_url.d.ts +60 -0
- package/dist/mdz_stream_parser_url.d.ts.map +1 -0
- package/dist/mdz_stream_parser_url.js +307 -0
- package/dist/mdz_stream_state.svelte.d.ts +44 -0
- package/dist/mdz_stream_state.svelte.d.ts.map +1 -0
- package/dist/mdz_stream_state.svelte.js +357 -0
- package/dist/mdz_token_parser.d.ts.map +1 -1
- package/dist/mdz_token_parser.js +8 -39
- package/dist/module.svelte.js +1 -1
- package/dist/site.svelte.d.ts +13 -0
- package/dist/site.svelte.d.ts.map +1 -1
- package/dist/site.svelte.js +8 -2
- package/dist/tsdoc_mdz.d.ts +2 -2
- package/dist/tsdoc_mdz.js +2 -2
- package/dist/vite_plugin_pkg_json.d.ts +63 -0
- package/dist/vite_plugin_pkg_json.d.ts.map +1 -0
- package/dist/vite_plugin_pkg_json.js +126 -0
- package/package.json +6 -5
- package/src/lib/declaration.svelte.ts +2 -2
- package/src/lib/library.svelte.ts +37 -20
- package/src/lib/library_helpers.ts +3 -3
- package/src/lib/logos.ts +10 -0
- package/src/lib/mdz.ts +38 -29
- package/src/lib/mdz_components.ts +40 -19
- package/src/lib/mdz_helpers.ts +199 -56
- package/src/lib/mdz_lexer.ts +18 -20
- package/src/lib/mdz_opcodes.ts +205 -0
- package/src/lib/mdz_opcodes_to_nodes.ts +375 -0
- package/src/lib/mdz_stream_parser.ts +415 -0
- package/src/lib/mdz_stream_parser_block.ts +532 -0
- package/src/lib/mdz_stream_parser_inline.ts +414 -0
- package/src/lib/mdz_stream_parser_link.ts +271 -0
- package/src/lib/mdz_stream_parser_state.ts +539 -0
- package/src/lib/mdz_stream_parser_text.ts +77 -0
- package/src/lib/mdz_stream_parser_url.ts +365 -0
- package/src/lib/mdz_stream_state.svelte.ts +387 -0
- package/src/lib/mdz_token_parser.ts +13 -40
- package/src/lib/module.svelte.ts +1 -1
- package/src/lib/site.svelte.ts +17 -2
- package/src/lib/tsdoc_mdz.ts +2 -2
- package/src/lib/vite_plugin_pkg_json.ts +142 -0
- package/dist/package_helpers.d.ts +0 -150
- package/dist/package_helpers.d.ts.map +0 -1
- package/dist/package_helpers.js +0 -179
- package/src/lib/package_helpers.ts +0 -186
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a stream of mdz opcodes to the `MdzNode[]` tree representation.
|
|
3
|
+
*
|
|
4
|
+
* Stack-based replay: `open` pushes a frame, `close` pops and builds the node,
|
|
5
|
+
* `text`/`void` create leaf nodes, `append_text` extends the last text node,
|
|
6
|
+
* `revert` undoes an optimistic open and re-parents children.
|
|
7
|
+
*
|
|
8
|
+
* The output is identical to `mdz_parse()` from `mdz.ts`, enabling
|
|
9
|
+
* validation of the streaming parser against the existing fixture suite.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { DEV } from 'esm-env';
|
|
14
|
+
import { extract_single_tag, mdz_heading_id, mdz_merge_adjacent_text, mdz_push_merging_text, } from './mdz_helpers.js';
|
|
15
|
+
/**
|
|
16
|
+
* Convert an array of mdz opcodes to the `MdzNode[]` tree.
|
|
17
|
+
* Produces output identical to `mdz_parse()`.
|
|
18
|
+
*/
|
|
19
|
+
export const mdz_opcodes_to_nodes = (opcodes) => {
|
|
20
|
+
const root = [];
|
|
21
|
+
const stack = [];
|
|
22
|
+
// index node IDs to their text content (for append_text and wrap)
|
|
23
|
+
const text_nodes = new Map();
|
|
24
|
+
// track which children array contains each text node (for wrap)
|
|
25
|
+
const node_parents = new Map();
|
|
26
|
+
const target = () => {
|
|
27
|
+
return stack.length > 0 ? stack[stack.length - 1].children : root;
|
|
28
|
+
};
|
|
29
|
+
for (const op of opcodes) {
|
|
30
|
+
switch (op.type) {
|
|
31
|
+
case 'open': {
|
|
32
|
+
stack.push({
|
|
33
|
+
id: op.id,
|
|
34
|
+
node_type: op.node_type,
|
|
35
|
+
children: [],
|
|
36
|
+
start: op.start,
|
|
37
|
+
level: op.level,
|
|
38
|
+
name: op.name,
|
|
39
|
+
lang: op.lang,
|
|
40
|
+
});
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
case 'close': {
|
|
44
|
+
if (DEV && stack.length === 0) {
|
|
45
|
+
throw new Error(`mdz_opcodes_to_nodes: close for id ${op.id} but stack is empty`);
|
|
46
|
+
}
|
|
47
|
+
const frame = stack.pop();
|
|
48
|
+
if (!frame)
|
|
49
|
+
break;
|
|
50
|
+
// discard signal: the parser determined this node and its descendants
|
|
51
|
+
// should not appear in the tree (e.g. whitespace-only paragraph)
|
|
52
|
+
if (op.discard)
|
|
53
|
+
break;
|
|
54
|
+
// apply deferred metadata
|
|
55
|
+
frame.end = op.end;
|
|
56
|
+
if (op.reference !== undefined)
|
|
57
|
+
frame.reference = op.reference;
|
|
58
|
+
if (op.link_type !== undefined)
|
|
59
|
+
frame.link_type = op.link_type;
|
|
60
|
+
if (op.heading_id !== undefined)
|
|
61
|
+
frame.heading_id = op.heading_id;
|
|
62
|
+
const node = build_node(frame);
|
|
63
|
+
if (node)
|
|
64
|
+
target().push(node);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'text': {
|
|
68
|
+
const node = op.text_type === 'Code'
|
|
69
|
+
? { type: 'Code', content: op.content, start: op.start, end: op.end }
|
|
70
|
+
: { type: 'Text', content: op.content, start: op.start, end: op.end };
|
|
71
|
+
text_nodes.set(op.id, node);
|
|
72
|
+
const dest = target();
|
|
73
|
+
dest.push(node);
|
|
74
|
+
node_parents.set(op.id, dest);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'append_text': {
|
|
78
|
+
if (DEV && !text_nodes.has(op.id)) {
|
|
79
|
+
throw new Error(`mdz_opcodes_to_nodes: append_text for unknown id ${op.id}`);
|
|
80
|
+
}
|
|
81
|
+
const existing = text_nodes.get(op.id);
|
|
82
|
+
if (existing) {
|
|
83
|
+
existing.content += op.content;
|
|
84
|
+
existing.end += op.content.length;
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'trim_text': {
|
|
89
|
+
if (DEV && !text_nodes.has(op.id)) {
|
|
90
|
+
throw new Error(`mdz_opcodes_to_nodes: trim_text for unknown id ${op.id}`);
|
|
91
|
+
}
|
|
92
|
+
const existing = text_nodes.get(op.id);
|
|
93
|
+
if (existing) {
|
|
94
|
+
existing.content = existing.content.slice(0, existing.content.length - op.count);
|
|
95
|
+
existing.end -= op.count;
|
|
96
|
+
if (existing.content.length === 0) {
|
|
97
|
+
const parent = node_parents.get(op.id);
|
|
98
|
+
if (parent) {
|
|
99
|
+
const idx = parent.indexOf(existing);
|
|
100
|
+
if (idx !== -1)
|
|
101
|
+
parent.splice(idx, 1);
|
|
102
|
+
}
|
|
103
|
+
text_nodes.delete(op.id);
|
|
104
|
+
node_parents.delete(op.id);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'void': {
|
|
110
|
+
target().push({ type: 'Hr', start: op.start, end: op.end });
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'revert': {
|
|
114
|
+
// find and remove the reverted node's frame from the stack.
|
|
115
|
+
// fast path: reverts from #revert_all_optimistic always target the
|
|
116
|
+
// top of stack, so check that first to avoid splice + array alloc.
|
|
117
|
+
let reverted_frame = null;
|
|
118
|
+
if (stack.length > 0 && stack[stack.length - 1].id === op.id) {
|
|
119
|
+
reverted_frame = stack.pop();
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
123
|
+
if (stack[i].id === op.id) {
|
|
124
|
+
reverted_frame = stack.splice(i, 1)[0];
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (DEV && !reverted_frame) {
|
|
130
|
+
throw new Error(`mdz_opcodes_to_nodes: revert for id ${op.id} but not found on stack`);
|
|
131
|
+
}
|
|
132
|
+
if (reverted_frame) {
|
|
133
|
+
if (op.wrap_node_type != null && op.wrap_id != null) {
|
|
134
|
+
// block-level revert: wrap content in a new container (e.g. Paragraph)
|
|
135
|
+
// and push it onto the stack so future opcodes flow into it.
|
|
136
|
+
const wrapper = {
|
|
137
|
+
id: op.wrap_id,
|
|
138
|
+
node_type: op.wrap_node_type,
|
|
139
|
+
children: [],
|
|
140
|
+
start: op.start,
|
|
141
|
+
};
|
|
142
|
+
if (op.replacement_text) {
|
|
143
|
+
mdz_push_merging_text(wrapper.children, {
|
|
144
|
+
type: 'Text',
|
|
145
|
+
content: op.replacement_text,
|
|
146
|
+
start: op.start,
|
|
147
|
+
end: op.start + op.replacement_text.length,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
for (const child of reverted_frame.children) {
|
|
151
|
+
mdz_push_merging_text(wrapper.children, child);
|
|
152
|
+
}
|
|
153
|
+
stack.push(wrapper);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
const dest = target();
|
|
157
|
+
// Re-parent replacement text and children, coalescing adjacent
|
|
158
|
+
// Text nodes inline. This reduces deeply nested reverts from
|
|
159
|
+
// O(n²) array pushes to O(n) string concatenations — each revert
|
|
160
|
+
// merges into the parent's last text node instead of growing the array.
|
|
161
|
+
if (op.replacement_text) {
|
|
162
|
+
mdz_push_merging_text(dest, {
|
|
163
|
+
type: 'Text',
|
|
164
|
+
content: op.replacement_text,
|
|
165
|
+
start: op.start,
|
|
166
|
+
end: op.start + op.replacement_text.length,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
for (const child of reverted_frame.children) {
|
|
170
|
+
mdz_push_merging_text(dest, child);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case 'wrap': {
|
|
177
|
+
const text_node = text_nodes.get(op.target_id);
|
|
178
|
+
const parent_children = node_parents.get(op.target_id);
|
|
179
|
+
if (!text_node || !parent_children)
|
|
180
|
+
break;
|
|
181
|
+
const idx = parent_children.indexOf(text_node);
|
|
182
|
+
if (idx === -1)
|
|
183
|
+
break;
|
|
184
|
+
// handle trailing punctuation trim
|
|
185
|
+
let trimmed_node = null;
|
|
186
|
+
if (op.trim_end && op.trim_end > 0 && op.trim_id != null) {
|
|
187
|
+
const trimmed_content = text_node.content.slice(text_node.content.length - op.trim_end);
|
|
188
|
+
text_node.content = text_node.content.slice(0, text_node.content.length - op.trim_end);
|
|
189
|
+
text_node.end -= op.trim_end;
|
|
190
|
+
trimmed_node = {
|
|
191
|
+
type: 'Text',
|
|
192
|
+
content: trimmed_content,
|
|
193
|
+
start: text_node.end,
|
|
194
|
+
end: text_node.end + trimmed_content.length,
|
|
195
|
+
};
|
|
196
|
+
text_nodes.set(op.trim_id, trimmed_node);
|
|
197
|
+
node_parents.set(op.trim_id, parent_children);
|
|
198
|
+
}
|
|
199
|
+
// create Link wrapping the text node
|
|
200
|
+
const link = {
|
|
201
|
+
type: 'Link',
|
|
202
|
+
reference: op.reference,
|
|
203
|
+
children: [text_node],
|
|
204
|
+
link_type: op.link_type,
|
|
205
|
+
start: op.start,
|
|
206
|
+
end: op.end,
|
|
207
|
+
};
|
|
208
|
+
// replace text node with [Link, trimmed?] in parent
|
|
209
|
+
if (trimmed_node) {
|
|
210
|
+
parent_children.splice(idx, 1, link, trimmed_node);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
parent_children[idx] = link;
|
|
214
|
+
}
|
|
215
|
+
node_parents.delete(op.target_id);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return root;
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Build an `MdzNode` from a completed stack frame.
|
|
224
|
+
*/
|
|
225
|
+
const build_node = (frame) => {
|
|
226
|
+
switch (frame.node_type) {
|
|
227
|
+
case 'Paragraph': {
|
|
228
|
+
const children = mdz_merge_adjacent_text(frame.children);
|
|
229
|
+
if (children.length === 0)
|
|
230
|
+
return null;
|
|
231
|
+
// extract single tag (MDX convention)
|
|
232
|
+
const single_tag = extract_single_tag(children);
|
|
233
|
+
if (single_tag)
|
|
234
|
+
return single_tag;
|
|
235
|
+
return {
|
|
236
|
+
type: 'Paragraph',
|
|
237
|
+
children,
|
|
238
|
+
start: children[0].start,
|
|
239
|
+
end: children[children.length - 1].end,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
case 'Heading': {
|
|
243
|
+
const children = mdz_merge_adjacent_text(frame.children);
|
|
244
|
+
const id = frame.heading_id ?? mdz_heading_id(children);
|
|
245
|
+
return {
|
|
246
|
+
type: 'Heading',
|
|
247
|
+
level: frame.level ?? 1,
|
|
248
|
+
id,
|
|
249
|
+
children,
|
|
250
|
+
start: frame.start,
|
|
251
|
+
end: frame.end,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
case 'Bold':
|
|
255
|
+
return {
|
|
256
|
+
type: 'Bold',
|
|
257
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
258
|
+
start: frame.start,
|
|
259
|
+
end: frame.end,
|
|
260
|
+
};
|
|
261
|
+
case 'Italic':
|
|
262
|
+
return {
|
|
263
|
+
type: 'Italic',
|
|
264
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
265
|
+
start: frame.start,
|
|
266
|
+
end: frame.end,
|
|
267
|
+
};
|
|
268
|
+
case 'Strikethrough':
|
|
269
|
+
return {
|
|
270
|
+
type: 'Strikethrough',
|
|
271
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
272
|
+
start: frame.start,
|
|
273
|
+
end: frame.end,
|
|
274
|
+
};
|
|
275
|
+
case 'Link':
|
|
276
|
+
return {
|
|
277
|
+
type: 'Link',
|
|
278
|
+
reference: frame.reference ?? '',
|
|
279
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
280
|
+
link_type: frame.link_type ?? 'internal',
|
|
281
|
+
start: frame.start,
|
|
282
|
+
end: frame.end,
|
|
283
|
+
};
|
|
284
|
+
case 'Code': {
|
|
285
|
+
// optimistic inline code container — concatenate children text into leaf MdzCodeNode
|
|
286
|
+
let content = '';
|
|
287
|
+
for (const c of frame.children) {
|
|
288
|
+
if (c.type === 'Text')
|
|
289
|
+
content += c.content;
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
type: 'Code',
|
|
293
|
+
content,
|
|
294
|
+
start: frame.start,
|
|
295
|
+
end: frame.end,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
case 'Codeblock': {
|
|
299
|
+
// code block content is in children as text
|
|
300
|
+
let content = '';
|
|
301
|
+
for (const c of frame.children) {
|
|
302
|
+
if (c.type === 'Text')
|
|
303
|
+
content += c.content;
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
type: 'Codeblock',
|
|
307
|
+
lang: frame.lang ?? null,
|
|
308
|
+
content,
|
|
309
|
+
start: frame.start,
|
|
310
|
+
end: frame.end,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
case 'Element':
|
|
314
|
+
return {
|
|
315
|
+
type: 'Element',
|
|
316
|
+
name: frame.name ?? '',
|
|
317
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
318
|
+
start: frame.start,
|
|
319
|
+
end: frame.end,
|
|
320
|
+
};
|
|
321
|
+
case 'Component':
|
|
322
|
+
return {
|
|
323
|
+
type: 'Component',
|
|
324
|
+
name: frame.name ?? '',
|
|
325
|
+
children: mdz_merge_adjacent_text(frame.children),
|
|
326
|
+
start: frame.start,
|
|
327
|
+
end: frame.end,
|
|
328
|
+
};
|
|
329
|
+
default:
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming opcode parser for mdz.
|
|
3
|
+
*
|
|
4
|
+
* Fed chunks of text (e.g., from LLM output), emits opcodes as rendering
|
|
5
|
+
* instructions. Makes optimistic assumptions about ambiguous syntax and
|
|
6
|
+
* emits `revert` opcodes to correct when wrong. Never re-parses.
|
|
7
|
+
*
|
|
8
|
+
* The design was independently arrived at but shares goals with
|
|
9
|
+
* {@link https://bsky.app/profile/pngwn.at/post/3mi527zntb22n @pngwn.at}'s
|
|
10
|
+
* Penguin-Flavoured Markdown (PFM): restrict the syntax so streaming is tractable,
|
|
11
|
+
* render optimistically and correct when wrong, emit serializable opcodes
|
|
12
|
+
* to avoid re-parsing, and keep the opcodes target-agnostic so any renderer
|
|
13
|
+
* can consume them. mdz diverges in one respect: the Svelte consumer
|
|
14
|
+
* (`MdzStreamState`) does build a reactive tree from opcodes — the platform
|
|
15
|
+
* dictates this — but mutations are fine-grained via `$state`, not diffed.
|
|
16
|
+
*
|
|
17
|
+
* The parser is split across sibling modules: this file holds the public
|
|
18
|
+
* `MdzStreamParser` class and the `process_loop` / `process_inline`
|
|
19
|
+
* orchestrators. Per-category handlers (block / inline / link / url / text)
|
|
20
|
+
* live in `mdz_stream_parser_*.ts` as free functions taking the shared
|
|
21
|
+
* `MdzStreamParserState` as first argument.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ```ts
|
|
25
|
+
* const parser = new MdzStreamParser();
|
|
26
|
+
* parser.feed('hello **bold');
|
|
27
|
+
* const ops1 = parser.take_opcodes(); // open Paragraph, text "hello ", open Bold, text "bold"
|
|
28
|
+
* parser.feed('** world');
|
|
29
|
+
* const ops2 = parser.take_opcodes(); // close Bold, text " world"
|
|
30
|
+
* parser.finish();
|
|
31
|
+
* const ops3 = parser.take_opcodes(); // close Paragraph
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @module
|
|
35
|
+
*/
|
|
36
|
+
import type { MdzOpcode } from './mdz_opcodes.js';
|
|
37
|
+
/**
|
|
38
|
+
* Streaming opcode parser for mdz content.
|
|
39
|
+
* Feed chunks via `feed()`, retrieve opcodes via `take_opcodes()`, call `finish()` at end.
|
|
40
|
+
*
|
|
41
|
+
* The opcode sequence is not deterministic across chunk boundaries — the same input
|
|
42
|
+
* fed in different chunk sizes may produce different `text`/`append_text` splits and
|
|
43
|
+
* different optimistic/revert sequences. The final tree (via `mdz_opcodes_to_nodes`)
|
|
44
|
+
* matches the one-shot result for all input except one case: italic (`_..._`) where
|
|
45
|
+
* the opening and closing delimiters straddle a chunk boundary. Italic is
|
|
46
|
+
* non-optimistic — it requires a confirmed closer in the buffer — so when the
|
|
47
|
+
* closer arrives only in a later chunk, the opening `_` has already been emitted
|
|
48
|
+
* as text and italic cannot apply retroactively. See `try_italic` in
|
|
49
|
+
* `mdz_stream_parser_inline.ts`.
|
|
50
|
+
*/
|
|
51
|
+
export declare class MdzStreamParser {
|
|
52
|
+
#private;
|
|
53
|
+
/**
|
|
54
|
+
* Feed a chunk of text to the parser.
|
|
55
|
+
* Opcodes are accumulated and retrieved via `take_opcodes()`.
|
|
56
|
+
*/
|
|
57
|
+
feed(chunk: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Signal end of input. Resolves all pending state: closes open blocks,
|
|
60
|
+
* reverts unclosed optimistic opens, trims trailing newlines.
|
|
61
|
+
*
|
|
62
|
+
* Trailing-newline trimming is handled in one place: `trim_trailing_newline()`
|
|
63
|
+
* called at the top of `close_paragraph()` and `close_codeblock_at_eof()`,
|
|
64
|
+
* before either function reverts its inner stack. The trim sees the
|
|
65
|
+
* just-flushed text node's `last_text_id` (or a still-accumulated `\n`) and
|
|
66
|
+
* emits a `trim_text` opcode. Revert opcodes only fire after.
|
|
67
|
+
*
|
|
68
|
+
* Optimistic-container revert is handled by `close_paragraph` and
|
|
69
|
+
* `close_heading` (each pops its own inner stack), so no separate
|
|
70
|
+
* `revert_all_optimistic` is needed — optimistic containers can only exist
|
|
71
|
+
* inside an open Paragraph or Heading (parser invariant).
|
|
72
|
+
*/
|
|
73
|
+
finish(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Drain and return all accumulated opcodes.
|
|
76
|
+
* Destructive — empties the internal queue. The returned array is owned by the caller.
|
|
77
|
+
*/
|
|
78
|
+
take_opcodes(): Array<MdzOpcode>;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=mdz_stream_parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mdz_stream_parser.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAC;AAgEhD;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;;IAG3B;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAczB;;;;;;;;;;;;;;OAcG;IACH,MAAM,IAAI,IAAI;IA0Bd;;;OAGG;IACH,YAAY,IAAI,KAAK,CAAC,SAAS,CAAC;CAKhC"}
|