@fuzdev/fuz_ui 0.198.1 → 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.
Files changed (101) hide show
  1. package/dist/ApiIndex.svelte +2 -2
  2. package/dist/ApiModule.svelte +1 -1
  3. package/dist/LibraryDetail.svelte +14 -16
  4. package/dist/LibraryDetail.svelte.d.ts.map +1 -1
  5. package/dist/LibrarySummary.svelte +12 -12
  6. package/dist/Mdz.svelte +2 -2
  7. package/dist/MdzNodeView.svelte +8 -6
  8. package/dist/MdzNodeView.svelte.d.ts.map +1 -1
  9. package/dist/MdzRoot.svelte +30 -0
  10. package/dist/MdzRoot.svelte.d.ts +12 -0
  11. package/dist/MdzRoot.svelte.d.ts.map +1 -0
  12. package/dist/MdzStream.svelte +32 -0
  13. package/dist/MdzStream.svelte.d.ts +12 -0
  14. package/dist/MdzStream.svelte.d.ts.map +1 -0
  15. package/dist/MdzStreamNodeView.svelte +106 -0
  16. package/dist/MdzStreamNodeView.svelte.d.ts +9 -0
  17. package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -0
  18. package/dist/declaration.svelte.js +2 -2
  19. package/dist/library.svelte.d.ts +9 -70
  20. package/dist/library.svelte.d.ts.map +1 -1
  21. package/dist/library.svelte.js +24 -18
  22. package/dist/library_helpers.d.ts +3 -3
  23. package/dist/library_helpers.js +3 -3
  24. package/dist/mdz.d.ts.map +1 -1
  25. package/dist/mdz.js +37 -29
  26. package/dist/mdz_components.d.ts +37 -23
  27. package/dist/mdz_components.d.ts.map +1 -1
  28. package/dist/mdz_components.js +16 -4
  29. package/dist/mdz_helpers.d.ts +46 -14
  30. package/dist/mdz_helpers.d.ts.map +1 -1
  31. package/dist/mdz_helpers.js +189 -56
  32. package/dist/mdz_lexer.d.ts.map +1 -1
  33. package/dist/mdz_lexer.js +18 -22
  34. package/dist/mdz_opcodes.d.ts +174 -0
  35. package/dist/mdz_opcodes.d.ts.map +1 -0
  36. package/dist/mdz_opcodes.js +14 -0
  37. package/dist/mdz_opcodes_to_nodes.d.ts +20 -0
  38. package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -0
  39. package/dist/mdz_opcodes_to_nodes.js +332 -0
  40. package/dist/mdz_stream_parser.d.ts +80 -0
  41. package/dist/mdz_stream_parser.d.ts.map +1 -0
  42. package/dist/mdz_stream_parser.js +354 -0
  43. package/dist/mdz_stream_parser_block.d.ts +76 -0
  44. package/dist/mdz_stream_parser_block.d.ts.map +1 -0
  45. package/dist/mdz_stream_parser_block.js +458 -0
  46. package/dist/mdz_stream_parser_inline.d.ts +52 -0
  47. package/dist/mdz_stream_parser_inline.d.ts.map +1 -0
  48. package/dist/mdz_stream_parser_inline.js +378 -0
  49. package/dist/mdz_stream_parser_link.d.ts +22 -0
  50. package/dist/mdz_stream_parser_link.d.ts.map +1 -0
  51. package/dist/mdz_stream_parser_link.js +215 -0
  52. package/dist/mdz_stream_parser_state.d.ts +187 -0
  53. package/dist/mdz_stream_parser_state.d.ts.map +1 -0
  54. package/dist/mdz_stream_parser_state.js +398 -0
  55. package/dist/mdz_stream_parser_text.d.ts +14 -0
  56. package/dist/mdz_stream_parser_text.d.ts.map +1 -0
  57. package/dist/mdz_stream_parser_text.js +50 -0
  58. package/dist/mdz_stream_parser_url.d.ts +60 -0
  59. package/dist/mdz_stream_parser_url.d.ts.map +1 -0
  60. package/dist/mdz_stream_parser_url.js +307 -0
  61. package/dist/mdz_stream_state.svelte.d.ts +44 -0
  62. package/dist/mdz_stream_state.svelte.d.ts.map +1 -0
  63. package/dist/mdz_stream_state.svelte.js +357 -0
  64. package/dist/mdz_token_parser.d.ts.map +1 -1
  65. package/dist/mdz_token_parser.js +8 -39
  66. package/dist/module.svelte.js +1 -1
  67. package/dist/site.svelte.d.ts +13 -0
  68. package/dist/site.svelte.d.ts.map +1 -1
  69. package/dist/site.svelte.js +8 -2
  70. package/dist/tsdoc_mdz.d.ts +2 -2
  71. package/dist/tsdoc_mdz.js +2 -2
  72. package/dist/vite_plugin_pkg_json.d.ts +63 -0
  73. package/dist/vite_plugin_pkg_json.d.ts.map +1 -0
  74. package/dist/vite_plugin_pkg_json.js +126 -0
  75. package/package.json +6 -5
  76. package/src/lib/declaration.svelte.ts +2 -2
  77. package/src/lib/library.svelte.ts +37 -20
  78. package/src/lib/library_helpers.ts +3 -3
  79. package/src/lib/mdz.ts +38 -29
  80. package/src/lib/mdz_components.ts +40 -19
  81. package/src/lib/mdz_helpers.ts +199 -56
  82. package/src/lib/mdz_lexer.ts +18 -20
  83. package/src/lib/mdz_opcodes.ts +205 -0
  84. package/src/lib/mdz_opcodes_to_nodes.ts +375 -0
  85. package/src/lib/mdz_stream_parser.ts +415 -0
  86. package/src/lib/mdz_stream_parser_block.ts +532 -0
  87. package/src/lib/mdz_stream_parser_inline.ts +414 -0
  88. package/src/lib/mdz_stream_parser_link.ts +271 -0
  89. package/src/lib/mdz_stream_parser_state.ts +539 -0
  90. package/src/lib/mdz_stream_parser_text.ts +77 -0
  91. package/src/lib/mdz_stream_parser_url.ts +365 -0
  92. package/src/lib/mdz_stream_state.svelte.ts +387 -0
  93. package/src/lib/mdz_token_parser.ts +13 -40
  94. package/src/lib/module.svelte.ts +1 -1
  95. package/src/lib/site.svelte.ts +17 -2
  96. package/src/lib/tsdoc_mdz.ts +2 -2
  97. package/src/lib/vite_plugin_pkg_json.ts +142 -0
  98. package/dist/package_helpers.d.ts +0 -150
  99. package/dist/package_helpers.d.ts.map +0 -1
  100. package/dist/package_helpers.js +0 -179
  101. package/src/lib/package_helpers.ts +0 -186
