duto 0.260906.0 → 0.261001.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 +34 -12
- package/package.json +9 -3
- package/src/cli.ts +10 -7
- package/src/commands/new.ts +172 -0
- package/src/commands/templates/pages/.editorconfig +21 -0
- package/src/commands/templates/pages/README.md +21 -0
- package/src/commands/templates/pages/_gitignore +24 -0
- package/src/commands/templates/pages/components/locale-select.tsx +59 -0
- package/src/commands/templates/pages/components/select.tsx +95 -0
- package/src/commands/templates/pages/i18n/en.ts +17 -0
- package/src/commands/templates/pages/i18n/index.ts +19 -0
- package/src/commands/templates/pages/i18n/pt-br.ts +17 -0
- package/src/commands/templates/pages/package.json +22 -0
- package/src/commands/templates/pages/pages/404.tsx +12 -0
- package/src/commands/templates/pages/pages/index.tsx +16 -0
- package/src/commands/templates/pages/pages/layout.tsx +24 -0
- package/src/commands/templates/pages/style.css +24 -0
- package/src/commands/templates/pages/tsconfig.json +54 -0
- package/src/commands/templates/pages/types.ts +8 -0
- package/src/commands/templates/server/base/.editorconfig +21 -0
- package/src/commands/templates/server/base/.env.dev.example +2 -0
- package/src/commands/templates/server/base/.env.prod.example +2 -0
- package/src/commands/templates/server/base/README.md +29 -0
- package/src/commands/templates/server/base/_gitignore +100 -0
- package/src/commands/templates/server/base/actions/blog/index.get.ts +9 -0
- package/src/commands/templates/server/base/actions/blog/post/[id].get.ts +9 -0
- package/src/commands/templates/server/base/actions/index.get.ts +5 -0
- package/src/commands/templates/server/base/configs/duto.ts +11 -0
- package/src/commands/templates/server/base/configs/roles.ts +5 -0
- package/src/commands/templates/server/base/package.json +24 -0
- package/src/commands/templates/server/base/tsconfig.json +42 -0
- package/src/commands/templates/server/workerd/wrangler.toml +47 -0
- package/src/commands/upgrade.ts +30 -0
- package/src/index.ts +7 -2
- package/src/pages/{commands → cli/commands}/build.ts +13 -7
- package/src/pages/{commands → cli/commands}/dev.ts +19 -6
- package/src/pages/{commands → cli/commands}/preview.ts +6 -4
- package/src/pages/cli/index.ts +10 -0
- package/src/pages/cli/utils.ts +126 -0
- package/src/pages/client/app.tsx +27 -74
- package/src/pages/client/router.ts +15 -281
- package/src/pages/compiler/aliases.ts +2 -8
- package/src/pages/compiler/ast.ts +1 -538
- package/src/pages/compiler/constants.ts +95 -13
- package/src/pages/compiler/file.ts +1 -1
- package/src/pages/compiler/index.ts +20 -128
- package/src/pages/compiler/meta.ts +39 -228
- package/src/pages/compiler/routes.ts +4 -5
- package/src/pages/compiler/types.ts +11 -101
- package/src/pages/compiler/vite-plugin.ts +90 -69
- package/src/pages/i18n/client.ts +19 -7
- package/src/pages/i18n/element.ts +1 -1
- package/src/pages/i18n/server.ts +22 -7
- package/src/pages/index.ts +1 -2
- package/src/pages/preact/server.ts +1 -1
- package/src/server/app.ts +5 -10
- package/src/server/auth/ability.ts +1 -1
- package/src/server/auth/token.ts +5 -5
- package/src/server/cli/commands/build.ts +2 -2
- package/src/server/cli/commands/deploy.ts +1 -2
- package/src/server/cli/commands/dev.ts +6 -4
- package/src/server/cli/commands/routes.ts +0 -1
- package/src/server/cli/utils.ts +2 -8
- package/src/server/config.ts +18 -3
- package/src/server/entry.ts +3 -3
- package/src/server/open-api/register.ts +3 -3
- package/src/server/open-api/spec.ts +11 -4
- package/src/server/request.ts +46 -14
- package/src/server/routes.ts +8 -31
- package/src/server/utils.ts +25 -0
- package/src/utils.ts +43 -2
- package/src/pages/commands/dev-old.ts +0 -213
- package/src/pages/compiler/island.ts +0 -108
- package/src/pages/compiler/utils.ts +0 -5
- package/src/server/http.ts +0 -23
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { IMPORT, Datte } from 't0n'
|
|
2
|
+
import { join } from 'pathe'
|
|
3
|
+
import { gray, green, yellow, red, cyan } from 't0n/color'
|
|
4
|
+
import type { UserConfig } from 'vite'
|
|
5
|
+
|
|
6
|
+
import { resolveExtension } from '#/compiler/file'
|
|
7
|
+
import config from '#/compiler/vite-plugin'
|
|
8
|
+
import { _root } from '@/utils'
|
|
9
|
+
import { match, match404 } from '#/compiler/routes'
|
|
10
|
+
import type { Metadata, PluginOptions } from '#/compiler/types'
|
|
11
|
+
import { EXTENSIONS_LIST } from '#/compiler/constants'
|
|
12
|
+
|
|
13
|
+
export async function getConfig(name = 'config'): Promise<UserConfig & PluginOptions> {
|
|
14
|
+
let opts = {} as UserConfig
|
|
15
|
+
const file = resolveExtension(name)
|
|
16
|
+
if (file) opts = await IMPORT(join(_root, file), 'default')
|
|
17
|
+
return config(opts)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const statusColorMap = new Map([
|
|
21
|
+
[5, red],
|
|
22
|
+
[4, yellow],
|
|
23
|
+
[3, cyan],
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
const getStatusColor = (status: number) => (statusColorMap.get(Math.floor(status / 100)) ?? green)(String(status))
|
|
27
|
+
|
|
28
|
+
const clients = new Set<Bun.ServerWebSocket<void>>()
|
|
29
|
+
export function reload() {
|
|
30
|
+
for (const ws of clients) {
|
|
31
|
+
if (ws.readyState === WebSocket.OPEN)
|
|
32
|
+
ws.send('reload')
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function preview(
|
|
37
|
+
meta: Metadata,
|
|
38
|
+
host: string = '0.0.0.0',
|
|
39
|
+
port: number = 4173
|
|
40
|
+
) {
|
|
41
|
+
return Bun.serve({
|
|
42
|
+
hostname: host,
|
|
43
|
+
port,
|
|
44
|
+
|
|
45
|
+
websocket: {
|
|
46
|
+
open(ws) {
|
|
47
|
+
clients.add(ws)
|
|
48
|
+
},
|
|
49
|
+
close(ws) {
|
|
50
|
+
clients.delete(ws)
|
|
51
|
+
},
|
|
52
|
+
message() {},
|
|
53
|
+
},
|
|
54
|
+
async fetch(req, server) {
|
|
55
|
+
const start = performance.now()
|
|
56
|
+
|
|
57
|
+
const url = new URL(req.url)
|
|
58
|
+
const path = decodeURIComponent(url.pathname)
|
|
59
|
+
const headers = {
|
|
60
|
+
'Access-Control-Allow-Origin': '*',
|
|
61
|
+
'Access-Control-Allow-Methods': 'GET',
|
|
62
|
+
'Access-Control-Allow-Headers': '*',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (req.method === 'OPTIONS')
|
|
66
|
+
return new Response(null, { status: 204, headers })
|
|
67
|
+
|
|
68
|
+
if (req.headers.get('upgrade') === 'websocket'
|
|
69
|
+
&& req.headers.get('sec-websocket-protocol') === 'duto') {
|
|
70
|
+
server.upgrade(req)
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let status = 500
|
|
75
|
+
let route: string | undefined
|
|
76
|
+
let matched: Bun.MatchedRoute | null | undefined
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
let res: Response
|
|
80
|
+
const dist = 'dist' // TODO: get from configs
|
|
81
|
+
|
|
82
|
+
let file = Bun.file(join(_root, dist, path))
|
|
83
|
+
|
|
84
|
+
if (await file.exists()) {
|
|
85
|
+
res = new Response(file)
|
|
86
|
+
} else {
|
|
87
|
+
matched = match(path)
|
|
88
|
+
route = matched?.name || match404(meta, path)
|
|
89
|
+
res = new Response(null, { status: 404 })
|
|
90
|
+
|
|
91
|
+
for (const asset of [
|
|
92
|
+
path,
|
|
93
|
+
join(path, 'index'),
|
|
94
|
+
'index',
|
|
95
|
+
]) {
|
|
96
|
+
file = Bun.file(join(_root, dist, asset +'.html'))
|
|
97
|
+
|
|
98
|
+
if (await file.exists()) {
|
|
99
|
+
res = new Response(file)
|
|
100
|
+
break
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
status = res.status
|
|
106
|
+
return res
|
|
107
|
+
} catch (err) {
|
|
108
|
+
status = 500
|
|
109
|
+
throw err
|
|
110
|
+
} finally {
|
|
111
|
+
if (EXTENSIONS_LIST.has(path.split('.').pop()!.toLowerCase())) {
|
|
112
|
+
} else if (route || matched) {
|
|
113
|
+
const elapsed = `${Math.max(1, Math.ceil(performance.now() - start))}ms`
|
|
114
|
+
|
|
115
|
+
console.log([
|
|
116
|
+
gray(Datte.dateTime()),
|
|
117
|
+
getStatusColor(status),
|
|
118
|
+
path,
|
|
119
|
+
route && route !== path ? gray(route) : '',
|
|
120
|
+
gray(elapsed),
|
|
121
|
+
].filter(Boolean).join(' '))
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
}
|
package/src/pages/client/app.tsx
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
// @ts-ignore
|
|
2
|
-
import ':duto/
|
|
2
|
+
import ':duto/hmr'
|
|
3
3
|
|
|
4
4
|
import { render, hydrate, h } from 'preact'
|
|
5
5
|
import { Switch, Route, Router } from 'wouter-preact'
|
|
6
6
|
import { useLocation, useParams, useSearchParams, } from 'wouter-preact'
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
fallbackLocale, locales, messages, routes, routeMap,
|
|
10
8
|
// @ts-ignore
|
|
11
|
-
} from ':duto/i18n'
|
|
9
|
+
import { fallbackLocale, locales, routeMap } from ':duto/i18n'
|
|
12
10
|
// import i18n from '../i18n/client'
|
|
13
11
|
import i18n, { updatePickers } from '../i18n/client'
|
|
14
12
|
|
|
15
|
-
i18n(fallbackLocale, locales,
|
|
13
|
+
await i18n(fallbackLocale, locales, {}, {}, routeMap)
|
|
16
14
|
|
|
15
|
+
// Custom elements
|
|
17
16
|
import EI18n from '../i18n/element'
|
|
18
|
-
import Island from './island'
|
|
19
17
|
import Link from './link'
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
for (let [tag, el, opts] of [
|
|
20
|
+
['i-i', EI18n],
|
|
21
|
+
['i-l', Link, { extends: 'a' }],
|
|
22
|
+
] as [string, new () => HTMLElement, ElementDefinitionOptions?][]) {
|
|
23
|
+
!customElements.get(tag) && customElements.define(tag, el, opts)
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
import {
|
|
24
27
|
views, SRoutes,
|
|
@@ -27,84 +30,34 @@ import {
|
|
|
27
30
|
// @ts-ignore
|
|
28
31
|
import ':root/styles'
|
|
29
32
|
|
|
30
|
-
window.$duto = {
|
|
31
|
-
sroutes: SRoutes,
|
|
32
|
-
location: '/',
|
|
33
|
-
navigate: {},
|
|
34
|
-
params: {},
|
|
35
|
-
search: {},
|
|
36
|
-
setSearch: {},
|
|
37
|
-
}
|
|
38
|
-
import { renderRoute } from './router'
|
|
39
|
-
// import { navigate } from 'wouter-preact/use-hash-location'
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// render(h(Router, null,
|
|
52
|
-
// h(() => {
|
|
53
|
-
// // const __ = useRoute(location.pathname)
|
|
54
|
-
// document.body.removeAttribute('hidden')
|
|
55
|
-
// const [, navigate] = useLocation()
|
|
56
|
-
// // console.log(navigate)
|
|
57
|
-
// // this.navigate = navigate
|
|
58
|
-
|
|
59
|
-
// // TODO: talvez registrar todos os valores pelo id do elemento em uma fila e atualizar nesse tick...
|
|
60
|
-
// // input, select etc registra um update val e aqui popula..
|
|
61
|
-
// updatePickers()
|
|
62
|
-
// return null
|
|
63
|
-
// }, null),
|
|
64
|
-
// h(Switch, null,
|
|
65
|
-
// h(Route, { path: SRoutes.has(location.pathname) ? location.pathname : '/' }),
|
|
66
|
-
// ...views.map(([path, Component, defs, getProps]) =>
|
|
67
|
-
// h(Route, {
|
|
68
|
-
// path,
|
|
69
|
-
// component: ({ params }: { params: Record<string, string> }) => {
|
|
70
|
-
// // Trigger async render (updates container imperatively to avoid
|
|
71
|
-
// // React/Preact hook rules issues with async components)
|
|
72
|
-
|
|
73
|
-
// renderRoute(document.body, Component, params, defs, getProps)
|
|
74
|
-
// // Return null — renderRoute will call render() directly on the container
|
|
75
|
-
// return null
|
|
76
|
-
// },
|
|
77
|
-
// })
|
|
78
|
-
// ),
|
|
34
|
+
// window.$duto = {
|
|
35
|
+
// sroutes: SRoutes,
|
|
36
|
+
// location: '/',
|
|
37
|
+
// navigate: {},
|
|
38
|
+
// params: {},
|
|
39
|
+
// search: {},
|
|
40
|
+
// setSearch: {},
|
|
41
|
+
// }
|
|
42
|
+
import { renderRoute } from './router'
|
|
79
43
|
|
|
80
|
-
// ) ), document.body)
|
|
81
44
|
render(<Router>
|
|
82
45
|
{h(() => {
|
|
83
46
|
document.body.removeAttribute('hidden')
|
|
47
|
+
self.$duto = self.$duto || {}
|
|
48
|
+
self.$duto.sroutes = SRoutes
|
|
84
49
|
const [location, navigate] = useLocation()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
50
|
+
self.$duto.location = location
|
|
51
|
+
self.$duto.navigate = navigate
|
|
52
|
+
self.$duto.params = useParams()
|
|
53
|
+
|
|
88
54
|
const [search, setSearch] = useSearchParams()
|
|
89
|
-
|
|
90
|
-
|
|
55
|
+
self.$duto.search = search
|
|
56
|
+
self.$duto.setSearch = setSearch
|
|
91
57
|
|
|
92
|
-
// TODO: talvez registrar todos os valores pelo id do elemento em uma fila e atualizar nesse tick...
|
|
93
|
-
// input, select etc registra um update val e aqui popula..
|
|
94
58
|
updatePickers()
|
|
95
|
-
|
|
96
|
-
// React.useEffect(() => {
|
|
97
|
-
// document.body.removeAttribute('hidden');
|
|
98
|
-
// navigateRef.current = navigate;
|
|
99
|
-
// updatePickers();
|
|
100
|
-
// }, [navigate]);
|
|
101
|
-
// return null;
|
|
102
59
|
}, null)}
|
|
103
60
|
<Switch>
|
|
104
|
-
<Route path={SRoutes.has(location.pathname) ? location.pathname : '/'} component={({ params }) => {
|
|
105
|
-
delete params[0]
|
|
106
|
-
window.$duto.route = { pattern: location.pathname, params, path: location.pathname }
|
|
107
|
-
}} />
|
|
108
61
|
{/* @ts-ignore */}
|
|
109
62
|
{...views.map(([path, Component, defs, getProps, layouts]) => (
|
|
110
63
|
<Route path={path} component={({ params }: { params: Record<string, string> }) => {
|
|
@@ -1,130 +1,5 @@
|
|
|
1
1
|
import { render, h } from 'preact'
|
|
2
|
-
|
|
3
|
-
// import { useLocation, Switch, Route, Router } from 'wouter-preact'
|
|
4
|
-
// import { matchRoute } from 'wouter-preact'
|
|
5
|
-
// import type { Routes, IRoute } from '../types'
|
|
6
|
-
import type { Page, GetProps, IRoute } from '@/types'
|
|
7
|
-
// import { updatePickers } from '../i18n/client'
|
|
8
|
-
|
|
9
|
-
// type Route = [string, Page, IRoute['params'], GetProps]
|
|
10
|
-
// type Route = [string, Page] | [string, Page, IRoute['params']] | [string, Page, IRoute['params'], GetProps]
|
|
11
|
-
// type Routes = Route[]
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// type WRouter = {
|
|
15
|
-
// navigate: ((href: string) => void) | null,
|
|
16
|
-
// routes: Set<string>,
|
|
17
|
-
// load: (routes: Set<string>) => WRouter,
|
|
18
|
-
// has: (path: string) => boolean,
|
|
19
|
-
// // loaded: () => void,
|
|
20
|
-
// mount: (routes: Routes) => void,
|
|
21
|
-
// // App({ container }: {
|
|
22
|
-
// // container: HTMLElement;
|
|
23
|
-
// // }): VNode<Attributes & RouterOptions & {
|
|
24
|
-
// // children: ComponentChild;
|
|
25
|
-
// // }>,
|
|
26
|
-
// }
|
|
27
|
-
|
|
28
|
-
// export default {
|
|
29
|
-
// navigate: null,
|
|
30
|
-
// routes: new Set<string>(),
|
|
31
|
-
// load(routes: Set<string>) {
|
|
32
|
-
// this.routes = routes
|
|
33
|
-
// return this
|
|
34
|
-
// },
|
|
35
|
-
// has(path: string) {
|
|
36
|
-
// return this.routes.has(path)
|
|
37
|
-
// },
|
|
38
|
-
// // loaded() {
|
|
39
|
-
// // document.body.removeAttribute('hidden')
|
|
40
|
-
// // const [, navigate] = useLocation()
|
|
41
|
-
// // this.navigate = navigate
|
|
42
|
-
|
|
43
|
-
// // },
|
|
44
|
-
// mount(routes: Routes) {
|
|
45
|
-
// // ( // If body it was server-rendered — hydrate instead of render
|
|
46
|
-
// // document.body.childElementCount > 0
|
|
47
|
-
// // ? hydrate
|
|
48
|
-
// // : render // @ts-ignore
|
|
49
|
-
// // )(this.App(routes), document.body)
|
|
50
|
-
|
|
51
|
-
// // @ts-ignore
|
|
52
|
-
// render(this.App(routes), document.body)
|
|
53
|
-
// },
|
|
54
|
-
|
|
55
|
-
// App(routes: Routes, container: HTMLElement = document.body) {
|
|
56
|
-
// return h(Router, null,
|
|
57
|
-
// h(() => {
|
|
58
|
-
// // const __ = useRoute(location.pathname)
|
|
59
|
-
// // console.log(__)
|
|
60
|
-
// document.body.removeAttribute('hidden')
|
|
61
|
-
// const [, navigate] = useLocation()
|
|
62
|
-
// this.navigate = navigate
|
|
63
|
-
|
|
64
|
-
// // TODO: talvez registrar todos os valores pelo id do elemento em uma fila e atualizar nesse tick...
|
|
65
|
-
// // input, select etc registra um update val e aqui popula..
|
|
66
|
-
// updatePickers()
|
|
67
|
-
// return null
|
|
68
|
-
// }, null),
|
|
69
|
-
// h(Switch,
|
|
70
|
-
// null,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// // ...[
|
|
74
|
-
// // ['/', 'index.tsx'],
|
|
75
|
-
// // ['/about', 'about.tsx'],
|
|
76
|
-
// // ['/blog/:slug', 'blog/[slug].tsx'],
|
|
77
|
-
// // ['/blog/:slug?', 'blog/[[slug]].tsx'],
|
|
78
|
-
// // ['/shop/*', 'shop/[...slug].tsx'],
|
|
79
|
-
// // ['/shop/*?', 'shop/[[...slug]].tsx'],
|
|
80
|
-
// // ['/:authorId/:postId', '[authorId]/[postId].tsx'],
|
|
81
|
-
// // ['/*', '404.tsx'],
|
|
82
|
-
// // ['/*', 'not-found.tsx'],
|
|
83
|
-
// // ['/users/*', 'users/not-found.tsx'],
|
|
84
|
-
// // ].map(([path, name]) =>
|
|
85
|
-
// // h(Route, {
|
|
86
|
-
// // key: path,
|
|
87
|
-
// // path,
|
|
88
|
-
// // component: ({ params }: { params: Record<string, string> }) => {
|
|
89
|
-
|
|
90
|
-
// // renderRoute(container, () => h("div", { class: "p-8" }, h("h1", { class: "text-white text-xl relative top-2", style: {zIndex:'999', position:'relative', padding: '12px'} }, name), dd(params)), params)
|
|
91
|
-
// // // renderRoute(container, () => h("pre", { class: "p-8" }, h("h1", null, JSON.stringify(params))), params)
|
|
92
|
-
// // return null
|
|
93
|
-
// // },
|
|
94
|
-
// // })
|
|
95
|
-
// // ),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// h(Route, {
|
|
99
|
-
// path: this.has(location.pathname) ? location.pathname : '/',
|
|
100
|
-
// component: () => null,
|
|
101
|
-
// }),
|
|
102
|
-
|
|
103
|
-
// ...routes.map(([path, Component, defs, getProps]) =>
|
|
104
|
-
// h(Route, {
|
|
105
|
-
// // key: path,
|
|
106
|
-
// path,
|
|
107
|
-
// component: ({ params }: { params: Record<string, string> }) => {
|
|
108
|
-
// // Trigger async render (updates container imperatively to avoid
|
|
109
|
-
// // React/Preact hook rules issues with async components)
|
|
110
|
-
|
|
111
|
-
// renderRoute(container, Component, params, defs, getProps)
|
|
112
|
-
// // Return null — renderRoute will call render() directly on the container
|
|
113
|
-
// return null
|
|
114
|
-
// },
|
|
115
|
-
// })
|
|
116
|
-
// ),
|
|
117
|
-
|
|
118
|
-
// ) )
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// }
|
|
122
|
-
// } as WRouter
|
|
123
|
-
|
|
124
|
-
/** Captures wouter's navigate() so the duto:navigate event can call it */
|
|
125
|
-
// let _navigate: ((href: string) => void) | null = null
|
|
126
|
-
|
|
127
|
-
// ─── Page renderer ────────────────────────────────────────────────────────────
|
|
2
|
+
import type { Page, GetProps, IRoute } from '#/compiler/types'
|
|
128
3
|
|
|
129
4
|
function normalizeParams(
|
|
130
5
|
raw: Record<string, string>,
|
|
@@ -148,22 +23,26 @@ export async function renderRoute(
|
|
|
148
23
|
container: HTMLElement,
|
|
149
24
|
Component: Page,
|
|
150
25
|
rawParams: Record<string, string>,
|
|
151
|
-
paramDefs?: IRoute['params'],
|
|
152
|
-
getProps?: GetProps,
|
|
26
|
+
paramDefs?: IRoute['params'] | 0,
|
|
27
|
+
getProps?: GetProps | 0 | 1,
|
|
153
28
|
layouts?: Page[]
|
|
154
29
|
) {
|
|
155
30
|
while (document.body.firstChild)
|
|
156
31
|
document.body.removeChild(document.body.firstChild)
|
|
157
32
|
|
|
158
|
-
// const params = normalizeParams(rawParams, paramDefs)
|
|
159
|
-
// const mod = await route._import()
|
|
160
|
-
|
|
161
|
-
// let props: Record<string, unknown> = { ...params }
|
|
162
|
-
|
|
163
|
-
|
|
164
33
|
let props: Record<string, unknown> = paramDefs ? normalizeParams(rawParams, paramDefs) : rawParams
|
|
165
34
|
|
|
166
|
-
if (typeof
|
|
35
|
+
if (typeof Component === 'string') {
|
|
36
|
+
const mod = await import(Component)
|
|
37
|
+
Component = mod.default
|
|
38
|
+
getProps = getProps === 1 ? mod.getProps : 0
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
const sProps = self.$duto?.props
|
|
43
|
+
if (typeof sProps === 'object' && sProps !== null) {
|
|
44
|
+
Object.assign(props, sProps)
|
|
45
|
+
} else if (typeof getProps === 'function') {
|
|
167
46
|
try { // TODO: melhorar tipagem do props
|
|
168
47
|
const fetched = await Promise.resolve(getProps(props as Record<string, string | string[] | undefined>))
|
|
169
48
|
props = { ...fetched, ...props }
|
|
@@ -172,6 +51,7 @@ export async function renderRoute(
|
|
|
172
51
|
}
|
|
173
52
|
}
|
|
174
53
|
|
|
54
|
+
|
|
175
55
|
let el = h(Component, props as any)
|
|
176
56
|
|
|
177
57
|
const _layouts = layouts ? (Array.isArray(layouts) ? layouts : [layouts]) : []
|
|
@@ -179,151 +59,5 @@ export async function renderRoute(
|
|
|
179
59
|
el = h(layout, null, el)
|
|
180
60
|
|
|
181
61
|
render(el, container)
|
|
182
|
-
|
|
183
|
-
// TODO: melhorar tipagem do props
|
|
184
|
-
// render(h(Component, props as any), container)
|
|
185
62
|
// render(h(Component, props as any), container)
|
|
186
63
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// TODO: remover..
|
|
196
|
-
// function dd(objeto) {
|
|
197
|
-
// // Transforma o objeto em string JSON formatada com 2 espaços de recuo
|
|
198
|
-
// const json = JSON.stringify(objeto, null, 2);
|
|
199
|
-
|
|
200
|
-
// const renderizarJsonColorido = (textoJson) => {
|
|
201
|
-
// // Regex para capturar propriedades, strings, números, booleanos, nulls E quebras de linha/espaços explicitamente
|
|
202
|
-
// const regex = /(\n|\r\n|\s+|"(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g;
|
|
203
|
-
// const partes = [];
|
|
204
|
-
// let ultimoIndex = 0;
|
|
205
|
-
|
|
206
|
-
// textoJson.replace(regex, (match, p1, offset) => {
|
|
207
|
-
// // Adiciona qualquer texto residual intermediário
|
|
208
|
-
// if (offset > ultimoIndex) {
|
|
209
|
-
// partes.push(textoJson.substring(ultimoIndex, offset));
|
|
210
|
-
// }
|
|
211
|
-
|
|
212
|
-
// // Se capturar uma quebra de linha, insere a tag <br /> correspondente
|
|
213
|
-
// if (match.trim() === '' && (match.includes('\n') || match.includes('\r'))) {
|
|
214
|
-
// partes.push(h('br', null));
|
|
215
|
-
|
|
216
|
-
// // Se após a quebra de linha houver espaços de indentação, renderiza como spans de espaço
|
|
217
|
-
// const espacos = match.replace(/[\n\r]/g, '');
|
|
218
|
-
// if (espacos.length > 0) {
|
|
219
|
-
// partes.push(h('span', { style: { whiteSpace: 'pre' } }, espacos));
|
|
220
|
-
// }
|
|
221
|
-
// }
|
|
222
|
-
// // Se for apenas espaços de recuo (sem quebra de linha)
|
|
223
|
-
// else if (match.trim() === '') {
|
|
224
|
-
// partes.push(h('span', { style: { whiteSpace: 'pre' } }, match));
|
|
225
|
-
// }
|
|
226
|
-
// // Se for um token de dado, aplica a colorização do Laravel
|
|
227
|
-
// else {
|
|
228
|
-
// let estilo = { color: '#bd93f9' }; // Roxo para números
|
|
229
|
-
|
|
230
|
-
// if (/^"/.test(match)) {
|
|
231
|
-
// if (/:$/.test(match)) {
|
|
232
|
-
// estilo = { color: '#ff79c6', fontWeight: 'bold' }; // Rosa para chaves (keys)
|
|
233
|
-
// } else {
|
|
234
|
-
// estilo = { color: '#f1fa8c' }; // Amarelo para strings
|
|
235
|
-
// }
|
|
236
|
-
// } else if (/true|false/.test(match)) {
|
|
237
|
-
// estilo = { color: '#8be9fd' }; // Ciano para booleanos
|
|
238
|
-
// } else if (/null/.test(match)) {
|
|
239
|
-
// estilo = { color: '#6272a4', fontStyle: 'italic' }; // Cinza para nulos
|
|
240
|
-
// }
|
|
241
|
-
|
|
242
|
-
// partes.push(h('span', { style: estilo }, match));
|
|
243
|
-
// }
|
|
244
|
-
|
|
245
|
-
// ultimoIndex = offset + match.length;
|
|
246
|
-
// });
|
|
247
|
-
|
|
248
|
-
// if (ultimoIndex < textoJson.length) {
|
|
249
|
-
// partes.push(textoJson.substring(ultimoIndex));
|
|
250
|
-
// }
|
|
251
|
-
|
|
252
|
-
// return partes;
|
|
253
|
-
// };
|
|
254
|
-
|
|
255
|
-
// // Estilo do container escuro em tela cheia
|
|
256
|
-
// const estiloContainer = {
|
|
257
|
-
// background: '#1e1e24', // Grafite escuro elegante
|
|
258
|
-
// color: '#f8f8f2',
|
|
259
|
-
// padding: '30px',
|
|
260
|
-
// fontFamily: '"Fira Code", "Courier New", Courier, monospace',
|
|
261
|
-
// fontSize: '14px',
|
|
262
|
-
// lineHeight: '1.6',
|
|
263
|
-
// overflow: 'auto',
|
|
264
|
-
// position: 'fixed',
|
|
265
|
-
// top: 0,
|
|
266
|
-
// left: 0,
|
|
267
|
-
// width: '100vw',
|
|
268
|
-
// height: '100vh',
|
|
269
|
-
// zIndex: 99,
|
|
270
|
-
// textAlign: 'left',
|
|
271
|
-
// boxSizing: 'border-box'
|
|
272
|
-
// };
|
|
273
|
-
|
|
274
|
-
// // Retorna a estrutura h() contendo o bloco quebrado e indentado linha por linha
|
|
275
|
-
// return h('div', { style: estiloContainer }, renderizarJsonColorido(json));
|
|
276
|
-
// }
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// function normalizeParams(
|
|
288
|
-
// raw: Record<string, string>,
|
|
289
|
-
// paramDefs: IRoute['params']
|
|
290
|
-
// ): Record<string, string | string[] | undefined> {
|
|
291
|
-
// const result: Record<string, string | string[] | undefined> = {};
|
|
292
|
-
// for (const def of paramDefs) {
|
|
293
|
-
// const val = raw[def.name];
|
|
294
|
-
// if (def.catchAll) {
|
|
295
|
-
// result[def.name] = val
|
|
296
|
-
// ? val.split('/').filter(Boolean)
|
|
297
|
-
// : def.optional ? undefined : []
|
|
298
|
-
// } else {
|
|
299
|
-
// result[def.name] = val === undefined && def.optional ? undefined : val;
|
|
300
|
-
// }
|
|
301
|
-
// }
|
|
302
|
-
// return result
|
|
303
|
-
// }
|
|
304
|
-
|
|
305
|
-
// async function renderRoute(
|
|
306
|
-
// route: IRoute,
|
|
307
|
-
// rawParams: Record<string, string>,
|
|
308
|
-
// container: HTMLElement
|
|
309
|
-
// ) {
|
|
310
|
-
// const params = normalizeParams(rawParams, route.params)
|
|
311
|
-
// const mod = await route._import()
|
|
312
|
-
|
|
313
|
-
// let props: Record<string, unknown> = { ...params }
|
|
314
|
-
|
|
315
|
-
// if (typeof mod.getProps === 'function') {
|
|
316
|
-
// try {
|
|
317
|
-
// const fetched = await Promise.resolve(mod.getProps(params))
|
|
318
|
-
// props = { ...fetched, ...params }
|
|
319
|
-
// } catch (e) {
|
|
320
|
-
// console.error('[ssg] getProps failed:', e)
|
|
321
|
-
// }
|
|
322
|
-
// } else {
|
|
323
|
-
// // No getProps → re-use SSG props (already in the DOM, nothing to do on first load)
|
|
324
|
-
// // props = { ...(window.__SSG_PROPS__ ?? {}), ...params }
|
|
325
|
-
// }
|
|
326
|
-
|
|
327
|
-
// render(h(mod.default, props as any), container)
|
|
328
|
-
// }
|
|
329
|
-
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { join, resolve } from 'node:path'
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
2
|
import { resolveExtension } from './file'
|
|
4
3
|
|
|
5
|
-
export function
|
|
6
|
-
const
|
|
7
|
-
return JSON.parse(content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, ''))
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function getAliases(root: string) {
|
|
11
|
-
const tsconfig = getTsConfig(join(root, './tsconfig.json'))
|
|
4
|
+
export async function getAliases(root: string) {
|
|
5
|
+
const tsconfig = await import(join(root, './tsconfig.json')) // @ts-ignore
|
|
12
6
|
const compilerOptions = tsconfig.compilerOptions || {}
|
|
13
7
|
const paths = Object.entries(compilerOptions.paths || {})
|
|
14
8
|
const baseUrl = compilerOptions.baseUrl || '.'
|