@fuzdev/mdz 0.4.0 → 0.5.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/LICENSE +10 -17
- package/README.md +2 -3
- package/dist/MdzNodeView.svelte +59 -23
- package/dist/MdzNodeView.svelte.d.ts.map +1 -1
- package/dist/MdzStreamNodeView.svelte +63 -23
- package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -1
- package/dist/mdz.d.ts +12 -1
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +1 -1
- package/dist/mdz_contexts.d.ts +33 -6
- package/dist/mdz_contexts.d.ts.map +1 -1
- package/dist/mdz_helpers.d.ts +31 -3
- package/dist/mdz_helpers.d.ts.map +1 -1
- package/dist/mdz_helpers.js +102 -10
- package/dist/mdz_lexer.d.ts +3 -1
- package/dist/mdz_lexer.d.ts.map +1 -1
- package/dist/mdz_lexer.js +89 -15
- package/dist/mdz_opcodes.d.ts +3 -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 +3 -0
- package/dist/mdz_stream_parser_link.d.ts.map +1 -1
- package/dist/mdz_stream_parser_link.js +81 -9
- package/dist/mdz_stream_parser_table.js +8 -1
- package/dist/mdz_stream_state.svelte.d.ts +3 -1
- package/dist/mdz_stream_state.svelte.d.ts.map +1 -1
- package/dist/mdz_stream_state.svelte.js +4 -0
- package/dist/mdz_to_svelte.d.ts +17 -4
- package/dist/mdz_to_svelte.d.ts.map +1 -1
- package/dist/mdz_to_svelte.js +22 -9
- package/dist/mdz_token_parser.d.ts.map +1 -1
- package/dist/mdz_token_parser.js +16 -2
- package/dist/svelte_preprocess_mdz.d.ts +5 -2
- package/dist/svelte_preprocess_mdz.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/lib/mdz.ts +13 -1
- package/src/lib/mdz_contexts.ts +36 -6
- package/src/lib/mdz_helpers.ts +129 -14
- package/src/lib/mdz_lexer.ts +98 -15
- package/src/lib/mdz_opcodes.ts +3 -1
- package/src/lib/mdz_opcodes_to_nodes.ts +5 -0
- package/src/lib/mdz_stream_parser_link.ts +77 -7
- package/src/lib/mdz_stream_parser_table.ts +8 -1
- package/src/lib/mdz_stream_state.svelte.ts +4 -1
- package/src/lib/mdz_to_svelte.ts +57 -13
- package/src/lib/mdz_token_parser.ts +16 -2
- package/src/lib/svelte_preprocess_mdz.ts +6 -4
package/src/lib/mdz_opcodes.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type { MdzTableAlign } from './mdz.ts';
|
|
15
|
+
import type { MdzAttribute, MdzTableAlign } from './mdz.ts';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Unique monotonic identifier for each node created by the parser.
|
|
@@ -66,6 +66,8 @@ export interface MdzOpcodeOpen {
|
|
|
66
66
|
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
67
67
|
/** Tag name. Present when `node_type` is `'Element'` or `'Component'`. */
|
|
68
68
|
name?: string;
|
|
69
|
+
/** Parsed attributes. Present (possibly empty) when `node_type` is `'Element'` or `'Component'`. */
|
|
70
|
+
attributes?: Array<MdzAttribute>;
|
|
69
71
|
/** Language hint. Present when `node_type` is `'Codeblock'`. */
|
|
70
72
|
lang?: string | null;
|
|
71
73
|
/** Whether the list is ordered. Present when `node_type` is `'List'`. */
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { DEV } from 'esm-env';
|
|
21
21
|
|
|
22
22
|
import type {
|
|
23
|
+
MdzAttribute,
|
|
23
24
|
MdzNode,
|
|
24
25
|
MdzNodeText,
|
|
25
26
|
MdzNodeLink,
|
|
@@ -42,6 +43,7 @@ interface StackFrame {
|
|
|
42
43
|
// metadata from open opcode
|
|
43
44
|
level?: number;
|
|
44
45
|
name?: string;
|
|
46
|
+
attributes?: Array<MdzAttribute>;
|
|
45
47
|
lang?: string | null;
|
|
46
48
|
ordered?: boolean;
|
|
47
49
|
start_number?: number;
|
|
@@ -77,6 +79,7 @@ export const mdz_opcodes_to_nodes = (opcodes: Array<MdzOpcode>): Array<MdzNode>
|
|
|
77
79
|
start: op.start,
|
|
78
80
|
level: op.level,
|
|
79
81
|
name: op.name,
|
|
82
|
+
attributes: op.attributes,
|
|
80
83
|
lang: op.lang,
|
|
81
84
|
ordered: op.ordered,
|
|
82
85
|
start_number: op.start_number,
|
|
@@ -489,6 +492,7 @@ const build_node = (frame: StackFrame, frame_children: Array<MdzNode>): MdzNode
|
|
|
489
492
|
return {
|
|
490
493
|
type: 'Element',
|
|
491
494
|
name: frame.name ?? '',
|
|
495
|
+
attributes: frame.attributes ?? [],
|
|
492
496
|
children: mdz_merge_adjacent_text(frame_children),
|
|
493
497
|
start: frame.start,
|
|
494
498
|
end: frame.end!
|
|
@@ -498,6 +502,7 @@ const build_node = (frame: StackFrame, frame_children: Array<MdzNode>): MdzNode
|
|
|
498
502
|
return {
|
|
499
503
|
type: 'Component',
|
|
500
504
|
name: frame.name ?? '',
|
|
505
|
+
attributes: frame.attributes ?? [],
|
|
501
506
|
children: mdz_merge_adjacent_text(frame_children),
|
|
502
507
|
start: frame.start,
|
|
503
508
|
end: frame.end!
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { MdzNodeTypeContainer } from './mdz_opcodes.ts';
|
|
9
|
+
import type { MdzAttribute } from './mdz.ts';
|
|
9
10
|
import {
|
|
10
11
|
A_UPPER,
|
|
12
|
+
APOSTROPHE,
|
|
13
|
+
DOUBLE_QUOTE,
|
|
14
|
+
EQUALS,
|
|
11
15
|
LEFT_BRACKET,
|
|
12
16
|
LEFT_PAREN,
|
|
13
17
|
MAX_INLINE_NESTING_DEPTH,
|
|
@@ -211,11 +215,77 @@ export const try_tag_open = (state: MdzStreamParserState): TryResult => {
|
|
|
211
215
|
|
|
212
216
|
const name = state.buffer.slice(name_start, i);
|
|
213
217
|
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
218
|
+
// Attribute loop: consume space-separated attributes until `/>` or `>`.
|
|
219
|
+
// This widens the held-tag-open rescan surface (the TODO above) with the
|
|
220
|
+
// attribute/value text — still line-bounded, since a newline anywhere aborts
|
|
221
|
+
// the whole tag (`not_match`). Every buffer-end point holds (`need_more`) so
|
|
222
|
+
// the same tree is produced regardless of where feeds split. The quoted-value
|
|
223
|
+
// terminator search reuses `buffer_index_of` (memoized, append-aware) so a
|
|
224
|
+
// long streamed value doesn't rescan quadratically across held retries,
|
|
225
|
+
// matching `try_complete_link`.
|
|
226
|
+
const attributes: Array<MdzAttribute> = [];
|
|
227
|
+
const seen = new Set<string>();
|
|
228
|
+
for (;;) {
|
|
229
|
+
// skip a run of literal spaces only (tabs/newlines are not SPACE)
|
|
230
|
+
let had_space = false;
|
|
231
|
+
while (i < state.buffer.length && state.buffer.charCodeAt(i) === SPACE) {
|
|
232
|
+
i++;
|
|
233
|
+
had_space = true;
|
|
234
|
+
}
|
|
235
|
+
if (i >= state.buffer.length) return 'need_more';
|
|
236
|
+
|
|
237
|
+
const c = state.buffer.charCodeAt(i);
|
|
238
|
+
// `/>` or `>` ends the open tag — break to the existing self-close / commit
|
|
239
|
+
if (c === SLASH || c === RIGHT_ANGLE) break;
|
|
240
|
+
// otherwise an attribute name must follow, space-separated from what
|
|
241
|
+
// precedes it (`<a x="1"y="2">` — `y` abuts the closing quote — reverts)
|
|
242
|
+
if (!is_letter(c)) return 'not_match';
|
|
243
|
+
if (!had_space) return 'not_match';
|
|
244
|
+
|
|
245
|
+
// collect the attribute name (same grammar as tag names)
|
|
246
|
+
const attr_start = i;
|
|
247
|
+
i++; // first char already passed is_letter
|
|
248
|
+
while (i < state.buffer.length && is_tag_name_char(state.buffer.charCodeAt(i))) {
|
|
249
|
+
i++;
|
|
250
|
+
}
|
|
251
|
+
if (i >= state.buffer.length) return 'need_more'; // mid-name — could still grow
|
|
252
|
+
const attr_name = state.buffer.slice(attr_start, i);
|
|
253
|
+
// duplicate names are ambiguous (Svelte compile-errors) → literal tag
|
|
254
|
+
if (seen.has(attr_name)) return 'not_match';
|
|
255
|
+
seen.add(attr_name);
|
|
256
|
+
|
|
257
|
+
let value: string | true = true; // bare name is boolean `true`
|
|
258
|
+
if (state.buffer.charCodeAt(i) === EQUALS) {
|
|
259
|
+
i++; // consume =
|
|
260
|
+
if (i >= state.buffer.length) return 'need_more'; // nothing after `=` yet
|
|
261
|
+
// the value must be immediately quoted — no space, no `{`, no unquoted
|
|
262
|
+
const quote_code = state.buffer.charCodeAt(i);
|
|
263
|
+
if (quote_code !== DOUBLE_QUOTE && quote_code !== APOSTROPHE) return 'not_match';
|
|
264
|
+
i++; // consume opening quote
|
|
265
|
+
const value_start = i;
|
|
266
|
+
// find the matching quote and the next newline via the memoized,
|
|
267
|
+
// append-aware search; a `>` inside the value is content, consumed
|
|
268
|
+
// atomically here so a `</Name>`-shaped substring never reaches
|
|
269
|
+
// `try_close_tag`
|
|
270
|
+
const quote_str = quote_code === DOUBLE_QUOTE ? '"' : "'";
|
|
271
|
+
const q = buffer_index_of(state, quote_str, value_start);
|
|
272
|
+
const n = buffer_index_of(state, '\n', value_start);
|
|
273
|
+
if (q !== -1 && (n === -1 || q < n)) {
|
|
274
|
+
value = state.buffer.slice(value_start, q);
|
|
275
|
+
i = q + 1; // past the closing quote
|
|
276
|
+
} else if (n !== -1 && (q === -1 || n < q)) {
|
|
277
|
+
return 'not_match'; // newline inside the value → literal tag
|
|
278
|
+
} else {
|
|
279
|
+
return 'need_more'; // neither found yet — unterminated so far, hold
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
attributes.push({
|
|
283
|
+
name: attr_name,
|
|
284
|
+
value,
|
|
285
|
+
start: offset(state, attr_start),
|
|
286
|
+
end: offset(state, i)
|
|
287
|
+
});
|
|
217
288
|
}
|
|
218
|
-
if (i >= state.buffer.length) return 'need_more';
|
|
219
289
|
|
|
220
290
|
// check for self-closing />
|
|
221
291
|
if (state.buffer.charCodeAt(i) === SLASH && i + 1 >= state.buffer.length) {
|
|
@@ -230,7 +300,7 @@ export const try_tag_open = (state: MdzStreamParserState): TryResult => {
|
|
|
230
300
|
ensure_paragraph(state);
|
|
231
301
|
const id = alloc_id(state);
|
|
232
302
|
const tag_start = offset(state, start);
|
|
233
|
-
emit(state, { type: 'open', id, node_type, start: tag_start, name });
|
|
303
|
+
emit(state, { type: 'open', id, node_type, start: tag_start, name, attributes });
|
|
234
304
|
emit(state, { type: 'close', id, end: offset(state, i + 2) });
|
|
235
305
|
state.active_text_id = null;
|
|
236
306
|
state.pos = i + 2;
|
|
@@ -253,8 +323,8 @@ export const try_tag_open = (state: MdzStreamParserState): TryResult => {
|
|
|
253
323
|
ensure_paragraph(state);
|
|
254
324
|
const id = alloc_id(state);
|
|
255
325
|
const tag_start = offset(state, start);
|
|
256
|
-
const delimiter = state.buffer.slice(start, i); // e.g., "<Alert>"
|
|
257
|
-
emit(state, { type: 'open', id, node_type, start: tag_start, name });
|
|
326
|
+
const delimiter = state.buffer.slice(start, i); // e.g., "<Alert>" or "<Alert x="1">"
|
|
327
|
+
emit(state, { type: 'open', id, node_type, start: tag_start, name, attributes });
|
|
258
328
|
push_stack_entry(state, id, node_type, tag_start, delimiter, name);
|
|
259
329
|
state.active_text_id = null;
|
|
260
330
|
state.pos = i;
|
|
@@ -402,7 +402,14 @@ const emit_inline_nodes = (state: MdzStreamParserState, nodes: Array<MdzNode>):
|
|
|
402
402
|
case 'Component': {
|
|
403
403
|
const id = alloc_id(state);
|
|
404
404
|
const s = offset(state, node.start);
|
|
405
|
-
emit(state, {
|
|
405
|
+
emit(state, {
|
|
406
|
+
type: 'open',
|
|
407
|
+
id,
|
|
408
|
+
node_type: node.type,
|
|
409
|
+
start: s,
|
|
410
|
+
name: node.name,
|
|
411
|
+
attributes: node.attributes
|
|
412
|
+
});
|
|
406
413
|
push_stack_entry(state, id, node.type, s, '', node.name);
|
|
407
414
|
emit_inline_nodes(state, node.children);
|
|
408
415
|
pop_stack_entry(state);
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { DEV } from 'esm-env';
|
|
12
12
|
|
|
13
13
|
import type { MdzNodeId, MdzNodeType, MdzOpcode } from './mdz_opcodes.ts';
|
|
14
|
-
import type { MdzTableAlign } from './mdz.ts';
|
|
14
|
+
import type { MdzAttribute, MdzTableAlign } from './mdz.ts';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* A reactive node in the stream renderer tree.
|
|
@@ -27,6 +27,8 @@ export class MdzStreamNode {
|
|
|
27
27
|
reference?: string = $state();
|
|
28
28
|
link_type?: 'external' | 'internal' = $state();
|
|
29
29
|
name?: string;
|
|
30
|
+
/** Parsed tag attributes (Element/Component nodes); known at open, never mutated, so plain not `$state`. */
|
|
31
|
+
attributes?: Array<MdzAttribute>;
|
|
30
32
|
lang?: string | null;
|
|
31
33
|
heading_id?: string = $state();
|
|
32
34
|
ordered?: boolean;
|
|
@@ -105,6 +107,7 @@ export class MdzStreamState {
|
|
|
105
107
|
const node = new MdzStreamNode(opcode.id, opcode.node_type);
|
|
106
108
|
if (opcode.level !== undefined) node.level = opcode.level;
|
|
107
109
|
if (opcode.name !== undefined) node.name = opcode.name;
|
|
110
|
+
if (opcode.attributes !== undefined) node.attributes = opcode.attributes;
|
|
108
111
|
if (opcode.lang !== undefined) node.lang = opcode.lang;
|
|
109
112
|
if (opcode.ordered !== undefined) node.ordered = opcode.ordered;
|
|
110
113
|
if (opcode.start_number !== undefined) node.start_number = opcode.start_number;
|
package/src/lib/mdz_to_svelte.ts
CHANGED
|
@@ -13,7 +13,34 @@ import { escape_svelte_text } from '@fuzdev/fuz_util/svelte_preprocess_helpers.t
|
|
|
13
13
|
import { escape_js_string } from '@fuzdev/fuz_util/string.ts';
|
|
14
14
|
|
|
15
15
|
import type { MdzNode, MdzNodeTableRow } from './mdz.ts';
|
|
16
|
-
import {
|
|
16
|
+
import type { MdzComponentProps } from './mdz_contexts.ts';
|
|
17
|
+
import {
|
|
18
|
+
mdz_is_void_element,
|
|
19
|
+
mdz_classify_link,
|
|
20
|
+
mdz_filter_element_attributes,
|
|
21
|
+
mdz_filter_component_attributes,
|
|
22
|
+
ALLOWED_ELEMENT_ATTRIBUTES
|
|
23
|
+
} from './mdz_helpers.ts';
|
|
24
|
+
|
|
25
|
+
// emits parsed attributes as Svelte markup, matching the file's `name={'...'}`
|
|
26
|
+
// idiom for string attrs. Booleans emit as `name={true}`, not bare — a bare
|
|
27
|
+
// attribute compiles to `name=""`, while the runtime views spread `true`, which
|
|
28
|
+
// Svelte renders per attribute (`aria-hidden="true"`); the expression form
|
|
29
|
+
// keeps precompiled and runtime output identical. Each entry gets a leading
|
|
30
|
+
// space, so the result splices straight after the tag name.
|
|
31
|
+
/**
|
|
32
|
+
* A build-time component registry entry: an import path, or an import path
|
|
33
|
+
* plus the attribute names passed as props (see `MdzComponentProps`).
|
|
34
|
+
*/
|
|
35
|
+
export type MdzComponentImport = string | { path: string; props?: MdzComponentProps };
|
|
36
|
+
|
|
37
|
+
const format_attributes = (entries: Array<[string, string | true]>): string => {
|
|
38
|
+
let out = '';
|
|
39
|
+
for (const [name, value] of entries) {
|
|
40
|
+
out += value === true ? ` ${name}={true}` : ` ${name}={'${escape_js_string(value)}'}`;
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
};
|
|
17
44
|
|
|
18
45
|
/**
|
|
19
46
|
* Result of converting `MdzNode` arrays to Svelte markup.
|
|
@@ -38,10 +65,13 @@ const component_local_name = (import_path: string): string =>
|
|
|
38
65
|
*/
|
|
39
66
|
export interface MdzToSvelteOptions {
|
|
40
67
|
/**
|
|
41
|
-
* Component name to import
|
|
68
|
+
* Component name to import mapping, mirroring the runtime `MdzComponents`
|
|
69
|
+
* registry: a bare import path receives no attributes
|
|
70
|
+
* (`{Note: '#lib/Note.svelte'}`), and the config form names the attributes
|
|
71
|
+
* passed as props (`{Alert: {path: '#lib/Alert.svelte', props: ['status']}}`).
|
|
42
72
|
* If content references a component not in this map, `has_unconfigured_tags` is set.
|
|
43
73
|
*/
|
|
44
|
-
components: Record<string,
|
|
74
|
+
components: Record<string, MdzComponentImport>;
|
|
45
75
|
|
|
46
76
|
/**
|
|
47
77
|
* Allowed HTML elements (e.g., `{aside: true, details: true}`).
|
|
@@ -53,8 +83,9 @@ export interface MdzToSvelteOptions {
|
|
|
53
83
|
|
|
54
84
|
/**
|
|
55
85
|
* Base path for resolving relative links (e.g., `'/docs/usage/'`).
|
|
56
|
-
* When provided, relative references (`./`, `../`) are resolved
|
|
57
|
-
*
|
|
86
|
+
* When provided, relative references (`./`, `../`) are resolved against it and,
|
|
87
|
+
* like absolute references, passed through `resolve()` in its pathname form.
|
|
88
|
+
* Trailing slash recommended.
|
|
58
89
|
*/
|
|
59
90
|
base?: string;
|
|
60
91
|
|
|
@@ -140,7 +171,7 @@ export const mdz_to_svelte = (
|
|
|
140
171
|
if (link.kind === 'unsafe') return children_markup;
|
|
141
172
|
if (link.kind === 'resolve') {
|
|
142
173
|
imports.set('resolve', { path: '$app/paths', kind: 'named' });
|
|
143
|
-
return `<a href={resolve('${escape_js_string(link.
|
|
174
|
+
return `<a href={resolve('${escape_js_string(link.path)}')}>${children_markup}</a>`;
|
|
144
175
|
}
|
|
145
176
|
if (link.kind === 'external') {
|
|
146
177
|
return `<a href={'${escape_js_string(link.href)}'} target="_blank" rel="noopener">${children_markup}</a>`;
|
|
@@ -208,25 +239,38 @@ export const mdz_to_svelte = (
|
|
|
208
239
|
}
|
|
209
240
|
|
|
210
241
|
case 'Element': {
|
|
211
|
-
if (elements[node.name]
|
|
242
|
+
if (elements[node.name] !== true) {
|
|
212
243
|
has_unconfigured_tags = true;
|
|
213
244
|
return '';
|
|
214
245
|
}
|
|
246
|
+
// filter via the SAME helper the node views use, so precompiled and
|
|
247
|
+
// runtime output stay identical (its DEV-warn fires at build time too)
|
|
248
|
+
const attrs_str = format_attributes(
|
|
249
|
+
Object.entries(
|
|
250
|
+
mdz_filter_element_attributes(node.name, node.attributes, ALLOWED_ELEMENT_ATTRIBUTES)
|
|
251
|
+
)
|
|
252
|
+
);
|
|
215
253
|
if (mdz_is_void_element(node.name)) {
|
|
216
254
|
// void elements cannot have content — any parsed children are dropped
|
|
217
|
-
return `<${node.name} />`;
|
|
255
|
+
return `<${node.name}${attrs_str} />`;
|
|
218
256
|
}
|
|
219
|
-
return `<${node.name}>${render_nodes(node.children)}</${node.name}>`;
|
|
257
|
+
return `<${node.name}${attrs_str}>${render_nodes(node.children)}</${node.name}>`;
|
|
220
258
|
}
|
|
221
259
|
|
|
222
260
|
case 'Component': {
|
|
223
|
-
const
|
|
224
|
-
if (!
|
|
261
|
+
const entry = components[node.name];
|
|
262
|
+
if (!entry) {
|
|
225
263
|
has_unconfigured_tags = true;
|
|
226
264
|
return '';
|
|
227
265
|
}
|
|
228
|
-
|
|
229
|
-
|
|
266
|
+
const { path, props } =
|
|
267
|
+
typeof entry === 'string' ? { path: entry, props: undefined } : entry;
|
|
268
|
+
imports.set(node.name, { path, kind: 'default' });
|
|
269
|
+
// filter via the SAME helper the node views use
|
|
270
|
+
const attrs_str = format_attributes(
|
|
271
|
+
Object.entries(mdz_filter_component_attributes(node.name, node.attributes, props))
|
|
272
|
+
);
|
|
273
|
+
return `<${node.name}${attrs_str}>${render_nodes(node.children)}</${node.name}>`;
|
|
230
274
|
}
|
|
231
275
|
|
|
232
276
|
default:
|
|
@@ -581,7 +581,14 @@ export class MdzTokenParser {
|
|
|
581
581
|
const t = this.#tokens[this.#index]!;
|
|
582
582
|
if (t.type === 'tag_close' && t.name === tag_name) {
|
|
583
583
|
this.#index++;
|
|
584
|
-
return {
|
|
584
|
+
return {
|
|
585
|
+
type: node_type,
|
|
586
|
+
name: tag_name,
|
|
587
|
+
attributes: open_token.attributes,
|
|
588
|
+
children,
|
|
589
|
+
start,
|
|
590
|
+
end: t.end
|
|
591
|
+
};
|
|
585
592
|
}
|
|
586
593
|
const node = this.#parse_inline();
|
|
587
594
|
if (node) mdz_push_merging_text(children, node);
|
|
@@ -595,7 +602,14 @@ export class MdzTokenParser {
|
|
|
595
602
|
const token = this.#tokens[this.#index]! as MdzTokenTagSelfClose;
|
|
596
603
|
const node_type: 'Component' | 'Element' = token.is_component ? 'Component' : 'Element';
|
|
597
604
|
this.#index++;
|
|
598
|
-
return {
|
|
605
|
+
return {
|
|
606
|
+
type: node_type,
|
|
607
|
+
name: token.name,
|
|
608
|
+
attributes: token.attributes,
|
|
609
|
+
children: [],
|
|
610
|
+
start: token.start,
|
|
611
|
+
end: token.end
|
|
612
|
+
};
|
|
599
613
|
}
|
|
600
614
|
|
|
601
615
|
// -- Paragraph flushing --
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
} from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
|
|
38
38
|
|
|
39
39
|
import { mdz_parse } from './mdz.ts';
|
|
40
|
-
import { mdz_to_svelte, type MdzToSvelteResult } from './mdz_to_svelte.ts';
|
|
40
|
+
import { mdz_to_svelte, type MdzComponentImport, type MdzToSvelteResult } from './mdz_to_svelte.ts';
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* An estree `ImportDeclaration` augmented with Svelte's position data.
|
|
@@ -56,12 +56,14 @@ export interface SveltePreprocessMdzOptions {
|
|
|
56
56
|
/**
|
|
57
57
|
* Component import mapping for mdz content.
|
|
58
58
|
* Key: component name as used in mdz (e.g., 'Alert').
|
|
59
|
-
* Value: import path (e.g., '#lib/Alert.svelte')
|
|
59
|
+
* Value: import path (e.g., '#lib/Alert.svelte'), which receives no attributes,
|
|
60
|
+
* or `{path, props}` naming the attributes passed as props
|
|
61
|
+
* (e.g., `{path: '#lib/Alert.svelte', props: ['status']}`, or `props: 'all'`).
|
|
60
62
|
*
|
|
61
63
|
* If mdz content references a component not in this map,
|
|
62
64
|
* that `Mdz` usage is skipped (left as runtime).
|
|
63
65
|
*/
|
|
64
|
-
components?: Record<string,
|
|
66
|
+
components?: Record<string, MdzComponentImport>;
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
69
|
* Allowed HTML elements in mdz content (e.g., `{aside: true, details: true}`).
|
|
@@ -235,7 +237,7 @@ interface FindMdzUsagesResult {
|
|
|
235
237
|
}
|
|
236
238
|
|
|
237
239
|
interface FindMdzUsagesContext {
|
|
238
|
-
components: Record<string,
|
|
240
|
+
components: Record<string, MdzComponentImport>;
|
|
239
241
|
elements: Record<string, boolean>;
|
|
240
242
|
filename: string | undefined;
|
|
241
243
|
source: string;
|