@fuzdev/mdz 0.2.0 → 0.4.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 (83) hide show
  1. package/README.md +4 -0
  2. package/dist/Mdz.svelte +18 -9
  3. package/dist/Mdz.svelte.d.ts +9 -2
  4. package/dist/Mdz.svelte.d.ts.map +1 -1
  5. package/dist/MdzNodeView.svelte +129 -115
  6. package/dist/MdzNodeView.svelte.d.ts +4 -1
  7. package/dist/MdzNodeView.svelte.d.ts.map +1 -1
  8. package/dist/MdzPrecompiled.svelte +3 -3
  9. package/dist/MdzPrecompiled.svelte.d.ts.map +1 -1
  10. package/dist/MdzRoot.svelte +3 -3
  11. package/dist/MdzRoot.svelte.d.ts.map +1 -1
  12. package/dist/MdzStream.svelte +6 -6
  13. package/dist/MdzStream.svelte.d.ts.map +1 -1
  14. package/dist/MdzStreamNodeView.svelte +129 -118
  15. package/dist/MdzStreamNodeView.svelte.d.ts +4 -1
  16. package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -1
  17. package/dist/context_helpers.js +1 -1
  18. package/dist/mdz.d.ts +6 -0
  19. package/dist/mdz.d.ts.map +1 -1
  20. package/dist/mdz.js +8 -0
  21. package/dist/mdz_contexts.d.ts.map +1 -1
  22. package/dist/mdz_debug_work.d.ts +38 -0
  23. package/dist/mdz_debug_work.d.ts.map +1 -0
  24. package/dist/mdz_debug_work.js +37 -0
  25. package/dist/mdz_helpers.d.ts +61 -0
  26. package/dist/mdz_helpers.d.ts.map +1 -1
  27. package/dist/mdz_helpers.js +74 -2
  28. package/dist/mdz_lexer.d.ts +12 -0
  29. package/dist/mdz_lexer.d.ts.map +1 -1
  30. package/dist/mdz_lexer.js +190 -40
  31. package/dist/mdz_opcodes.d.ts.map +1 -1
  32. package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -1
  33. package/dist/mdz_opcodes_to_nodes.js +22 -17
  34. package/dist/mdz_stream_parser.d.ts.map +1 -1
  35. package/dist/mdz_stream_parser.js +8 -8
  36. package/dist/mdz_stream_parser_block.js +5 -5
  37. package/dist/mdz_stream_parser_inline.d.ts.map +1 -1
  38. package/dist/mdz_stream_parser_inline.js +22 -20
  39. package/dist/mdz_stream_parser_link.d.ts.map +1 -1
  40. package/dist/mdz_stream_parser_link.js +88 -56
  41. package/dist/mdz_stream_parser_list.d.ts.map +1 -1
  42. package/dist/mdz_stream_parser_list.js +23 -9
  43. package/dist/mdz_stream_parser_state.d.ts +29 -0
  44. package/dist/mdz_stream_parser_state.d.ts.map +1 -1
  45. package/dist/mdz_stream_parser_state.js +59 -10
  46. package/dist/mdz_stream_parser_table.d.ts +3 -2
  47. package/dist/mdz_stream_parser_table.d.ts.map +1 -1
  48. package/dist/mdz_stream_parser_table.js +24 -13
  49. package/dist/mdz_stream_parser_text.d.ts.map +1 -1
  50. package/dist/mdz_stream_parser_text.js +36 -25
  51. package/dist/mdz_stream_parser_url.js +7 -7
  52. package/dist/mdz_stream_state.svelte.d.ts.map +1 -1
  53. package/dist/mdz_to_svelte.d.ts +1 -1
  54. package/dist/mdz_to_svelte.d.ts.map +1 -1
  55. package/dist/mdz_to_svelte.js +28 -31
  56. package/dist/mdz_token_parser.d.ts.map +1 -1
  57. package/dist/mdz_token_parser.js +24 -25
  58. package/dist/svelte_preprocess_mdz.d.ts +2 -2
  59. package/dist/svelte_preprocess_mdz.d.ts.map +1 -1
  60. package/dist/svelte_preprocess_mdz.js +41 -47
  61. package/package.json +28 -40
  62. package/src/lib/context_helpers.ts +2 -2
  63. package/src/lib/mdz.ts +11 -2
  64. package/src/lib/mdz_contexts.ts +5 -5
  65. package/src/lib/mdz_debug_work.ts +38 -0
  66. package/src/lib/mdz_helpers.ts +126 -23
  67. package/src/lib/mdz_lexer.ts +243 -93
  68. package/src/lib/mdz_opcodes.ts +1 -1
  69. package/src/lib/mdz_opcodes_to_nodes.ts +35 -30
  70. package/src/lib/mdz_stream_parser.ts +17 -17
  71. package/src/lib/mdz_stream_parser_block.ts +14 -14
  72. package/src/lib/mdz_stream_parser_inline.ts +38 -34
  73. package/src/lib/mdz_stream_parser_link.ts +99 -66
  74. package/src/lib/mdz_stream_parser_list.ts +41 -29
  75. package/src/lib/mdz_stream_parser_state.ts +100 -28
  76. package/src/lib/mdz_stream_parser_table.ts +47 -36
  77. package/src/lib/mdz_stream_parser_text.ts +40 -39
  78. package/src/lib/mdz_stream_parser_url.ts +11 -11
  79. package/src/lib/mdz_stream_state.svelte.ts +8 -8
  80. package/src/lib/mdz_to_svelte.ts +38 -46
  81. package/src/lib/mdz_token_parser.ts +55 -58
  82. package/src/lib/svelte_preprocess_mdz.ts +92 -89
  83. package/src/lib/tsdoc_mdz.ts +1 -1
