@fuzdev/mdz 0.1.0 → 0.3.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 (77) hide show
  1. package/README.md +4 -0
  2. package/dist/Mdz.svelte +15 -7
  3. package/dist/Mdz.svelte.d.ts +9 -2
  4. package/dist/Mdz.svelte.d.ts.map +1 -1
  5. package/dist/MdzNodeView.svelte +130 -95
  6. package/dist/MdzNodeView.svelte.d.ts +6 -2
  7. package/dist/MdzNodeView.svelte.d.ts.map +1 -1
  8. package/dist/MdzStream.svelte +3 -3
  9. package/dist/MdzStream.svelte.d.ts.map +1 -1
  10. package/dist/MdzStreamNodeView.svelte +129 -95
  11. package/dist/MdzStreamNodeView.svelte.d.ts +6 -2
  12. package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -1
  13. package/dist/context_helpers.d.ts +1 -1
  14. package/dist/mdz.d.ts +59 -2
  15. package/dist/mdz.d.ts.map +1 -1
  16. package/dist/mdz.js +37 -1
  17. package/dist/mdz_debug_work.d.ts +38 -0
  18. package/dist/mdz_debug_work.d.ts.map +1 -0
  19. package/dist/mdz_debug_work.js +37 -0
  20. package/dist/mdz_helpers.d.ts +96 -1
  21. package/dist/mdz_helpers.d.ts.map +1 -1
  22. package/dist/mdz_helpers.js +192 -0
  23. package/dist/mdz_lexer.d.ts +47 -1
  24. package/dist/mdz_lexer.d.ts.map +1 -1
  25. package/dist/mdz_lexer.js +364 -15
  26. package/dist/mdz_opcodes.d.ts +6 -1
  27. package/dist/mdz_opcodes.d.ts.map +1 -1
  28. package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -1
  29. package/dist/mdz_opcodes_to_nodes.js +26 -0
  30. package/dist/mdz_stream_parser.d.ts.map +1 -1
  31. package/dist/mdz_stream_parser.js +20 -1
  32. package/dist/mdz_stream_parser_inline.d.ts.map +1 -1
  33. package/dist/mdz_stream_parser_inline.js +19 -17
  34. package/dist/mdz_stream_parser_link.d.ts.map +1 -1
  35. package/dist/mdz_stream_parser_link.js +88 -56
  36. package/dist/mdz_stream_parser_list.d.ts.map +1 -1
  37. package/dist/mdz_stream_parser_list.js +32 -3
  38. package/dist/mdz_stream_parser_state.d.ts +41 -0
  39. package/dist/mdz_stream_parser_state.d.ts.map +1 -1
  40. package/dist/mdz_stream_parser_state.js +53 -3
  41. package/dist/mdz_stream_parser_table.d.ts +73 -0
  42. package/dist/mdz_stream_parser_table.d.ts.map +1 -0
  43. package/dist/mdz_stream_parser_table.js +362 -0
  44. package/dist/mdz_stream_parser_text.d.ts.map +1 -1
  45. package/dist/mdz_stream_parser_text.js +35 -24
  46. package/dist/mdz_stream_state.svelte.d.ts +5 -0
  47. package/dist/mdz_stream_state.svelte.d.ts.map +1 -1
  48. package/dist/mdz_stream_state.svelte.js +8 -0
  49. package/dist/mdz_to_svelte.d.ts.map +1 -1
  50. package/dist/mdz_to_svelte.js +51 -20
  51. package/dist/mdz_token_parser.d.ts +16 -0
  52. package/dist/mdz_token_parser.d.ts.map +1 -1
  53. package/dist/mdz_token_parser.js +112 -14
  54. package/dist/svelte_preprocess_mdz.js +33 -39
  55. package/package.json +11 -8
  56. package/src/lib/context_helpers.ts +1 -1
  57. package/src/lib/mdz.ts +79 -3
  58. package/src/lib/mdz_contexts.ts +1 -1
  59. package/src/lib/mdz_debug_work.ts +38 -0
  60. package/src/lib/mdz_helpers.ts +222 -1
  61. package/src/lib/mdz_lexer.ts +420 -21
  62. package/src/lib/mdz_opcodes.ts +10 -1
  63. package/src/lib/mdz_opcodes_to_nodes.ts +37 -3
  64. package/src/lib/mdz_stream_parser.ts +26 -9
  65. package/src/lib/mdz_stream_parser_block.ts +2 -2
  66. package/src/lib/mdz_stream_parser_inline.ts +25 -21
  67. package/src/lib/mdz_stream_parser_link.ts +92 -59
  68. package/src/lib/mdz_stream_parser_list.ts +34 -6
  69. package/src/lib/mdz_stream_parser_state.ts +87 -5
  70. package/src/lib/mdz_stream_parser_table.ts +420 -0
  71. package/src/lib/mdz_stream_parser_text.ts +40 -39
  72. package/src/lib/mdz_stream_parser_url.ts +2 -2
  73. package/src/lib/mdz_stream_state.svelte.ts +8 -1
  74. package/src/lib/mdz_to_svelte.ts +49 -23
  75. package/src/lib/mdz_token_parser.ts +135 -21
  76. package/src/lib/svelte_preprocess_mdz.ts +37 -38
  77. package/src/lib/tsdoc_mdz.ts +1 -1
