@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.
- package/README.md +4 -0
- package/dist/Mdz.svelte +15 -7
- package/dist/Mdz.svelte.d.ts +9 -2
- package/dist/Mdz.svelte.d.ts.map +1 -1
- package/dist/MdzNodeView.svelte +130 -95
- package/dist/MdzNodeView.svelte.d.ts +6 -2
- package/dist/MdzNodeView.svelte.d.ts.map +1 -1
- package/dist/MdzStream.svelte +3 -3
- package/dist/MdzStream.svelte.d.ts.map +1 -1
- package/dist/MdzStreamNodeView.svelte +129 -95
- package/dist/MdzStreamNodeView.svelte.d.ts +6 -2
- package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -1
- package/dist/context_helpers.d.ts +1 -1
- package/dist/mdz.d.ts +59 -2
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +37 -1
- package/dist/mdz_debug_work.d.ts +38 -0
- package/dist/mdz_debug_work.d.ts.map +1 -0
- package/dist/mdz_debug_work.js +37 -0
- package/dist/mdz_helpers.d.ts +96 -1
- package/dist/mdz_helpers.d.ts.map +1 -1
- package/dist/mdz_helpers.js +192 -0
- package/dist/mdz_lexer.d.ts +47 -1
- package/dist/mdz_lexer.d.ts.map +1 -1
- package/dist/mdz_lexer.js +364 -15
- package/dist/mdz_opcodes.d.ts +6 -1
- package/dist/mdz_opcodes.d.ts.map +1 -1
- package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -1
- package/dist/mdz_opcodes_to_nodes.js +26 -0
- package/dist/mdz_stream_parser.d.ts.map +1 -1
- package/dist/mdz_stream_parser.js +20 -1
- package/dist/mdz_stream_parser_inline.d.ts.map +1 -1
- package/dist/mdz_stream_parser_inline.js +19 -17
- package/dist/mdz_stream_parser_link.d.ts.map +1 -1
- package/dist/mdz_stream_parser_link.js +88 -56
- package/dist/mdz_stream_parser_list.d.ts.map +1 -1
- package/dist/mdz_stream_parser_list.js +32 -3
- package/dist/mdz_stream_parser_state.d.ts +41 -0
- package/dist/mdz_stream_parser_state.d.ts.map +1 -1
- package/dist/mdz_stream_parser_state.js +53 -3
- package/dist/mdz_stream_parser_table.d.ts +73 -0
- package/dist/mdz_stream_parser_table.d.ts.map +1 -0
- package/dist/mdz_stream_parser_table.js +362 -0
- package/dist/mdz_stream_parser_text.d.ts.map +1 -1
- package/dist/mdz_stream_parser_text.js +35 -24
- package/dist/mdz_stream_state.svelte.d.ts +5 -0
- package/dist/mdz_stream_state.svelte.d.ts.map +1 -1
- package/dist/mdz_stream_state.svelte.js +8 -0
- package/dist/mdz_to_svelte.d.ts.map +1 -1
- package/dist/mdz_to_svelte.js +51 -20
- package/dist/mdz_token_parser.d.ts +16 -0
- package/dist/mdz_token_parser.d.ts.map +1 -1
- package/dist/mdz_token_parser.js +112 -14
- package/dist/svelte_preprocess_mdz.js +33 -39
- package/package.json +11 -8
- package/src/lib/context_helpers.ts +1 -1
- package/src/lib/mdz.ts +79 -3
- package/src/lib/mdz_contexts.ts +1 -1
- package/src/lib/mdz_debug_work.ts +38 -0
- package/src/lib/mdz_helpers.ts +222 -1
- package/src/lib/mdz_lexer.ts +420 -21
- package/src/lib/mdz_opcodes.ts +10 -1
- package/src/lib/mdz_opcodes_to_nodes.ts +37 -3
- package/src/lib/mdz_stream_parser.ts +26 -9
- package/src/lib/mdz_stream_parser_block.ts +2 -2
- package/src/lib/mdz_stream_parser_inline.ts +25 -21
- package/src/lib/mdz_stream_parser_link.ts +92 -59
- package/src/lib/mdz_stream_parser_list.ts +34 -6
- package/src/lib/mdz_stream_parser_state.ts +87 -5
- package/src/lib/mdz_stream_parser_table.ts +420 -0
- package/src/lib/mdz_stream_parser_text.ts +40 -39
- package/src/lib/mdz_stream_parser_url.ts +2 -2
- package/src/lib/mdz_stream_state.svelte.ts +8 -1
- package/src/lib/mdz_to_svelte.ts +49 -23
- package/src/lib/mdz_token_parser.ts +135 -21
- package/src/lib/svelte_preprocess_mdz.ts +37 -38
- 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.
|
|
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.
|
|
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.
|
|
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;
|
package/src/lib/mdz_to_svelte.ts
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {UnreachableError} from '@fuzdev/fuz_util/error.
|
|
12
|
-
import {escape_svelte_text} from '@fuzdev/fuz_util/svelte_preprocess_helpers.
|
|
13
|
-
import {escape_js_string} from '@fuzdev/fuz_util/string.
|
|
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.
|
|
16
|
-
import {
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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(
|
|
143
|
+
return `<a href={resolve('${escape_js_string(link.href)}')}>${children_markup}</a>`;
|
|
151
144
|
}
|
|
152
|
-
|
|
153
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
37
|
+
} from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
|
|
38
38
|
|
|
39
|
-
import {mdz_parse} from './mdz.
|
|
40
|
-
import {mdz_to_svelte} from './mdz_to_svelte.
|
|
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
|
-
|
|
350
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
package/src/lib/tsdoc_mdz.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {mdz_is_url} from './mdz_helpers.
|
|
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}\``);
|