davaux 0.8.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/BASELINE.md +169 -0
- package/CLAUDE.md +518 -0
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/ROADMAP.md +198 -0
- package/build.mjs +101 -0
- package/client/control.ts +247 -0
- package/client/hydrate.ts +37 -0
- package/client/index.ts +19 -0
- package/client/jsx-runtime.ts +209 -0
- package/client/resource.ts +122 -0
- package/client/signal.ts +211 -0
- package/client/store.ts +110 -0
- package/client/useHead.ts +63 -0
- package/dist/build/config.d.ts +3 -0
- package/dist/build/config.d.ts.map +1 -0
- package/dist/build/config.js +38 -0
- package/dist/build/config.js.map +7 -0
- package/dist/build/index.d.ts +2 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +13 -0
- package/dist/build/index.js.map +7 -0
- package/dist/build/plugins.d.ts +7 -0
- package/dist/build/plugins.d.ts.map +1 -0
- package/dist/build/plugins.js +85 -0
- package/dist/build/plugins.js.map +7 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +7 -0
- package/dist/client/control.d.ts +49 -0
- package/dist/client/control.d.ts.map +1 -0
- package/dist/client/control.js +154 -0
- package/dist/client/control.js.map +7 -0
- package/dist/client/hydrate.d.ts +7 -0
- package/dist/client/hydrate.d.ts.map +1 -0
- package/dist/client/hydrate.js +23 -0
- package/dist/client/hydrate.js.map +7 -0
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +32 -0
- package/dist/client/index.js.map +7 -0
- package/dist/client/jsx-runtime.d.ts +40 -0
- package/dist/client/jsx-runtime.d.ts.map +1 -0
- package/dist/client/jsx-runtime.js +139 -0
- package/dist/client/jsx-runtime.js.map +7 -0
- package/dist/client/resource.d.ts +31 -0
- package/dist/client/resource.d.ts.map +1 -0
- package/dist/client/resource.js +64 -0
- package/dist/client/resource.js.map +7 -0
- package/dist/client/signal.d.ts +90 -0
- package/dist/client/signal.d.ts.map +1 -0
- package/dist/client/signal.js +115 -0
- package/dist/client/signal.js.map +7 -0
- package/dist/client/store.d.ts +26 -0
- package/dist/client/store.d.ts.map +1 -0
- package/dist/client/store.js +63 -0
- package/dist/client/store.js.map +7 -0
- package/dist/client/useHead.d.ts +28 -0
- package/dist/client/useHead.d.ts.map +1 -0
- package/dist/client/useHead.js +33 -0
- package/dist/client/useHead.js.map +7 -0
- package/dist/config.d.ts +182 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +21 -0
- package/dist/config.js.map +7 -0
- package/dist/create-multisite.d.ts +2 -0
- package/dist/create-multisite.d.ts.map +1 -0
- package/dist/create-multisite.js +291 -0
- package/dist/create-multisite.js.map +7 -0
- package/dist/create.d.ts +2 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +179 -0
- package/dist/create.js.map +7 -0
- package/dist/dev/blueprints.d.ts +11 -0
- package/dist/dev/blueprints.d.ts.map +1 -0
- package/dist/dev/blueprints.js +65 -0
- package/dist/dev/blueprints.js.map +7 -0
- package/dist/dev/components.d.ts +19 -0
- package/dist/dev/components.d.ts.map +1 -0
- package/dist/dev/components.js +87 -0
- package/dist/dev/components.js.map +7 -0
- package/dist/dev/insert.d.ts +11 -0
- package/dist/dev/insert.d.ts.map +1 -0
- package/dist/dev/insert.js +160 -0
- package/dist/dev/insert.js.map +7 -0
- package/dist/dev/remove.d.ts +53 -0
- package/dist/dev/remove.d.ts.map +1 -0
- package/dist/dev/remove.js +518 -0
- package/dist/dev/remove.js.map +7 -0
- package/dist/dev/watch.d.ts +26 -0
- package/dist/dev/watch.d.ts.map +1 -0
- package/dist/dev/watch.js +2905 -0
- package/dist/dev/watch.js.map +7 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +63 -0
- package/dist/errors.js.map +7 -0
- package/dist/generate.d.ts +2 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +191 -0
- package/dist/generate.js.map +7 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +7 -0
- package/dist/island.d.ts +24 -0
- package/dist/island.d.ts.map +1 -0
- package/dist/island.js +15 -0
- package/dist/island.js.map +7 -0
- package/dist/jsx-runtime.d.ts +406 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +90 -0
- package/dist/jsx-runtime.js.map +7 -0
- package/dist/link.d.ts +27 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +29 -0
- package/dist/link.js.map +7 -0
- package/dist/oml/fragment.d.ts +16 -0
- package/dist/oml/fragment.d.ts.map +1 -0
- package/dist/oml/fragment.js +26 -0
- package/dist/oml/fragment.js.map +7 -0
- package/dist/oml/index.d.ts +11 -0
- package/dist/oml/index.d.ts.map +1 -0
- package/dist/oml/index.js +21 -0
- package/dist/oml/index.js.map +7 -0
- package/dist/oml/jsx-runtime.d.ts +34 -0
- package/dist/oml/jsx-runtime.d.ts.map +1 -0
- package/dist/oml/jsx-runtime.js +59 -0
- package/dist/oml/jsx-runtime.js.map +7 -0
- package/dist/oml/jsx.d.ts +14 -0
- package/dist/oml/jsx.d.ts.map +1 -0
- package/dist/oml/jsx.js +96 -0
- package/dist/oml/jsx.js.map +7 -0
- package/dist/oml/page.d.ts +7 -0
- package/dist/oml/page.d.ts.map +1 -0
- package/dist/oml/page.js +6 -0
- package/dist/oml/page.js.map +7 -0
- package/dist/oml/render.d.ts +13 -0
- package/dist/oml/render.d.ts.map +1 -0
- package/dist/oml/render.js +117 -0
- package/dist/oml/render.js.map +7 -0
- package/dist/oml/types.d.ts +79 -0
- package/dist/oml/types.d.ts.map +1 -0
- package/dist/oml/types.js +64 -0
- package/dist/oml/types.js.map +7 -0
- package/dist/router/handler.d.ts +53 -0
- package/dist/router/handler.d.ts.map +1 -0
- package/dist/router/handler.js +342 -0
- package/dist/router/handler.js.map +7 -0
- package/dist/router/matcher.d.ts +21 -0
- package/dist/router/matcher.d.ts.map +1 -0
- package/dist/router/matcher.js +28 -0
- package/dist/router/matcher.js.map +7 -0
- package/dist/router/scanner.d.ts +17 -0
- package/dist/router/scanner.d.ts.map +1 -0
- package/dist/router/scanner.js +197 -0
- package/dist/router/scanner.js.map +7 -0
- package/dist/server/index.d.ts +23 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +29 -0
- package/dist/server/index.js.map +7 -0
- package/dist/signal.d.ts +15 -0
- package/dist/signal.d.ts.map +1 -0
- package/dist/signal.js +29 -0
- package/dist/signal.js.map +7 -0
- package/dist/ssg.d.ts +45 -0
- package/dist/ssg.d.ts.map +1 -0
- package/dist/ssg.js +175 -0
- package/dist/ssg.js.map +7 -0
- package/dist/test/actions.test.d.ts +2 -0
- package/dist/test/actions.test.d.ts.map +1 -0
- package/dist/test/body-limits.test.d.ts +2 -0
- package/dist/test/body-limits.test.d.ts.map +1 -0
- package/dist/test/errors.test.d.ts +2 -0
- package/dist/test/errors.test.d.ts.map +1 -0
- package/dist/test/fixtures/routes/[id].page.d.ts +4 -0
- package/dist/test/fixtures/routes/[id].page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_error.d.ts +3 -0
- package/dist/test/fixtures/routes/_error.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_global.d.ts +3 -0
- package/dist/test/fixtures/routes/_global.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout-template.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout-template.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_layout_scripts.d.ts +3 -0
- package/dist/test/fixtures/routes/_layout_scripts.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_middleware.d.ts +3 -0
- package/dist/test/fixtures/routes/_middleware.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_redirect301_mw.d.ts +3 -0
- package/dist/test/fixtures/routes/_redirect301_mw.d.ts.map +1 -0
- package/dist/test/fixtures/routes/_redirect_mw.d.ts +3 -0
- package/dist/test/fixtures/routes/_redirect_mw.d.ts.map +1 -0
- package/dist/test/fixtures/routes/about.page.d.ts +3 -0
- package/dist/test/fixtures/routes/about.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/action.page.d.ts +6 -0
- package/dist/test/fixtures/routes/action.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/form-all.post.d.ts +3 -0
- package/dist/test/fixtures/routes/api/form-all.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/form-limited.post.d.ts +6 -0
- package/dist/test/fixtures/routes/api/form-limited.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/response-obj.get.d.ts +3 -0
- package/dist/test/fixtures/routes/api/response-obj.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/upload.post.d.ts +12 -0
- package/dist/test/fixtures/routes/api/upload.post.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/users.get.d.ts +6 -0
- package/dist/test/fixtures/routes/api/users.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/api/xml.get.d.ts +3 -0
- package/dist/test/fixtures/routes/api/xml.get.d.ts.map +1 -0
- package/dist/test/fixtures/routes/auth/_middleware.d.ts +3 -0
- package/dist/test/fixtures/routes/auth/_middleware.d.ts.map +1 -0
- package/dist/test/fixtures/routes/auth/protected.page.d.ts +3 -0
- package/dist/test/fixtures/routes/auth/protected.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/index.page.d.ts +3 -0
- package/dist/test/fixtures/routes/index.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/oml.page.d.ts +3 -0
- package/dist/test/fixtures/routes/oml.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/redirect.page.d.ts +3 -0
- package/dist/test/fixtures/routes/redirect.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/ssg/[slug].page.d.ts +5 -0
- package/dist/test/fixtures/routes/ssg/[slug].page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/ssg/server.page.d.ts +4 -0
- package/dist/test/fixtures/routes/ssg/server.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/state.page.d.ts +3 -0
- package/dist/test/fixtures/routes/state.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/throw.page.d.ts +3 -0
- package/dist/test/fixtures/routes/throw.page.d.ts.map +1 -0
- package/dist/test/fixtures/routes/wiki/[...slug].page.d.ts +3 -0
- package/dist/test/fixtures/routes/wiki/[...slug].page.d.ts.map +1 -0
- package/dist/test/helpers.d.ts +37 -0
- package/dist/test/helpers.d.ts.map +1 -0
- package/dist/test/layouts.test.d.ts +2 -0
- package/dist/test/layouts.test.d.ts.map +1 -0
- package/dist/test/middleware.test.d.ts +2 -0
- package/dist/test/middleware.test.d.ts.map +1 -0
- package/dist/test/multipart.test.d.ts +2 -0
- package/dist/test/multipart.test.d.ts.map +1 -0
- package/dist/test/oml-routing.test.d.ts +2 -0
- package/dist/test/oml-routing.test.d.ts.map +1 -0
- package/dist/test/oml.test.d.ts +2 -0
- package/dist/test/oml.test.d.ts.map +1 -0
- package/dist/test/redirects.test.d.ts +2 -0
- package/dist/test/redirects.test.d.ts.map +1 -0
- package/dist/test/routing.test.d.ts +2 -0
- package/dist/test/routing.test.d.ts.map +1 -0
- package/dist/test/ssg.test.d.ts +2 -0
- package/dist/test/ssg.test.d.ts.map +1 -0
- package/dist/test/web-response.test.d.ts +2 -0
- package/dist/test/web-response.test.d.ts.map +1 -0
- package/dist/types.d.ts +314 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +292 -0
- package/dist/types.js.map +7 -0
- package/package.json +103 -0
- package/pka.config.json +32 -0
- package/src/build/config.ts +42 -0
- package/src/build/index.ts +6 -0
- package/src/build/plugins.ts +118 -0
- package/src/cli.ts +502 -0
- package/src/config.ts +197 -0
- package/src/create-multisite.ts +310 -0
- package/src/create.ts +194 -0
- package/src/dev/blueprints.ts +75 -0
- package/src/dev/components.ts +108 -0
- package/src/dev/insert.ts +221 -0
- package/src/dev/remove.ts +677 -0
- package/src/dev/watch.ts +3098 -0
- package/src/env.d.ts +5 -0
- package/src/errors.ts +64 -0
- package/src/generate.ts +228 -0
- package/src/index.ts +67 -0
- package/src/island.ts +47 -0
- package/src/jsx-runtime.d.ts +408 -0
- package/src/jsx-runtime.d.ts.map +1 -0
- package/src/jsx-runtime.ts +536 -0
- package/src/link.ts +49 -0
- package/src/oml/fragment.ts +54 -0
- package/src/oml/index.ts +21 -0
- package/src/oml/jsx-runtime.ts +121 -0
- package/src/oml/jsx.ts +151 -0
- package/src/oml/page.ts +13 -0
- package/src/oml/render.ts +181 -0
- package/src/oml/types.ts +159 -0
- package/src/router/handler.ts +515 -0
- package/src/router/matcher.ts +52 -0
- package/src/router/scanner.ts +272 -0
- package/src/server/index.ts +49 -0
- package/src/signal.ts +39 -0
- package/src/ssg.ts +253 -0
- package/src/test/actions.test.ts +40 -0
- package/src/test/body-limits.test.ts +83 -0
- package/src/test/errors.test.ts +53 -0
- package/src/test/fixtures/routes/[id].page.ts +3 -0
- package/src/test/fixtures/routes/_error.ts +6 -0
- package/src/test/fixtures/routes/_global.ts +8 -0
- package/src/test/fixtures/routes/_layout-template.ts +7 -0
- package/src/test/fixtures/routes/_layout.ts +7 -0
- package/src/test/fixtures/routes/_layout_scripts.ts +8 -0
- package/src/test/fixtures/routes/_middleware.ts +8 -0
- package/src/test/fixtures/routes/_redirect301_mw.ts +5 -0
- package/src/test/fixtures/routes/_redirect_mw.ts +5 -0
- package/src/test/fixtures/routes/about.page.ts +6 -0
- package/src/test/fixtures/routes/action.page.ts +11 -0
- package/src/test/fixtures/routes/api/form-all.post.ts +5 -0
- package/src/test/fixtures/routes/api/form-limited.post.ts +6 -0
- package/src/test/fixtures/routes/api/response-obj.get.ts +17 -0
- package/src/test/fixtures/routes/api/upload.post.ts +14 -0
- package/src/test/fixtures/routes/api/users.get.ts +3 -0
- package/src/test/fixtures/routes/api/xml.get.ts +5 -0
- package/src/test/fixtures/routes/auth/_middleware.ts +11 -0
- package/src/test/fixtures/routes/auth/protected.page.ts +3 -0
- package/src/test/fixtures/routes/index.page.ts +3 -0
- package/src/test/fixtures/routes/oml.page.ts +7 -0
- package/src/test/fixtures/routes/redirect.page.ts +3 -0
- package/src/test/fixtures/routes/ssg/[slug].page.ts +8 -0
- package/src/test/fixtures/routes/ssg/server.page.ts +5 -0
- package/src/test/fixtures/routes/state.page.ts +4 -0
- package/src/test/fixtures/routes/throw.page.ts +5 -0
- package/src/test/fixtures/routes/wiki/[...slug].page.ts +3 -0
- package/src/test/helpers.ts +132 -0
- package/src/test/layouts.test.ts +76 -0
- package/src/test/middleware.test.ts +69 -0
- package/src/test/multipart.test.ts +91 -0
- package/src/test/oml-routing.test.ts +59 -0
- package/src/test/oml.test.ts +429 -0
- package/src/test/redirects.test.ts +32 -0
- package/src/test/routing.test.ts +118 -0
- package/src/test/ssg.test.ts +273 -0
- package/src/test/web-response.test.ts +33 -0
- package/src/types.ts +670 -0
- package/tsconfig.client.json +17 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
// Server JSX runtime — renders component trees to HTML strings.
|
|
2
|
+
// TypeScript resolves this via jsxImportSource: "davaux" in tsconfig.json.
|
|
3
|
+
// Async components are fully supported: any component may return Promise<string>.
|
|
4
|
+
|
|
5
|
+
type Primitive = string | number | boolean | null | undefined
|
|
6
|
+
// Promise<object|null> lets OML JSX elements (Promise<OmlNode|string>) pass as children without errors.
|
|
7
|
+
type Child = Primitive | Promise<string | object | null> | Child[]
|
|
8
|
+
type StyleObject = Record<string, string | number>
|
|
9
|
+
|
|
10
|
+
export type Props = {
|
|
11
|
+
children?: Child | Child[]
|
|
12
|
+
key?: string | number
|
|
13
|
+
ref?: unknown
|
|
14
|
+
dangerouslySetInnerHTML?: { __html: string }
|
|
15
|
+
style?: string | StyleObject
|
|
16
|
+
className?: string
|
|
17
|
+
htmlFor?: string
|
|
18
|
+
tabIndex?: number
|
|
19
|
+
[prop: string]: unknown
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ComponentType<P extends Props = Props> = (props: P) => JSX.Element
|
|
23
|
+
|
|
24
|
+
// ─── HTML helpers ─────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
const VOID_ELEMENTS = new Set([
|
|
27
|
+
'area',
|
|
28
|
+
'base',
|
|
29
|
+
'br',
|
|
30
|
+
'col',
|
|
31
|
+
'embed',
|
|
32
|
+
'hr',
|
|
33
|
+
'img',
|
|
34
|
+
'input',
|
|
35
|
+
'link',
|
|
36
|
+
'meta',
|
|
37
|
+
'param',
|
|
38
|
+
'source',
|
|
39
|
+
'track',
|
|
40
|
+
'wbr',
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
function escapeHtml(s: string): string {
|
|
44
|
+
return s
|
|
45
|
+
.replace(/&/g, '&')
|
|
46
|
+
.replace(/</g, '<')
|
|
47
|
+
.replace(/>/g, '>')
|
|
48
|
+
.replace(/"/g, '"')
|
|
49
|
+
.replace(/'/g, ''')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function styleToString(style: StyleObject): string {
|
|
53
|
+
return Object.entries(style)
|
|
54
|
+
.map(([k, v]) => {
|
|
55
|
+
// camelCase → kebab-case
|
|
56
|
+
const prop = k.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)
|
|
57
|
+
return `${prop}:${v}`
|
|
58
|
+
})
|
|
59
|
+
.join(';')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function renderChildren(children: Child | Child[] | undefined): Promise<string> {
|
|
63
|
+
if (children == null || children === false) return ''
|
|
64
|
+
if (Array.isArray(children)) {
|
|
65
|
+
const parts = await Promise.all(children.map((c) => renderChildren(c)))
|
|
66
|
+
return parts.join('')
|
|
67
|
+
}
|
|
68
|
+
if (children instanceof Promise) {
|
|
69
|
+
const resolved = await children
|
|
70
|
+
// The OML jsx runtime produces OmlNode objects instead of strings. Render them to
|
|
71
|
+
// HTML on the fly — the import is cached by Node after the first call.
|
|
72
|
+
if (resolved !== null && typeof resolved === 'object') {
|
|
73
|
+
const { renderToHtml } = await import('./oml/render.js')
|
|
74
|
+
return renderToHtml(resolved as never)
|
|
75
|
+
}
|
|
76
|
+
return (resolved ?? '') as string
|
|
77
|
+
}
|
|
78
|
+
if (typeof children === 'boolean') return ''
|
|
79
|
+
return escapeHtml(String(children))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderAttrs(props: Props): string {
|
|
83
|
+
const parts: string[] = []
|
|
84
|
+
|
|
85
|
+
for (const [key, val] of Object.entries(props)) {
|
|
86
|
+
if (key === 'children' || key === 'key' || key === 'ref' || key === 'dangerouslySetInnerHTML')
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
if (val === false || val == null) continue
|
|
90
|
+
|
|
91
|
+
// Map React-isms to HTML attributes
|
|
92
|
+
const attr =
|
|
93
|
+
key === 'className'
|
|
94
|
+
? 'class'
|
|
95
|
+
: key === 'htmlFor'
|
|
96
|
+
? 'for'
|
|
97
|
+
: key === 'tabIndex'
|
|
98
|
+
? 'tabindex'
|
|
99
|
+
: key
|
|
100
|
+
|
|
101
|
+
// Skip event handlers — they have no meaning in SSR
|
|
102
|
+
if (attr.startsWith('on') && attr[2] === attr[2]?.toUpperCase()) continue
|
|
103
|
+
|
|
104
|
+
if (val === true) {
|
|
105
|
+
parts.push(attr)
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (attr === 'style') {
|
|
110
|
+
const css = typeof val === 'string' ? val : styleToString(val as StyleObject)
|
|
111
|
+
parts.push(`style="${escapeHtml(css)}"`)
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
parts.push(`${attr}="${escapeHtml(String(val))}"`)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return parts.length ? ` ${parts.join(' ')}` : ''
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ─── JSX factory ──────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
export async function jsx(
|
|
124
|
+
type: string | ComponentType,
|
|
125
|
+
props: Props,
|
|
126
|
+
_key?: string | number,
|
|
127
|
+
): Promise<string> {
|
|
128
|
+
if (typeof type === 'function') {
|
|
129
|
+
const result = type(props)
|
|
130
|
+
return (result instanceof Promise ? await result : result) as unknown as string
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (type === Fragment) {
|
|
134
|
+
return renderChildren(props.children)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (props.dangerouslySetInnerHTML) {
|
|
138
|
+
const attrs = renderAttrs(props)
|
|
139
|
+
return `<${type}${attrs}>${props.dangerouslySetInnerHTML.__html}</${type}>`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const attrs = renderAttrs(props)
|
|
143
|
+
if (VOID_ELEMENTS.has(type)) return `<${type}${attrs}>`
|
|
144
|
+
|
|
145
|
+
const children = await renderChildren(props.children)
|
|
146
|
+
return `<${type}${attrs}>${children}</${type}>`
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const jsxs = jsx
|
|
150
|
+
export const jsxDEV = jsx
|
|
151
|
+
|
|
152
|
+
export const Fragment = '__Fragment__'
|
|
153
|
+
|
|
154
|
+
// ─── JSX namespace (used by TypeScript for element type checking) ──────────────
|
|
155
|
+
|
|
156
|
+
export namespace JSX {
|
|
157
|
+
// Always Promise<string> — async functions returning JSX auto-unwrap to Promise<string>.
|
|
158
|
+
// Sync functions returning JSX also satisfy this because JSX.Element = Promise<string>
|
|
159
|
+
// and a sync function returning a promise is valid where Promise<string> is expected.
|
|
160
|
+
export type Element = Promise<string>
|
|
161
|
+
|
|
162
|
+
export interface ElementChildrenAttribute {
|
|
163
|
+
children: object
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface IntrinsicAttributes {
|
|
167
|
+
key?: string | number
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Shared HTML attribute base
|
|
171
|
+
interface HTMLAttributes {
|
|
172
|
+
id?: string
|
|
173
|
+
class?: string
|
|
174
|
+
className?: string
|
|
175
|
+
style?: string | StyleObject
|
|
176
|
+
title?: string
|
|
177
|
+
lang?: string
|
|
178
|
+
dir?: 'ltr' | 'rtl' | 'auto'
|
|
179
|
+
hidden?: boolean
|
|
180
|
+
tabIndex?: number
|
|
181
|
+
tabindex?: number
|
|
182
|
+
role?: string
|
|
183
|
+
slot?: string
|
|
184
|
+
draggable?: boolean
|
|
185
|
+
spellcheck?: boolean
|
|
186
|
+
contenteditable?: boolean | 'true' | 'false'
|
|
187
|
+
dangerouslySetInnerHTML?: { __html: string }
|
|
188
|
+
// data-* and aria-*
|
|
189
|
+
[attr: string]: unknown
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interface AnchorAttributes extends HTMLAttributes {
|
|
193
|
+
href?: string
|
|
194
|
+
target?: '_blank' | '_self' | '_parent' | '_top' | string
|
|
195
|
+
rel?: string
|
|
196
|
+
download?: string | boolean
|
|
197
|
+
hreflang?: string
|
|
198
|
+
type?: string
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface InputAttributes extends HTMLAttributes {
|
|
202
|
+
type?: string
|
|
203
|
+
name?: string
|
|
204
|
+
value?: string | number
|
|
205
|
+
defaultValue?: string | number
|
|
206
|
+
checked?: boolean
|
|
207
|
+
defaultChecked?: boolean
|
|
208
|
+
placeholder?: string
|
|
209
|
+
disabled?: boolean
|
|
210
|
+
readonly?: boolean
|
|
211
|
+
required?: boolean
|
|
212
|
+
min?: string | number
|
|
213
|
+
max?: string | number
|
|
214
|
+
step?: string | number
|
|
215
|
+
multiple?: boolean
|
|
216
|
+
accept?: string
|
|
217
|
+
autocomplete?: string
|
|
218
|
+
autofocus?: boolean
|
|
219
|
+
form?: string
|
|
220
|
+
pattern?: string
|
|
221
|
+
list?: string
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface FormAttributes extends HTMLAttributes {
|
|
225
|
+
action?: string
|
|
226
|
+
method?: 'get' | 'post'
|
|
227
|
+
enctype?: string
|
|
228
|
+
target?: string
|
|
229
|
+
novalidate?: boolean
|
|
230
|
+
autocomplete?: string
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
interface ButtonAttributes extends HTMLAttributes {
|
|
234
|
+
type?: 'button' | 'submit' | 'reset'
|
|
235
|
+
disabled?: boolean
|
|
236
|
+
form?: string
|
|
237
|
+
name?: string
|
|
238
|
+
value?: string
|
|
239
|
+
autofocus?: boolean
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
interface ImgAttributes extends HTMLAttributes {
|
|
243
|
+
src?: string
|
|
244
|
+
alt?: string
|
|
245
|
+
width?: number | string
|
|
246
|
+
height?: number | string
|
|
247
|
+
loading?: 'lazy' | 'eager'
|
|
248
|
+
decoding?: 'async' | 'auto' | 'sync'
|
|
249
|
+
srcset?: string
|
|
250
|
+
sizes?: string
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
interface LinkAttributes extends HTMLAttributes {
|
|
254
|
+
href?: string
|
|
255
|
+
rel?: string
|
|
256
|
+
type?: string
|
|
257
|
+
media?: string
|
|
258
|
+
as?: string
|
|
259
|
+
crossorigin?: string
|
|
260
|
+
integrity?: string
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
interface ScriptAttributes extends HTMLAttributes {
|
|
264
|
+
src?: string
|
|
265
|
+
type?: string
|
|
266
|
+
async?: boolean
|
|
267
|
+
defer?: boolean
|
|
268
|
+
module?: boolean
|
|
269
|
+
crossorigin?: string
|
|
270
|
+
integrity?: string
|
|
271
|
+
nonce?: string
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface MetaAttributes extends HTMLAttributes {
|
|
275
|
+
name?: string
|
|
276
|
+
content?: string
|
|
277
|
+
charset?: string
|
|
278
|
+
httpEquiv?: string
|
|
279
|
+
property?: string
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface LabelAttributes extends HTMLAttributes {
|
|
283
|
+
htmlFor?: string
|
|
284
|
+
for?: string
|
|
285
|
+
form?: string
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
interface SelectAttributes extends HTMLAttributes {
|
|
289
|
+
name?: string
|
|
290
|
+
value?: string
|
|
291
|
+
defaultValue?: string
|
|
292
|
+
multiple?: boolean
|
|
293
|
+
disabled?: boolean
|
|
294
|
+
required?: boolean
|
|
295
|
+
size?: number
|
|
296
|
+
form?: string
|
|
297
|
+
autocomplete?: string
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
interface TextareaAttributes extends HTMLAttributes {
|
|
301
|
+
name?: string
|
|
302
|
+
value?: string
|
|
303
|
+
defaultValue?: string
|
|
304
|
+
placeholder?: string
|
|
305
|
+
disabled?: boolean
|
|
306
|
+
readonly?: boolean
|
|
307
|
+
required?: boolean
|
|
308
|
+
rows?: number
|
|
309
|
+
cols?: number
|
|
310
|
+
maxlength?: number
|
|
311
|
+
form?: string
|
|
312
|
+
autocomplete?: string
|
|
313
|
+
autofocus?: boolean
|
|
314
|
+
wrap?: 'hard' | 'soft'
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
interface VideoAttributes extends HTMLAttributes {
|
|
318
|
+
src?: string
|
|
319
|
+
controls?: boolean
|
|
320
|
+
autoplay?: boolean
|
|
321
|
+
loop?: boolean
|
|
322
|
+
muted?: boolean
|
|
323
|
+
poster?: string
|
|
324
|
+
width?: number | string
|
|
325
|
+
height?: number | string
|
|
326
|
+
preload?: 'auto' | 'metadata' | 'none'
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
interface AudioAttributes extends HTMLAttributes {
|
|
330
|
+
src?: string
|
|
331
|
+
controls?: boolean
|
|
332
|
+
autoplay?: boolean
|
|
333
|
+
loop?: boolean
|
|
334
|
+
muted?: boolean
|
|
335
|
+
preload?: 'auto' | 'metadata' | 'none'
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
interface ColAttributes extends HTMLAttributes {
|
|
339
|
+
span?: number
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
interface TdAttributes extends HTMLAttributes {
|
|
343
|
+
colspan?: number
|
|
344
|
+
rowspan?: number
|
|
345
|
+
headers?: string
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
interface ThAttributes extends TdAttributes {
|
|
349
|
+
scope?: 'col' | 'row' | 'colgroup' | 'rowgroup'
|
|
350
|
+
abbr?: string
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
interface IframeAttributes extends HTMLAttributes {
|
|
354
|
+
src?: string
|
|
355
|
+
srcdoc?: string
|
|
356
|
+
name?: string
|
|
357
|
+
sandbox?: string
|
|
358
|
+
allow?: string
|
|
359
|
+
allowfullscreen?: boolean
|
|
360
|
+
width?: number | string
|
|
361
|
+
height?: number | string
|
|
362
|
+
loading?: 'lazy' | 'eager'
|
|
363
|
+
referrerpolicy?: string
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface IntrinsicElements {
|
|
367
|
+
// Document structure
|
|
368
|
+
html: HTMLAttributes
|
|
369
|
+
head: HTMLAttributes
|
|
370
|
+
body: HTMLAttributes
|
|
371
|
+
title: HTMLAttributes
|
|
372
|
+
base: HTMLAttributes & { href?: string; target?: string }
|
|
373
|
+
link: LinkAttributes
|
|
374
|
+
meta: MetaAttributes
|
|
375
|
+
style: HTMLAttributes & { media?: string }
|
|
376
|
+
script: ScriptAttributes
|
|
377
|
+
noscript: HTMLAttributes
|
|
378
|
+
|
|
379
|
+
// Sectioning
|
|
380
|
+
main: HTMLAttributes
|
|
381
|
+
header: HTMLAttributes
|
|
382
|
+
footer: HTMLAttributes
|
|
383
|
+
nav: HTMLAttributes
|
|
384
|
+
section: HTMLAttributes
|
|
385
|
+
article: HTMLAttributes
|
|
386
|
+
aside: HTMLAttributes
|
|
387
|
+
h1: HTMLAttributes
|
|
388
|
+
h2: HTMLAttributes
|
|
389
|
+
h3: HTMLAttributes
|
|
390
|
+
h4: HTMLAttributes
|
|
391
|
+
h5: HTMLAttributes
|
|
392
|
+
h6: HTMLAttributes
|
|
393
|
+
hgroup: HTMLAttributes
|
|
394
|
+
address: HTMLAttributes
|
|
395
|
+
|
|
396
|
+
// Content
|
|
397
|
+
div: HTMLAttributes
|
|
398
|
+
span: HTMLAttributes
|
|
399
|
+
p: HTMLAttributes
|
|
400
|
+
pre: HTMLAttributes
|
|
401
|
+
blockquote: HTMLAttributes & { cite?: string }
|
|
402
|
+
hr: HTMLAttributes
|
|
403
|
+
br: HTMLAttributes
|
|
404
|
+
wbr: HTMLAttributes
|
|
405
|
+
figure: HTMLAttributes
|
|
406
|
+
figcaption: HTMLAttributes
|
|
407
|
+
details: HTMLAttributes & { open?: boolean }
|
|
408
|
+
summary: HTMLAttributes
|
|
409
|
+
dialog: HTMLAttributes & { open?: boolean }
|
|
410
|
+
|
|
411
|
+
// Lists
|
|
412
|
+
ul: HTMLAttributes
|
|
413
|
+
ol: HTMLAttributes & { start?: number; reversed?: boolean; type?: string }
|
|
414
|
+
li: HTMLAttributes & { value?: number }
|
|
415
|
+
dl: HTMLAttributes
|
|
416
|
+
dt: HTMLAttributes
|
|
417
|
+
dd: HTMLAttributes
|
|
418
|
+
|
|
419
|
+
// Inline text
|
|
420
|
+
a: AnchorAttributes
|
|
421
|
+
em: HTMLAttributes
|
|
422
|
+
strong: HTMLAttributes
|
|
423
|
+
small: HTMLAttributes
|
|
424
|
+
s: HTMLAttributes
|
|
425
|
+
cite: HTMLAttributes
|
|
426
|
+
q: HTMLAttributes & { cite?: string }
|
|
427
|
+
dfn: HTMLAttributes
|
|
428
|
+
abbr: HTMLAttributes
|
|
429
|
+
code: HTMLAttributes
|
|
430
|
+
var: HTMLAttributes
|
|
431
|
+
samp: HTMLAttributes
|
|
432
|
+
kbd: HTMLAttributes
|
|
433
|
+
sub: HTMLAttributes
|
|
434
|
+
sup: HTMLAttributes
|
|
435
|
+
b: HTMLAttributes
|
|
436
|
+
u: HTMLAttributes
|
|
437
|
+
i: HTMLAttributes
|
|
438
|
+
mark: HTMLAttributes
|
|
439
|
+
ruby: HTMLAttributes
|
|
440
|
+
rp: HTMLAttributes
|
|
441
|
+
rt: HTMLAttributes
|
|
442
|
+
bdi: HTMLAttributes
|
|
443
|
+
bdo: HTMLAttributes
|
|
444
|
+
time: HTMLAttributes & { datetime?: string }
|
|
445
|
+
data: HTMLAttributes & { value?: string }
|
|
446
|
+
|
|
447
|
+
// Forms
|
|
448
|
+
form: FormAttributes
|
|
449
|
+
label: LabelAttributes
|
|
450
|
+
input: InputAttributes
|
|
451
|
+
button: ButtonAttributes
|
|
452
|
+
select: SelectAttributes
|
|
453
|
+
datalist: HTMLAttributes
|
|
454
|
+
optgroup: HTMLAttributes & { label?: string; disabled?: boolean }
|
|
455
|
+
option: HTMLAttributes & {
|
|
456
|
+
value?: string
|
|
457
|
+
disabled?: boolean
|
|
458
|
+
selected?: boolean
|
|
459
|
+
label?: string
|
|
460
|
+
}
|
|
461
|
+
textarea: TextareaAttributes
|
|
462
|
+
output: HTMLAttributes & { for?: string; form?: string; name?: string }
|
|
463
|
+
progress: HTMLAttributes & { value?: number; max?: number }
|
|
464
|
+
meter: HTMLAttributes & {
|
|
465
|
+
value?: number
|
|
466
|
+
min?: number
|
|
467
|
+
max?: number
|
|
468
|
+
low?: number
|
|
469
|
+
high?: number
|
|
470
|
+
optimum?: number
|
|
471
|
+
}
|
|
472
|
+
fieldset: HTMLAttributes & { disabled?: boolean; form?: string; name?: string }
|
|
473
|
+
legend: HTMLAttributes
|
|
474
|
+
|
|
475
|
+
// Media
|
|
476
|
+
img: ImgAttributes
|
|
477
|
+
video: VideoAttributes
|
|
478
|
+
audio: AudioAttributes
|
|
479
|
+
source: HTMLAttributes & {
|
|
480
|
+
src?: string
|
|
481
|
+
type?: string
|
|
482
|
+
srcset?: string
|
|
483
|
+
sizes?: string
|
|
484
|
+
media?: string
|
|
485
|
+
}
|
|
486
|
+
track: HTMLAttributes & {
|
|
487
|
+
src?: string
|
|
488
|
+
kind?: string
|
|
489
|
+
label?: string
|
|
490
|
+
srclang?: string
|
|
491
|
+
default?: boolean
|
|
492
|
+
}
|
|
493
|
+
embed: HTMLAttributes & {
|
|
494
|
+
src?: string
|
|
495
|
+
type?: string
|
|
496
|
+
width?: number | string
|
|
497
|
+
height?: number | string
|
|
498
|
+
}
|
|
499
|
+
object: HTMLAttributes & {
|
|
500
|
+
data?: string
|
|
501
|
+
type?: string
|
|
502
|
+
width?: number | string
|
|
503
|
+
height?: number | string
|
|
504
|
+
}
|
|
505
|
+
picture: HTMLAttributes
|
|
506
|
+
canvas: HTMLAttributes & { width?: number | string; height?: number | string }
|
|
507
|
+
map: HTMLAttributes & { name?: string }
|
|
508
|
+
area: HTMLAttributes & {
|
|
509
|
+
alt?: string
|
|
510
|
+
coords?: string
|
|
511
|
+
shape?: string
|
|
512
|
+
href?: string
|
|
513
|
+
target?: string
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Tables
|
|
517
|
+
table: HTMLAttributes
|
|
518
|
+
caption: HTMLAttributes
|
|
519
|
+
colgroup: HTMLAttributes & { span?: number }
|
|
520
|
+
col: ColAttributes
|
|
521
|
+
thead: HTMLAttributes
|
|
522
|
+
tbody: HTMLAttributes
|
|
523
|
+
tfoot: HTMLAttributes
|
|
524
|
+
tr: HTMLAttributes
|
|
525
|
+
td: TdAttributes
|
|
526
|
+
th: ThAttributes
|
|
527
|
+
|
|
528
|
+
// Interactive
|
|
529
|
+
iframe: IframeAttributes
|
|
530
|
+
portal: HTMLAttributes
|
|
531
|
+
menu: HTMLAttributes
|
|
532
|
+
|
|
533
|
+
// Obsolete / catch-all
|
|
534
|
+
[tag: string]: HTMLAttributes
|
|
535
|
+
}
|
|
536
|
+
}
|
package/src/link.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { JSX } from './jsx-runtime.js'
|
|
2
|
+
import { jsx } from './jsx-runtime.js'
|
|
3
|
+
import type { RequestContext } from './types.js'
|
|
4
|
+
|
|
5
|
+
type AnchorProps = JSX.IntrinsicElements['a']
|
|
6
|
+
type LinkProps = AnchorProps & {
|
|
7
|
+
activeClass?: string
|
|
8
|
+
external?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create basePath-aware link utilities for use in layouts and pages.
|
|
13
|
+
*
|
|
14
|
+
* Returns `{ link, Link }`:
|
|
15
|
+
* - `link(href)` — prefixes the configured `basePath` to absolute paths.
|
|
16
|
+
* - `Link` — a JSX `<a>` component that also handles `activeClass` detection
|
|
17
|
+
* and sets safe defaults (`rel="noopener noreferrer"`, `target="_blank"`) for
|
|
18
|
+
* external links.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const { link, Link } = createLink(ctx)
|
|
22
|
+
* <Link href="/about" activeClass="active">About</Link>
|
|
23
|
+
* <Link href="https://example.com" external>External</Link>
|
|
24
|
+
*/
|
|
25
|
+
export function createLink(ctx: RequestContext) {
|
|
26
|
+
const link = (href: string) => (href.startsWith('/') ? `${ctx.basePath}${href}` : href)
|
|
27
|
+
const Link = ({
|
|
28
|
+
href = '',
|
|
29
|
+
activeClass,
|
|
30
|
+
external,
|
|
31
|
+
class: className,
|
|
32
|
+
rel,
|
|
33
|
+
target,
|
|
34
|
+
...rest
|
|
35
|
+
}: LinkProps) => {
|
|
36
|
+
const resolvedHref = link(href)
|
|
37
|
+
const isActive = activeClass != null && resolvedHref === ctx.url.pathname
|
|
38
|
+
const classes =
|
|
39
|
+
[className, isActive ? activeClass : undefined].filter(Boolean).join(' ') || undefined
|
|
40
|
+
const resolvedTarget = external && !target ? '_blank' : target
|
|
41
|
+
const resolvedRel = external && !rel ? 'noopener noreferrer' : rel
|
|
42
|
+
return jsx(
|
|
43
|
+
'a',
|
|
44
|
+
{ href: resolvedHref, class: classes, target: resolvedTarget, rel: resolvedRel, ...rest },
|
|
45
|
+
undefined,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
return { link, Link }
|
|
49
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { OmlNode } from './types.js'
|
|
2
|
+
|
|
3
|
+
export type OmlFragmentOptions<P> = {
|
|
4
|
+
/** Derive a stable string cache key from props. Defaults to JSON.stringify(props). */
|
|
5
|
+
key?: (props: P) => string
|
|
6
|
+
/** Time-to-live in milliseconds. Omit for indefinite caching. */
|
|
7
|
+
ttl?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type CacheEntry = { node: OmlNode; at: number }
|
|
11
|
+
|
|
12
|
+
const registry = new Set<Map<string, CacheEntry>>()
|
|
13
|
+
|
|
14
|
+
/** Invalidate all fragment caches — useful after CMS updates or programmatic cache busting. */
|
|
15
|
+
export function clearAllFragments(): void {
|
|
16
|
+
for (const cache of registry) cache.clear()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Define a cached, no-props OML fragment. The function runs once; subsequent calls return the cached node. */
|
|
20
|
+
export function defineFragment(
|
|
21
|
+
fn: () => OmlNode | Promise<OmlNode>,
|
|
22
|
+
options?: { ttl?: number },
|
|
23
|
+
): () => Promise<OmlNode>
|
|
24
|
+
|
|
25
|
+
/** Define a cached OML fragment that accepts props. Caches per unique prop combination. */
|
|
26
|
+
export function defineFragment<P extends Record<string, unknown>>(
|
|
27
|
+
fn: (props: P) => OmlNode | Promise<OmlNode>,
|
|
28
|
+
options?: OmlFragmentOptions<P>,
|
|
29
|
+
): (props: P) => Promise<OmlNode>
|
|
30
|
+
|
|
31
|
+
export function defineFragment<P extends Record<string, unknown>>(
|
|
32
|
+
fn: (props?: P) => OmlNode | Promise<OmlNode>,
|
|
33
|
+
options?: OmlFragmentOptions<P>,
|
|
34
|
+
): (props?: P) => Promise<OmlNode> {
|
|
35
|
+
const cache = new Map<string, CacheEntry>()
|
|
36
|
+
registry.add(cache)
|
|
37
|
+
|
|
38
|
+
return async (props?: P): Promise<OmlNode> => {
|
|
39
|
+
const key =
|
|
40
|
+
options?.key && props !== undefined ? options.key(props) : JSON.stringify(props ?? null)
|
|
41
|
+
|
|
42
|
+
const entry = cache.get(key)
|
|
43
|
+
if (entry !== undefined) {
|
|
44
|
+
if (!options?.ttl || Date.now() - entry.at < options.ttl) {
|
|
45
|
+
return entry.node
|
|
46
|
+
}
|
|
47
|
+
cache.delete(key)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const node = await fn(props)
|
|
51
|
+
cache.set(key, { node, at: Date.now() })
|
|
52
|
+
return node
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/oml/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type { OmlFragmentOptions } from './fragment.js'
|
|
2
|
+
export { clearAllFragments, defineFragment } from './fragment.js'
|
|
3
|
+
export { blueprintToFile, renderToJsx } from './jsx.js'
|
|
4
|
+
export type { ComponentType as OmlComponentType, Props as OmlJsxProps } from './jsx-runtime.js'
|
|
5
|
+
export { Fragment, jsx, jsxDEV, jsxs } from './jsx-runtime.js'
|
|
6
|
+
export type { OmlPageHandler } from './page.js'
|
|
7
|
+
export { defineOmlPage } from './page.js'
|
|
8
|
+
export { renderToHtml } from './render.js'
|
|
9
|
+
export type {
|
|
10
|
+
OmlBlueprint,
|
|
11
|
+
OmlComponent,
|
|
12
|
+
OmlElement,
|
|
13
|
+
OmlFragment,
|
|
14
|
+
OmlNode,
|
|
15
|
+
OmlPropSchema,
|
|
16
|
+
OmlProps,
|
|
17
|
+
OmlPropType,
|
|
18
|
+
OmlRaw,
|
|
19
|
+
OmlText,
|
|
20
|
+
} from './types.js'
|
|
21
|
+
export { parseOml, parseOmlBlueprint } from './types.js'
|