@@ -8,6 +8,7 @@
8
8
  * @module
9
9
  */
10
10
  import type { MdzNodeTypeContainer, MdzNodeId, MdzOpcode } from './mdz_opcodes.js';
11
+ import type { MdzTableCellParser } from './mdz.js';
11
12
  /**
12
13
  * Tri-state result for `try_*` parser handlers.
13
14
  * - `'consumed'`: input matched and the parser advanced
@@ -206,10 +207,12 @@ export interface MdzStreamParserState {
206
207
  * is `null` for a top-level table (column-0 rows) or the enclosing list item's
207
208
  * marker indent for a table nested as a block child (rows skip the indent and
208
209
  * a dedent to that indent ends the table, returning control to the list).
210
+ * `cell_parser` is the table's shared cell parser, rebound per row.
209
211
  */
210
212
  table: {
211
213
  id: MdzNodeId;
212
214
  item_indent: number | null;
215
+ cell_parser: MdzTableCellParser;
213
216
  } | null;
214
217
  /**
215
218
  * Whether the innermost open ListItem's first inline run is current.
@@ -238,6 +241,32 @@ export interface MdzStreamParserState {
238
241
  search_memo: Map<string, BufferSearchMemo> | null;
239
242
  /** Open-container counts for `find_open`'s O(1) "nothing open" early exit. */
240
243
  open_counts: OpenInlineCounts;
244
+ /**
245
+ * Count of open `Link`/`Element`/`Component` frames in the current run — the
246
+ * streaming analogue of the sync lexer's `#inline_depth`. Kept as an O(1)
247
+ * counter (not a stack walk, which would reintroduce the deep-stack
248
+ * quadratic `open_counts` exists to avoid) so `try_link_open`/`try_tag_open`
249
+ * can cap nesting at `MAX_INLINE_NESTING_DEPTH` — rendering a deeper `[`/`<`
250
+ * literal, matching the sync cap on pure/symmetric nesting. It counts
251
+ * **optimistic** opens, though, so it diverges from the sync `#inline_depth`
252
+ * (which the sync tag path only bumps after a closer precheck) on an
253
+ * asymmetric cap-saturating prefix — 100+ *unclosed* `<a>` before a valid
254
+ * `[x](/u)` saturates this counter and suppresses the trailing link that sync
255
+ * still forms. Adversarial-only, documented not fixed (streaming can't
256
+ * precheck closers): see the flip-at-cap case in `mdz_nesting_cap.test.ts`.
257
+ * Run-scoped for free like `open_counts`: a
258
+ * run close reverts every inline frame above it, decrementing back to zero.
259
+ */
260
+ open_link_tag_depth: number;
261
+ /**
262
+ * Per-name counts of open Element/Component frames, the tag analogue of
263
+ * `open_counts`: `try_close_tag` bails in O(1) when the closing name isn't
264
+ * open, instead of walking a stack that grows one frame per leaked unclosed
265
+ * `<Tag>`. Lazily created on the first tag open — tag-free inputs never
266
+ * allocate the map. Run-scoped like `open_counts`: run closes revert every
267
+ * inline frame above them, decrementing the counts back to zero.
268
+ */
269
+ open_tag_counts: Map<string, number> | null;
241
270
  /** Whether we're inside a heading (newline ends it). */
242
271
  in_heading: boolean;
243
272
  /** Whether we're inside an optimistic inline Code container. */
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_stream_parser_state.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mdz_stream_parser_state.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_state.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@
8
8
  * @module
9
9
  */
10
10
  import { NEWLINE, has_non_whitespace, mdz_heading_id_from_text } from './mdz_helpers.js';
11
+ import { mdz_debug_work } from './mdz_debug_work.js';
11
12
  /** @nodocs */
