@emkodev/emroute 1.7.2 → 1.8.0-beta.1
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 +1 -1
- package/core/component/abstract.component.ts +74 -0
- package/{src → core}/component/page.component.ts +3 -61
- package/core/component/widget.component.ts +54 -0
- package/core/pipeline/pipeline.ts +224 -0
- package/{src/renderer/ssr → core/renderer}/html.renderer.ts +19 -45
- package/{src/renderer/ssr → core/renderer}/md.renderer.ts +21 -40
- package/{src/renderer/ssr → core/renderer}/ssr.renderer.ts +42 -53
- package/{src/route → core/router}/route.resolver.ts +1 -10
- package/core/router/route.trie.ts +175 -0
- package/core/runtime/abstract.runtime.ts +47 -0
- package/core/server/emroute.server.ts +346 -0
- package/core/type/component.type.ts +39 -0
- package/core/type/element.type.ts +10 -0
- package/core/type/logger.type.ts +20 -0
- package/core/type/markdown.type.ts +8 -0
- package/core/type/route-tree.type.ts +28 -0
- package/core/type/route.type.ts +75 -0
- package/core/type/widget.type.ts +27 -0
- package/core/util/html.util.ts +50 -0
- package/{src → core}/util/md.util.ts +0 -2
- package/{src/route → core/util}/route-tree.util.ts +0 -2
- package/{src → core}/util/widget-resolve.util.ts +15 -45
- package/{src → core}/widget/widget.parser.ts +0 -21
- package/core/widget/widget.registry.ts +24 -0
- package/dist/core/component/abstract.component.d.ts +48 -0
- package/dist/core/component/abstract.component.js +42 -0
- package/dist/core/component/abstract.component.js.map +1 -0
- package/dist/core/component/page.component.d.ts +23 -0
- package/dist/core/component/page.component.js +49 -0
- package/dist/core/component/page.component.js.map +1 -0
- package/dist/core/component/widget.component.d.ts +17 -0
- package/dist/core/component/widget.component.js +37 -0
- package/dist/core/component/widget.component.js.map +1 -0
- package/dist/core/pipeline/pipeline.d.ts +61 -0
- package/dist/core/pipeline/pipeline.js +189 -0
- package/dist/core/pipeline/pipeline.js.map +1 -0
- package/dist/{src/renderer/ssr → core/renderer}/html.renderer.d.ts +8 -24
- package/dist/{src/renderer/ssr → core/renderer}/html.renderer.js +12 -33
- package/dist/core/renderer/html.renderer.js.map +1 -0
- package/dist/{src/renderer/ssr → core/renderer}/md.renderer.d.ts +6 -21
- package/dist/{src/renderer/ssr → core/renderer}/md.renderer.js +14 -31
- package/dist/core/renderer/md.renderer.js.map +1 -0
- package/dist/{src/renderer/ssr → core/renderer}/ssr.renderer.d.ts +11 -17
- package/dist/{src/renderer/ssr → core/renderer}/ssr.renderer.js +34 -36
- package/dist/core/renderer/ssr.renderer.js.map +1 -0
- package/dist/{src/route → core/router}/route.resolver.d.ts +1 -8
- package/dist/{src/route → core/router}/route.resolver.js +0 -1
- package/dist/core/router/route.resolver.js.map +1 -0
- package/dist/core/router/route.trie.d.ts +32 -0
- package/dist/core/router/route.trie.js +152 -0
- package/dist/core/router/route.trie.js.map +1 -0
- package/dist/core/runtime/abstract.runtime.d.ts +32 -0
- package/dist/core/runtime/abstract.runtime.js +26 -0
- package/dist/core/runtime/abstract.runtime.js.map +1 -0
- package/dist/core/server/emroute.server.d.ts +48 -0
- package/dist/core/server/emroute.server.js +261 -0
- package/dist/core/server/emroute.server.js.map +1 -0
- package/dist/core/server/server.type.d.ts +45 -0
- package/dist/core/server/server.type.js +11 -0
- package/dist/core/server/server.type.js.map +1 -0
- package/dist/core/type/component.type.d.ts +37 -0
- package/dist/core/type/component.type.js +7 -0
- package/dist/core/type/component.type.js.map +1 -0
- package/dist/core/type/element.type.d.ts +9 -0
- package/dist/core/type/element.type.js +5 -0
- package/dist/core/type/element.type.js.map +1 -0
- package/dist/core/type/logger.type.d.ts +14 -0
- package/dist/core/type/logger.type.js +8 -0
- package/dist/core/type/logger.type.js.map +1 -0
- package/dist/core/type/markdown.type.d.ts +7 -0
- package/dist/core/type/markdown.type.js +5 -0
- package/dist/core/type/markdown.type.js.map +1 -0
- package/dist/{src → core}/type/route-tree.type.d.ts +0 -12
- package/dist/{src → core}/type/route-tree.type.js +0 -1
- package/dist/core/type/route-tree.type.js.map +1 -0
- package/dist/core/type/route.type.d.ts +62 -0
- package/dist/core/type/route.type.js +7 -0
- package/dist/core/type/route.type.js.map +1 -0
- package/dist/core/type/widget.type.d.ts +27 -0
- package/dist/core/type/widget.type.js +5 -0
- package/dist/core/type/widget.type.js.map +1 -0
- package/dist/core/util/html.util.d.ts +14 -0
- package/dist/core/util/html.util.js +43 -0
- package/dist/core/util/html.util.js.map +1 -0
- package/dist/{src → core}/util/md.util.d.ts +0 -1
- package/dist/{src → core}/util/md.util.js +0 -2
- package/dist/core/util/md.util.js.map +1 -0
- package/dist/{src/route → core/util}/route-tree.util.js +0 -2
- package/dist/core/util/route-tree.util.js.map +1 -0
- package/dist/core/util/widget-resolve.util.d.ts +32 -0
- package/dist/{src → core}/util/widget-resolve.util.js +11 -41
- package/dist/core/util/widget-resolve.util.js.map +1 -0
- package/dist/{src → core}/widget/widget.parser.d.ts +0 -13
- package/dist/{src → core}/widget/widget.parser.js +0 -21
- package/dist/core/widget/widget.parser.js.map +1 -0
- package/dist/core/widget/widget.registry.d.ts +13 -0
- package/dist/core/widget/widget.registry.js +19 -0
- package/dist/core/widget/widget.registry.js.map +1 -0
- package/dist/emroute.js +1137 -1151
- package/dist/emroute.js.map +36 -5
- package/dist/runtime/abstract.runtime.d.ts +50 -5
- package/dist/runtime/abstract.runtime.js +446 -6
- package/dist/runtime/abstract.runtime.js.map +1 -1
- package/dist/runtime/bun/fs/bun-fs.runtime.d.ts +1 -0
- package/dist/runtime/bun/fs/bun-fs.runtime.js +18 -2
- package/dist/runtime/bun/fs/bun-fs.runtime.js.map +1 -1
- package/dist/runtime/bun/sqlite/bun-sqlite.runtime.d.ts +2 -0
- package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js +11 -1
- package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js.map +1 -1
- package/dist/runtime/fetch.runtime.d.ts +3 -3
- package/dist/runtime/fetch.runtime.js +3 -3
- package/dist/runtime/sitemap.generator.d.ts +1 -1
- package/dist/runtime/sitemap.generator.js +1 -1
- package/dist/runtime/sitemap.generator.js.map +1 -1
- package/dist/runtime/universal/fs/universal-fs.runtime.d.ts +1 -0
- package/dist/runtime/universal/fs/universal-fs.runtime.js +18 -2
- package/dist/runtime/universal/fs/universal-fs.runtime.js.map +1 -1
- package/dist/server/build.util.d.ts +9 -10
- package/dist/server/build.util.js +45 -36
- package/dist/server/build.util.js.map +1 -1
- package/dist/server/codegen.util.d.ts +1 -1
- package/dist/server/emroute.server.d.ts +8 -35
- package/dist/server/emroute.server.js +7 -341
- package/dist/server/emroute.server.js.map +1 -1
- package/dist/server/esbuild-manifest.plugin.js +1 -1
- package/dist/server/esbuild-manifest.plugin.js.map +1 -1
- package/dist/server/server-api.type.d.ts +3 -68
- package/dist/server/server-api.type.js +1 -8
- package/dist/server/server-api.type.js.map +1 -1
- package/dist/src/element/component.element.d.ts +4 -7
- package/dist/src/element/component.element.js +23 -22
- package/dist/src/element/component.element.js.map +1 -1
- package/dist/src/element/markdown.element.d.ts +2 -2
- package/dist/src/element/markdown.element.js +4 -3
- package/dist/src/element/markdown.element.js.map +1 -1
- package/dist/src/index.d.ts +15 -13
- package/dist/src/index.js +8 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/renderer/spa/emroute.app.d.ts +50 -0
- package/dist/src/renderer/spa/emroute.app.js +246 -0
- package/dist/src/renderer/spa/emroute.app.js.map +1 -0
- package/dist/src/renderer/spa/mod.d.ts +17 -16
- package/dist/src/renderer/spa/mod.js +9 -9
- package/dist/src/renderer/spa/mod.js.map +1 -1
- package/dist/src/renderer/spa/thin-client.d.ts +3 -3
- package/dist/src/renderer/spa/thin-client.js +34 -12
- package/dist/src/renderer/spa/thin-client.js.map +1 -1
- package/dist/src/route/route.core.d.ts +3 -3
- package/dist/src/route/route.core.js +21 -7
- package/dist/src/route/route.core.js.map +1 -1
- package/dist/src/util/html.util.d.ts +5 -22
- package/dist/src/util/html.util.js +8 -56
- package/dist/src/util/html.util.js.map +1 -1
- package/dist/src/widget/breadcrumb.widget.d.ts +2 -2
- package/dist/src/widget/breadcrumb.widget.js +2 -2
- package/dist/src/widget/breadcrumb.widget.js.map +1 -1
- package/dist/src/widget/page-title.widget.d.ts +1 -1
- package/dist/src/widget/page-title.widget.js +1 -1
- package/dist/src/widget/page-title.widget.js.map +1 -1
- package/package.json +8 -8
- package/runtime/abstract.runtime.ts +483 -8
- package/runtime/bun/fs/bun-fs.runtime.ts +17 -1
- package/runtime/bun/sqlite/bun-sqlite.runtime.ts +11 -0
- package/runtime/fetch.runtime.ts +3 -3
- package/runtime/sitemap.generator.ts +2 -2
- package/runtime/universal/fs/universal-fs.runtime.ts +17 -1
- package/server/build.util.ts +53 -47
- package/server/codegen.util.ts +1 -1
- package/server/emroute.server.ts +12 -412
- package/src/element/component.element.ts +24 -31
- package/src/element/markdown.element.ts +5 -4
- package/src/index.ts +22 -18
- package/src/renderer/spa/{thin-client.ts → emroute.app.ts} +46 -22
- package/src/renderer/spa/mod.ts +22 -22
- package/src/util/html.util.ts +16 -61
- package/src/widget/breadcrumb.widget.ts +3 -3
- package/src/widget/page-title.widget.ts +1 -1
- package/dist/src/component/abstract.component.d.ts +0 -199
- package/dist/src/component/abstract.component.js +0 -84
- package/dist/src/component/abstract.component.js.map +0 -1
- package/dist/src/component/page.component.d.ts +0 -74
- package/dist/src/component/page.component.js +0 -107
- package/dist/src/component/page.component.js.map +0 -1
- package/dist/src/component/widget.component.d.ts +0 -47
- package/dist/src/component/widget.component.js +0 -69
- package/dist/src/component/widget.component.js.map +0 -1
- package/dist/src/renderer/ssr/html.renderer.js.map +0 -1
- package/dist/src/renderer/ssr/md.renderer.js.map +0 -1
- package/dist/src/renderer/ssr/ssr.renderer.js.map +0 -1
- package/dist/src/route/route-tree.util.js.map +0 -1
- package/dist/src/route/route.matcher.d.ts +0 -86
- package/dist/src/route/route.matcher.js +0 -214
- package/dist/src/route/route.matcher.js.map +0 -1
- package/dist/src/route/route.resolver.js.map +0 -1
- package/dist/src/route/route.trie.d.ts +0 -38
- package/dist/src/route/route.trie.js +0 -206
- package/dist/src/route/route.trie.js.map +0 -1
- package/dist/src/type/logger.type.d.ts +0 -17
- package/dist/src/type/logger.type.js +0 -9
- package/dist/src/type/logger.type.js.map +0 -1
- package/dist/src/type/markdown.type.d.ts +0 -20
- package/dist/src/type/markdown.type.js +0 -2
- package/dist/src/type/markdown.type.js.map +0 -1
- package/dist/src/type/route-tree.type.js.map +0 -1
- package/dist/src/type/route.type.d.ts +0 -94
- package/dist/src/type/route.type.js +0 -8
- package/dist/src/type/route.type.js.map +0 -1
- package/dist/src/type/widget.type.d.ts +0 -55
- package/dist/src/type/widget.type.js +0 -10
- package/dist/src/type/widget.type.js.map +0 -1
- package/dist/src/util/logger.util.d.ts +0 -26
- package/dist/src/util/logger.util.js +0 -80
- package/dist/src/util/logger.util.js.map +0 -1
- package/dist/src/util/md.util.js.map +0 -1
- package/dist/src/util/widget-resolve.util.d.ts +0 -52
- package/dist/src/util/widget-resolve.util.js.map +0 -1
- package/dist/src/widget/widget.parser.js.map +0 -1
- package/dist/src/widget/widget.registry.d.ts +0 -23
- package/dist/src/widget/widget.registry.js +0 -42
- package/dist/src/widget/widget.registry.js.map +0 -1
- package/runtime/bun/esbuild-runtime-loader.plugin.ts +0 -112
- package/server/esbuild-manifest.plugin.ts +0 -209
- package/server/server-api.type.ts +0 -97
- package/src/component/abstract.component.ts +0 -231
- package/src/component/widget.component.ts +0 -85
- package/src/route/route.core.ts +0 -362
- package/src/route/route.trie.ts +0 -265
- package/src/type/logger.type.ts +0 -24
- package/src/type/markdown.type.ts +0 -21
- package/src/type/route-tree.type.ts +0 -51
- package/src/type/route.type.ts +0 -124
- package/src/type/widget.type.ts +0 -65
- package/src/util/logger.util.ts +0 -83
- package/src/widget/widget.registry.ts +0 -51
- /package/dist/{src/route → core/util}/route-tree.util.d.ts +0 -0
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* Calls getData() + renderHTML() on widgets and injects SSR hydration data.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Component
|
|
9
|
-
import {
|
|
8
|
+
import type { Component } from '../component/abstract.component.ts';
|
|
9
|
+
import type { ComponentContext, ContextProvider } from '../type/component.type.ts';
|
|
10
|
+
import { type Logger, defaultLogger } from '../type/logger.type.ts';
|
|
10
11
|
import type { RouteInfo } from '../type/route.type.ts';
|
|
11
12
|
import { LAZY_ATTR, SSR_ATTR } from './html.util.ts';
|
|
12
13
|
|
|
@@ -15,17 +16,6 @@ export const MAX_WIDGET_DEPTH = 10;
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Recursively resolve widgets in content with depth limit.
|
|
18
|
-
*
|
|
19
|
-
* Generic utility used by both HTML and Markdown widget resolution.
|
|
20
|
-
* Each depth level processes all widgets concurrently, then recurses
|
|
21
|
-
* into each rendered result to resolve nested widgets.
|
|
22
|
-
*
|
|
23
|
-
* @param content - Content containing widgets
|
|
24
|
-
* @param parse - Find widgets in content
|
|
25
|
-
* @param resolve - Resolve a single widget to rendered output
|
|
26
|
-
* @param replace - Replace widgets with resolved content
|
|
27
|
-
* @param depth - Current recursion depth (internal)
|
|
28
|
-
* @returns Content with all widgets recursively resolved
|
|
29
19
|
*/
|
|
30
20
|
export async function resolveRecursively<T>(
|
|
31
21
|
content: string,
|
|
@@ -33,6 +23,7 @@ export async function resolveRecursively<T>(
|
|
|
33
23
|
resolve: (widget: T) => Promise<string>,
|
|
34
24
|
replace: (content: string, replacements: Map<T, string>) => string,
|
|
35
25
|
depth = 0,
|
|
26
|
+
logger: Logger = defaultLogger,
|
|
36
27
|
): Promise<string> {
|
|
37
28
|
if (depth >= MAX_WIDGET_DEPTH) {
|
|
38
29
|
logger.warn(
|
|
@@ -49,10 +40,7 @@ export async function resolveRecursively<T>(
|
|
|
49
40
|
await Promise.all(
|
|
50
41
|
widgets.map(async (widget) => {
|
|
51
42
|
let rendered = await resolve(widget);
|
|
52
|
-
|
|
53
|
-
// Recursively resolve any nested widgets in the rendered output
|
|
54
|
-
rendered = await resolveRecursively(rendered, parse, resolve, replace, depth + 1);
|
|
55
|
-
|
|
43
|
+
rendered = await resolveRecursively(rendered, parse, resolve, replace, depth + 1, logger);
|
|
56
44
|
replacements.set(widget, rendered);
|
|
57
45
|
}),
|
|
58
46
|
);
|
|
@@ -61,18 +49,7 @@ export async function resolveRecursively<T>(
|
|
|
61
49
|
}
|
|
62
50
|
|
|
63
51
|
/**
|
|
64
|
-
* Resolve <widget-*> tags in HTML by calling getData() + renderHTML()
|
|
65
|
-
* via the widget registry. Injects rendered content and boolean ssr attribute.
|
|
66
|
-
*
|
|
67
|
-
* Supports nested widgets: if a widget's renderHTML() returns HTML containing
|
|
68
|
-
* other <widget-*> tags, those will be resolved recursively up to MAX_WIDGET_DEPTH.
|
|
69
|
-
*
|
|
70
|
-
* Before: <widget-crypto-price coin="bitcoin"></widget-crypto-price>
|
|
71
|
-
* After: <widget-crypto-price coin="bitcoin" ssr><template shadowrootmode="open"><span>$42,000</span></template></widget-crypto-price>
|
|
72
|
-
*
|
|
73
|
-
* When a widget has `exposeSsrData = true`, the getData() result is serialized
|
|
74
|
-
* as JSON text in the light DOM (alongside the shadow root template):
|
|
75
|
-
* After: <widget-crypto-price coin="bitcoin" ssr><template shadowrootmode="open"><span>$42,000</span></template>{"price":42000}</widget-crypto-price>
|
|
52
|
+
* Resolve <widget-*> tags in HTML by calling getData() + renderHTML().
|
|
76
53
|
*/
|
|
77
54
|
export function resolveWidgetTags(
|
|
78
55
|
html: string,
|
|
@@ -83,17 +60,14 @@ export function resolveWidgetTags(
|
|
|
83
60
|
declaredFiles?: { html?: string; md?: string; css?: string },
|
|
84
61
|
) => Promise<{ html?: string; md?: string; css?: string }>,
|
|
85
62
|
contextProvider?: ContextProvider,
|
|
63
|
+
logger: Logger = defaultLogger,
|
|
86
64
|
): Promise<string> {
|
|
87
65
|
const tagPattern =
|
|
88
66
|
/<widget-(?<name>[a-z][a-z0-9-]*)(?<attrs>\s[^>]*)?>(?<content>.*?)<\/widget-\k<name>>/gis;
|
|
89
67
|
|
|
90
|
-
// Wrapping info stored per-match so replace() can apply it after recursion
|
|
91
68
|
const wrappers = new Map<RegExpExecArray, { tagName: string; attrs: string; ssrData: string }>();
|
|
92
|
-
|
|
93
|
-
// Matches standalone ssr attribute (boolean or with value), not as substring of another value
|
|
94
69
|
const ssrAttrPattern = new RegExp(`\\s${SSR_ATTR}(?:\\s|=|$)`);
|
|
95
70
|
|
|
96
|
-
// Parse: find unprocessed widget tags
|
|
97
71
|
const parse = (content: string) => {
|
|
98
72
|
const matches = content.matchAll(tagPattern).toArray();
|
|
99
73
|
return matches.filter((match) => {
|
|
@@ -102,13 +76,12 @@ export function resolveWidgetTags(
|
|
|
102
76
|
});
|
|
103
77
|
};
|
|
104
78
|
|
|
105
|
-
// Resolve: render a single widget's inner content (no outer tag wrapping — that's in replace)
|
|
106
79
|
const resolve = async (match: RegExpExecArray): Promise<string> => {
|
|
107
80
|
const widgetName = match.groups!.name;
|
|
108
81
|
const attrsString = match.groups!.attrs?.trim() ?? '';
|
|
109
82
|
const widget = registry.get(widgetName);
|
|
110
83
|
|
|
111
|
-
if (!widget) return match[0];
|
|
84
|
+
if (!widget) return match[0];
|
|
112
85
|
|
|
113
86
|
const params = parseAttrsToParams(attrsString);
|
|
114
87
|
|
|
@@ -118,18 +91,17 @@ export function resolveWidgetTags(
|
|
|
118
91
|
files = await loadFiles(widgetName, widget.files);
|
|
119
92
|
}
|
|
120
93
|
|
|
121
|
-
const baseContext = {
|
|
94
|
+
const baseContext: ComponentContext = {
|
|
122
95
|
...routeInfo,
|
|
123
96
|
pathname: routeInfo.url.pathname,
|
|
124
97
|
searchParams: routeInfo.url.searchParams,
|
|
125
|
-
files,
|
|
98
|
+
...(files ? { files } : {}),
|
|
126
99
|
};
|
|
127
|
-
const context = contextProvider ? contextProvider(baseContext) : baseContext;
|
|
100
|
+
const context: ComponentContext = contextProvider ? contextProvider(baseContext) : baseContext;
|
|
128
101
|
|
|
129
102
|
const data = await widget.getData({ params, context });
|
|
130
103
|
const rendered = widget.renderHTML({ data, params, context });
|
|
131
104
|
|
|
132
|
-
// Store wrapping info — applied in replace() after recursion resolves nested widgets
|
|
133
105
|
wrappers.set(match, {
|
|
134
106
|
tagName: `widget-${widgetName}`,
|
|
135
107
|
attrs: attrsString ? ` ${attrsString}` : '',
|
|
@@ -142,11 +114,10 @@ export function resolveWidgetTags(
|
|
|
142
114
|
`[SSR HTML] Widget "${widgetName}" render failed`,
|
|
143
115
|
e instanceof Error ? e : undefined,
|
|
144
116
|
);
|
|
145
|
-
return match[0];
|
|
117
|
+
return match[0];
|
|
146
118
|
}
|
|
147
119
|
};
|
|
148
120
|
|
|
149
|
-
// Replace: wrap resolved content in outer tag + DSD template, then substitute by index
|
|
150
121
|
const replace = (content: string, replacements: Map<RegExpExecArray, string>) => {
|
|
151
122
|
let result = content;
|
|
152
123
|
const entries = [...replacements.entries()].sort((a, b) => b[0].index! - a[0].index!);
|
|
@@ -157,16 +128,16 @@ export function resolveWidgetTags(
|
|
|
157
128
|
const lightDomData = wrap?.ssrData ? wrap.ssrData : '';
|
|
158
129
|
const replacement = wrap
|
|
159
130
|
? `<${wrap.tagName}${wrap.attrs} ${SSR_ATTR}><template shadowrootmode="open">${innerHtml}</template>${lightDomData}</${wrap.tagName}>`
|
|
160
|
-
: innerHtml;
|
|
131
|
+
: innerHtml;
|
|
161
132
|
result = result.slice(0, start) + replacement + result.slice(end);
|
|
162
133
|
}
|
|
163
134
|
return result;
|
|
164
135
|
};
|
|
165
136
|
|
|
166
|
-
return resolveRecursively(html, parse, resolve, replace);
|
|
137
|
+
return resolveRecursively(html, parse, resolve, replace, 0, logger);
|
|
167
138
|
}
|
|
168
139
|
|
|
169
|
-
/** Parse HTML attribute string into params object
|
|
140
|
+
/** Parse HTML attribute string into params object. */
|
|
170
141
|
export function parseAttrsToParams(attrsString: string): Record<string, unknown> {
|
|
171
142
|
const params: Record<string, unknown> = {};
|
|
172
143
|
if (!attrsString) return params;
|
|
@@ -196,7 +167,6 @@ export function parseAttrsToParams(attrsString: string): Record<string, unknown>
|
|
|
196
167
|
return params;
|
|
197
168
|
}
|
|
198
169
|
|
|
199
|
-
/** Escape a value for use in a single-quoted HTML attribute. */
|
|
200
170
|
function escapeAttr(value: string): string {
|
|
201
171
|
return value.replaceAll('&', '&').replaceAll("'", ''');
|
|
202
172
|
}
|
|
@@ -11,18 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
import type { ParsedWidgetBlock } from '../type/widget.type.ts';
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Pattern to match widget fenced code blocks.
|
|
16
|
-
* Captures: widget name, params content
|
|
17
|
-
*/
|
|
18
14
|
const WIDGET_PATTERN = /```widget:(?<name>[a-z][a-z0-9-]*)\n(?<params>.*?)```/gs;
|
|
19
15
|
|
|
20
|
-
/**
|
|
21
|
-
* Parse all widget blocks from markdown content.
|
|
22
|
-
*
|
|
23
|
-
* @param markdown - Markdown content to parse
|
|
24
|
-
* @returns Array of parsed widget blocks with positions
|
|
25
|
-
*/
|
|
26
16
|
export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
|
|
27
17
|
const blocks: ParsedWidgetBlock[] = [];
|
|
28
18
|
|
|
@@ -40,7 +30,6 @@ export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
|
|
|
40
30
|
endIndex: startIndex + fullMatch.length,
|
|
41
31
|
};
|
|
42
32
|
|
|
43
|
-
// Parse JSON params if present
|
|
44
33
|
if (paramsJson) {
|
|
45
34
|
try {
|
|
46
35
|
const parsed = JSON.parse(paramsJson);
|
|
@@ -53,7 +42,6 @@ export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
|
|
|
53
42
|
block.parseError = `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`;
|
|
54
43
|
}
|
|
55
44
|
} else {
|
|
56
|
-
// Empty params is valid - use empty object
|
|
57
45
|
block.params = {};
|
|
58
46
|
}
|
|
59
47
|
|
|
@@ -63,19 +51,10 @@ export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
|
|
|
63
51
|
return blocks;
|
|
64
52
|
}
|
|
65
53
|
|
|
66
|
-
/**
|
|
67
|
-
* Replace widget blocks in markdown with rendered content.
|
|
68
|
-
*
|
|
69
|
-
* @param markdown - Original markdown content
|
|
70
|
-
* @param replacements - Map of parsed blocks to replacement strings
|
|
71
|
-
* @returns Markdown with widget blocks replaced
|
|
72
|
-
*/
|
|
73
54
|
export function replaceWidgetBlocks(
|
|
74
55
|
markdown: string,
|
|
75
56
|
replacements: Map<ParsedWidgetBlock, string>,
|
|
76
57
|
): string {
|
|
77
|
-
// Sort blocks by position descending to replace from end first
|
|
78
|
-
// This preserves indices during replacement
|
|
79
58
|
const sortedBlocks = [...replacements.entries()].sort(
|
|
80
59
|
([a], [b]) => b.startIndex - a.startIndex,
|
|
81
60
|
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Registry
|
|
3
|
+
*
|
|
4
|
+
* Name → Component lookup. Used by all renderers.
|
|
5
|
+
* Pages are NOT in this registry — they live in the routes manifest.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { WidgetComponent } from '../component/widget.component.ts';
|
|
9
|
+
|
|
10
|
+
export class WidgetRegistry {
|
|
11
|
+
private widgets = new Map<string, WidgetComponent>();
|
|
12
|
+
|
|
13
|
+
add(widget: WidgetComponent): void {
|
|
14
|
+
this.widgets.set(widget.name, widget);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get(name: string): WidgetComponent | undefined {
|
|
18
|
+
return this.widgets.get(name);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[Symbol.iterator](): IterableIterator<WidgetComponent> {
|
|
22
|
+
return this.widgets.values();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Base Class
|
|
3
|
+
*
|
|
4
|
+
* Everything is a Component: pages and widgets.
|
|
5
|
+
* Components render differently based on context:
|
|
6
|
+
* - /md/* → Markdown (LLMs, text clients)
|
|
7
|
+
* - /html/* → Pre-rendered HTML (SSR)
|
|
8
|
+
* - SPA → Hydrated custom elements
|
|
9
|
+
*/
|
|
10
|
+
import type { ComponentContext } from '../type/component.type.ts';
|
|
11
|
+
export declare abstract class Component<TParams = unknown, TData = unknown, TContext extends ComponentContext = ComponentContext> {
|
|
12
|
+
readonly DataArgs: {
|
|
13
|
+
params: TParams;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
context: TContext;
|
|
16
|
+
};
|
|
17
|
+
readonly RenderArgs: {
|
|
18
|
+
data: TData | null;
|
|
19
|
+
params: TParams;
|
|
20
|
+
context: TContext;
|
|
21
|
+
};
|
|
22
|
+
abstract readonly name: string;
|
|
23
|
+
/** Host element reference, set by ComponentElement in the browser. */
|
|
24
|
+
element?: HTMLElement | undefined;
|
|
25
|
+
/** Associated file paths for pre-loaded content (html, md, css). */
|
|
26
|
+
readonly files?: {
|
|
27
|
+
html?: string;
|
|
28
|
+
md?: string;
|
|
29
|
+
css?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* When true, SSR serializes the getData() result into the element's
|
|
33
|
+
* light DOM so the client can access it immediately in hydrate()
|
|
34
|
+
* without re-fetching.
|
|
35
|
+
*/
|
|
36
|
+
readonly exposeSsrData?: boolean;
|
|
37
|
+
abstract getData(args: this['DataArgs']): Promise<TData | null>;
|
|
38
|
+
abstract renderMarkdown(args: this['RenderArgs']): string;
|
|
39
|
+
renderHTML(args: this['RenderArgs']): string;
|
|
40
|
+
hydrate?(args: this['RenderArgs']): void;
|
|
41
|
+
destroy?(): void;
|
|
42
|
+
validateParams?(params: TParams): string | undefined;
|
|
43
|
+
renderError(args: {
|
|
44
|
+
error: unknown;
|
|
45
|
+
params: TParams;
|
|
46
|
+
}): string;
|
|
47
|
+
renderMarkdownError(error: unknown): string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Base Class
|
|
3
|
+
*
|
|
4
|
+
* Everything is a Component: pages and widgets.
|
|
5
|
+
* Components render differently based on context:
|
|
6
|
+
* - /md/* → Markdown (LLMs, text clients)
|
|
7
|
+
* - /html/* → Pre-rendered HTML (SSR)
|
|
8
|
+
* - SPA → Hydrated custom elements
|
|
9
|
+
*/
|
|
10
|
+
import { escapeHtml } from "../util/html.util.js";
|
|
11
|
+
export class Component {
|
|
12
|
+
/** Host element reference, set by ComponentElement in the browser. */
|
|
13
|
+
element;
|
|
14
|
+
/** Associated file paths for pre-loaded content (html, md, css). */
|
|
15
|
+
files;
|
|
16
|
+
/**
|
|
17
|
+
* When true, SSR serializes the getData() result into the element's
|
|
18
|
+
* light DOM so the client can access it immediately in hydrate()
|
|
19
|
+
* without re-fetching.
|
|
20
|
+
*/
|
|
21
|
+
exposeSsrData;
|
|
22
|
+
renderHTML(args) {
|
|
23
|
+
if (args.data === null) {
|
|
24
|
+
return `<div data-component="${this.name}">Loading...</div>`;
|
|
25
|
+
}
|
|
26
|
+
const markdown = this.renderMarkdown({
|
|
27
|
+
data: args.data,
|
|
28
|
+
params: args.params,
|
|
29
|
+
context: args.context,
|
|
30
|
+
});
|
|
31
|
+
return `<div data-component="${this.name}" data-markdown>${escapeHtml(markdown)}</div>`;
|
|
32
|
+
}
|
|
33
|
+
renderError(args) {
|
|
34
|
+
const msg = args.error instanceof Error ? args.error.message : String(args.error);
|
|
35
|
+
return `<div data-component="${this.name}">Error: ${escapeHtml(msg)}</div>`;
|
|
36
|
+
}
|
|
37
|
+
renderMarkdownError(error) {
|
|
38
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
39
|
+
return `> **Error** (\`${this.name}\`): ${msg}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=abstract.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstract.component.js","sourceRoot":"","sources":["../../../core/component/abstract.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAgB,SAAS;IAmB7B,sEAAsE;IACtE,OAAO,CAA2B;IAElC,oEAAoE;IAC3D,KAAK,CAAgD;IAE9D;;;;OAIG;IACM,aAAa,CAAW;IAKjC,UAAU,CAAC,IAAwB;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,wBAAwB,IAAI,CAAC,IAAI,oBAAoB,CAAC;QAC/D,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;YACnC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QACH,OAAO,wBAAwB,IAAI,CAAC,IAAI,mBAAmB,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1F,CAAC;IAMD,WAAW,CAAC,IAAyC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClF,OAAO,wBAAwB,IAAI,CAAC,IAAI,YAAY,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC9E,CAAC;IAED,mBAAmB,CAAC,KAAc;QAChC,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnE,OAAO,kBAAkB,IAAI,CAAC,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Component
|
|
3
|
+
*
|
|
4
|
+
* Params come from URL, context carries file content.
|
|
5
|
+
*
|
|
6
|
+
* Default implementations follow the fallback table:
|
|
7
|
+
* - renderHTML: html file → md via <mark-down> → <router-slot /> (non-leaf only)
|
|
8
|
+
* - renderMarkdown: md file → ```router-slot\n``` (non-leaf only)
|
|
9
|
+
* - getData: no-op (returns null)
|
|
10
|
+
*/
|
|
11
|
+
import { Component } from './abstract.component.ts';
|
|
12
|
+
import type { ComponentContext } from '../type/component.type.ts';
|
|
13
|
+
export declare class PageComponent<TParams extends Record<string, string> = Record<string, string>, TData = unknown, TContext extends ComponentContext = ComponentContext> extends Component<TParams, TData, TContext> {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly pattern?: string;
|
|
16
|
+
getData(_args: this['DataArgs']): Promise<TData | null>;
|
|
17
|
+
renderHTML(args: this['RenderArgs']): string;
|
|
18
|
+
renderMarkdown(args: this['RenderArgs']): string;
|
|
19
|
+
getTitle(_args: this['RenderArgs']): string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Shared default instance used by renderers when no custom .page.ts exists. */
|
|
22
|
+
declare const _default: PageComponent<Record<string, string>, unknown, ComponentContext>;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Component
|
|
3
|
+
*
|
|
4
|
+
* Params come from URL, context carries file content.
|
|
5
|
+
*
|
|
6
|
+
* Default implementations follow the fallback table:
|
|
7
|
+
* - renderHTML: html file → md via <mark-down> → <router-slot /> (non-leaf only)
|
|
8
|
+
* - renderMarkdown: md file → ```router-slot\n``` (non-leaf only)
|
|
9
|
+
* - getData: no-op (returns null)
|
|
10
|
+
*/
|
|
11
|
+
import { Component } from "./abstract.component.js";
|
|
12
|
+
import { escapeHtml } from "../util/html.util.js";
|
|
13
|
+
export class PageComponent extends Component {
|
|
14
|
+
name = 'page';
|
|
15
|
+
pattern;
|
|
16
|
+
getData(_args) {
|
|
17
|
+
return Promise.resolve(null);
|
|
18
|
+
}
|
|
19
|
+
renderHTML(args) {
|
|
20
|
+
const files = args.context.files;
|
|
21
|
+
const style = files?.css ? `<style>${files.css}</style>\n` : '';
|
|
22
|
+
if (files?.html) {
|
|
23
|
+
let html = style + files.html;
|
|
24
|
+
if (files.md && html.includes('<mark-down></mark-down>')) {
|
|
25
|
+
html = html.replace('<mark-down></mark-down>', `<mark-down>${escapeHtml(files.md)}</mark-down>`);
|
|
26
|
+
}
|
|
27
|
+
return html;
|
|
28
|
+
}
|
|
29
|
+
if (files?.md) {
|
|
30
|
+
const hasSlot = files.md.includes('```router-slot');
|
|
31
|
+
const slot = args.context.isLeaf || hasSlot ? '' : '\n<router-slot></router-slot>';
|
|
32
|
+
return `${style}<mark-down>${escapeHtml(files.md)}</mark-down>${slot}`;
|
|
33
|
+
}
|
|
34
|
+
return args.context.isLeaf ? '' : '<router-slot></router-slot>';
|
|
35
|
+
}
|
|
36
|
+
renderMarkdown(args) {
|
|
37
|
+
const files = args.context.files;
|
|
38
|
+
if (files?.md) {
|
|
39
|
+
return files.md;
|
|
40
|
+
}
|
|
41
|
+
return args.context.isLeaf ? '' : '```router-slot\n```';
|
|
42
|
+
}
|
|
43
|
+
getTitle(_args) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Shared default instance used by renderers when no custom .page.ts exists. */
|
|
48
|
+
export default new PageComponent();
|
|
49
|
+
//# sourceMappingURL=page.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.component.js","sourceRoot":"","sources":["../../../core/component/page.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAO,aAIX,SAAQ,SAAmC;IACzB,IAAI,GAAW,MAAM,CAAC;IAC/B,OAAO,CAAU;IAEjB,OAAO,CACd,KAAuB;QAEvB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAEQ,UAAU,CACjB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAEhE,IAAI,KAAK,EAAE,IAAI,EAAE,CAAC;YAChB,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;YAC9B,IAAI,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC;gBACzD,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,yBAAyB,EACzB,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CACjD,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YACpD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,+BAA+B,CAAC;YACnF,OAAO,GAAG,KAAK,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,IAAI,EAAE,CAAC;QACzE,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6BAA6B,CAAC;IAClE,CAAC;IAEQ,cAAc,CACrB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAEjC,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;IAC1D,CAAC;IAED,QAAQ,CACN,KAAyB;QAEzB,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AAED,gFAAgF;AAChF,eAAe,IAAI,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Component
|
|
3
|
+
*
|
|
4
|
+
* Embeddable unit within page content. Everything reusable that is not
|
|
5
|
+
* a page is a Widget. Widgets render across all contexts (HTML, Markdown, SPA)
|
|
6
|
+
* and are resolved by name via WidgetRegistry.
|
|
7
|
+
*
|
|
8
|
+
* Default rendering fallback chains (parallel to PageComponent):
|
|
9
|
+
* - renderHTML: html file → md file in <mark-down> → base Component default
|
|
10
|
+
* - renderMarkdown: md file → ''
|
|
11
|
+
*/
|
|
12
|
+
import { Component } from './abstract.component.ts';
|
|
13
|
+
import type { ComponentContext } from '../type/component.type.ts';
|
|
14
|
+
export declare abstract class WidgetComponent<TParams = unknown, TData = unknown, TContext extends ComponentContext = ComponentContext> extends Component<TParams, TData, TContext> {
|
|
15
|
+
renderHTML(args: this['RenderArgs']): string;
|
|
16
|
+
renderMarkdown(args: this['RenderArgs']): string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Component
|
|
3
|
+
*
|
|
4
|
+
* Embeddable unit within page content. Everything reusable that is not
|
|
5
|
+
* a page is a Widget. Widgets render across all contexts (HTML, Markdown, SPA)
|
|
6
|
+
* and are resolved by name via WidgetRegistry.
|
|
7
|
+
*
|
|
8
|
+
* Default rendering fallback chains (parallel to PageComponent):
|
|
9
|
+
* - renderHTML: html file → md file in <mark-down> → base Component default
|
|
10
|
+
* - renderMarkdown: md file → ''
|
|
11
|
+
*/
|
|
12
|
+
import { Component } from "./abstract.component.js";
|
|
13
|
+
import { escapeHtml, scopeWidgetCss } from "../util/html.util.js";
|
|
14
|
+
export class WidgetComponent extends Component {
|
|
15
|
+
renderHTML(args) {
|
|
16
|
+
const files = args.context.files;
|
|
17
|
+
const style = files?.css ? `<style>${scopeWidgetCss(files.css, this.name)}</style>\n` : '';
|
|
18
|
+
if (files?.html) {
|
|
19
|
+
return style + files.html;
|
|
20
|
+
}
|
|
21
|
+
if (files?.md) {
|
|
22
|
+
return `${style}<mark-down>${escapeHtml(files.md)}</mark-down>`;
|
|
23
|
+
}
|
|
24
|
+
if (style) {
|
|
25
|
+
return style + super.renderHTML(args);
|
|
26
|
+
}
|
|
27
|
+
return super.renderHTML(args);
|
|
28
|
+
}
|
|
29
|
+
renderMarkdown(args) {
|
|
30
|
+
const files = args.context.files;
|
|
31
|
+
if (files?.md) {
|
|
32
|
+
return files.md;
|
|
33
|
+
}
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=widget.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget.component.js","sourceRoot":"","sources":["../../../core/component/widget.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAElE,MAAM,OAAgB,eAIpB,SAAQ,SAAmC;IAClC,UAAU,CACjB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAE3F,IAAI,KAAK,EAAE,IAAI,EAAE,CAAC;YAChB,OAAO,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,GAAG,KAAK,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC;QAClE,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAEQ,cAAc,CACrB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAEjC,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Orchestration layer between Router, Runtime, and Component.
|
|
5
|
+
*
|
|
6
|
+
* Owns:
|
|
7
|
+
* - Route matching (reads manifest from Runtime, walks RouteNode tree)
|
|
8
|
+
* - Module loading (delegates to Runtime)
|
|
9
|
+
* - Companion file reading (delegates to Runtime)
|
|
10
|
+
* - ComponentContext building
|
|
11
|
+
* - Route hierarchy construction
|
|
12
|
+
*
|
|
13
|
+
* Does NOT own:
|
|
14
|
+
* - Rendering (that's Renderer)
|
|
15
|
+
* - HTTP routing / base paths (that's Server)
|
|
16
|
+
* - Storage I/O (that's Runtime)
|
|
17
|
+
* - Navigation events (that's the browser adapter)
|
|
18
|
+
*/
|
|
19
|
+
import type { RouteConfig, MatchedRoute, RouteInfo } from '../type/route.type.ts';
|
|
20
|
+
import type { ComponentContext, ContextProvider, FileContents } from '../type/component.type.ts';
|
|
21
|
+
import type { Runtime } from '../runtime/abstract.runtime.ts';
|
|
22
|
+
import { type Logger } from '../type/logger.type.ts';
|
|
23
|
+
/** Default root route — renders a slot for child routes. */
|
|
24
|
+
export declare const DEFAULT_ROOT_ROUTE: RouteConfig;
|
|
25
|
+
/** Pipeline configuration. */
|
|
26
|
+
export interface PipelineOptions {
|
|
27
|
+
runtime: Runtime;
|
|
28
|
+
contextProvider?: ContextProvider;
|
|
29
|
+
/** Pre-bundled module loaders (browser boot passes these). */
|
|
30
|
+
moduleLoaders?: Record<string, () => Promise<unknown>>;
|
|
31
|
+
logger?: Logger;
|
|
32
|
+
}
|
|
33
|
+
export declare class Pipeline {
|
|
34
|
+
private readonly runtime;
|
|
35
|
+
readonly contextProvider: ContextProvider | undefined;
|
|
36
|
+
readonly logger: Logger;
|
|
37
|
+
private readonly moduleLoaders;
|
|
38
|
+
constructor(options: PipelineOptions);
|
|
39
|
+
private getResolver;
|
|
40
|
+
match(url: URL): Promise<MatchedRoute | undefined>;
|
|
41
|
+
findRoute(pattern: string): Promise<RouteConfig | undefined>;
|
|
42
|
+
findErrorBoundary(pathname: string): Promise<{
|
|
43
|
+
pattern: string;
|
|
44
|
+
modulePath: string;
|
|
45
|
+
} | undefined>;
|
|
46
|
+
getStatusPage(status: number): Promise<RouteConfig | undefined>;
|
|
47
|
+
getErrorHandler(): Promise<RouteConfig | undefined>;
|
|
48
|
+
buildRouteHierarchy(pattern: string): string[];
|
|
49
|
+
loadModule<T>(modulePath: string): Promise<T>;
|
|
50
|
+
/**
|
|
51
|
+
* Get inlined `__files` from a loaded module (merged module pattern).
|
|
52
|
+
*/
|
|
53
|
+
getModuleFiles(mod: unknown): FileContents | undefined;
|
|
54
|
+
loadFiles(files: {
|
|
55
|
+
html?: string;
|
|
56
|
+
md?: string;
|
|
57
|
+
css?: string;
|
|
58
|
+
}): Promise<FileContents>;
|
|
59
|
+
toRouteInfo(matched: MatchedRoute, url: URL): RouteInfo;
|
|
60
|
+
buildContext(routeInfo: RouteInfo, route: RouteConfig, signal?: AbortSignal, isLeaf?: boolean, loadedModule?: unknown): Promise<ComponentContext>;
|
|
61
|
+
}
|