@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.
- package/README.md +4 -0
- package/dist/Mdz.svelte +18 -9
- package/dist/Mdz.svelte.d.ts +9 -2
- package/dist/Mdz.svelte.d.ts.map +1 -1
- package/dist/MdzNodeView.svelte +129 -115
- package/dist/MdzNodeView.svelte.d.ts +4 -1
- package/dist/MdzNodeView.svelte.d.ts.map +1 -1
- package/dist/MdzPrecompiled.svelte +3 -3
- package/dist/MdzPrecompiled.svelte.d.ts.map +1 -1
- package/dist/MdzRoot.svelte +3 -3
- package/dist/MdzRoot.svelte.d.ts.map +1 -1
- package/dist/MdzStream.svelte +6 -6
- package/dist/MdzStream.svelte.d.ts.map +1 -1
- package/dist/MdzStreamNodeView.svelte +129 -118
- package/dist/MdzStreamNodeView.svelte.d.ts +4 -1
- package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -1
- package/dist/context_helpers.js +1 -1
- package/dist/mdz.d.ts +6 -0
- package/dist/mdz.d.ts.map +1 -1
- package/dist/mdz.js +8 -0
- package/dist/mdz_contexts.d.ts.map +1 -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 +61 -0
- package/dist/mdz_helpers.d.ts.map +1 -1
- package/dist/mdz_helpers.js +74 -2
- package/dist/mdz_lexer.d.ts +12 -0
- package/dist/mdz_lexer.d.ts.map +1 -1
- package/dist/mdz_lexer.js +190 -40
- 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 +22 -17
- package/dist/mdz_stream_parser.d.ts.map +1 -1
- package/dist/mdz_stream_parser.js +8 -8
- package/dist/mdz_stream_parser_block.js +5 -5
- package/dist/mdz_stream_parser_inline.d.ts.map +1 -1
- package/dist/mdz_stream_parser_inline.js +22 -20
- 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 +23 -9
- package/dist/mdz_stream_parser_state.d.ts +29 -0
- package/dist/mdz_stream_parser_state.d.ts.map +1 -1
- package/dist/mdz_stream_parser_state.js +59 -10
- package/dist/mdz_stream_parser_table.d.ts +3 -2
- package/dist/mdz_stream_parser_table.d.ts.map +1 -1
- package/dist/mdz_stream_parser_table.js +24 -13
- package/dist/mdz_stream_parser_text.d.ts.map +1 -1
- package/dist/mdz_stream_parser_text.js +36 -25
- package/dist/mdz_stream_parser_url.js +7 -7
- package/dist/mdz_stream_state.svelte.d.ts.map +1 -1
- package/dist/mdz_to_svelte.d.ts +1 -1
- package/dist/mdz_to_svelte.d.ts.map +1 -1
- package/dist/mdz_to_svelte.js +28 -31
- package/dist/mdz_token_parser.d.ts.map +1 -1
- package/dist/mdz_token_parser.js +24 -25
- package/dist/svelte_preprocess_mdz.d.ts +2 -2
- package/dist/svelte_preprocess_mdz.d.ts.map +1 -1
- package/dist/svelte_preprocess_mdz.js +41 -47
- package/package.json +28 -40
- package/src/lib/context_helpers.ts +2 -2
- package/src/lib/mdz.ts +11 -2
- package/src/lib/mdz_contexts.ts +5 -5
- package/src/lib/mdz_debug_work.ts +38 -0
- package/src/lib/mdz_helpers.ts +126 -23
- package/src/lib/mdz_lexer.ts +243 -93
- package/src/lib/mdz_opcodes.ts +1 -1
- package/src/lib/mdz_opcodes_to_nodes.ts +35 -30
- package/src/lib/mdz_stream_parser.ts +17 -17
- package/src/lib/mdz_stream_parser_block.ts +14 -14
- package/src/lib/mdz_stream_parser_inline.ts +38 -34
- package/src/lib/mdz_stream_parser_link.ts +99 -66
- package/src/lib/mdz_stream_parser_list.ts +41 -29
- package/src/lib/mdz_stream_parser_state.ts +100 -28
- package/src/lib/mdz_stream_parser_table.ts +47 -36
- package/src/lib/mdz_stream_parser_text.ts +40 -39
- package/src/lib/mdz_stream_parser_url.ts +11 -11
- package/src/lib/mdz_stream_state.svelte.ts +8 -8
- package/src/lib/mdz_to_svelte.ts +38 -46
- package/src/lib/mdz_token_parser.ts +55 -58
- package/src/lib/svelte_preprocess_mdz.ts +92 -89
- package/src/lib/tsdoc_mdz.ts +1 -1
package/dist/mdz_token_parser.js
CHANGED
|
@@ -6,8 +6,21 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import { has_non_whitespace, mdz_extract_single_tag, mdz_heading_id, mdz_merge_adjacent_text, mdz_push_merging_text
|
|
9
|
+
import { has_non_whitespace, mdz_extract_single_tag, mdz_heading_id, mdz_merge_adjacent_text, mdz_push_merging_text } from './mdz_helpers.js';
|
|
10
10
|
import {} from './mdz_lexer.js';
|
|
11
|
+
/**
|
|
12
|
+
* Whether a token type ends the current inline context — the block-boundary
|
|
13
|
+
* set shared by the delimiter-pair and link children loops (an unclosed
|
|
14
|
+
* inline never swallows block structure).
|
|
15
|
+
*/
|
|
16
|
+
const token_is_block_boundary = (type) => type === 'paragraph_break' ||
|
|
17
|
+
type === 'heading_start' ||
|
|
18
|
+
type === 'hr' ||
|
|
19
|
+
type === 'codeblock' ||
|
|
20
|
+
type === 'list_open' ||
|
|
21
|
+
type === 'list_item_close' ||
|
|
22
|
+
type === 'blockquote_open' ||
|
|
23
|
+
type === 'table_open';
|
|
11
24
|
/**
|
|
12
25
|
* Builds an `MdzNode[]` tree from a lexed `MdzToken[]` stream.
|
|
13
26
|
* Used by `mdz_parse`, which should be preferred for simple usage.
|
|
@@ -88,7 +101,7 @@ export class MdzTokenParser {
|
|
|
88
101
|
lang: token.lang,
|
|
89
102
|
content: token.content,
|
|
90
103
|
start: token.start,
|
|
91
|
-
end: token.end
|
|
104
|
+
end: token.end
|
|
92
105
|
});
|
|
93
106
|
this.#index++;
|
|
94
107
|
continue;
|
|
@@ -243,7 +256,7 @@ export class MdzTokenParser {
|
|
|
243
256
|
start_number: children[0]?.number ?? 1,
|
|
244
257
|
children,
|
|
245
258
|
start: open.start,
|
|
246
|
-
end
|
|
259
|
+
end
|
|
247
260
|
};
|
|
248
261
|
}
|
|
249
262
|
return { type: 'List', ordered: false, children, start: open.start, end };
|
|
@@ -293,7 +306,7 @@ export class MdzTokenParser {
|
|
|
293
306
|
lang: t.lang,
|
|
294
307
|
content: t.content,
|
|
295
308
|
start: t.start,
|
|
296
|
-
end: t.end
|
|
309
|
+
end: t.end
|
|
297
310
|
});
|
|
298
311
|
this.#index++;
|
|
299
312
|
continue;
|
|
@@ -365,7 +378,7 @@ export class MdzTokenParser {
|
|
|
365
378
|
type: 'Text',
|
|
366
379
|
content: `(${token.reference})`,
|
|
367
380
|
start: token.start,
|
|
368
|
-
end: token.end
|
|
381
|
+
end: token.end
|
|
369
382
|
};
|
|
370
383
|
case 'tag_close':
|
|
371
384
|
this.#index++;
|
|
@@ -373,7 +386,7 @@ export class MdzTokenParser {
|
|
|
373
386
|
type: 'Text',
|
|
374
387
|
content: `</${token.name}>`,
|
|
375
388
|
start: token.start,
|
|
376
|
-
end: token.end
|
|
389
|
+
end: token.end
|
|
377
390
|
};
|
|
378
391
|
default:
|
|
379
392
|
this.#index++;
|
|
@@ -398,14 +411,7 @@ export class MdzTokenParser {
|
|
|
398
411
|
this.#index++;
|
|
399
412
|
return { type: node_type, children, start, end: t.end };
|
|
400
413
|
}
|
|
401
|
-
if (t.type
|
|
402
|
-
t.type === 'heading_start' ||
|
|
403
|
-
t.type === 'hr' ||
|
|
404
|
-
t.type === 'codeblock' ||
|
|
405
|
-
t.type === 'list_open' ||
|
|
406
|
-
t.type === 'list_item_close' ||
|
|
407
|
-
t.type === 'blockquote_open' ||
|
|
408
|
-
t.type === 'table_open') {
|
|
414
|
+
if (token_is_block_boundary(t.type)) {
|
|
409
415
|
break;
|
|
410
416
|
}
|
|
411
417
|
const node = this.#parse_inline();
|
|
@@ -434,20 +440,13 @@ export class MdzTokenParser {
|
|
|
434
440
|
children,
|
|
435
441
|
link_type: ref_token.link_type,
|
|
436
442
|
start,
|
|
437
|
-
end: ref_token.end
|
|
443
|
+
end: ref_token.end
|
|
438
444
|
};
|
|
439
445
|
}
|
|
440
446
|
// No link_ref - treat as text
|
|
441
447
|
return { type: 'Text', content: '[', start, end: start + 1 };
|
|
442
448
|
}
|
|
443
|
-
if (t.type
|
|
444
|
-
t.type === 'heading_start' ||
|
|
445
|
-
t.type === 'hr' ||
|
|
446
|
-
t.type === 'codeblock' ||
|
|
447
|
-
t.type === 'list_open' ||
|
|
448
|
-
t.type === 'list_item_close' ||
|
|
449
|
-
t.type === 'blockquote_open' ||
|
|
450
|
-
t.type === 'table_open') {
|
|
449
|
+
if (token_is_block_boundary(t.type)) {
|
|
451
450
|
break;
|
|
452
451
|
}
|
|
453
452
|
const node = this.#parse_inline();
|
|
@@ -465,7 +464,7 @@ export class MdzTokenParser {
|
|
|
465
464
|
children: [{ type: 'Text', content: token.reference, start: token.start, end: token.end }],
|
|
466
465
|
link_type: token.link_type,
|
|
467
466
|
start: token.start,
|
|
468
|
-
end: token.end
|
|
467
|
+
end: token.end
|
|
469
468
|
};
|
|
470
469
|
}
|
|
471
470
|
#parse_tag_node() {
|
|
@@ -542,7 +541,7 @@ export class MdzTokenParser {
|
|
|
542
541
|
type: 'Paragraph',
|
|
543
542
|
children: merged,
|
|
544
543
|
start: merged[0].start,
|
|
545
|
-
end: merged[merged.length - 1].end
|
|
544
|
+
end: merged[merged.length - 1].end
|
|
546
545
|
};
|
|
547
546
|
}
|
|
548
547
|
}
|
|
@@ -23,7 +23,7 @@ export interface SveltePreprocessMdzOptions {
|
|
|
23
23
|
/**
|
|
24
24
|
* Component import mapping for mdz content.
|
|
25
25
|
* Key: component name as used in mdz (e.g., 'Alert').
|
|
26
|
-
* Value: import path (e.g., '
|
|
26
|
+
* Value: import path (e.g., '#lib/Alert.svelte').
|
|
27
27
|
*
|
|
28
28
|
* If mdz content references a component not in this map,
|
|
29
29
|
* that `Mdz` usage is skipped (left as runtime).
|
|
@@ -74,7 +74,7 @@ export interface SveltePreprocessMdzOptions {
|
|
|
74
74
|
* Creates a Svelte preprocessor that compiles static `Mdz` content at build time.
|
|
75
75
|
*
|
|
76
76
|
* @param options - configuration for component/element resolution and file filtering
|
|
77
|
-
* @returns a Svelte `PreprocessorGroup` for
|
|
77
|
+
* @returns a Svelte `PreprocessorGroup` for a `preprocess` option, like `sveltekit({preprocess})` in `vite.config.ts`
|
|
78
78
|
*/
|
|
79
79
|
export declare const svelte_preprocess_mdz: (options?: SveltePreprocessMdzOptions) => PreprocessorGroup;
|
|
80
80
|
//# sourceMappingURL=svelte_preprocess_mdz.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"svelte_preprocess_mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"svelte_preprocess_mdz.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/svelte_preprocess_mdz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAS,KAAK,iBAAiB,EAAY,MAAM,iBAAiB,CAAC;AA+B1E;;GAEG;AACH,MAAM,WAAW,0BAA0B;IAC1C,gCAAgC;IAChC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAEjC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtC;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CAC3B;AAID;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GACjC,UAAS,0BAA+B,KACtC,iBA6FF,CAAC"}
|
|
@@ -17,7 +17,7 @@ import { parse } from 'svelte/compiler';
|
|
|
17
17
|
import MagicString from 'magic-string';
|
|
18
18
|
import { walk } from 'zimmerframe';
|
|
19
19
|
import { should_exclude_path } from '@fuzdev/fuz_util/path.ts';
|
|
20
|
-
import { find_attribute, extract_static_string, try_extract_conditional_chain, build_static_bindings, resolve_component_names, has_identifier_in_tree, find_import_insert_position, generate_import_lines, remove_variable_declaration, remove_import_declaration, remove_import_specifier, handle_preprocess_error
|
|
20
|
+
import { find_attribute, extract_static_string, try_extract_conditional_chain, build_static_bindings, resolve_component_names, has_identifier_in_tree, find_import_insert_position, generate_import_lines, remove_variable_declaration, remove_import_declaration, remove_import_specifier, handle_preprocess_error } from '@fuzdev/fuz_util/svelte_preprocess_helpers.ts';
|
|
21
21
|
import { mdz_parse } from './mdz.js';
|
|
22
22
|
import { mdz_to_svelte } from './mdz_to_svelte.js';
|
|
23
23
|
const PRECOMPILED_NAME = 'MdzPrecompiled';
|
|
@@ -25,10 +25,10 @@ const PRECOMPILED_NAME = 'MdzPrecompiled';
|
|
|
25
25
|
* Creates a Svelte preprocessor that compiles static `Mdz` content at build time.
|
|
26
26
|
*
|
|
27
27
|
* @param options - configuration for component/element resolution and file filtering
|
|
28
|
-
* @returns a Svelte `PreprocessorGroup` for
|
|
28
|
+
* @returns a Svelte `PreprocessorGroup` for a `preprocess` option, like `sveltekit({preprocess})` in `vite.config.ts`
|
|
29
29
|
*/
|
|
30
30
|
export const svelte_preprocess_mdz = (options = {}) => {
|
|
31
|
-
const { exclude = [], components = {}, elements = {}, mdz_component_imports = ['@fuzdev/mdz/Mdz.svelte'], compiled_component_import = '@fuzdev/mdz/MdzPrecompiled.svelte', code_component_import, codeblock_component_import, on_error = process.env.CI === 'true' ? 'throw' : 'log'
|
|
31
|
+
const { exclude = [], components = {}, elements = {}, mdz_component_imports = ['@fuzdev/mdz/Mdz.svelte'], compiled_component_import = '@fuzdev/mdz/MdzPrecompiled.svelte', code_component_import, codeblock_component_import, on_error = process.env.CI === 'true' ? 'throw' : 'log' } = options;
|
|
32
32
|
return {
|
|
33
33
|
name: 'fuz-mdz',
|
|
34
34
|
markup: ({ content, filename }) => {
|
|
@@ -60,7 +60,7 @@ export const svelte_preprocess_mdz = (options = {}) => {
|
|
|
60
60
|
bindings,
|
|
61
61
|
on_error,
|
|
62
62
|
code_component_import,
|
|
63
|
-
codeblock_component_import
|
|
63
|
+
codeblock_component_import
|
|
64
64
|
});
|
|
65
65
|
if (transformations.length === 0) {
|
|
66
66
|
return { code: content };
|
|
@@ -77,9 +77,9 @@ export const svelte_preprocess_mdz = (options = {}) => {
|
|
|
77
77
|
manage_imports(s, ast, transformations, removable_imports, compiled_component_import, content);
|
|
78
78
|
return {
|
|
79
79
|
code: s.toString(),
|
|
80
|
-
map: s.generateMap({ hires: true })
|
|
80
|
+
map: s.generateMap({ hires: true })
|
|
81
81
|
};
|
|
82
|
-
}
|
|
82
|
+
}
|
|
83
83
|
};
|
|
84
84
|
};
|
|
85
85
|
/**
|
|
@@ -138,6 +138,29 @@ const collect_consumed_bindings = (value, bindings) => {
|
|
|
138
138
|
collect_from_expr(value.expression);
|
|
139
139
|
return consumed;
|
|
140
140
|
};
|
|
141
|
+
/**
|
|
142
|
+
* Parse a static mdz string and render it to Svelte markup. Returns `null` to
|
|
143
|
+
* leave the usage for the runtime — either the content raised a parse error
|
|
144
|
+
* (reported via `on_error`) or it contains unconfigured tags (which the
|
|
145
|
+
* precompiler emits nothing for; the runtime renders the fallback chrome).
|
|
146
|
+
*/
|
|
147
|
+
const render_static_mdz = (content, base, context) => {
|
|
148
|
+
let result;
|
|
149
|
+
try {
|
|
150
|
+
result = mdz_to_svelte(mdz_parse(content), {
|
|
151
|
+
components: context.components,
|
|
152
|
+
elements: context.elements,
|
|
153
|
+
base,
|
|
154
|
+
code_component_import: context.code_component_import,
|
|
155
|
+
codeblock_component_import: context.codeblock_component_import
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
return result.has_unconfigured_tags ? null : result;
|
|
163
|
+
};
|
|
141
164
|
/**
|
|
142
165
|
* Walks the AST to find `Mdz` component usages with static `content` props
|
|
143
166
|
* and generates transformations to replace them with `MdzPrecompiled` children.
|
|
@@ -181,25 +204,9 @@ const find_mdz_usages = (ast, mdz_names, context) => {
|
|
|
181
204
|
// Extract static string value
|
|
182
205
|
const content_value = extract_static_string(content_attr.value, context.bindings);
|
|
183
206
|
if (content_value !== null) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const nodes = mdz_parse(content_value);
|
|
188
|
-
result = mdz_to_svelte(nodes, {
|
|
189
|
-
components: context.components,
|
|
190
|
-
elements: context.elements,
|
|
191
|
-
base,
|
|
192
|
-
code_component_import: context.code_component_import,
|
|
193
|
-
codeblock_component_import: context.codeblock_component_import,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
// If content has unconfigured tags, skip this usage (fall back to runtime)
|
|
201
|
-
if (result.has_unconfigured_tags)
|
|
202
|
-
return;
|
|
207
|
+
const result = render_static_mdz(content_value, base, context);
|
|
208
|
+
if (result === null)
|
|
209
|
+
return; // parse error or unconfigured tags — leave for runtime
|
|
203
210
|
const consumed = collect_consumed_bindings(content_attr.value, context.bindings);
|
|
204
211
|
const replacement = build_replacement(node, exclude_attrs, result.markup, context.source);
|
|
205
212
|
transformed_usages.set(node.name, (transformed_usages.get(node.name) ?? 0) + 1);
|
|
@@ -209,7 +216,7 @@ const find_mdz_usages = (ast, mdz_names, context) => {
|
|
|
209
216
|
replacement,
|
|
210
217
|
required_imports: result.imports,
|
|
211
218
|
consumed_bindings: consumed,
|
|
212
|
-
component_node: node
|
|
219
|
+
component_node: node
|
|
213
220
|
});
|
|
214
221
|
return;
|
|
215
222
|
}
|
|
@@ -219,24 +226,11 @@ const find_mdz_usages = (ast, mdz_names, context) => {
|
|
|
219
226
|
return;
|
|
220
227
|
// Parse and render each branch
|
|
221
228
|
const branch_results = [];
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
elements: context.elements,
|
|
228
|
-
base,
|
|
229
|
-
code_component_import: context.code_component_import,
|
|
230
|
-
codeblock_component_import: context.codeblock_component_import,
|
|
231
|
-
});
|
|
232
|
-
if (result.has_unconfigured_tags)
|
|
233
|
-
return;
|
|
234
|
-
branch_results.push({ markup: result.markup, imports: result.imports });
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
handle_preprocess_error(error, '[fuz-mdz]', context.filename, context.on_error);
|
|
239
|
-
return;
|
|
229
|
+
for (const branch of chain) {
|
|
230
|
+
const result = render_static_mdz(branch.value, base, context);
|
|
231
|
+
if (result === null)
|
|
232
|
+
return; // parse error or unconfigured tags — leave for runtime
|
|
233
|
+
branch_results.push({ markup: result.markup, imports: result.imports });
|
|
240
234
|
}
|
|
241
235
|
// Build {#if}/{:else if}/{:else} markup
|
|
242
236
|
let children_markup = '';
|
|
@@ -270,9 +264,9 @@ const find_mdz_usages = (ast, mdz_names, context) => {
|
|
|
270
264
|
replacement,
|
|
271
265
|
required_imports: merged_imports,
|
|
272
266
|
consumed_bindings: consumed,
|
|
273
|
-
component_node: node
|
|
267
|
+
component_node: node
|
|
274
268
|
});
|
|
275
|
-
}
|
|
269
|
+
}
|
|
276
270
|
});
|
|
277
271
|
return { transformations, total_usages, transformed_usages };
|
|
278
272
|
};
|
|
@@ -402,7 +396,7 @@ const find_removable_mdz_imports = (ast, mdz_names, total_usages, transformed_us
|
|
|
402
396
|
removable.set(name, {
|
|
403
397
|
node: positioned_node,
|
|
404
398
|
kind: 'partial',
|
|
405
|
-
specifier_to_remove: specifier
|
|
399
|
+
specifier_to_remove: specifier
|
|
406
400
|
});
|
|
407
401
|
}
|
|
408
402
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuzdev/mdz",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "a strict markdown dialect built for streaming, Svelte authoring, docs websites, and untrusted content",
|
|
5
5
|
"tagline": "markdown for fuz",
|
|
6
6
|
"glyph": "📝",
|
|
@@ -30,15 +30,22 @@
|
|
|
30
30
|
"deploy": "gro deploy",
|
|
31
31
|
"benchmark": "gro run src/benchmarks/mdz.benchmark.ts",
|
|
32
32
|
"benchmark:save": "gro run src/benchmarks/mdz.benchmark.ts --save",
|
|
33
|
-
"benchmark:clean": "rm -f src/benchmarks/baseline.json"
|
|
33
|
+
"benchmark:clean": "rm -f src/benchmarks/baseline.json",
|
|
34
|
+
"benchmark:render": "BENCHMARK_RENDER=1 gro test render.benchmark",
|
|
35
|
+
"benchmark:render:save": "BENCHMARK_RENDER=save gro test render.benchmark",
|
|
36
|
+
"benchmark:render:clean": "rm -f src/benchmarks/render/baseline.json"
|
|
34
37
|
},
|
|
35
38
|
"type": "module",
|
|
39
|
+
"imports": {
|
|
40
|
+
"#lib/*": "./src/lib/*",
|
|
41
|
+
"#routes/*": "./src/routes/*"
|
|
42
|
+
},
|
|
36
43
|
"engines": {
|
|
37
44
|
"node": ">=24.14"
|
|
38
45
|
},
|
|
39
46
|
"peerDependencies": {
|
|
40
47
|
"@fuzdev/fuz_util": ">=0.65.1",
|
|
41
|
-
"@sveltejs/kit": "^
|
|
48
|
+
"@sveltejs/kit": "^3",
|
|
42
49
|
"@types/estree": "^1",
|
|
43
50
|
"esm-env": "^1",
|
|
44
51
|
"svelte": "^5"
|
|
@@ -56,52 +63,33 @@
|
|
|
56
63
|
"zimmerframe": "^1.1.4"
|
|
57
64
|
},
|
|
58
65
|
"devDependencies": {
|
|
59
|
-
"@fuzdev/
|
|
60
|
-
"@fuzdev/fuz_code": "^0.
|
|
61
|
-
"@fuzdev/fuz_css": "^0.
|
|
62
|
-
"@fuzdev/fuz_ui": "^0.
|
|
63
|
-
"@fuzdev/fuz_util": "^0.
|
|
64
|
-
"@fuzdev/gro": "^0.
|
|
65
|
-
"@ryanatkn/eslint-config": "^0.12.
|
|
66
|
+
"@fuzdev/blake3-wasm": "^0.2.0",
|
|
67
|
+
"@fuzdev/fuz_code": "^0.50.0",
|
|
68
|
+
"@fuzdev/fuz_css": "^0.66.1",
|
|
69
|
+
"@fuzdev/fuz_ui": "^0.212.0",
|
|
70
|
+
"@fuzdev/fuz_util": "^0.72.0",
|
|
71
|
+
"@fuzdev/gro": "^0.214.0",
|
|
72
|
+
"@ryanatkn/eslint-config": "^0.12.2",
|
|
66
73
|
"@sveltejs/acorn-typescript": "^1.0.10",
|
|
67
|
-
"@sveltejs/adapter-static": "^
|
|
68
|
-
"@sveltejs/kit": "
|
|
69
|
-
"@sveltejs/package": "^
|
|
70
|
-
"@sveltejs/vite-plugin-svelte": "^7.1
|
|
74
|
+
"@sveltejs/adapter-static": "^4.0.0",
|
|
75
|
+
"@sveltejs/kit": "^3.0.1",
|
|
76
|
+
"@sveltejs/package": "^3.0.0",
|
|
77
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
71
78
|
"@types/estree": "^1.0.8",
|
|
72
79
|
"@types/node": "^24.12.4",
|
|
73
80
|
"@webref/css": "^8.2.0",
|
|
74
81
|
"eslint": "^9.39.1",
|
|
75
82
|
"eslint-plugin-svelte": "^3.13.1",
|
|
76
83
|
"esm-env": "^1.2.2",
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"svelte": "^
|
|
80
|
-
"svelte-check": "^4.6.0",
|
|
81
|
-
"svelte-docinfo": "^0.5.3",
|
|
84
|
+
"svelte": "^5.57.2",
|
|
85
|
+
"svelte-check": "^4.7.6",
|
|
86
|
+
"svelte-docinfo": "^0.8.0",
|
|
82
87
|
"svelte2tsx": "^0.7.56",
|
|
83
88
|
"tslib": "^2.8.1",
|
|
84
|
-
"typescript": "^
|
|
85
|
-
"typescript-eslint": "^8.
|
|
86
|
-
"vite": "^8.
|
|
87
|
-
"vitest": "^
|
|
88
|
-
},
|
|
89
|
-
"prettier": {
|
|
90
|
-
"plugins": [
|
|
91
|
-
"prettier-plugin-svelte"
|
|
92
|
-
],
|
|
93
|
-
"useTabs": true,
|
|
94
|
-
"printWidth": 100,
|
|
95
|
-
"singleQuote": true,
|
|
96
|
-
"bracketSpacing": false,
|
|
97
|
-
"overrides": [
|
|
98
|
-
{
|
|
99
|
-
"files": "package.json",
|
|
100
|
-
"options": {
|
|
101
|
-
"useTabs": false
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
]
|
|
89
|
+
"typescript": "^6.0.3",
|
|
90
|
+
"typescript-eslint": "^8.71.1",
|
|
91
|
+
"vite": "^8.3.4",
|
|
92
|
+
"vitest": "^5.0.0"
|
|
105
93
|
},
|
|
106
94
|
"sideEffects": [
|
|
107
95
|
"**/*.css"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {getContext, setContext} from 'svelte';
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
2
|
|
|
3
3
|
// This uses a function instead of a class because of the overloaded type signatures.
|
|
4
4
|
// It could be implemented internally with a class like `SvelteContext`
|
|
@@ -47,6 +47,6 @@ export function create_context<T>(fallback?: () => T): {
|
|
|
47
47
|
},
|
|
48
48
|
get_maybe,
|
|
49
49
|
// this is typesafe, so no runtime check:
|
|
50
|
-
set: (value: T | undefined = fallback?.()) => setContext(key, value)
|
|
50
|
+
set: (value: T | undefined = fallback?.()) => setContext(key, value)!
|
|
51
51
|
};
|
|
52
52
|
}
|
package/src/lib/mdz.ts
CHANGED
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
* @module
|
|
51
51
|
*/
|
|
52
52
|
|
|
53
|
-
import {MdzLexer} from './mdz_lexer.ts';
|
|
54
|
-
import {MdzTokenParser} from './mdz_token_parser.ts';
|
|
53
|
+
import { MdzLexer } from './mdz_lexer.ts';
|
|
54
|
+
import { MdzTokenParser } from './mdz_token_parser.ts';
|
|
55
55
|
|
|
56
56
|
// TODO design incremental parsing or some system that preserves Svelte components across re-renders when possible
|
|
57
57
|
|
|
@@ -89,6 +89,15 @@ export class MdzTableCellParser {
|
|
|
89
89
|
this.#lexer = new MdzLexer(text);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Rebind to a new buffer so one instance serves a whole table — the
|
|
94
|
+
* streaming path rebinds per row (the buffer string changes across feeds;
|
|
95
|
+
* the lexer's search memo survives when it doesn't).
|
|
96
|
+
*/
|
|
97
|
+
rebind(text: string): void {
|
|
98
|
+
this.#lexer.rebind(text);
|
|
99
|
+
}
|
|
100
|
+
|
|
92
101
|
parse(cell_start: number, cell_end: number): Array<MdzNode> {
|
|
93
102
|
this.#parser.reset(this.#lexer.lex_table_cell(cell_start, cell_end));
|
|
94
103
|
return this.#parser.parse_inline_run();
|
package/src/lib/mdz_contexts.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {Component} from 'svelte';
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
2
|
|
|
3
|
-
import {create_context} from './context_helpers.ts';
|
|
3
|
+
import { create_context } from './context_helpers.ts';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Component registry for custom Svelte components that can be used in mdz content.
|
|
@@ -56,7 +56,7 @@ export const mdz_base_context = create_context<() => string | undefined>();
|
|
|
56
56
|
* content as `reference` — the prop name matches `fuz_ui`'s `DocsLink`, so it
|
|
57
57
|
* can be injected directly to auto-link backticked API identifiers.
|
|
58
58
|
*/
|
|
59
|
-
export type MdzCodeComponent = Component<{reference: string}>;
|
|
59
|
+
export type MdzCodeComponent = Component<{ reference: string }>;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Context for overriding how inline `` `code` `` spans render, via a getter
|
|
@@ -69,7 +69,7 @@ export const mdz_code_context = create_context<() => MdzCodeComponent | undefine
|
|
|
69
69
|
* matching `@fuzdev/fuz_code`'s `Code`, so it can be injected directly for
|
|
70
70
|
* syntax highlighting.
|
|
71
71
|
*/
|
|
72
|
-
export type MdzCodeblockComponent = Component<{lang: string | null; content: string}>;
|
|
72
|
+
export type MdzCodeblockComponent = Component<{ lang: string | null; content: string }>;
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* Context for overriding how fenced code blocks render, via a getter function.
|
|
@@ -92,7 +92,7 @@ interface MdzGetterContext<T> {
|
|
|
92
92
|
*/
|
|
93
93
|
export const mdz_set_context_with_fallback = <T>(
|
|
94
94
|
context: MdzGetterContext<T>,
|
|
95
|
-
value_fn: () => T | undefined
|
|
95
|
+
value_fn: () => T | undefined
|
|
96
96
|
): void => {
|
|
97
97
|
const ancestor = context.get_maybe();
|
|
98
98
|
context.set(() => value_fn() ?? ancestor?.());
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic scan-work counter for the complexity-ratio guards
|
|
3
|
+
* (`mdz_scaling_ratio.test.ts`). Off by default; when `enabled`, the parser hot
|
|
4
|
+
* paths accumulate the number of characters scanned (and tag-stack frames
|
|
5
|
+
* walked) into `total`. Unlike wall-clock timing this is a pure function of
|
|
6
|
+
* input + algorithm — invariant across machines, runs, and thermal state — so a
|
|
7
|
+
* super-linear regression shows up as a work ratio > ~linear regardless of the
|
|
8
|
+
* ~2× machine variance that makes absolute timing unusable here. Its sole
|
|
9
|
+
* consumer is `mdz_scaling_ratio.test.ts`.
|
|
10
|
+
*
|
|
11
|
+
* Coverage is the dominant re-scan choke points — `#index_of` + `#tokenize_text`
|
|
12
|
+
* (sync) and the streaming memo scans, `consume_text_run`, and `try_close_tag`'s
|
|
13
|
+
* stack walk — not every scan. A super-linear regression isolated to an
|
|
14
|
+
* *uncounted* probe (e.g. `#has_paragraph_break_between`, the tag-name collection
|
|
15
|
+
* loop, the URL/path probes) wouldn't move the ratio; extend the instrumentation
|
|
16
|
+
* if hot cost ever migrates there.
|
|
17
|
+
*
|
|
18
|
+
* Zero store when disabled: each instrumented site guards on `enabled` (a single
|
|
19
|
+
* branch-predicted property load, the same category as the shipped `DEV`
|
|
20
|
+
* checks). It is deliberately NOT the `esm-env` `DEV` flag — `DEV` is true under
|
|
21
|
+
* every `gro test`/`gro dev` run, which would leave the counter live in ordinary
|
|
22
|
+
* development; this flag is flipped true only by the ratio test.
|
|
23
|
+
*
|
|
24
|
+
* @nodocs
|
|
25
|
+
*/
|
|
26
|
+
export const mdz_debug_work: { enabled: boolean; total: number } = { enabled: false, total: 0 };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reset the counter and set whether the hot paths accumulate into it. Tests call
|
|
30
|
+
* `mdz_debug_work_reset()` immediately before a parse and read
|
|
31
|
+
* `mdz_debug_work.total` immediately after; pass `false` to disable and zero it.
|
|
32
|
+
*
|
|
33
|
+
* @nodocs
|
|
34
|
+
*/
|
|
35
|
+
export const mdz_debug_work_reset = (enabled = true): void => {
|
|
36
|
+
mdz_debug_work.enabled = enabled;
|
|
37
|
+
mdz_debug_work.total = 0;
|
|
38
|
+
};
|