comark 0.3.2 → 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/README.md +25 -1
- package/dist/context.d.ts +78 -0
- package/dist/context.js +127 -0
- package/dist/devtools/bridge.d.ts +1 -0
- package/dist/devtools/bridge.js +1 -0
- package/dist/devtools/constants.d.ts +1 -0
- package/dist/devtools/constants.js +1 -0
- package/dist/devtools/renderer/dom.d.ts +1 -0
- package/dist/devtools/renderer/dom.js +1 -0
- package/dist/devtools/renderer/index.d.ts +2 -0
- package/dist/devtools/renderer/index.js +2 -0
- package/dist/devtools/renderer/output.d.ts +1 -0
- package/dist/devtools/renderer/output.js +1 -0
- package/dist/devtools/renderer/panel.d.ts +1 -0
- package/dist/devtools/renderer/panel.js +1 -0
- package/dist/devtools/renderer/styles.d.ts +1 -0
- package/dist/devtools/renderer/styles.js +1 -0
- package/dist/devtools/renderer/theme.d.ts +1 -0
- package/dist/devtools/renderer/theme.js +1 -0
- package/dist/devtools/types.d.ts +1 -0
- package/dist/devtools/types.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/internal/parse/auto-close/index.js +96 -31
- package/dist/internal/parse/auto-unwrap.js +5 -1
- package/dist/internal/parse/html/html_block_rule.js +9 -15
- package/dist/internal/parse/html/index.d.ts +1 -0
- package/dist/internal/parse/html/index.js +1 -1
- package/dist/internal/parse/token-processor.js +70 -32
- package/dist/internal/stringify/attributes.d.ts +8 -1
- package/dist/internal/stringify/attributes.js +53 -0
- package/dist/internal/stringify/handlers/blockquote.js +17 -0
- package/dist/internal/stringify/handlers/heading.js +6 -1
- package/dist/internal/stringify/handlers/html.js +8 -2
- package/dist/internal/stringify/handlers/li.js +19 -9
- package/dist/internal/stringify/handlers/mdc.js +1 -1
- package/dist/internal/stringify/handlers/ol.js +15 -2
- package/dist/internal/stringify/handlers/p.js +4 -0
- package/dist/internal/stringify/handlers/pre.js +11 -2
- package/dist/internal/stringify/handlers/table.js +7 -0
- package/dist/internal/stringify/handlers/template.js +4 -1
- package/dist/internal/stringify/handlers/ul.js +11 -1
- package/dist/internal/stringify/state.js +13 -1
- package/dist/parse.d.ts +4 -4
- package/dist/parse.js +7 -3
- package/dist/plugins/alert.d.ts +1 -1
- package/dist/plugins/binding.d.ts +1 -1
- package/dist/plugins/breaks.d.ts +1 -1
- package/dist/plugins/emoji.d.ts +1 -1
- package/dist/plugins/footnotes.d.ts +1 -1
- package/dist/plugins/headings.d.ts +19 -8
- package/dist/plugins/headings.js +25 -15
- package/dist/plugins/highlight.d.ts +1 -1
- package/dist/plugins/highlight.js +4 -2
- package/dist/plugins/json-render.d.ts +1 -1
- package/dist/plugins/math.d.ts +1 -1
- package/dist/plugins/mermaid.d.ts +1 -1
- package/dist/plugins/punctuation.d.ts +1 -1
- package/dist/plugins/security.d.ts +12 -1
- package/dist/plugins/security.js +13 -6
- package/dist/plugins/summary.d.ts +4 -1
- package/dist/plugins/syntax.d.ts +1 -1
- package/dist/plugins/syntax.js +95 -36
- package/dist/plugins/task-list.d.ts +1 -1
- package/dist/plugins/toc.d.ts +3 -1
- package/dist/render.d.ts +6 -2
- package/dist/render.js +2 -2
- package/dist/types.d.ts +61 -12
- package/dist/utils/helpers.d.ts +16 -4
- package/dist/utils/helpers.js +15 -3
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.js +30 -14
- package/package.json +6 -3
- package/skills/comark/references/rendering-svelte.md +51 -7
- package/dist/internal/stringify/indent.d.ts +0 -1
- package/dist/internal/stringify/indent.js +0 -1
- package/dist/vite.d.ts +0 -1
- package/dist/vite.js +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { DumpOptions } from 'js-yaml';
|
|
2
2
|
import type MarkdownExit from 'markdown-exit';
|
|
3
3
|
import type MarkdownIt from 'markdown-it';
|
|
4
|
+
/**
|
|
5
|
+
* The `[keyof T] extends [never]` form (rather than `keyof T extends never`)
|
|
6
|
+
* is the standard trick to prevent TS from distributing the check over a
|
|
7
|
+
* union — we want to test "is T's keyset empty?" as one yes/no question.
|
|
8
|
+
*/
|
|
9
|
+
type Writable<T> = [keyof T] extends [never] ? Record<string, any> : T;
|
|
4
10
|
/**
|
|
5
11
|
* The Comark text
|
|
6
12
|
* @param string - The text content
|
|
@@ -43,11 +49,14 @@ export type ComarkNode = ComarkElement | ComarkText | ComarkComment;
|
|
|
43
49
|
* @param nodes - The nodes of the tree
|
|
44
50
|
* @param frontmatter - The frontmatter data which is the data at the top of the file
|
|
45
51
|
* @param meta - The meta data of tree, it can be used to store additional data for the tree
|
|
52
|
+
*
|
|
53
|
+
* The `TMeta` and `TFrontmatter` type parameters allow `parse` / `createParse`
|
|
54
|
+
* to surface plugin-contributed keys with narrow types (see `MergePluginMeta`).
|
|
46
55
|
*/
|
|
47
|
-
export interface ComarkTree {
|
|
56
|
+
export interface ComarkTree<TMeta = Record<string, any>, TFrontmatter = Record<string, any>> {
|
|
48
57
|
nodes: ComarkNode[];
|
|
49
|
-
frontmatter:
|
|
50
|
-
meta:
|
|
58
|
+
frontmatter: TFrontmatter;
|
|
59
|
+
meta: TMeta;
|
|
51
60
|
}
|
|
52
61
|
export interface ContextBase {
|
|
53
62
|
/**
|
|
@@ -234,26 +243,60 @@ export type ComarkParsePreState = {
|
|
|
234
243
|
options: ParseOptions;
|
|
235
244
|
[key: string]: any;
|
|
236
245
|
};
|
|
237
|
-
export type ComarkParsePostState = {
|
|
246
|
+
export type ComarkParsePostState<TMeta = Record<string, any>, TFrontmatter = Record<string, any>> = {
|
|
238
247
|
markdown: string;
|
|
239
|
-
tree: ComarkTree
|
|
248
|
+
tree: ComarkTree<TMeta, TFrontmatter>;
|
|
240
249
|
options: ParseOptions;
|
|
241
250
|
tokens: unknown[];
|
|
242
251
|
[key: string]: any;
|
|
243
252
|
};
|
|
244
|
-
|
|
253
|
+
/**
|
|
254
|
+
* A Comark plugin.
|
|
255
|
+
*
|
|
256
|
+
* `TMeta` / `TFrontmatter` are phantom type parameters that record what this
|
|
257
|
+
* plugin contributes to `tree.meta` / `tree.frontmatter`. They are surfaced
|
|
258
|
+
* only via the optional `__meta` / `__frontmatter` markers — implementations
|
|
259
|
+
* never set these at runtime; they exist purely so the contribution survives
|
|
260
|
+
* `ReturnType<typeof factory>` inference and can be merged in `createParse`.
|
|
261
|
+
*/
|
|
262
|
+
export type ComarkPlugin<TMeta = {}, TFrontmatter = {}> = {
|
|
245
263
|
name: string;
|
|
246
264
|
markdownItPlugins?: MarkdownItPlugin[];
|
|
247
265
|
pre?: (state: ComarkParsePreState) => Promise<void> | void;
|
|
248
|
-
post?: (state: ComarkParsePostState) => Promise<void> | void;
|
|
266
|
+
post?: (state: ComarkParsePostState<Writable<TMeta>, Writable<TFrontmatter>>) => Promise<void> | void;
|
|
267
|
+
/** Phantom — used for type inference only. Never set at runtime. */
|
|
268
|
+
__meta?: TMeta;
|
|
269
|
+
/** Phantom — used for type inference only. Never set at runtime. */
|
|
270
|
+
__frontmatter?: TFrontmatter;
|
|
249
271
|
};
|
|
250
|
-
export type ComarkPluginFactory<Options> = (opts?: Options) => ComarkPlugin
|
|
251
|
-
|
|
272
|
+
export type ComarkPluginFactory<Options, TMeta = {}, TFrontmatter = {}> = (opts?: Options) => ComarkPlugin<TMeta, TFrontmatter>;
|
|
273
|
+
type PluginMetaOf<P> = P extends ComarkPlugin<infer M, any> ? M : {};
|
|
274
|
+
type PluginFrontmatterOf<P> = P extends ComarkPlugin<any, infer F> ? F : {};
|
|
275
|
+
/**
|
|
276
|
+
* Walk a tuple of plugins and intersect their meta contributions.
|
|
277
|
+
* Returns `{}` when the tuple is empty or when nothing was contributed.
|
|
278
|
+
*/
|
|
279
|
+
export type MergePluginMeta<TPlugins extends readonly unknown[]> = TPlugins extends readonly [infer Head, ...infer Rest] ? PluginMetaOf<Head> & MergePluginMeta<Rest extends readonly unknown[] ? Rest : []> : {};
|
|
280
|
+
/**
|
|
281
|
+
* Walk a tuple of plugins and intersect their frontmatter contributions.
|
|
282
|
+
*/
|
|
283
|
+
export type MergePluginFrontmatter<TPlugins extends readonly unknown[]> = TPlugins extends readonly [
|
|
284
|
+
infer Head,
|
|
285
|
+
...infer Rest
|
|
286
|
+
] ? PluginFrontmatterOf<Head> & MergePluginFrontmatter<Rest extends readonly unknown[] ? Rest : []> : {};
|
|
287
|
+
/**
|
|
288
|
+
* When no plugin contributed meta keys, fall back to the permissive
|
|
289
|
+
* `Record<string, any>` (backwards-compatible). Otherwise, preserve narrow
|
|
290
|
+
* keys and type unknown accesses as `unknown` (safer than `any`).
|
|
291
|
+
*/
|
|
292
|
+
export type ResolvedMeta<T> = [keyof T] extends [never] ? Record<string, any> : T & Record<string, unknown>;
|
|
293
|
+
export type ResolvedFrontmatter<T> = [keyof T] extends [never] ? Record<string, any> : T & Record<string, unknown>;
|
|
294
|
+
export type ComponentManifest = (name: string) => unknown | Promise<unknown> | undefined | null;
|
|
252
295
|
export interface ComarkContextProvider {
|
|
253
296
|
components: Record<string, any>;
|
|
254
297
|
componentManifest: ComponentManifest;
|
|
255
298
|
}
|
|
256
|
-
export interface ParseOptions {
|
|
299
|
+
export interface ParseOptions<TPlugins extends readonly ComarkPlugin<any, any>[] = readonly ComarkPlugin<any, any>[]> {
|
|
257
300
|
/**
|
|
258
301
|
* Whether to automatically unwrap single paragraphs in container components.
|
|
259
302
|
* When enabled, if a container component (alert, card, callout, note, warning, tip, info)
|
|
@@ -296,11 +339,16 @@ export interface ParseOptions {
|
|
|
296
339
|
* // With html: false — HTML tags are left as raw text / ignored
|
|
297
340
|
*/
|
|
298
341
|
html?: boolean;
|
|
342
|
+
/**
|
|
343
|
+
* Set `false` to disable autoconvert URL-like text to links.
|
|
344
|
+
* @default true
|
|
345
|
+
*/
|
|
346
|
+
linkify?: boolean;
|
|
299
347
|
/**
|
|
300
348
|
* Additional plugins to use
|
|
301
349
|
* @default []
|
|
302
350
|
*/
|
|
303
|
-
plugins?:
|
|
351
|
+
plugins?: TPlugins;
|
|
304
352
|
}
|
|
305
353
|
/**
|
|
306
354
|
* Type signature for the options object passed to the Comark parser function returned by createParse().
|
|
@@ -312,4 +360,5 @@ export type ComarkParseFnOptions = {
|
|
|
312
360
|
* Type signature for the async Comark parser function returned by createParse().
|
|
313
361
|
* Accepts a markdown string and optional parsing options, and returns a Promise of ComarkTree.
|
|
314
362
|
*/
|
|
315
|
-
export type ComarkParseFn = (markdown: string, opts?: ComarkParseFnOptions) => Promise<ComarkTree
|
|
363
|
+
export type ComarkParseFn<TMeta = Record<string, any>, TFrontmatter = Record<string, any>> = (markdown: string, opts?: ComarkParseFnOptions) => Promise<ComarkTree<TMeta, TFrontmatter>>;
|
|
364
|
+
export {};
|
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -5,8 +5,20 @@ import type { ComarkPluginFactory } from '../types.ts';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function createSerializedTask<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>): (...args: TArgs) => Promise<TResult>;
|
|
7
7
|
/**
|
|
8
|
-
* Define a Comark plugin
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Define a Comark plugin.
|
|
9
|
+
*
|
|
10
|
+
* `TMeta` and `TFrontmatter` declare what the plugin contributes to
|
|
11
|
+
* `tree.meta` / `tree.frontmatter`. They are inferred from the factory's
|
|
12
|
+
* return type when set via the `__meta` / `__frontmatter` phantom markers,
|
|
13
|
+
* or can be passed explicitly. Plugins that don't contribute typed keys can
|
|
14
|
+
* omit them entirely.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* defineComarkPlugin<Options, { toc: Toc }>((opts) => ({
|
|
19
|
+
* name: 'toc',
|
|
20
|
+
* post(state) { state.tree.meta.toc = ... },
|
|
21
|
+
* }))
|
|
22
|
+
* ```
|
|
11
23
|
*/
|
|
12
|
-
export declare function defineComarkPlugin<Options>(fn: ComarkPluginFactory<Options>): ComarkPluginFactory<Options>;
|
|
24
|
+
export declare function defineComarkPlugin<Options, TMeta = {}, TFrontmatter = {}>(fn: ComarkPluginFactory<Options, TMeta, TFrontmatter>): ComarkPluginFactory<Options, TMeta, TFrontmatter>;
|
package/dist/utils/helpers.js
CHANGED
|
@@ -11,9 +11,21 @@ export function createSerializedTask(fn) {
|
|
|
11
11
|
}
|
|
12
12
|
// #region define plugin
|
|
13
13
|
/**
|
|
14
|
-
* Define a Comark plugin
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Define a Comark plugin.
|
|
15
|
+
*
|
|
16
|
+
* `TMeta` and `TFrontmatter` declare what the plugin contributes to
|
|
17
|
+
* `tree.meta` / `tree.frontmatter`. They are inferred from the factory's
|
|
18
|
+
* return type when set via the `__meta` / `__frontmatter` phantom markers,
|
|
19
|
+
* or can be passed explicitly. Plugins that don't contribute typed keys can
|
|
20
|
+
* omit them entirely.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* defineComarkPlugin<Options, { toc: Toc }>((opts) => ({
|
|
25
|
+
* name: 'toc',
|
|
26
|
+
* post(state) { state.tree.meta.toc = ... },
|
|
27
|
+
* }))
|
|
28
|
+
* ```
|
|
17
29
|
*/
|
|
18
30
|
export function defineComarkPlugin(fn) {
|
|
19
31
|
return fn;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComarkNode, ComarkTree } from 'comark';
|
|
2
|
+
type VisitResult = ComarkNode | false | undefined | void;
|
|
2
3
|
/**
|
|
3
4
|
* Get the text content of a Comark node
|
|
4
5
|
*
|
|
@@ -17,7 +18,8 @@ export declare function textContent(node: ComarkNode, options?: {
|
|
|
17
18
|
* @param checker - A function that checks if a node should be visited
|
|
18
19
|
* @param visitor - A function that visits a node
|
|
19
20
|
*/
|
|
20
|
-
export declare function visit(tree: ComarkTree, checker: (node: ComarkNode) => boolean, visitor: (node: ComarkNode) =>
|
|
21
|
+
export declare function visit(tree: ComarkTree, checker: (node: ComarkNode) => boolean, visitor: (node: ComarkNode) => VisitResult): void;
|
|
22
|
+
export declare function visitAsync(tree: ComarkTree, checker: (node: ComarkNode) => boolean, visitor: (node: ComarkNode) => Promise<VisitResult> | VisitResult): Promise<void>;
|
|
21
23
|
export declare function indent(text: string, { ignoreFirstLine, level, width }?: {
|
|
22
24
|
ignoreFirstLine?: boolean;
|
|
23
25
|
level?: number;
|
package/dist/utils/index.js
CHANGED
|
@@ -22,20 +22,11 @@ export function textContent(node, options = {}) {
|
|
|
22
22
|
}
|
|
23
23
|
return out;
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
* @param tree - The Comark tree
|
|
29
|
-
* @param checker - A function that checks if a node should be visited
|
|
30
|
-
* @param visitor - A function that visits a node
|
|
31
|
-
*/
|
|
32
|
-
export function visit(tree, checker,
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
34
|
-
visitor) {
|
|
35
|
-
function walk(node, parent, index) {
|
|
25
|
+
function* walkGenerator(tree, checker) {
|
|
26
|
+
function* walk(node, parent, index) {
|
|
36
27
|
let currentNode = node;
|
|
37
28
|
if (checker(node)) {
|
|
38
|
-
const res =
|
|
29
|
+
const res = yield node;
|
|
39
30
|
if (res === false) {
|
|
40
31
|
// remove the node from the parent
|
|
41
32
|
;
|
|
@@ -52,7 +43,7 @@ visitor) {
|
|
|
52
43
|
// Use a while loop to handle removals correctly - don't increment if node was removed
|
|
53
44
|
let i = 2;
|
|
54
45
|
while (i < currentNode.length) {
|
|
55
|
-
const childRemoved = walk(currentNode[i], currentNode, i);
|
|
46
|
+
const childRemoved = yield* walk(currentNode[i], currentNode, i);
|
|
56
47
|
if (childRemoved) {
|
|
57
48
|
// If removed, i stays the same (next node is now at this index)
|
|
58
49
|
continue;
|
|
@@ -65,7 +56,7 @@ visitor) {
|
|
|
65
56
|
// Use a while loop to handle removals correctly - don't increment if node was removed
|
|
66
57
|
let i = 0;
|
|
67
58
|
while (i < tree.nodes.length) {
|
|
68
|
-
const removed = walk(tree.nodes[i], tree.nodes, i);
|
|
59
|
+
const removed = yield* walk(tree.nodes[i], tree.nodes, i);
|
|
69
60
|
if (removed) {
|
|
70
61
|
// If removed, i stays the same (next node is now at this index)
|
|
71
62
|
continue;
|
|
@@ -73,6 +64,31 @@ visitor) {
|
|
|
73
64
|
i += 1;
|
|
74
65
|
}
|
|
75
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Visit a Comark tree and apply a visitor function to each node
|
|
69
|
+
*
|
|
70
|
+
* @param tree - The Comark tree
|
|
71
|
+
* @param checker - A function that checks if a node should be visited
|
|
72
|
+
* @param visitor - A function that visits a node
|
|
73
|
+
*/
|
|
74
|
+
export function visit(tree, checker,
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
76
|
+
visitor) {
|
|
77
|
+
const iterator = walkGenerator(tree, checker);
|
|
78
|
+
let step = iterator.next();
|
|
79
|
+
while (!step.done) {
|
|
80
|
+
const res = visitor(step.value);
|
|
81
|
+
step = iterator.next(res);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export async function visitAsync(tree, checker, visitor) {
|
|
85
|
+
const iterator = walkGenerator(tree, checker);
|
|
86
|
+
let step = iterator.next();
|
|
87
|
+
while (!step.done) {
|
|
88
|
+
const res = await visitor(step.value);
|
|
89
|
+
step = iterator.next(res);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
76
92
|
// #region String Utils
|
|
77
93
|
export function indent(text, { ignoreFirstLine = false, level = 1, width } = {}) {
|
|
78
94
|
const pad = width ? ' '.repeat(width) : ' '.repeat(level);
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comark",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Components in Markdown (Comark) parser with streaming support for Vue, React, Svelte and HTML",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Components in Markdown (Comark) parser with streaming support for Vue, React, Svelte, Angular and HTML",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"angular",
|
|
6
7
|
"markdown",
|
|
7
8
|
"mdc",
|
|
8
9
|
"parser",
|
|
9
10
|
"react",
|
|
10
11
|
"streaming",
|
|
12
|
+
"svelte",
|
|
11
13
|
"vue"
|
|
12
14
|
],
|
|
13
15
|
"homepage": "https://comark.dev",
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
"skills"
|
|
26
28
|
],
|
|
27
29
|
"type": "module",
|
|
30
|
+
"sideEffects": false,
|
|
28
31
|
"main": "./dist/index.js",
|
|
29
32
|
"module": "./dist/index.js",
|
|
30
33
|
"types": "./dist/index.d.ts",
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
"github-slugger": "^2.0.0",
|
|
53
56
|
"hast-util-to-string": "^3.0.1",
|
|
54
57
|
"minimark": "0.2.0",
|
|
55
|
-
"tsx": "^4.
|
|
58
|
+
"tsx": "^4.22.4",
|
|
56
59
|
"twoslash": "^0.3.6",
|
|
57
60
|
"vitest": "^4.1.4"
|
|
58
61
|
},
|
|
@@ -48,9 +48,9 @@ Map custom Svelte components to Comark elements:
|
|
|
48
48
|
```svelte
|
|
49
49
|
<script lang="ts">
|
|
50
50
|
import { Comark } from '@comark/svelte'
|
|
51
|
-
import CustomHeading from './CustomHeading.svelte'
|
|
52
|
-
import CustomAlert from './CustomAlert.svelte'
|
|
53
|
-
import CustomCard from './CustomCard.svelte'
|
|
51
|
+
import CustomHeading from './components/comark/CustomHeading.svelte'
|
|
52
|
+
import CustomAlert from './components/comark/CustomAlert.svelte'
|
|
53
|
+
import CustomCard from './components/comark/CustomCard.svelte'
|
|
54
54
|
|
|
55
55
|
const customComponents = {
|
|
56
56
|
h1: CustomHeading,
|
|
@@ -127,9 +127,9 @@ Load components dynamically using `componentsManifest`:
|
|
|
127
127
|
import { Comark } from '@comark/svelte'
|
|
128
128
|
|
|
129
129
|
const componentMap: Record<string, () => Promise<any>> = {
|
|
130
|
-
'alert': () => import('./Alert.svelte'),
|
|
131
|
-
'card': () => import('./Card.svelte'),
|
|
132
|
-
'button': () => import('./Button.svelte'),
|
|
130
|
+
'alert': () => import('./components/comark/Alert.svelte'),
|
|
131
|
+
'card': () => import('./components/comark/Card.svelte'),
|
|
132
|
+
'button': () => import('./components/comark/Button.svelte'),
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async function loadComponent(name: string) {
|
|
@@ -144,6 +144,50 @@ Load components dynamically using `componentsManifest`:
|
|
|
144
144
|
<Comark markdown={content} componentsManifest={loadComponent} />
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
In SvelteKit projects, keep components rendered from Markdown in a dedicated folder such as `$lib/components/comark/`. This keeps Comark-rendered components separate from normal app UI components and makes `componentsManifest` globs easier to audit.
|
|
148
|
+
|
|
149
|
+
For SvelteKit SSR with non-eager lazy components, use `ComarkAsync` and a manifest that returns dynamic imports. An explicit map is the easiest option to audit:
|
|
150
|
+
|
|
151
|
+
```svelte
|
|
152
|
+
<script lang="ts">
|
|
153
|
+
import { ComarkAsync } from '@comark/svelte/async'
|
|
154
|
+
|
|
155
|
+
const componentMap: Record<string, () => Promise<any>> = {
|
|
156
|
+
'alert': () => import('$lib/components/comark/Alert.svelte'),
|
|
157
|
+
'lazy-card': () => import('$lib/components/comark/LazyCard.svelte'),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const componentsManifest = (name: string) => componentMap[name]?.()
|
|
161
|
+
</script>
|
|
162
|
+
|
|
163
|
+
<svelte:boundary>
|
|
164
|
+
<ComarkAsync markdown={content} {componentsManifest} />
|
|
165
|
+
</svelte:boundary>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Use `import.meta.glob` when you want the manifest to cover every Svelte component in a folder:
|
|
169
|
+
|
|
170
|
+
```svelte
|
|
171
|
+
<script lang="ts">
|
|
172
|
+
import { ComarkAsync } from '@comark/svelte/async'
|
|
173
|
+
import { pascalCase } from '@comark/svelte/utils'
|
|
174
|
+
|
|
175
|
+
const modules = import.meta.glob('../lib/components/comark/*.svelte')
|
|
176
|
+
|
|
177
|
+
const componentsManifest = (name: string) => {
|
|
178
|
+
return modules[`../lib/components/comark/${pascalCase(name)}.svelte`]?.()
|
|
179
|
+
}
|
|
180
|
+
</script>
|
|
181
|
+
|
|
182
|
+
<svelte:boundary>
|
|
183
|
+
<ComarkAsync markdown={content} {componentsManifest} />
|
|
184
|
+
</svelte:boundary>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Omit the boundary `pending` snippet when you want SvelteKit SSR to wait and include the resolved lazy components in the initial HTML.
|
|
188
|
+
|
|
189
|
+
Use eager/static components with `ComarkRenderer` when you need stable SSR without Svelte's experimental async support.
|
|
190
|
+
|
|
147
191
|
---
|
|
148
192
|
|
|
149
193
|
## Slots Support
|
|
@@ -319,7 +363,7 @@ Override native HTML elements using the `Prose` prefix:
|
|
|
319
363
|
|
|
320
364
|
## Experimental Async
|
|
321
365
|
|
|
322
|
-
The `ComarkAsync` component uses Svelte's experimental `await` in `$derived` for a declarative approach. Requires `experimental.async` in your Svelte config:
|
|
366
|
+
The `ComarkAsync` component uses Svelte's experimental `await` in `$derived` for a declarative approach. It can also await async `componentsManifest` entries during SSR, so lazy dynamic imports render into SvelteKit server HTML. Requires `experimental.async` in your Svelte config:
|
|
323
367
|
|
|
324
368
|
```js
|
|
325
369
|
// svelte.config.js
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../../../src/internal/stringify/indent'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../../../src/internal/stringify/indent.ts'
|
package/dist/vite.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../src/vite'
|
package/dist/vite.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '../src/vite.ts'
|