@@ -24,7 +24,7 @@ import {
24
24
  is_word_char,
25
25
  match_url_prefix_case_insensitive,
26
26
  mdz_trim_url_punctuation,
27
- } from './mdz_helpers.js';
27
+ } from './mdz_helpers.ts';
28
28
  import {
29
29
  type MdzStreamParserState,
30
30
  type TryResult,
@@ -34,7 +34,7 @@ import {
34
34
  ensure_paragraph,
35
35
  flush_text,
36
36
  offset,
37
- } from './mdz_stream_parser_state.js';
37
+ } from './mdz_stream_parser_state.ts';
38
38
 
39
39
  const HTTPS_PREFIX = 'https://';
40
40
  const HTTP_PREFIX = 'http://';
@@ -10,7 +10,8 @@
10
10
 
11
11
  import {DEV} from 'esm-env';
12
12
 
13
- import type {MdzNodeId, MdzNodeType, MdzOpcode} from './mdz_opcodes.js';
13
+ import type {MdzNodeId, MdzNodeType, MdzOpcode} from './mdz_opcodes.ts';
14
+ import type {MdzTableAlign} from './mdz.ts';
14
15
 
15
16
  /**
16
17
  * A reactive node in the stream renderer tree.
@@ -31,6 +32,10 @@ export class MdzStreamNode {
31
32
  ordered?: boolean;
32
33
  start_number?: number;
33
34
  number?: number;
35
+ /** Per-column alignment (Table nodes). */
36
+ align?: Array<MdzTableAlign>;
37
+ /** Whether this is the header row (TableRow nodes). */
38
+ header?: boolean;
34
39
 