12
13
  export const create_state = () => ({
13
14
  buffer: '',
@@ -30,6 +31,8 @@ export const create_state = () => ({
30
31
  base_offset: 0,
31
32
  search_memo: null,
32
33
  open_counts: { Bold: 0, Italic: 0, Strikethrough: 0, Link: 0 },
34
+ open_link_tag_depth: 0,
35
+ open_tag_counts: null,
33
36
  in_heading: false,
34
37
  in_code: false,
35
38
  in_paragraph: false,
@@ -41,7 +44,7 @@ export const create_state = () => ({
41
44
  paragraph_stack_idx: -1,
42
45
  last_text_id: null,
43
46
  last_text_ended_with_newline: false,
44
- last_text_was_singleton_newline: false,
47
+ last_text_was_singleton_newline: false
45
48
  });
46
49
  /** @nodocs */
47
50
  export const alloc_id = (state) => state.next_id++;
@@ -61,7 +64,7 @@ export const push_stack_entry = (state, id, node_type, start, delimiter = '', ta
61
64
  tag_name,
62
65
  has_children: false,
63
66
  has_non_whitespace_content: false,
64
- start,
67
+ start
65
68
  });
66
69
  if (node_type === 'Paragraph') {
67
70
  state.paragraph_stack_idx = state.stack.length - 1;
@@ -69,6 +72,14 @@ export const push_stack_entry = (state, id, node_type, start, delimiter = '', ta
69
72
  else {
70
73
  bump_open_count(state, node_type, 1);
71
74
  }
75
+ if (tag_name !== undefined) {
76
+ const counts = (state.open_tag_counts ??= new Map());
77
+ counts.set(tag_name, (counts.get(tag_name) ?? 0) + 1);
78
+ }
79
+ // Link/Element/Component contribute to the nesting-depth cap (tag_name is
80
+ // set for Element/Component only, so `Link || tag_name` is exactly the three)
81
+ if (node_type === 'Link' || tag_name !== undefined)
82
+ state.open_link_tag_depth++;
72
83
  };
73
84
  /**
74
85
  * Adjust the `open_counts` entry for a counted container type; no-op for
@@ -99,6 +110,19 @@ const bump_open_count = (state, node_type, delta) => {
99
110
  export const pop_stack_entry = (state) => {
100
111
  const entry = state.stack.pop();
101
112
  bump_open_count(state, entry.node_type, -1);
113
+ if (entry.tag_name !== undefined) {
114
+ const counts = state.open_tag_counts;
115
+ // drop zero-count keys so a long stream of many distinct tag names can't
116
+ // grow the map unboundedly — the `!counts.get(name)` bail in `try_close_tag`
117
+ // treats a missing key and a 0 count identically, so this is behavior-neutral
118
+ const remaining = counts.get(entry.tag_name) - 1;
119
+ if (remaining === 0)
120
+ counts.delete(entry.tag_name);
121
+ else
122
+ counts.set(entry.tag_name, remaining);
123
+ }
124
+ if (entry.node_type === 'Link' || entry.tag_name !== undefined)
125
+ state.open_link_tag_depth--;
102
126
  return entry;
103
127
  };
104
128
  /**
@@ -163,7 +187,11 @@ const memo_index_of = (state, memo, needle, from) => {
163
187
  // rescan only the appended tail, overlapping the old boundary so a
164
188
  // straddling needle isn't missed
165
189
  const rescan_from = Math.max(global_from, memo.searched_to - (needle.length - 1));
166
- const result = state.buffer.indexOf(needle, rescan_from - state.base_offset);
190
+ const local_from = rescan_from - state.base_offset;
191
+ const result = state.buffer.indexOf(needle, local_from);
192
+ if (mdz_debug_work.enabled) {
193
+ mdz_debug_work.total += (result === -1 ? state.buffer.length : result) - local_from;
194
+ }
167
195
  memo.from = global_from;
168
196
  memo.result = result === -1 ? -1 : state.base_offset + result;
169
197
  memo.searched_to = global_end;
@@ -172,6 +200,9 @@ const memo_index_of = (state, memo, needle, from) => {
172
200
  // found result already behind `from` — fall through to a fresh scan
173
201
  }
174
202
  const result = state.buffer.indexOf(needle, from);
203
+ if (mdz_debug_work.enabled) {
204
+ mdz_debug_work.total += (result === -1 ? state.buffer.length : result) - from;
205
+ }
175
206
  memo.from = global_from;
176
207
  memo.result = result === -1 ? -1 : state.base_offset + result;
177
208
  memo.searched_to = global_end;
@@ -211,8 +242,11 @@ export const emit = (state, op) => {
211
242
  if (top) {
212
243
  top.has_children = true;
213
244
  // propagate non-whitespace marker to the nearest Paragraph so
214
- // whitespace-only paragraphs can be discarded at close
215
- if (op.type === 'void' || has_non_whitespace(op.content)) {
245
+ // whitespace-only paragraphs can be discarded at close — the O(1)
246
+ // no-paragraph check runs first so codeblock/table-cell emissions
247
+ // (never inside a Paragraph) skip the content scan entirely
248
+ if (op.type === 'void' ||
249
+ (state.paragraph_stack_idx !== -1 && has_non_whitespace(op.content))) {
216
250
  mark_paragraph_non_whitespace(state);
217
251
  }
218
252
  }
@@ -311,7 +345,7 @@ export const flush_text = (state) => {
311
345
  type: 'append_text',
312
346
  id: state.active_text_id,
313
347
  content: state.accumulated_text,
314
- end: state.accumulated_text_end,
348
+ end: state.accumulated_text_end
315
349
  });
316
350
  }
317
351
  else {
@@ -324,7 +358,7 @@ export const flush_text = (state) => {
324
358
  content: state.accumulated_text,
325
359
  text_type: 'Text',
326
360
  start,
327
- end: state.accumulated_text_end,
361
+ end: state.accumulated_text_end
328
362
  });
329
363
  state.active_text_id = id;
330
364
  }
@@ -402,7 +436,7 @@ export const revert_above = (state, target_idx) => {
402
436
  type: 'revert',
403
437
  id: entry.id,
404
438
  replacement_text: entry.delimiter,
405
- start: entry.start,
439
+ start: entry.start
406
440
  });
407
441
  }
408
442
  state.active_text_id = null;
@@ -436,11 +470,26 @@ export const revert_failed_close = (state, stack_idx) => {
436
470
  const frames_above = state.stack.length - 1 - stack_idx;
437
471
  state.stack.splice(stack_idx, 1);
438
472
  bump_open_count(state, entry.node_type, -1);
473
+ if (entry.tag_name !== undefined) {
474
+ const counts = state.open_tag_counts;
475
+ // drop zero-count keys so a long stream of many distinct tag names can't
476
+ // grow the map unboundedly — the `!counts.get(name)` bail in `try_close_tag`
477
+ // treats a missing key and a 0 count identically, so this is behavior-neutral
478
+ const remaining = counts.get(entry.tag_name) - 1;
479
+ if (remaining === 0)
480
+ counts.delete(entry.tag_name);
481
+ else
482
+ counts.set(entry.tag_name, remaining);
483
+ }
484
+ // only ever reverts an Italic today, but keep the depth counter honest if a
485
+ // Link/Element/Component is ever failed-closed mid-stack
486
+ if (entry.node_type === 'Link' || entry.tag_name !== undefined)
487
+ state.open_link_tag_depth--;
439
488
  state.opcodes.push({
440
489
  type: 'revert',
441
490
  id: entry.id,
442
491
  replacement_text: entry.delimiter,
443
- start: entry.start,
492
+ start: entry.start
444
493
  });
445
494
  // structural opcode seals the prior text run (mirrors `emit`)
446
495
  seal_text_run(state);
@@ -602,7 +651,7 @@ export const close_list_item = (state) => {
602
651
  emit(state, {
603
652
  type: 'close',
604
653
  id: entry.id,
605
- end: entry.has_children ? offset(state) : state.last_empty_item_end,
654
+ end: entry.has_children ? offset(state) : state.last_empty_item_end
606
655
  });
607
656
  state.active_text_id = null;
608
657
  };
@@ -7,8 +7,9 @@
7
7
  * whole header emits at once. Body rows then stream one per line. Because a row
8
8
  * is always fully buffered before it emits (no within-row streaming), each
9
9
  * cell's inline content is parsed with the sync reference (`MdzTableCellParser`,
10
- * one `MdzLexer`/`MdzTokenParser` shared across the row's cells) and replayed
11
- * as opcodes — guaranteeing sync↔stream parity by construction.
10
+ * one `MdzLexer`/`MdzTokenParser` shared across the whole table's cells,
11
+ * rebound per row) and replayed as opcodes — guaranteeing sync↔stream parity
12
+ * by construction.
12
13
  *
13
14
  * @module
14
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_stream_parser_table.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAWH,OAAO,EAAmC,KAAK,aAAa,EAAC,MAAM,UAAU,CAAC;AAC9E,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAQd,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,oBAAoB,EAAE,QAAQ,OAAO,KAAG,SAqC9E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,oBAAoB,EAAE,QAAQ,OAAO,KAAG,OAyCjF,CAAC;AA2DF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,oBAAoB,KAAG,IAczD,CAAC;AAEF,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACpC,OAAO,oBAAoB,EAC3B,cAAc,MAAM,EACpB,eAAe,MAAM,EACrB,QAAQ,OAAO,KACb,eAAe,GAAG,SAAS,GAAG,IAmBhC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC9B,OAAO,oBAAoB,EAC3B,cAAc,MAAM,EACpB,eAAe,MAAM,EACrB,MAAM,eAAe,KACnB,IAkBF,CAAC"}
1
+ {"version":3,"file":"mdz_stream_parser_table.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,OAAO,EAAoC,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAChF,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,SAAS,EAQd,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,oBAAoB,EAAE,QAAQ,OAAO,KAAG,SAyC9E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,oBAAoB,EAAE,QAAQ,OAAO,KAAG,OAyCjF,CAAC;AA2DF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,oBAAoB,KAAG,IAczD,CAAC;AAEF,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACpC,OAAO,oBAAoB,EAC3B,cAAc,MAAM,EACpB,eAAe,MAAM,EACrB,QAAQ,OAAO,KACb,eAAe,GAAG,SAAS,GAAG,IAmBhC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC9B,OAAO,oBAAoB,EAC3B,cAAc,MAAM,EACpB,eAAe,MAAM,EACrB,MAAM,eAAe,KACnB,IAsBF,CAAC"}
@@ -7,15 +7,16 @@
7
7
  * whole header emits at once. Body rows then stream one per line. Because a row
8
8
  * is always fully buffered before it emits (no within-row streaming), each
9
9
  * cell's inline content is parsed with the sync reference (`MdzTableCellParser`,
10
- * one `MdzLexer`/`MdzTokenParser` shared across the row's cells) and replayed
11
- * as opcodes — guaranteeing sync↔stream parity by construction.
10
+ * one `MdzLexer`/`MdzTokenParser` shared across the whole table's cells,
11
+ * rebound per row) and replayed as opcodes — guaranteeing sync↔stream parity
12
+ * by construction.
12
13
  *
13
14
  * @module
14
15
  */
15
16
  import { DEV } from 'esm-env';
16
- import { NEWLINE, PIPE, is_line_whitespace, mdz_split_table_row, mdz_parse_table_delimiter, } from './mdz_helpers.js';
17
+ import { NEWLINE, PIPE, is_line_whitespace, mdz_split_table_row, mdz_parse_table_delimiter } from './mdz_helpers.js';
17
18
  import { MdzTableCellParser } from './mdz.js';
18
- import { alloc_id, close_paragraph, emit, flush_text, offset, pop_stack_entry, push_stack_entry, } from './mdz_stream_parser_state.js';
19
+ import { alloc_id, close_paragraph, emit, flush_text, offset, pop_stack_entry, push_stack_entry } from './mdz_stream_parser_state.js';
19
20
  /**
20
21
  * Try to open a table at a column-0 pipe row. Returns `need_more` until both
21
22
  * the header line and its delimiter line are buffered (or, in forced mode,
@@ -52,7 +53,11 @@ export const try_table_start = (state, forced) => {
52
53
  const table_start = offset(state, start);
53
54
  emit(state, { type: 'open', id: table_id, node_type: 'Table', start: table_start, align });
54
55
  push_stack_entry(state, table_id, 'Table', table_start);
55
- state.table = { id: table_id, item_indent: null };
56
+ state.table = {
57
+ id: table_id,
58
+ item_indent: null,
59
+ cell_parser: new MdzTableCellParser(state.buffer)
60
+ };
56
61
  emit_table_row(state, header_cells, true, start, header_end);
57
62
  // skip past the delimiter row to the first potential body line
58
63
  state.pos = delim_end === state.buffer.length ? delim_end : delim_end + 1;
@@ -233,10 +238,14 @@ export const open_table_in_item = (state, header_first, marker_indent, head) =>
233
238
  id: table_id,
234
239
  node_type: 'Table',
235
240
  start: table_start,
236
- align: head.align,
241
+ align: head.align
237
242
  });
238
243
  push_stack_entry(state, table_id, 'Table', table_start);
239
- state.table = { id: table_id, item_indent: marker_indent };
244
+ state.table = {
245
+ id: table_id,
246
+ item_indent: marker_indent,
247
+ cell_parser: new MdzTableCellParser(state.buffer)
248
+ };
240
249
  emit_table_row(state, head.header_cells, true, header_first, head.header_end);
241
250
  // leave the cursor on the delimiter's newline (or EOF) — the in-item body-row
242
251
  // handler reads from the line after it and hands back on this same convention
@@ -250,9 +259,11 @@ const emit_table_row = (state, cells, header, row_start, row_end) => {
250
259
  const row_off = offset(state, row_start);
251
260
  emit(state, { type: 'open', id: row_id, node_type: 'TableRow', start: row_off, header });
252
261
  push_stack_entry(state, row_id, 'TableRow', row_off);
253
- // one lexer/parser shared across the row's cells (all index into the same
254
- // buffer) rather than allocated per cell
255
- const cell_parser = new MdzTableCellParser(state.buffer);
262
+ // one lexer/parser shared across the whole table rather than allocated per
263
+ // row (or per cell) — rebound per row because the buffer string changes
264
+ // across feeds; the lexer's search memo survives when it doesn't
265
+ const cell_parser = state.table.cell_parser;
266
+ cell_parser.rebind(state.buffer);
256
267
  for (const cell of cells) {
257
268
  emit_table_cell(state, cell_parser, cell.start, cell.end);
258
269
  }
@@ -288,7 +299,7 @@ const emit_inline_nodes = (state, nodes) => {
288
299
  content: node.content,
289
300
  text_type: 'Text',
290
301
  start: offset(state, node.start),
291
- end: offset(state, node.end),
302
+ end: offset(state, node.end)
292
303
  });
293
304
  break;
294
305
  case 'Code':
@@ -298,7 +309,7 @@ const emit_inline_nodes = (state, nodes) => {
298
309
  content: node.content,
299
310
  text_type: 'Code',
300
311
  start: offset(state, node.start),
301
- end: offset(state, node.end),
312
+ end: offset(state, node.end)
302
313
  });
303
314
  break;
304
315
  case 'Bold':
@@ -325,7 +336,7 @@ const emit_inline_nodes = (state, nodes) => {
325
336
  id,
326
337
  end: offset(state, node.end),
327
338
  reference: node.reference,
328
- link_type: node.link_type,
339
+ link_type: node.link_type
329
340
  });
330
341
  break;
331
342
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_stream_parser_text.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH,OAAO,EACN,KAAK,oBAAoB,EAIzB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GAAI,OAAO,oBAAoB,EAAE,WAAW,MAAM,KAAG,IAM1F,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,oBAAoB,KAAG,IAsC9D,CAAC"}
1
+ {"version":3,"file":"mdz_stream_parser_text.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,EACN,KAAK,oBAAoB,EAIzB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,GAAI,OAAO,oBAAoB,EAAE,WAAW,MAAM,KAAG,IAM1F,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,oBAAoB,KAAG,IA4C9D,CAAC"}
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import { ASTERISK, BACKTICK, HTTPS_PREFIX_LENGTH, H_LOWER, H_UPPER, LEFT_ANGLE, LEFT_BRACKET, NEWLINE, PERIOD, RIGHT_BRACKET, SLASH, SPACE, TAB, TILDE, UNDERSCORE, is_word_char, match_url_prefix_case_insensitive, } from './mdz_helpers.js';
7
- import { accumulate_text, ensure_paragraph, offset, } from './mdz_stream_parser_state.js';
6
+ import { HTTPS_PREFIX_LENGTH, NEWLINE, SPACE, TAB, TEXT_CLASS_NEWLINE, TEXT_CLASS_PATH, TEXT_CLASS_STOP, TEXT_CLASS_URL, TEXT_SCAN_CLASS, is_word_char, match_url_prefix_case_insensitive } from './mdz_helpers.js';
7
+ import { accumulate_text, ensure_paragraph, offset } from './mdz_stream_parser_state.js';
8
+ import { mdz_debug_work } from './mdz_debug_work.js';
8
9
  /**
9
10
  * Consume a delimiter at the current position as literal text — the shared
10
11
  * tail of every "this delimiter doesn't open/close anything here" decision
@@ -34,33 +35,43 @@ export const consume_text_run = (state) => {
34
35
  state.pos++;
35
36
  while (state.pos < state.buffer.length) {
36
37
  const c = state.buffer.charCodeAt(state.pos);
37
- if (c === BACKTICK ||
38
- c === ASTERISK ||
39
- c === UNDERSCORE ||
40
- c === TILDE ||
41
- c === LEFT_BRACKET ||
42
- c === RIGHT_BRACKET ||
43
- c === LEFT_ANGLE ||
44
- c === NEWLINE ||
45
- // URL/path: only break when actually at a URL or path start.
46
- // Most h/H/./slash in prose are not URLs/paths — continuing the scan
47
- // avoids the full dispatch cycle through process_loop → process_inline.
48
- // For `h`/`H` at a word boundary, also break when there isn't enough
49
- // buffer left to confirm `https://` / `http://` — process_inline's
50
- // speculator then carries the prefix match across chunk boundaries.
51
- // Scheme matching is case-insensitive (RFC 3986).
52
- ((c === H_LOWER || c === H_UPPER) &&
53
- (match_url_prefix_case_insensitive(state.buffer, state.pos) > 0 ||
54
- (state.buffer.length - state.pos < HTTPS_PREFIX_LENGTH &&
55
- !is_word_char(state.buffer.charCodeAt(state.pos - 1))))) ||
56
- ((c === SLASH || c === PERIOD) &&
57
- (state.buffer.charCodeAt(state.pos - 1) === SPACE ||
58
- state.buffer.charCodeAt(state.pos - 1) === NEWLINE ||
59
- state.buffer.charCodeAt(state.pos - 1) === TAB))) {
38
+ // one table load classifies the char; zero (the common case) continues
39
+ // the run without any further checks. `TEXT_SCAN_CLASS` is shared with
40
+ // the sync lexer's `#tokenize_text` (`mdz_lexer.ts`); the dispatch bodies
41
+ // intentionally differ — that one handles `\|` escapes and list-run
42
+ // strip, this one URL speculation across chunk boundaries.
43
+ const char_class = c < 128 ? TEXT_SCAN_CLASS[c] : 0;
44
+ if (char_class === 0) {
45
+ state.pos++;
46
+ continue;
47
+ }
48
+ if ((char_class & (TEXT_CLASS_STOP | TEXT_CLASS_NEWLINE)) !== 0)
60
49
  break;
50
+ if ((char_class & TEXT_CLASS_URL) !== 0) {
51
+ // URL: only break when actually at a URL start. Most h/H in prose are
52
+ // not URLs — continuing the scan avoids the full dispatch cycle
53
+ // through process_loop → process_inline. At a word boundary, also
54
+ // break when there isn't enough buffer left to confirm `https://` /
55
+ // `http://` — process_inline's speculator then carries the prefix
56
+ // match across chunk boundaries. Scheme matching is case-insensitive
57
+ // (RFC 3986).
58
+ if (match_url_prefix_case_insensitive(state.buffer, state.pos) > 0 ||
59
+ (state.buffer.length - state.pos < HTTPS_PREFIX_LENGTH &&
60
+ !is_word_char(state.buffer.charCodeAt(state.pos - 1)))) {
61
+ break;
62
+ }
63
+ }
64
+ else if ((char_class & TEXT_CLASS_PATH) !== 0) {
65
+ // path (`/` or `.`): only break at a plausible path start
66
+ const prev = state.buffer.charCodeAt(state.pos - 1);
67
+ if (prev === SPACE || prev === NEWLINE || prev === TAB)
68
+ break;
61
69
  }
70
+ // backslash (or a non-starting path char) — ordinary text
62
71
  state.pos++;
63
72
  }
73
+ if (mdz_debug_work.enabled)
74
+ mdz_debug_work.total += state.pos - start;
64
75
  accumulate_text(state, state.buffer.slice(start, state.pos), offset(state, start));
65
76
  state.prev_char = state.buffer.charCodeAt(state.pos - 1);
66
77
  state.column += state.pos - start;
@@ -12,8 +12,8 @@
12
12
  *
13
13
  * @module
14
14
  */
15
- import { NEWLINE, SPACE, TAB, PERIOD, SLASH, ascii_to_lower, is_valid_path_char, is_word_char, match_url_prefix_case_insensitive, mdz_trim_url_punctuation, } from './mdz_helpers.js';
16
- import { accumulate_text, alloc_id, emit, ensure_paragraph, flush_text, offset, } from './mdz_stream_parser_state.js';
15
+ import { NEWLINE, SPACE, TAB, PERIOD, SLASH, ascii_to_lower, is_valid_path_char, is_word_char, match_url_prefix_case_insensitive, mdz_trim_url_punctuation } from './mdz_helpers.js';
16
+ import { accumulate_text, alloc_id, emit, ensure_paragraph, flush_text, offset } from './mdz_stream_parser_state.js';
17
17
  const HTTPS_PREFIX = 'https://';
18
18
  const HTTP_PREFIX = 'http://';
19
19
  /**
@@ -113,7 +113,7 @@ export const start_pending_url = (state, link_type) => {
113
113
  link_type,
114
114
  confirmed: true,
115
115
  viable_https: false,
116
- viable_http: false,
116
+ viable_http: false
117
117
  };
118
118
  // don't advance pos — URL chars start at current position, handled by process_url_content
119
119
  };
@@ -134,7 +134,7 @@ export const start_speculative_url = (state) => {
134
134
  link_type: 'external',
135
135
  confirmed: false,
136
136
  viable_https: true,
137
- viable_http: true,
137
+ viable_http: true
138
138
  };
139
139
  };
140
140
  /**
@@ -261,7 +261,7 @@ export const complete_pending_url = (state) => {
261
261
  start: pu.start,
262
262
  end: url_end,
263
263
  trim_end,
264
- trim_id,
264
+ trim_id
265
265
  });
266
266
  state.active_text_id = trim_id;
267
267
  }
@@ -274,7 +274,7 @@ export const complete_pending_url = (state) => {
274
274
  reference,
275
275
  link_type: pu.link_type,
276
276
  start: pu.start,
277
- end: url_end,
277
+ end: url_end
278
278
  });
279
279
  state.active_text_id = null;
280
280
  }
@@ -317,7 +317,7 @@ export const scan_auto_link_forced = (state, link_type) => {
317
317
  content: reference,
318
318
  text_type: 'Text',
319
319
  start: link_start,
320
- end: link_end,
320
+ end: link_end
321
321
  });
322
322
  emit(state, { type: 'close', id: link_id, end: link_end, reference, link_type });
323
323
  state.active_text_id = null;
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_stream_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_state.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAC,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AAE5C;;;GAGG;AACH,qBAAa,aAAa;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC,CAAc;IAE5C,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAY;IAC9B,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,CAAY;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAY;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC7B,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;gBAEL,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW;CAI5C;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;;IAC1B,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAc;IAqCxC;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IA6R9B;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI;CAK5C"}
1
+ {"version":3,"file":"mdz_stream_state.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_state.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;GAGG;AACH,qBAAa,aAAa;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC,CAAc;IAE5C,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAY;IAC9B,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,CAAY;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAY;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC7B,uDAAuD;IACvD,MAAM,CAAC,EAAE,OAAO,CAAC;gBAEL,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW;CAI5C;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;;IAC1B,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAc;IAqCxC;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IA6R9B;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI;CAK5C"}
@@ -27,7 +27,7 @@ export interface MdzToSvelteResult {
27
27
  */
28
28
  export interface MdzToSvelteOptions {
29
29
  /**
30
- * Component name to import path mapping (e.g., `{Alert: '$lib/Alert.svelte'}`).
30
+ * Component name to import path mapping (e.g., `{Alert: '#lib/Alert.svelte'}`).
31
31
  * If content references a component not in this map, `has_unconfigured_tags` is set.
32
32
  */
33
33
  components: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_to_svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_to_svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAC,OAAO,EAAkB,MAAM,UAAU,CAAC;AAGvD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;KAAC,CAAC,CAAC;IAEhE,yEAAyE;IACzE,qBAAqB,EAAE,OAAO,CAAC;CAC/B;AAMD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GACzB,OAAO,KAAK,CAAC,OAAO,CAAC,EACrB,SAAS,kBAAkB,KACzB,iBA8JF,CAAC"}
1
+ {"version":3,"file":"mdz_to_svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_to_svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAC;AAGzD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;IAElE,yEAAyE;IACzE,qBAAqB,EAAE,OAAO,CAAC;CAC/B;AAMD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GACzB,OAAO,KAAK,CAAC,OAAO,CAAC,EACrB,SAAS,kBAAkB,KACzB,iBAsJF,CAAC"}
@@ -10,7 +10,7 @@
10
10
  import { UnreachableError } from '@fuzdev/fuz_util/error.ts';
11
11
  import { escape_svelte_text } from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
12
12
  import { escape_js_string } from '@fuzdev/fuz_util/string.ts';
13
- import { mdz_resolve_relative_path, mdz_is_void_element } from './mdz_helpers.js';
13
+ import { mdz_is_void_element, mdz_classify_link } from './mdz_helpers.js';
14
14
  /** Derives an import's local identifier from a `.svelte` import path's basename. */
15
15
  const component_local_name = (import_path) => import_path.slice(import_path.lastIndexOf('/') + 1).replace(/\.svelte$/, '');
16
16
  /**
@@ -58,24 +58,22 @@ export const mdz_to_svelte = (nodes, options) => {
58
58
  return `<s>${render_nodes(node.children)}</s>`;
59
59
  case 'Link': {
60
60
  const children_markup = render_nodes(node.children);
61
- if (node.link_type === 'internal') {
62
- if (node.reference.startsWith('.') && base) {
63
- const resolved = mdz_resolve_relative_path(node.reference, base);
64
- imports.set('resolve', { path: '$app/paths', kind: 'named' });
65
- return `<a href={resolve('${escape_js_string(resolved)}')}>${children_markup}</a>`;
66
- }
67
- if (node.reference.startsWith('#') ||
68
- node.reference.startsWith('?') ||
69
- node.reference.startsWith('.') ||
70
- // Bare references (e.g. `foo`) aren't absolute — resolve() throws on them
71
- !node.reference.startsWith('/')) {
72
- return `<a href={'${escape_js_string(node.reference)}'}>${children_markup}</a>`;
73
- }
61
+ // safety gate + resolve-vs-raw classification shared with the runtime
62
+ // views via `mdz_classify_link`, so the three renderers can't drift
63
+ // (an unsafe `javascript:`/`data:` ref renders as plain children, no
64
+ // `<a>` — defense in depth, since `mdz_to_svelte` is a public entry
65
+ // callable with hand-built trees that never went through `mdz_parse`)
66
+ const link = mdz_classify_link(node.reference, node.link_type, base);
67
+ if (link.kind === 'unsafe')
68
+ return children_markup;
69
+ if (link.kind === 'resolve') {
74
70
  imports.set('resolve', { path: '$app/paths', kind: 'named' });
75
- return `<a href={resolve('${escape_js_string(node.reference)}')}>${children_markup}</a>`;
71
+ return `<a href={resolve('${escape_js_string(link.href)}')}>${children_markup}</a>`;
72
+ }
73
+ if (link.kind === 'external') {
74
+ return `<a href={'${escape_js_string(link.href)}'} target="_blank" rel="noopener">${children_markup}</a>`;
76
75
  }
77
- // External link — matches MdzNodeView: target="_blank" rel="noopener"
78
- return `<a href={'${escape_js_string(node.reference)}'} target="_blank" rel="noopener">${children_markup}</a>`;
76
+ return `<a href={'${escape_js_string(link.href)}'}>${children_markup}</a>`;
79
77
  }
80
78
  case 'Paragraph':
81
79
  return `<p>${render_nodes(node.children)}</p>`;
@@ -103,21 +101,20 @@ export const mdz_to_svelte = (nodes, options) => {
103
101
  }
104
102
  return `<tr>${cells}</tr>`;
105
103
  };
104
+ // by grammar the header row is always first (and the only one) —
105
+ // read it by index and skip it in the body, mirroring the node
106
+ // views (a `.filter()` pair re-partitions every row; see
107
+ // `MdzNodeView.svelte`'s "Table rendering de-quadratified" note)
106
108
  let out = '<table>';
107
- const header_rows = node.children.filter((r) => r.header);
108
- const body_rows = node.children.filter((r) => !r.header);
109
- if (header_rows.length > 0) {
110
- out += '<thead>';
111
- for (const row of header_rows)
112
- out += render_row(row, 'th');
113
- out += '</thead>';
114
- }
115
- if (body_rows.length > 0) {
116
- out += '<tbody>';
117
- for (const row of body_rows)
118
- out += render_row(row, 'td');
119
- out += '</tbody>';
120
- }
109
+ const header_row = node.children[0]?.header ? node.children[0] : undefined;
110
+ if (header_row)
111
+ out += '<thead>' + render_row(header_row, 'th') + '</thead>';
112
+ let body = '';
113
+ for (const row of node.children)
114
+ if (!row.header)
115
+ body += render_row(row, 'td');
116
+ if (body)
117
+ out += '<tbody>' + body + '</tbody>';
121
118
  return out + '</table>';
122
119
  }
123
120
  case 'TableRow':
@@ -1 +1 @@
1
- {"version":3,"file":"mdz_token_parser.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_token_parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACX,OAAO,EAeP,MAAM,UAAU,CAAC;AAQlB,OAAO,EACN,KAAK,QAAQ,EAYb,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,qBAAa,cAAc;;gBAId,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;IAInC;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI;IAKpC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;IAIvB;;;;;;OAMG;IACH,gBAAgB,IAAI,KAAK,CAAC,OAAO,CAAC;CAikBlC"}
1
+ {"version":3,"file":"mdz_token_parser.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_token_parser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACX,OAAO,EAeP,MAAM,UAAU,CAAC;AAQlB,OAAO,EACN,KAAK,QAAQ,EAYb,MAAM,gBAAgB,CAAC;AAiBxB;;;GAGG;AACH,qBAAa,cAAc;;gBAId,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC;IAInC;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI;IAKpC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC;IAIvB;;;;;;OAMG;IACH,gBAAgB,IAAI,KAAK,CAAC,OAAO,CAAC;CA+iBlC"}