@@ -0,0 +1,375 @@
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
+
14
+ import {DEV} from 'esm-env';
15
+
16
+ import type {MdzNode, MdzTextNode, MdzLinkNode, MdzHeadingNode, MdzCodeNode} from './mdz.js';
17
+ import type {MdzOpcode, MdzNodeId} from './mdz_opcodes.js';
18
+ import {
19
+ extract_single_tag,
20
+ mdz_heading_id,
21
+ mdz_merge_adjacent_text,
22
+ mdz_push_merging_text,
23
+ } from './mdz_helpers.js';
24
+
25
+ interface StackFrame {
26
+ id: MdzNodeId;
27
+ node_type: string;
28
+ children: Array<MdzNode>;
29
+ start: number;
30
+ // metadata from open opcode
31
+ level?: number;
32
+ name?: string;
33
+ lang?: string | null;
34
+ // metadata from close opcode (deferred)
35
+ end?: number;
36
+ reference?: string;
37
+ link_type?: 'external' | 'internal';
38
+ heading_id?: string;
39
+ }
40
+
41
+ /**
42
+ * Convert an array of mdz opcodes to the `MdzNode[]` tree.
43
+ * Produces output identical to `mdz_parse()`.
44
+ */
45
+ export const mdz_opcodes_to_nodes = (opcodes: Array<MdzOpcode>): Array<MdzNode> => {
46
+ const root: Array<MdzNode> = [];
47
+ const stack: Array<StackFrame> = [];
48
+ // index node IDs to their text content (for append_text and wrap)
49
+ const text_nodes = new Map<MdzNodeId, MdzTextNode | MdzCodeNode>();
50
+ // track which children array contains each text node (for wrap)
51
+ const node_parents = new Map<number, Array<MdzNode>>();
52
+
53
+ const target = (): Array<MdzNode> => {
54
+ return stack.length > 0 ? stack[stack.length - 1]!.children : root;
55
+ };
56
+
57
+ for (const op of opcodes) {
58
+ switch (op.type) {
59
+ case 'open': {
60
+ stack.push({
61
+ id: op.id,
62
+ node_type: op.node_type,
63
+ children: [],
64
+ start: op.start,
65
+ level: op.level,
66
+ name: op.name,
67
+ lang: op.lang,
68
+ });
69
+ break;
70
+ }
71
+
72
+ case 'close': {
73
+ if (DEV && stack.length === 0) {
74
+ throw new Error(`mdz_opcodes_to_nodes: close for id ${op.id} but stack is empty`);
75
+ }
76
+ const frame = stack.pop();
77
+ if (!frame) break;
78
+
79
+ // discard signal: the parser determined this node and its descendants
80
+ // should not appear in the tree (e.g. whitespace-only paragraph)
81
+ if (op.discard) break;
82
+
83
+ // apply deferred metadata
84
+ frame.end = op.end;
85
+ if (op.reference !== undefined) frame.reference = op.reference;
86
+ if (op.link_type !== undefined) frame.link_type = op.link_type;
87
+ if (op.heading_id !== undefined) frame.heading_id = op.heading_id;
88
+
89
+ const node = build_node(frame);
90
+ if (node) target().push(node);
91
+ break;
92
+ }
93
+
94
+ case 'text': {
95
+ const node: MdzTextNode | MdzCodeNode =
96
+ op.text_type === 'Code'
97
+ ? {type: 'Code', content: op.content, start: op.start, end: op.end}
98
+ : {type: 'Text', content: op.content, start: op.start, end: op.end};
99
+ text_nodes.set(op.id, node);
100
+ const dest = target();
101
+ dest.push(node);
102
+ node_parents.set(op.id, dest);
103
+ break;
104
+ }
105
+
106
+ case 'append_text': {
107
+ if (DEV && !text_nodes.has(op.id)) {
108
+ throw new Error(`mdz_opcodes_to_nodes: append_text for unknown id ${op.id}`);
109
+ }
110
+ const existing = text_nodes.get(op.id);
111
+ if (existing) {
112
+ existing.content += op.content;
113
+ existing.end += op.content.length;
114
+ }
115
+ break;
116
+ }
117
+
118
+ case 'trim_text': {
119
+ if (DEV && !text_nodes.has(op.id)) {
120
+ throw new Error(`mdz_opcodes_to_nodes: trim_text for unknown id ${op.id}`);
121
+ }
122
+ const existing = text_nodes.get(op.id);
123
+ if (existing) {
124
+ existing.content = existing.content.slice(0, existing.content.length - op.count);
125
+ existing.end -= op.count;
126
+ if (existing.content.length === 0) {
127
+ const parent = node_parents.get(op.id);
128
+ if (parent) {
129
+ const idx = parent.indexOf(existing);
130
+ if (idx !== -1) parent.splice(idx, 1);
131
+ }
132
+ text_nodes.delete(op.id);
133
+ node_parents.delete(op.id);
134
+ }
135
+ }
136
+ break;
137
+ }
138
+
139
+ case 'void': {
140
+ target().push({type: 'Hr', start: op.start, end: op.end});
141
+ break;
142
+ }
143
+
144
+ case 'revert': {
145
+ // find and remove the reverted node's frame from the stack.
146
+ // fast path: reverts from #revert_all_optimistic always target the
147
+ // top of stack, so check that first to avoid splice + array alloc.
148
+ let reverted_frame: StackFrame | null = null;
149
+ if (stack.length > 0 && stack[stack.length - 1]!.id === op.id) {
150
+ reverted_frame = stack.pop()!;
151
+ } else {
152
+ for (let i = stack.length - 1; i >= 0; i--) {
153
+ if (stack[i]!.id === op.id) {
154
+ reverted_frame = stack.splice(i, 1)[0]!;
155
+ break;
156
+ }
157
+ }
158
+ }
159
+
160
+ if (DEV && !reverted_frame) {
161
+ throw new Error(`mdz_opcodes_to_nodes: revert for id ${op.id} but not found on stack`);
162
+ }
163
+ if (reverted_frame) {
164
+ if (op.wrap_node_type != null && op.wrap_id != null) {
165
+ // block-level revert: wrap content in a new container (e.g. Paragraph)
166
+ // and push it onto the stack so future opcodes flow into it.
167
+ const wrapper: StackFrame = {
168
+ id: op.wrap_id,
169
+ node_type: op.wrap_node_type,
170
+ children: [],
171
+ start: op.start,
172
+ };
173
+ if (op.replacement_text) {
174
+ mdz_push_merging_text(wrapper.children, {
175
+ type: 'Text',
176
+ content: op.replacement_text,
177
+ start: op.start,
178
+ end: op.start + op.replacement_text.length,
179
+ });
180
+ }
181
+ for (const child of reverted_frame.children) {
182
+ mdz_push_merging_text(wrapper.children, child);
183
+ }
184
+ stack.push(wrapper);
185
+ } else {
186
+ const dest = target();
187
+ // Re-parent replacement text and children, coalescing adjacent
188
+ // Text nodes inline. This reduces deeply nested reverts from
189
+ // O(n²) array pushes to O(n) string concatenations — each revert
190
+ // merges into the parent's last text node instead of growing the array.
191
+ if (op.replacement_text) {
192
+ mdz_push_merging_text(dest, {
193
+ type: 'Text',
194
+ content: op.replacement_text,
195
+ start: op.start,
196
+ end: op.start + op.replacement_text.length,
197
+ });
198
+ }
199
+ for (const child of reverted_frame.children) {
200
+ mdz_push_merging_text(dest, child);
201
+ }
202
+ }
203
+ }
204
+ break;
205
+ }
206
+
207
+ case 'wrap': {
208
+ const text_node = text_nodes.get(op.target_id);
209
+ const parent_children = node_parents.get(op.target_id);
210
+ if (!text_node || !parent_children) break;
211
+
212
+ const idx = parent_children.indexOf(text_node);
213
+ if (idx === -1) break;
214
+
215
+ // handle trailing punctuation trim
216
+ let trimmed_node: MdzTextNode | null = null;
217
+ if (op.trim_end && op.trim_end > 0 && op.trim_id != null) {
218
+ const trimmed_content = text_node.content.slice(text_node.content.length - op.trim_end);
219
+ text_node.content = text_node.content.slice(0, text_node.content.length - op.trim_end);
220
+ text_node.end -= op.trim_end;
221
+ trimmed_node = {
222
+ type: 'Text',
223
+ content: trimmed_content,
224
+ start: text_node.end,
225
+ end: text_node.end + trimmed_content.length,
226
+ };
227
+ text_nodes.set(op.trim_id, trimmed_node);
228
+ node_parents.set(op.trim_id, parent_children);
229
+ }
230
+
231
+ // create Link wrapping the text node
232
+ const link: MdzLinkNode = {
233
+ type: 'Link',
234
+ reference: op.reference,
235
+ children: [text_node],
236
+ link_type: op.link_type,
237
+ start: op.start,
238
+ end: op.end,
239
+ };
240
+
241
+ // replace text node with [Link, trimmed?] in parent
242
+ if (trimmed_node) {
243
+ parent_children.splice(idx, 1, link as MdzNode, trimmed_node as MdzNode);
244
+ } else {
245
+ parent_children[idx] = link;
246
+ }
247
+
248
+ node_parents.delete(op.target_id);
249
+ break;
250
+ }
251
+ }
252
+ }
253
+
254
+ return root;
255
+ };
256
+
257
+ /**
258
+ * Build an `MdzNode` from a completed stack frame.
259
+ */
260
+ const build_node = (frame: StackFrame): MdzNode | null => {
261
+ switch (frame.node_type) {
262
+ case 'Paragraph': {
263
+ const children = mdz_merge_adjacent_text(frame.children);
264
+ if (children.length === 0) return null;
265
+
266
+ // extract single tag (MDX convention)
267
+ const single_tag = extract_single_tag(children);
268
+ if (single_tag) return single_tag;
269
+
270
+ return {
271
+ type: 'Paragraph',
272
+ children,
273
+ start: children[0]!.start,
274
+ end: children[children.length - 1]!.end,
275
+ };
276
+ }
277
+
278
+ case 'Heading': {
279
+ const children = mdz_merge_adjacent_text(frame.children);
280
+ const id = frame.heading_id ?? mdz_heading_id(children);
281
+ return {
282
+ type: 'Heading',
283
+ level: frame.level ?? 1,
284
+ id,
285
+ children,
286
+ start: frame.start,
287
+ end: frame.end!,
288
+ } as MdzHeadingNode;
289
+ }
290
+
291
+ case 'Bold':
292
+ return {
293
+ type: 'Bold',
294
+ children: mdz_merge_adjacent_text(frame.children),
295
+ start: frame.start,
296
+ end: frame.end!,
297
+ };
298
+
299
+ case 'Italic':
300
+ return {
301
+ type: 'Italic',
302
+ children: mdz_merge_adjacent_text(frame.children),
303
+ start: frame.start,
304
+ end: frame.end!,
305
+ };
306
+
307
+ case 'Strikethrough':
308
+ return {
309
+ type: 'Strikethrough',
310
+ children: mdz_merge_adjacent_text(frame.children),
311
+ start: frame.start,
312
+ end: frame.end!,
313
+ };
314
+
315
+ case 'Link':
316
+ return {
317
+ type: 'Link',
318
+ reference: frame.reference ?? '',
319
+ children: mdz_merge_adjacent_text(frame.children),
320
+ link_type: frame.link_type ?? 'internal',
321
+ start: frame.start,
322
+ end: frame.end!,
323
+ };
324
+
325
+ case 'Code': {
326
+ // optimistic inline code container — concatenate children text into leaf MdzCodeNode
327
+ let content = '';
328
+ for (const c of frame.children) {
329
+ if (c.type === 'Text') content += c.content;
330
+ }
331
+ return {
332
+ type: 'Code',
333
+ content,
334
+ start: frame.start,
335
+ end: frame.end!,
336
+ };
337
+ }
338
+
339
+ case 'Codeblock': {
340
+ // code block content is in children as text
341
+ let content = '';
342
+ for (const c of frame.children) {
343
+ if (c.type === 'Text') content += c.content;
344
+ }
345
+ return {
346
+ type: 'Codeblock',
347
+ lang: frame.lang ?? null,
348
+ content,
349
+ start: frame.start,
350
+ end: frame.end!,
351
+ };
352
+ }
353
+
354
+ case 'Element':
355
+ return {
356
+ type: 'Element',
357
+ name: frame.name ?? '',
358
+ children: mdz_merge_adjacent_text(frame.children),
359
+ start: frame.start,
360
+ end: frame.end!,
361
+ };
362
+
363
+ case 'Component':
364
+ return {
365
+ type: 'Component',
366
+ name: frame.name ?? '',
367
+ children: mdz_merge_adjacent_text(frame.children),
368
+ start: frame.start,
369
+ end: frame.end!,
370
+ };
371
+
372
+ default:
373
+ return null;
374
+ }
375
+ };