35
40
  constructor(id: MdzNodeId, type: MdzNodeType) {
36
41
  this.id = id;
@@ -104,6 +109,8 @@ export class MdzStreamState {
104
109
  if (opcode.ordered !== undefined) node.ordered = opcode.ordered;
105
110
  if (opcode.start_number !== undefined) node.start_number = opcode.start_number;
106
111
  if (opcode.number !== undefined) node.number = opcode.number;
112
+ if (opcode.align !== undefined) node.align = opcode.align;
113
+ if (opcode.header !== undefined) node.header = opcode.header;
107
114
  this.#attach(node);
108
115
  this.#stack.push(opcode.id);
109
116
  break;
@@ -8,12 +8,12 @@
8
8
  * @module
9
9
  */
10
10
 
11
- import {UnreachableError} from '@fuzdev/fuz_util/error.js';
12
- import {escape_svelte_text} from '@fuzdev/fuz_util/svelte_preprocess_helpers.js';
13
- import {escape_js_string} from '@fuzdev/fuz_util/string.js';
11
+ import {UnreachableError} from '@fuzdev/fuz_util/error.ts';
12
+ import {escape_svelte_text} from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
13
+ import {escape_js_string} from '@fuzdev/fuz_util/string.ts';
14
14
 
15
- import type {MdzNode} from './mdz.js';
16
- import {mdz_resolve_relative_path, mdz_is_void_element} from './mdz_helpers.js';
15
+ import type {MdzNode, MdzNodeTableRow} from './mdz.ts';
16
+ import {mdz_is_void_element, mdz_classify_link} from './mdz_helpers.ts';
17
17
 
18
18
  /**
19
19
  * Result of converting `MdzNode` arrays to Svelte markup.
@@ -131,26 +131,21 @@ export const mdz_to_svelte = (
131
131
 
132
132
  case 'Link': {
133
133
  const children_markup = render_nodes(node.children);
134
- if (node.link_type === 'internal') {
135
- if (node.reference.startsWith('.') && base) {
136
- const resolved = mdz_resolve_relative_path(node.reference, base);
137
- imports.set('resolve', {path: '$app/paths', kind: 'named'});
138
- return `<a href={resolve('${escape_js_string(resolved)}')}>${children_markup}</a>`;
139
- }
140
- if (
141
- node.reference.startsWith('#') ||
142
- node.reference.startsWith('?') ||
143
- node.reference.startsWith('.') ||
144
- // Bare references (e.g. `foo`) aren't absolute — resolve() throws on them
145
- !node.reference.startsWith('/')
146
- ) {
147
- return `<a href={'${escape_js_string(node.reference)}'}>${children_markup}</a>`;
148
- }
134
+ // safety gate + resolve-vs-raw classification shared with the runtime
135
+ // views via `mdz_classify_link`, so the three renderers can't drift
136
+ // (an unsafe `javascript:`/`data:` ref renders as plain children, no
137
+ // `<a>` — defense in depth, since `mdz_to_svelte` is a public entry
138
+ // callable with hand-built trees that never went through `mdz_parse`)
139
+ const link = mdz_classify_link(node.reference, node.link_type, base);
140
+ if (link.kind === 'unsafe') return children_markup;
141
+ if (link.kind === 'resolve') {
149
142
  imports.set('resolve', {path: '$app/paths', kind: 'named'});
150
- return `<a href={resolve('${escape_js_string(node.reference)}')}>${children_markup}</a>`;
143
+ return `<a href={resolve('${escape_js_string(link.href)}')}>${children_markup}</a>`;
151
144
  }
152
- // External link — matches MdzNodeView: target="_blank" rel="noopener"
153
- return `<a href={'${escape_js_string(node.reference)}'} target="_blank" rel="noopener">${children_markup}</a>`;
145
+ if (link.kind === 'external') {
146
+ return `<a href={'${escape_js_string(link.href)}'} target="_blank" rel="noopener">${children_markup}</a>`;
147
+ }
148
+ return `<a href={'${escape_js_string(link.href)}'}>${children_markup}</a>`;
154
149
  }
155
150
 
156
151
  case 'Paragraph':
@@ -171,6 +166,37 @@ export const mdz_to_svelte = (
171
166
  case 'Blockquote':
172
167
  return `<blockquote>${render_nodes(node.children)}</blockquote>`;
173
168
 
169
+ case 'Table': {
170
+ const {align} = node;
171
+ const render_row = (row: MdzNodeTableRow, tag: 'th' | 'td'): string => {
172
+ let cells = '';
173
+ // normalize to the column count: pad short rows, ignore extra cells
174
+ for (let i = 0; i < align.length; i++) {
175
+ const a = align[i];
176
+ const style = a ? ` style="text-align:${a}"` : '';
177
+ const cell = row.children[i];
178
+ cells += `<${tag}${style}>${cell ? render_nodes(cell.children) : ''}</${tag}>`;
179
+ }
180
+ return `<tr>${cells}</tr>`;
181
+ };
182
+ // by grammar the header row is always first (and the only one) —
183
+ // read it by index and skip it in the body, mirroring the node
184
+ // views (a `.filter()` pair re-partitions every row; see
185
+ // `MdzNodeView.svelte`'s "Table rendering de-quadratified" note)
186
+ let out = '<table>';
187
+ const header_row = node.children[0]?.header ? node.children[0] : undefined;
188
+ if (header_row) out += '<thead>' + render_row(header_row, 'th') + '</thead>';
189
+ let body = '';
190
+ for (const row of node.children) if (!row.header) body += render_row(row, 'td');
191
+ if (body) out += '<tbody>' + body + '</tbody>';
192
+ return out + '</table>';
193
+ }
194
+
195
+ case 'TableRow':
196
+ case 'TableCell':
197
+ // rendered within their `Table`; never reached through `render_nodes`
198
+ throw new Error(`mdz: ${node.type} must render within a Table`);
199
+
174
200
  case 'Hr':
175
201
  return '<hr />';
176
202
 
@@ -18,16 +18,19 @@ import type {
18
18
  MdzNodeList,
19
19
  MdzNodeListItem,
20
20
  MdzNodeBlockquote,
21
+ MdzNodeTable,
22
+ MdzNodeTableRow,
23
+ MdzNodeTableCell,
21
24
  MdzNodeElement,
22
25
  MdzNodeComponent,
23
- } from './mdz.js';
26
+ } from './mdz.ts';
24
27
  import {
25
28
  has_non_whitespace,
26
29
  mdz_extract_single_tag,
27
30
  mdz_heading_id,
28
31
  mdz_merge_adjacent_text,
29
32
  mdz_push_merging_text,
30
- } from './mdz_helpers.js';
33
+ } from './mdz_helpers.ts';
31
34
  import {
32
35
  type MdzToken,
33
36
  type MdzTokenHeadingStart,
@@ -38,7 +41,25 @@ import {
38
41
  type MdzTokenTagSelfClose,
39
42
  type MdzTokenListOpen,
40
43
  type MdzTokenListItemOpen,
41
- } from './mdz_lexer.js';
44
+ type MdzTokenTableOpen,
45
+ type MdzTokenTableRowOpen,
46
+ type MdzTokenTableCellOpen,
47
+ } from './mdz_lexer.ts';
48
+
49
+ /**
50
+ * Whether a token type ends the current inline context — the block-boundary
51
+ * set shared by the delimiter-pair and link children loops (an unclosed
52
+ * inline never swallows block structure).
53
+ */
54
+ const token_is_block_boundary = (type: MdzToken['type']): boolean =>
55
+ type === 'paragraph_break' ||
56
+ type === 'heading_start' ||
57
+ type === 'hr' ||
58
+ type === 'codeblock' ||
59
+ type === 'list_open' ||
60
+ type === 'list_item_close' ||
61
+ type === 'blockquote_open' ||
62
+ type === 'table_open';
42
63
 
43
64
  /**
44
65
  * Builds an `MdzNode[]` tree from a lexed `MdzToken[]` stream.
@@ -52,10 +73,38 @@ export class MdzTokenParser {
52
73
  this.#tokens = tokens;
53
74
  }
54
75
 
76
+ /**
77
+ * Rebind to a new token stream and rewind, so one parser instance can be
78
+ * reused across inputs — the streaming table path reuses one across a row's
79
+ * cells via `MdzTableCellParser`.
80
+ *
81
+ * @nodocs
82
+ */
83
+ reset(tokens: Array<MdzToken>): void {
84
+ this.#tokens = tokens;
85
+ this.#index = 0;
86
+ }
87
+
55
88
  parse(): Array<MdzNode> {
56
89
  return this.#parse_block_stream(false);
57
90
  }
58
91
 
92
+ /**
93
+ * Parse the entire token stream as a single inline run — used for table
94
+ * cells, whose tokens come from `MdzLexer.lex_table_cell`. Adjacent text
95
+ * merges as it accumulates, matching `#parse_table_cell`.
96
+ *
97
+ * @nodocs
98
+ */
99
+ parse_inline_run(): Array<MdzNode> {
100
+ const children: Array<MdzNode> = [];
101
+ while (this.#index < this.#tokens.length) {
102
+ const node = this.#parse_inline();
103
+ if (node) mdz_push_merging_text(children, node);
104
+ }
105
+ return children;
106
+ }
107
+
59
108
  /**
60
109
  * Parse a run of block-level tokens into nodes — the document root, or a
61
110
  * blockquote's contents (a quote's content is a mini-document, so both
@@ -118,6 +167,13 @@ export class MdzTokenParser {
118
167
  continue;
119
168
  }
120
169
 
170
+ if (token.type === 'table_open') {
171
+ const flushed = this.#flush_paragraph(paragraph_children, true);
172
+ if (flushed) nodes.push(flushed);
173
+ nodes.push(this.#parse_table());
174
+ continue;
175
+ }
176
+
121
177
  if (token.type === 'paragraph_break') {
122
178
  const flushed = this.#flush_paragraph(paragraph_children, true);
123
179
  if (flushed) nodes.push(flushed);
@@ -147,6 +203,74 @@ export class MdzTokenParser {
147
203
  return {type: 'Blockquote', children, start: open.start, end};
148
204
  }
149
205
 
206
+ #parse_table(): MdzNodeTable {
207
+ const open = this.#tokens[this.#index]! as MdzTokenTableOpen;
208
+ this.#index++;
209
+
210
+ const rows: Array<MdzNodeTableRow> = [];
211
+
212
+ while (this.#index < this.#tokens.length) {
213
+ const t = this.#tokens[this.#index]!;
214
+ if (t.type === 'table_row_open') {
215
+ rows.push(this.#parse_table_row());
216
+ continue;
217
+ }
218
+ if (t.type === 'table_close') {
219
+ this.#index++;
220
+ break;
221
+ }
222
+ this.#index++; // skip anything unexpected (defensive)
223
+ }
224
+
225
+ const end = rows.length > 0 ? rows[rows.length - 1]!.end : open.end;
226
+ return {type: 'Table', align: open.align, children: rows, start: open.start, end};
227
+ }
228
+
229
+ #parse_table_row(): MdzNodeTableRow {
230
+ const open = this.#tokens[this.#index]! as MdzTokenTableRowOpen;
231
+ const header = open.header;
232
+ this.#index++;
233
+
234
+ const cells: Array<MdzNodeTableCell> = [];
235
+
236
+ while (this.#index < this.#tokens.length) {
237
+ const t = this.#tokens[this.#index]!;
238
+ if (t.type === 'table_cell_open') {
239
+ cells.push(this.#parse_table_cell());
240
+ continue;
241
+ }
242
+ if (t.type === 'table_row_close') {
243
+ this.#index++;
244
+ return {type: 'TableRow', header, children: cells, start: open.start, end: t.end};
245
+ }
246
+ this.#index++; // skip anything unexpected (defensive)
247
+ }
248
+
249
+ const end = cells.length > 0 ? cells[cells.length - 1]!.end : open.end;
250
+ return {type: 'TableRow', header, children: cells, start: open.start, end};
251
+ }
252
+
253
+ #parse_table_cell(): MdzNodeTableCell {
254
+ const open = this.#tokens[this.#index]! as MdzTokenTableCellOpen;
255
+ const start = open.start;
256
+ this.#index++;
257
+
258
+ const children: Array<MdzNode> = [];
259
+
260
+ while (this.#index < this.#tokens.length) {
261
+ const t = this.#tokens[this.#index]!;
262
+ if (t.type === 'table_cell_close') {
263
+ this.#index++;
264
+ return {type: 'TableCell', children, start, end: t.end};
265
+ }
266
+ const node = this.#parse_inline();
267
+ if (node) mdz_push_merging_text(children, node);
268
+ }
269
+
270
+ const end = children.length > 0 ? children[children.length - 1]!.end : open.end;
271
+ return {type: 'TableCell', children, start, end};
272
+ }
273
+
150
274
  #parse_heading(): MdzNodeHeading {
151
275
  const token = this.#tokens[this.#index]! as MdzTokenHeadingStart;
152
276
  const start = token.start;
@@ -238,6 +362,12 @@ export class MdzTokenParser {
238
362
  children.push(this.#parse_blockquote());
239
363
  continue;
240
364
  }
365
+ if (t.type === 'table_open') {
366
+ flush();
367
+ in_paragraph = false;
368
+ children.push(this.#parse_table());
369
+ continue;
370
+ }
241
371
  if (t.type === 'codeblock') {
242
372
  flush();
243
373
  in_paragraph = false;
@@ -375,15 +505,7 @@ export class MdzTokenParser {
375
505
  this.#index++;
376
506
  return {type: node_type, children, start, end: t.end};
377
507
  }
378
- if (
379
- t.type === 'paragraph_break' ||
380
- t.type === 'heading_start' ||
381
- t.type === 'hr' ||
382
- t.type === 'codeblock' ||
383
- t.type === 'list_open' ||
384
- t.type === 'list_item_close' ||
385
- t.type === 'blockquote_open'
386
- ) {
508
+ if (token_is_block_boundary(t.type)) {
387
509
  break;
388
510
  }
389
511
  const node = this.#parse_inline();
@@ -423,15 +545,7 @@ export class MdzTokenParser {
423
545
  // No link_ref - treat as text
424
546
  return {type: 'Text', content: '[', start, end: start + 1};
425
547
  }
426
- if (
427
- t.type === 'paragraph_break' ||
428
- t.type === 'heading_start' ||
429
- t.type === 'hr' ||
430
- t.type === 'codeblock' ||
431
- t.type === 'list_open' ||
432
- t.type === 'list_item_close' ||
433
- t.type === 'blockquote_open'
434
- ) {
548
+ if (token_is_block_boundary(t.type)) {
435
549
  break;
436
550
  }
437
551
  const node = this.#parse_inline();
@@ -18,7 +18,7 @@ import type {ImportDeclaration, VariableDeclaration} from 'estree';
18
18
  import {parse, type PreprocessorGroup, type AST} from 'svelte/compiler';
19
19
  import MagicString from 'magic-string';
20
20
  import {walk} from 'zimmerframe';
21
- import {should_exclude_path} from '@fuzdev/fuz_util/path.js';
21
+ import {should_exclude_path} from '@fuzdev/fuz_util/path.ts';
22
22
  import {
23
23
  find_attribute,
24
24
  extract_static_string,
@@ -34,10 +34,10 @@ import {
34
34
  handle_preprocess_error,
35
35
  type PreprocessImportInfo,
36
36
  type ResolvedComponentImport,
37
- } from '@fuzdev/fuz_util/svelte_preprocess_helpers.js';
37
+ } from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
38
38
 
39
- import {mdz_parse} from './mdz.js';
40
- import {mdz_to_svelte} from './mdz_to_svelte.js';
39
+ import {mdz_parse} from './mdz.ts';
40
+ import {mdz_to_svelte, type MdzToSvelteResult} from './mdz_to_svelte.ts';
41
41
 
42
42
  /**
43
43
  * An estree `ImportDeclaration` augmented with Svelte's position data.
@@ -296,6 +296,33 @@ const collect_consumed_bindings = (
296
296
  return consumed;
297
297
  };
298
298
 
299
+ /**
300
+ * Parse a static mdz string and render it to Svelte markup. Returns `null` to
301
+ * leave the usage for the runtime — either the content raised a parse error
302
+ * (reported via `on_error`) or it contains unconfigured tags (which the
303
+ * precompiler emits nothing for; the runtime renders the fallback chrome).
304
+ */
305
+ const render_static_mdz = (
306
+ content: string,
307
+ base: string | undefined,
308
+ context: FindMdzUsagesContext,
309
+ ): MdzToSvelteResult | null => {
310
+ let result: MdzToSvelteResult;
311
+ try {
312
+ result = mdz_to_svelte(mdz_parse(content), {
313
+ components: context.components,
314
+ elements: context.elements,
315
+ base,
316
+ code_component_import: context.code_component_import,
317
+ codeblock_component_import: context.codeblock_component_import,
318
+ });
319
+ } catch (error) {
320
+ handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
321
+ return null;
322
+ }
323
+ return result.has_unconfigured_tags ? null : result;
324
+ };
325
+
299
326
  /**
300
327
  * Walks the AST to find `Mdz` component usages with static `content` props
301
328
  * and generates transformations to replace them with `MdzPrecompiled` children.
@@ -346,24 +373,8 @@ const find_mdz_usages = (
346
373
  // Extract static string value
347
374
  const content_value = extract_static_string(content_attr.value, context.bindings);
348
375
  if (content_value !== null) {
349
- // Parse mdz content and render to Svelte markup
350
- let result;
351
- try {
352
- const nodes = mdz_parse(content_value);
353
- result = mdz_to_svelte(nodes, {
354
- components: context.components,
355
- elements: context.elements,
356
- base,
357
- code_component_import: context.code_component_import,
358
- codeblock_component_import: context.codeblock_component_import,
359
- });
360
- } catch (error) {
361
- handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
362
- return;
363
- }
364
-
365
- // If content has unconfigured tags, skip this usage (fall back to runtime)
366
- if (result.has_unconfigured_tags) return;
376
+ const result = render_static_mdz(content_value, base, context);
377
+ if (result === null) return; // parse error or unconfigured tags — leave for runtime
367
378
 
368
379
  const consumed = collect_consumed_bindings(content_attr.value, context.bindings);
369
380
  const replacement = build_replacement(node, exclude_attrs, result.markup, context.source);
@@ -390,22 +401,10 @@ const find_mdz_usages = (
390
401
  // Parse and render each branch
391
402
  const branch_results: Array<{markup: string; imports: Map<string, PreprocessImportInfo>}> =
392
403
  [];
393
- try {
394
- for (const branch of chain) {
395
- const nodes = mdz_parse(branch.value);
396
- const result = mdz_to_svelte(nodes, {
397
- components: context.components,
398
- elements: context.elements,
399
- base,
400
- code_component_import: context.code_component_import,
401
- codeblock_component_import: context.codeblock_component_import,
402
- });
403
- if (result.has_unconfigured_tags) return;
404
- branch_results.push({markup: result.markup, imports: result.imports});
405
- }
406
- } catch (error) {
407
- handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
408
- return;
404
+ for (const branch of chain) {
405
+ const result = render_static_mdz(branch.value, base, context);
406
+ if (result === null) return; // parse error or unconfigured tags — leave for runtime
407
+ branch_results.push({markup: result.markup, imports: result.imports});
409
408
  }
410
409
 
411
410
  // Build {#if}/{:else if}/{:else} markup
@@ -8,7 +8,7 @@
8
8
  * @module
9
9
  */
10
10
 
11
- import {mdz_is_url} from './mdz_helpers.js';
11
+ import {mdz_is_url} from './mdz_helpers.ts';
12
12
 
13
13
  /** Format a reference as mdz: URLs pass through, identifiers get backticks. */
14
14
  const format_reference = (ref: string): string => (mdz_is_url(ref) ? ref : `\`${ref}\``);