@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
package/README.md
CHANGED
|
@@ -27,6 +27,10 @@ For more see the [docs](https://mdz.fuz.dev/docs).
|
|
|
27
27
|
AI disclosure: almost everything here was generated by machine agents except
|
|
28
28
|
for the designs and intros. mdz is the result of 5+ years of prototyping ideas.
|
|
29
29
|
|
|
30
|
+
> ⚠️ This project is pre-stable: breaking changes are expected and
|
|
31
|
+
> some features (like attributes) are not yet implemented.
|
|
32
|
+
> Feedback is welcome!
|
|
33
|
+
|
|
30
34
|
## License
|
|
31
35
|
|
|
32
36
|
[MIT](LICENSE)
|
package/dist/Mdz.svelte
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type {SvelteHTMLElements} from 'svelte/elements';
|
|
3
|
+
import {DEV} from 'esm-env';
|
|
3
4
|
|
|
4
|
-
import {mdz_parse} from './mdz.js';
|
|
5
|
+
import {mdz_parse, type MdzNode} from './mdz.js';
|
|
5
6
|
import MdzNodeView from './MdzNodeView.svelte';
|
|
6
7
|
import {
|
|
7
8
|
mdz_base_context,
|
|
@@ -11,12 +12,12 @@
|
|
|
11
12
|
|
|
12
13
|
const {
|
|
13
14
|
content,
|
|
15
|
+
nodes: nodes_prop,
|
|
14
16
|
inline = false,
|
|
15
17
|
whitespace,
|
|
16
18
|
base,
|
|
17
19
|
...rest
|
|
18
20
|
}: (SvelteHTMLElements['div'] | SvelteHTMLElements['span']) & {
|
|
19
|
-
content: string;
|
|
20
21
|
inline?: boolean;
|
|
21
22
|
/**
|
|
22
23
|
* Sets `white-space` on the wrapper. When omitted, whitespace collapses
|
|
@@ -25,15 +26,22 @@
|
|
|
25
26
|
*/
|
|
26
27
|
whitespace?: MdzWhitespace;
|
|
27
28
|
base?: string;
|
|
28
|
-
}
|
|
29
|
+
} & // pass `content` to parse at render, or `nodes` to render a pre-parsed
|
|
30
|
+
// tree (e.g. build-time-parsed docs content) and skip `mdz_parse` entirely
|
|
31
|
+
(| {content: string; nodes?: undefined}
|
|
32
|
+
| {content?: undefined; nodes: Array<MdzNode>}
|
|
33
|
+
) = $props();
|
|
29
34
|
|
|
30
35
|
mdz_set_context_with_fallback(mdz_base_context, () => base);
|
|
31
36
|
|
|
32
|
-
const nodes = $derived(
|
|
37
|
+
const nodes = $derived.by(() => {
|
|
38
|
+
if (DEV && (content === undefined) === (nodes_prop === undefined)) {
|
|
39
|
+
throw new Error('Mdz: pass exactly one of `content` or `nodes`');
|
|
40
|
+
}
|
|
41
|
+
return nodes_prop ?? mdz_parse(content ?? '');
|
|
42
|
+
});
|
|
33
43
|
</script>
|
|
34
44
|
|
|
35
45
|
<svelte:element this={inline ? 'span' : 'div'} {...rest} style:white-space={whitespace}>
|
|
36
|
-
{
|
|
37
|
-
<MdzNodeView {node} />
|
|
38
|
-
{/each}
|
|
46
|
+
<MdzNodeView {nodes} />
|
|
39
47
|
</svelte:element>
|
package/dist/Mdz.svelte.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SvelteHTMLElements } from 'svelte/elements';
|
|
2
|
+
import { type MdzNode } from './mdz.js';
|
|
2
3
|
import { type MdzWhitespace } from './mdz_contexts.js';
|
|
3
4
|
type $$ComponentProps = (SvelteHTMLElements['div'] | SvelteHTMLElements['span']) & {
|
|
4
|
-
content: string;
|
|
5
5
|
inline?: boolean;
|
|
6
6
|
/**
|
|
7
7
|
* Sets `white-space` on the wrapper. When omitted, whitespace collapses
|
|
@@ -10,7 +10,14 @@ type $$ComponentProps = (SvelteHTMLElements['div'] | SvelteHTMLElements['span'])
|
|
|
10
10
|
*/
|
|
11
11
|
whitespace?: MdzWhitespace;
|
|
12
12
|
base?: string;
|
|
13
|
-
}
|
|
13
|
+
} & // pass `content` to parse at render, or `nodes` to render a pre-parsed
|
|
14
|
+
({
|
|
15
|
+
content: string;
|
|
16
|
+
nodes?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
content?: undefined;
|
|
19
|
+
nodes: Array<MdzNode>;
|
|
20
|
+
});
|
|
14
21
|
declare const Mdz: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
15
22
|
type Mdz = ReturnType<typeof Mdz>;
|
|
16
23
|
export default Mdz;
|
package/dist/Mdz.svelte.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mdz.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/Mdz.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Mdz.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/Mdz.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,UAAU,CAAC;AAEjD,OAAO,EAGL,KAAK,aAAa,EAClB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,gBAAgB,GAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,uEAAuE;AAE1E,CAAG;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAC,GACpC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;CAAC,CAC9C,CAAC;AAkCJ,QAAA,MAAM,GAAG,sDAAwC,CAAC;AAClD,KAAK,GAAG,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,CAAC;AAClC,eAAe,GAAG,CAAC"}
|
package/dist/MdzNodeView.svelte
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import {resolve} from '$app/paths';
|
|
3
3
|
|
|
4
|
-
import type {MdzNode} from './mdz.js';
|
|
5
|
-
import {
|
|
6
|
-
mdz_resolve_relative_path,
|
|
7
|
-
mdz_is_safe_reference,
|
|
8
|
-
mdz_is_void_element,
|
|
9
|
-
} from './mdz_helpers.js';
|
|
10
|
-
import MdzNodeView from './MdzNodeView.svelte';
|
|
4
|
+
import type {MdzNode, MdzNodeTableRow, MdzTableAlign} from './mdz.js';
|
|
5
|
+
import {mdz_classify_link, mdz_is_void_element} from './mdz_helpers.js';
|
|
11
6
|
import {
|
|
12
7
|
mdz_components_context,
|
|
13
8
|
mdz_elements_context,
|
|
@@ -18,9 +13,10 @@
|
|
|
18
13
|
|
|
19
14
|
const {
|
|
20
15
|
node,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
nodes,
|
|
17
|
+
}: // exactly one of `node`/`nodes` — the array form renders a whole tree
|
|
18
|
+
// through this single component instance (used by `Mdz`)
|
|
19
|
+
{node: MdzNode; nodes?: undefined} | {node?: undefined; nodes: Array<MdzNode>} = $props();
|
|
24
20
|
|
|
25
21
|
const get_components = mdz_components_context.get_maybe();
|
|
26
22
|
const get_elements = mdz_elements_context.get_maybe();
|
|
@@ -29,103 +25,142 @@
|
|
|
29
25
|
const get_codeblock = mdz_codeblock_context.get_maybe();
|
|
30
26
|
</script>
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
<!-- The tree renders through recursive snippets rather than recursive
|
|
29
|
+
component instances — one component (and one set of context reads) per
|
|
30
|
+
tree instead of per node. -->
|
|
31
|
+
{#if nodes}
|
|
32
|
+
{@render render_children(nodes)}
|
|
33
|
+
{:else if node}
|
|
34
|
+
{@render render_node(node)}
|
|
35
|
+
{/if}
|
|
36
|
+
|
|
37
|
+
{#snippet render_node(node: MdzNode)}
|
|
38
|
+
{#if node.type === 'Element'}
|
|
39
|
+
{@const element_config = get_elements?.()?.get(node.name)}
|
|
40
|
+
{#if element_config !== undefined}
|
|
41
|
+
{#if mdz_is_void_element(node.name)}
|
|
42
|
+
<!-- void elements cannot have content — any parsed children are dropped -->
|
|
43
|
+
<svelte:element this={node.name} />
|
|
44
|
+
{:else}
|
|
45
|
+
<svelte:element this={node.name}>
|
|
46
|
+
{#if node.children.length > 0}
|
|
47
|
+
{@render render_children(node.children)}
|
|
48
|
+
{/if}
|
|
49
|
+
</svelte:element>
|
|
50
|
+
{/if}
|
|
38
51
|
{:else}
|
|
39
|
-
|
|
52
|
+
{@render render_unregistered_tag(node.name, node.children)}
|
|
53
|
+
{/if}
|
|
54
|
+
{:else if node.type === 'Component'}
|
|
55
|
+
{@const Component = get_components?.()?.get(node.name)}
|
|
56
|
+
{#if Component}
|
|
57
|
+
<Component>
|
|
40
58
|
{#if node.children.length > 0}
|
|
41
59
|
{@render render_children(node.children)}
|
|
42
60
|
{/if}
|
|
43
|
-
</
|
|
61
|
+
</Component>
|
|
62
|
+
{:else}
|
|
63
|
+
{@render render_unregistered_tag(node.name, node.children)}
|
|
44
64
|
{/if}
|
|
45
|
-
{:else}
|
|
46
|
-
{
|
|
47
|
-
{
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</
|
|
56
|
-
{:else}
|
|
57
|
-
{@render
|
|
58
|
-
{
|
|
59
|
-
{
|
|
60
|
-
{node.
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{/if}
|
|
68
|
-
{:else if node.type === 'Bold'}
|
|
69
|
-
<strong>{@render render_children(node.children)}</strong>
|
|
70
|
-
{:else if node.type === 'Italic'}
|
|
71
|
-
<em>{@render render_children(node.children)}</em>
|
|
72
|
-
{:else if node.type === 'Strikethrough'}
|
|
73
|
-
<s>{@render render_children(node.children)}</s>
|
|
74
|
-
{:else if node.type === 'Link'}
|
|
75
|
-
{@const {reference} = node}
|
|
76
|
-
{#if !mdz_is_safe_reference(reference)}
|
|
77
|
-
{@render render_children(node.children)}
|
|
78
|
-
{:else if node.link_type === 'internal'}
|
|
79
|
-
{@const skip_resolve = reference.startsWith('#') || reference.startsWith('?')}
|
|
80
|
-
{@const mdz_base = get_mdz_base?.()}
|
|
81
|
-
{#if reference.startsWith('.') && mdz_base}
|
|
82
|
-
{@const resolved = mdz_resolve_relative_path(reference, mdz_base)}
|
|
83
|
-
<a href={resolve(resolved as any)}>{@render render_children(node.children)}</a>
|
|
84
|
-
{:else if skip_resolve || reference.startsWith('.') || !reference.startsWith('/')}
|
|
85
|
-
<!-- Fragment, query, and relative links (including bare references like `foo`) skip resolve() -->
|
|
86
|
-
<!-- resolve() only accepts absolute pathnames or route IDs and throws on anything else -->
|
|
65
|
+
{:else if node.type === 'Text'}
|
|
66
|
+
{node.content}
|
|
67
|
+
{:else if node.type === 'Code'}
|
|
68
|
+
{@const Code = get_code?.()}
|
|
69
|
+
{#if Code}
|
|
70
|
+
<Code reference={node.content} />
|
|
71
|
+
{:else}
|
|
72
|
+
<code>{node.content}</code>
|
|
73
|
+
{/if}
|
|
74
|
+
{:else if node.type === 'Bold'}
|
|
75
|
+
<strong>{@render render_children(node.children)}</strong>
|
|
76
|
+
{:else if node.type === 'Italic'}
|
|
77
|
+
<em>{@render render_children(node.children)}</em>
|
|
78
|
+
{:else if node.type === 'Strikethrough'}
|
|
79
|
+
<s>{@render render_children(node.children)}</s>
|
|
80
|
+
{:else if node.type === 'Link'}
|
|
81
|
+
{@const link = mdz_classify_link(node.reference, node.link_type, get_mdz_base?.())}
|
|
82
|
+
{#if link.kind === 'unsafe'}
|
|
83
|
+
{@render render_children(node.children)}
|
|
84
|
+
{:else if link.kind === 'resolve'}
|
|
85
|
+
<a href={resolve(link.href as any)}>{@render render_children(node.children)}</a>
|
|
86
|
+
{:else if link.kind === 'external'}
|
|
87
87
|
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
88
|
-
<a href={
|
|
88
|
+
<a href={link.href} target="_blank" rel="noopener">{@render render_children(node.children)}</a
|
|
89
|
+
>
|
|
89
90
|
{:else}
|
|
90
|
-
|
|
91
|
+
<!-- fragment/query/relative/bare references skip resolve() (it accepts only absolute paths) -->
|
|
92
|
+
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
93
|
+
<a href={link.href}>{@render render_children(node.children)}</a>
|
|
91
94
|
{/if}
|
|
92
|
-
{:else}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
{:else
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
{:else if node.type === 'Paragraph'}
|
|
96
|
+
<p>{@render render_children(node.children)}</p>
|
|
97
|
+
{:else if node.type === 'List'}
|
|
98
|
+
{#if node.ordered}
|
|
99
|
+
<ol start={node.start_number === 1 ? undefined : node.start_number}>
|
|
100
|
+
{@render render_children(node.children)}
|
|
101
|
+
</ol>
|
|
102
|
+
{:else}
|
|
103
|
+
<ul>{@render render_children(node.children)}</ul>
|
|
104
|
+
{/if}
|
|
105
|
+
{:else if node.type === 'ListItem'}
|
|
106
|
+
<li>{@render render_children(node.children)}</li>
|
|
107
|
+
{:else if node.type === 'Blockquote'}
|
|
108
|
+
<blockquote>{@render render_children(node.children)}</blockquote>
|
|
109
|
+
{:else if node.type === 'Table'}
|
|
110
|
+
<!-- by grammar the header row is always first (and the only one) — read
|
|
111
|
+
it by index and skip it per-row in the body, rather than filtering
|
|
112
|
+
twice (matches the streaming view, where a filter would go O(n²)
|
|
113
|
+
across a streamed table) -->
|
|
114
|
+
{@const header_row = node.children[0]?.header ? node.children[0] : undefined}
|
|
115
|
+
<table>
|
|
116
|
+
{#if header_row}
|
|
117
|
+
<thead>
|
|
118
|
+
<tr>{@render render_cells(header_row, 'th', node.align)}</tr>
|
|
119
|
+
</thead>
|
|
120
|
+
{/if}
|
|
121
|
+
{#if node.children.length > (header_row ? 1 : 0)}
|
|
122
|
+
<tbody>
|
|
123
|
+
{#each node.children as row, i (i)}
|
|
124
|
+
{#if !row.header}
|
|
125
|
+
<tr>{@render render_cells(row, 'td', node.align)}</tr>
|
|
126
|
+
{/if}
|
|
127
|
+
{/each}
|
|
128
|
+
</tbody>
|
|
129
|
+
{/if}
|
|
130
|
+
</table>
|
|
131
|
+
{:else if node.type === 'Hr'}
|
|
132
|
+
<hr />
|
|
133
|
+
{:else if node.type === 'Heading'}
|
|
134
|
+
<svelte:element this={`h${node.level}`} id={node.id || undefined}>
|
|
102
135
|
{@render render_children(node.children)}
|
|
103
|
-
</
|
|
104
|
-
{:else}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
|
|
111
|
-
{:else if node.type === 'Hr'}
|
|
112
|
-
<hr />
|
|
113
|
-
{:else if node.type === 'Heading'}
|
|
114
|
-
<svelte:element this={`h${node.level}`} id={node.id || undefined}>
|
|
115
|
-
{@render render_children(node.children)}
|
|
116
|
-
</svelte:element>
|
|
117
|
-
{:else if node.type === 'Codeblock'}
|
|
118
|
-
{@const Codeblock = get_codeblock?.()}
|
|
119
|
-
{#if Codeblock}
|
|
120
|
-
<Codeblock lang={node.lang} content={node.content} />
|
|
121
|
-
{:else}
|
|
122
|
-
<pre><code>{node.content}</code></pre>
|
|
136
|
+
</svelte:element>
|
|
137
|
+
{:else if node.type === 'Codeblock'}
|
|
138
|
+
{@const Codeblock = get_codeblock?.()}
|
|
139
|
+
{#if Codeblock}
|
|
140
|
+
<Codeblock lang={node.lang} content={node.content} />
|
|
141
|
+
{:else}
|
|
142
|
+
<pre><code>{node.content}</code></pre>
|
|
143
|
+
{/if}
|
|
123
144
|
{/if}
|
|
124
|
-
{/
|
|
145
|
+
{/snippet}
|
|
125
146
|
|
|
126
147
|
{#snippet render_children(nodes: Array<MdzNode>)}
|
|
127
|
-
|
|
128
|
-
|
|
148
|
+
<!-- index keys, not object identity: `mdz_parse` yields a fresh node graph
|
|
149
|
+
on every `content` change, so identity keys never match and Svelte rebuilds
|
|
150
|
+
the whole subtree; positional keys let it patch in place. (Sync nodes have
|
|
151
|
+
no stable id; the stream view keys by `node.id`.) -->
|
|
152
|
+
{#each nodes as node, i (i)}
|
|
153
|
+
{@render render_node(node)}
|
|
154
|
+
{/each}
|
|
155
|
+
{/snippet}
|
|
156
|
+
|
|
157
|
+
{#snippet render_cells(row: MdzNodeTableRow, tag: 'th' | 'td', align: Array<MdzTableAlign>)}
|
|
158
|
+
<!-- normalize to the column count: pad short rows, ignore extra cells -->
|
|
159
|
+
{#each align as a, i (i)}
|
|
160
|
+
{@const cell = row.children[i]}
|
|
161
|
+
<svelte:element this={tag} style={a ? `text-align:${a}` : undefined}>
|
|
162
|
+
{#if cell}{@render render_children(cell.children)}{/if}
|
|
163
|
+
</svelte:element>
|
|
129
164
|
{/each}
|
|
130
165
|
{/snippet}
|
|
131
166
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { MdzNode } from './mdz.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
type $$ComponentProps = // exactly one of `node`/`nodes` — the array form renders a whole tree
|
|
3
|
+
{
|
|
4
4
|
node: MdzNode;
|
|
5
|
+
nodes?: undefined;
|
|
6
|
+
} | {
|
|
7
|
+
node?: undefined;
|
|
8
|
+
nodes: Array<MdzNode>;
|
|
5
9
|
};
|
|
6
10
|
declare const MdzNodeView: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
11
|
type MdzNodeView = ReturnType<typeof MdzNodeView>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MdzNodeView.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/MdzNodeView.svelte"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"MdzNodeView.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/MdzNodeView.svelte"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,OAAO,EAAiC,MAAM,UAAU,CAAC;AAUrE,KAAK,gBAAgB,GAEpB,AAFwB,sEAAsE;AAE9F;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAC,GAAG;IAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;CAAC,CAAC;AAgKjF,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
package/dist/MdzStream.svelte
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</script>
|
|
32
32
|
|
|
33
33
|
<svelte:element this={inline ? 'span' : 'div'} {...rest} style:white-space={whitespace}>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{
|
|
34
|
+
<!-- the array form renders the whole stream through one MdzStreamNodeView
|
|
35
|
+
instance (one set of context reads) instead of one per top-level block -->
|
|
36
|
+
<MdzStreamNodeView nodes={stream.root} />
|
|
37
37
|
</svelte:element>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MdzStream.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/MdzStream.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAGL,KAAK,aAAa,EAClB,MAAM,mBAAmB,CAAC;AAC5B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAEhE,KAAK,gBAAgB,GAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG;IACnF,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;
|
|
1
|
+
{"version":3,"file":"MdzStream.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/MdzStream.svelte"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAGxD,OAAO,EAGL,KAAK,aAAa,EAClB,MAAM,mBAAmB,CAAC;AAC5B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AAEhE,KAAK,gBAAgB,GAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG;IACnF,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AA0BH,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import {resolve} from '$app/paths';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
mdz_resolve_relative_path,
|
|
6
|
-
mdz_is_safe_reference,
|
|
7
|
-
mdz_is_void_element,
|
|
8
|
-
} from './mdz_helpers.js';
|
|
9
|
-
import MdzStreamNodeView from './MdzStreamNodeView.svelte';
|
|
4
|
+
import {mdz_classify_link, mdz_is_void_element} from './mdz_helpers.js';
|
|
10
5
|
import {
|
|
11
6
|
mdz_components_context,
|
|
12
7
|
mdz_elements_context,
|
|
@@ -15,12 +10,15 @@
|
|
|
15
10
|
mdz_codeblock_context,
|
|
16
11
|
} from './mdz_contexts.js';
|
|
17
12
|
import type {MdzStreamNode} from './mdz_stream_state.svelte.js';
|
|
13
|
+
import type {MdzTableAlign} from './mdz.js';
|
|
18
14
|
|
|
19
15
|
const {
|
|
20
16
|
node,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
nodes,
|
|
18
|
+
}: // exactly one of `node`/`nodes` — the array form renders a whole tree
|
|
19
|
+
// through this single component instance (used by `MdzStream`)
|
|
20
|
+
{node: MdzStreamNode; nodes?: undefined} | {node?: undefined; nodes: Array<MdzStreamNode>} =
|
|
21
|
+
$props();
|
|
24
22
|
|
|
25
23
|
const get_components = mdz_components_context.get_maybe();
|
|
26
24
|
const get_elements = mdz_elements_context.get_maybe();
|
|
@@ -37,105 +35,141 @@
|
|
|
37
35
|
n.content || n.children.map((c) => c.content).join('');
|
|
38
36
|
</script>
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
<!-- The tree renders through recursive snippets rather than recursive
|
|
39
|
+
component instances — one component (and one set of context reads) per
|
|
40
|
+
tree instead of per node. -->
|
|
41
|
+
{#if nodes}
|
|
42
|
+
{@render render_children(nodes)}
|
|
43
|
+
{:else if node}
|
|
44
|
+
{@render render_node(node)}
|
|
45
|
+
{/if}
|
|
46
|
+
|
|
47
|
+
{#snippet render_node(node: MdzStreamNode)}
|
|
48
|
+
{#if node.type === 'Element'}
|
|
49
|
+
{@const element_config = get_elements?.()?.get(node.name ?? '')}
|
|
50
|
+
{#if element_config !== undefined}
|
|
51
|
+
{#if mdz_is_void_element(node.name ?? '')}
|
|
52
|
+
<!-- void elements cannot have content — any parsed children are dropped -->
|
|
53
|
+
<svelte:element this={node.name} />
|
|
54
|
+
{:else}
|
|
55
|
+
<svelte:element this={node.name}>
|
|
56
|
+
{#if node.children.length > 0}
|
|
57
|
+
{@render render_children(node.children)}
|
|
58
|
+
{/if}
|
|
59
|
+
</svelte:element>
|
|
60
|
+
{/if}
|
|
46
61
|
{:else}
|
|
47
|
-
|
|
62
|
+
{@render render_unregistered_tag(node.name ?? '', node.children)}
|
|
63
|
+
{/if}
|
|
64
|
+
{:else if node.type === 'Component'}
|
|
65
|
+
{@const Component = get_components?.()?.get(node.name ?? '')}
|
|
66
|
+
{#if Component}
|
|
67
|
+
<Component>
|
|
48
68
|
{#if node.children.length > 0}
|
|
49
69
|
{@render render_children(node.children)}
|
|
50
70
|
{/if}
|
|
51
|
-
</
|
|
71
|
+
</Component>
|
|
72
|
+
{:else}
|
|
73
|
+
{@render render_unregistered_tag(node.name ?? '', node.children)}
|
|
52
74
|
{/if}
|
|
53
|
-
{:else}
|
|
54
|
-
{
|
|
55
|
-
{
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{:else if node.type === '
|
|
68
|
-
|
|
69
|
-
{:else if node.type === '
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{/if}
|
|
77
|
-
{:else if node.type === 'Bold'}
|
|
78
|
-
<strong>{@render render_children(node.children)}</strong>
|
|
79
|
-
{:else if node.type === 'Italic'}
|
|
80
|
-
<em>{@render render_children(node.children)}</em>
|
|
81
|
-
{:else if node.type === 'Strikethrough'}
|
|
82
|
-
<s>{@render render_children(node.children)}</s>
|
|
83
|
-
{:else if node.type === 'Link'}
|
|
84
|
-
{@const reference = node.reference ?? ''}
|
|
85
|
-
{#if !mdz_is_safe_reference(reference)}
|
|
86
|
-
{@render render_children(node.children)}
|
|
87
|
-
{:else if node.link_type === 'internal'}
|
|
88
|
-
{@const skip_resolve = reference.startsWith('#') || reference.startsWith('?')}
|
|
89
|
-
{@const mdz_base = get_mdz_base?.()}
|
|
90
|
-
{#if reference.startsWith('.') && mdz_base}
|
|
91
|
-
{@const resolved = mdz_resolve_relative_path(reference, mdz_base)}
|
|
92
|
-
<a href={resolve(resolved as any)}>{@render render_children(node.children)}</a>
|
|
93
|
-
{:else if skip_resolve || reference.startsWith('.') || !reference.startsWith('/')}
|
|
94
|
-
<!-- Fragment, query, and relative links (including bare references like `foo`) skip resolve() -->
|
|
95
|
-
<!-- resolve() only accepts absolute pathnames or route IDs and throws on anything else -->
|
|
75
|
+
{:else if node.type === 'Text'}
|
|
76
|
+
{node.content}
|
|
77
|
+
{:else if node.type === 'Code'}
|
|
78
|
+
{@const Code = get_code?.()}
|
|
79
|
+
{@const code_content = streaming_content(node)}
|
|
80
|
+
{#if Code}
|
|
81
|
+
<Code reference={code_content} />
|
|
82
|
+
{:else}
|
|
83
|
+
<code>{code_content}</code>
|
|
84
|
+
{/if}
|
|
85
|
+
{:else if node.type === 'Bold'}
|
|
86
|
+
<strong>{@render render_children(node.children)}</strong>
|
|
87
|
+
{:else if node.type === 'Italic'}
|
|
88
|
+
<em>{@render render_children(node.children)}</em>
|
|
89
|
+
{:else if node.type === 'Strikethrough'}
|
|
90
|
+
<s>{@render render_children(node.children)}</s>
|
|
91
|
+
{:else if node.type === 'Link'}
|
|
92
|
+
{@const link = mdz_classify_link(node.reference ?? '', node.link_type, get_mdz_base?.())}
|
|
93
|
+
{#if link.kind === 'unsafe'}
|
|
94
|
+
{@render render_children(node.children)}
|
|
95
|
+
{:else if link.kind === 'resolve'}
|
|
96
|
+
<a href={resolve(link.href as any)}>{@render render_children(node.children)}</a>
|
|
97
|
+
{:else if link.kind === 'external'}
|
|
96
98
|
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
97
|
-
<a href={
|
|
99
|
+
<a href={link.href} target="_blank" rel="noopener">{@render render_children(node.children)}</a
|
|
100
|
+
>
|
|
98
101
|
{:else}
|
|
99
|
-
|
|
102
|
+
<!-- fragment/query/relative/bare references skip resolve() (it accepts only absolute paths) -->
|
|
103
|
+
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
|
104
|
+
<a href={link.href}>{@render render_children(node.children)}</a>
|
|
100
105
|
{/if}
|
|
101
|
-
{:else}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
{:else
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
{:else if node.type === 'Paragraph'}
|
|
107
|
+
<p>{@render render_children(node.children)}</p>
|
|
108
|
+
{:else if node.type === 'List'}
|
|
109
|
+
{#if node.ordered}
|
|
110
|
+
<ol start={node.start_number === 1 ? undefined : node.start_number}>
|
|
111
|
+
{@render render_children(node.children)}
|
|
112
|
+
</ol>
|
|
113
|
+
{:else}
|
|
114
|
+
<ul>{@render render_children(node.children)}</ul>
|
|
115
|
+
{/if}
|
|
116
|
+
{:else if node.type === 'ListItem'}
|
|
117
|
+
<li>{@render render_children(node.children)}</li>
|
|
118
|
+
{:else if node.type === 'Blockquote'}
|
|
119
|
+
<blockquote>{@render render_children(node.children)}</blockquote>
|
|
120
|
+
{:else if node.type === 'Table'}
|
|
121
|
+
{@const align = node.align ?? []}
|
|
122
|
+
<!-- by grammar the header row is always first (and the only one) — read
|
|
123
|
+
it by index and skip it per-row in the body, rather than filtering: a
|
|
124
|
+
filter re-partitions every prior row on each streamed row append,
|
|
125
|
+
going O(n²) across a streamed table -->
|
|
126
|
+
{@const header_row = node.children[0]?.header ? node.children[0] : undefined}
|
|
127
|
+
<table>
|
|
128
|
+
{#if header_row}
|
|
129
|
+
<thead>
|
|
130
|
+
<tr>{@render render_cells(header_row, 'th', align)}</tr>
|
|
131
|
+
</thead>
|
|
132
|
+
{/if}
|
|
133
|
+
{#if node.children.length > (header_row ? 1 : 0)}
|
|
134
|
+
<tbody>
|
|
135
|
+
{#each node.children as row (row.id)}
|
|
136
|
+
{#if !row.header}
|
|
137
|
+
<tr>{@render render_cells(row, 'td', align)}</tr>
|
|
138
|
+
{/if}
|
|
139
|
+
{/each}
|
|
140
|
+
</tbody>
|
|
141
|
+
{/if}
|
|
142
|
+
</table>
|
|
143
|
+
{:else if node.type === 'Hr'}
|
|
144
|
+
<hr />
|
|
145
|
+
{:else if node.type === 'Heading'}
|
|
146
|
+
<svelte:element this={`h${node.level}`} id={node.heading_id || undefined}>
|
|
111
147
|
{@render render_children(node.children)}
|
|
112
|
-
</
|
|
113
|
-
{:else}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
|
|
118
|
-
{:else
|
|
119
|
-
|
|
120
|
-
{
|
|
121
|
-
<hr />
|
|
122
|
-
{:else if node.type === 'Heading'}
|
|
123
|
-
<svelte:element this={`h${node.level}`} id={node.heading_id || undefined}>
|
|
124
|
-
{@render render_children(node.children)}
|
|
125
|
-
</svelte:element>
|
|
126
|
-
{:else if node.type === 'Codeblock'}
|
|
127
|
-
{@const Codeblock = get_codeblock?.()}
|
|
128
|
-
{@const codeblock_content = streaming_content(node)}
|
|
129
|
-
{#if Codeblock}
|
|
130
|
-
<Codeblock lang={node.lang ?? null} content={codeblock_content} />
|
|
131
|
-
{:else}
|
|
132
|
-
<pre><code>{codeblock_content}</code></pre>
|
|
148
|
+
</svelte:element>
|
|
149
|
+
{:else if node.type === 'Codeblock'}
|
|
150
|
+
{@const Codeblock = get_codeblock?.()}
|
|
151
|
+
{@const codeblock_content = streaming_content(node)}
|
|
152
|
+
{#if Codeblock}
|
|
153
|
+
<Codeblock lang={node.lang ?? null} content={codeblock_content} />
|
|
154
|
+
{:else}
|
|
155
|
+
<pre><code>{codeblock_content}</code></pre>
|
|
156
|
+
{/if}
|
|
133
157
|
{/if}
|
|
134
|
-
{/
|
|
158
|
+
{/snippet}
|
|
135
159
|
|
|
136
160
|
{#snippet render_children(nodes: Array<MdzStreamNode>)}
|
|
137
161
|
{#each nodes as node (node.id)}
|
|
138
|
-
|
|
162
|
+
{@render render_node(node)}
|
|
163
|
+
{/each}
|
|
164
|
+
{/snippet}
|
|
165
|
+
|
|
166
|
+
{#snippet render_cells(row: MdzStreamNode, tag: 'th' | 'td', align: Array<MdzTableAlign>)}
|
|
167
|
+
<!-- normalize to the column count: pad short rows, ignore extra cells -->
|
|
168
|
+
{#each align as a, i (i)}
|
|
169
|
+
{@const cell = row.children[i]}
|
|
170
|
+
<svelte:element this={tag} style={a ? `text-align:${a}` : undefined}>
|
|
171
|
+
{#if cell}{@render render_children(cell.children)}{/if}
|
|
172
|
+
</svelte:element>
|
|
139
173
|
{/each}
|
|
140
174
|
{/snippet}
|
|
141
175
|
|