duto 0.0.0 → 0.260808.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/LICENSE +21 -0
- package/README.md +21 -12
- package/package.json +56 -2
- package/src/cli/commands/build.ts +74 -0
- package/src/cli/commands/dev-old.ts +213 -0
- package/src/cli/commands/dev.ts +87 -0
- package/src/cli/commands/preview.ts +33 -0
- package/src/cli/index.ts +28 -0
- package/src/cli/utils.ts +146 -0
- package/src/client/app.tsx +123 -0
- package/src/client/hmr.ts +13 -0
- package/src/client/island.ts +136 -0
- package/src/client/link.ts +70 -0
- package/src/client/router.ts +329 -0
- package/src/client/storage.ts +95 -0
- package/src/compiler/aliases.ts +36 -0
- package/src/compiler/assets.ts +43 -0
- package/src/compiler/ast.ts +764 -0
- package/src/compiler/constants.ts +24 -0
- package/src/compiler/file.ts +60 -0
- package/src/compiler/index.ts +307 -0
- package/src/compiler/island.ts +108 -0
- package/src/compiler/meta.ts +601 -0
- package/src/compiler/routes.ts +29 -0
- package/src/compiler/types.ts +209 -0
- package/src/compiler/utils.ts +5 -0
- package/src/compiler/vite-plugin.ts +324 -0
- package/src/components/link.tsx +38 -0
- package/src/i18n/client.ts +403 -0
- package/src/i18n/element.ts +44 -0
- package/src/i18n/server.ts +56 -0
- package/src/index.ts +28 -0
- package/src/preact/client-dev.ts +5 -0
- package/src/preact/client.ts +87 -0
- package/src/preact/context.ts +41 -0
- package/src/preact/server.ts +186 -0
- package/src/preact/signals.ts +89 -0
- package/src/preact/static-html.ts +45 -0
- package/src/preact/types.ts +26 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { render, h } from 'preact'
|
|
2
|
+
// import { render, hydrate, h } from 'preact'
|
|
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 ────────────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
function normalizeParams(
|
|
130
|
+
raw: Record<string, string>,
|
|
131
|
+
paramDefs: IRoute['params']
|
|
132
|
+
): Record<string, string | string[] | undefined> {
|
|
133
|
+
const result: Record<string, string | string[] | undefined> = {};
|
|
134
|
+
for (const def of paramDefs) {
|
|
135
|
+
const val = raw[def.name];
|
|
136
|
+
if (def.catchAll) {
|
|
137
|
+
result[def.name] = val
|
|
138
|
+
? val.split('/').filter(Boolean)
|
|
139
|
+
: def.optional ? undefined : []
|
|
140
|
+
} else {
|
|
141
|
+
result[def.name] = val === undefined && def.optional ? undefined : val;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return result
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function renderRoute(
|
|
148
|
+
container: HTMLElement,
|
|
149
|
+
Component: Page,
|
|
150
|
+
rawParams: Record<string, string>,
|
|
151
|
+
paramDefs?: IRoute['params'],
|
|
152
|
+
getProps?: GetProps,
|
|
153
|
+
layouts?: Page[]
|
|
154
|
+
) {
|
|
155
|
+
while (document.body.firstChild)
|
|
156
|
+
document.body.removeChild(document.body.firstChild)
|
|
157
|
+
|
|
158
|
+
// const params = normalizeParams(rawParams, paramDefs)
|
|
159
|
+
// const mod = await route._import()
|
|
160
|
+
|
|
161
|
+
// let props: Record<string, unknown> = { ...params }
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
let props: Record<string, unknown> = paramDefs ? normalizeParams(rawParams, paramDefs) : rawParams
|
|
165
|
+
|
|
166
|
+
if (typeof getProps === 'function') {
|
|
167
|
+
try { // TODO: melhorar tipagem do props
|
|
168
|
+
const fetched = await Promise.resolve(getProps(props as Record<string, string | string[] | undefined>))
|
|
169
|
+
props = { ...fetched, ...props }
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.error('[ssg] getProps failed:', e)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let el = h(Component, props as any)
|
|
176
|
+
|
|
177
|
+
const _layouts = layouts ? (Array.isArray(layouts) ? layouts : [layouts]) : []
|
|
178
|
+
for (const layout of _layouts)
|
|
179
|
+
el = h(layout, null, el)
|
|
180
|
+
|
|
181
|
+
render(el, container)
|
|
182
|
+
|
|
183
|
+
// TODO: melhorar tipagem do props
|
|
184
|
+
// render(h(Component, props as any), container)
|
|
185
|
+
// render(h(Component, props as any), container)
|
|
186
|
+
}
|
|
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
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { emit, on } from 't0n'
|
|
2
|
+
|
|
3
|
+
interface IStoreChange<TValue> {
|
|
4
|
+
key: string,
|
|
5
|
+
val: TValue | null,
|
|
6
|
+
old: TValue | null,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type IStoreListener<TValue> = (change: IStoreChange<TValue>) => void
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Store reativo que encapsula o localStorage.
|
|
13
|
+
*
|
|
14
|
+
* - Nenhum componente toca em `window.localStorage` diretamente, só nesta classe.
|
|
15
|
+
* - Mudanças feitas via `.set()`/`.remove()` disparam eventos na mesma aba.
|
|
16
|
+
* - Mudanças feitas em outras abas chegam via evento nativo `storage` e são
|
|
17
|
+
* normalizadas para o mesmo formato de evento.
|
|
18
|
+
* - Chaves e valores são tipados a partir de um schema (`TSchema`), evitando
|
|
19
|
+
* strings soltas e `JSON.parse`/`JSON.stringify` espalhados pelo código.
|
|
20
|
+
*/
|
|
21
|
+
class LocalStore<TSchema extends Record<string, unknown>> extends EventTarget {
|
|
22
|
+
#prefix: string
|
|
23
|
+
|
|
24
|
+
constructor(prefix = '') {
|
|
25
|
+
super()
|
|
26
|
+
this.#prefix = prefix
|
|
27
|
+
|
|
28
|
+
if (typeof window !== 'undefined')
|
|
29
|
+
window.addEventListener('storage', this.#onCrossTabChange)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#buildKey<K extends keyof TSchema & string>(key: K): string {
|
|
33
|
+
return this.#prefix ? `${this.#prefix}:${key}` : key
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#parse<TValue>(raw: string | null): TValue | null {
|
|
37
|
+
if (raw === null) return null
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(raw) as TValue
|
|
41
|
+
} catch {
|
|
42
|
+
return raw as unknown as TValue
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#onCrossTabChange = (e: StorageEvent): void => {
|
|
47
|
+
if (!e.key) return
|
|
48
|
+
|
|
49
|
+
const hasPrefix = this.#prefix.length > 0
|
|
50
|
+
const expectedPrefix = `${this.#prefix}:`
|
|
51
|
+
|
|
52
|
+
if (hasPrefix && !e.key.startsWith(expectedPrefix)) return
|
|
53
|
+
|
|
54
|
+
const key = hasPrefix ? e.key.slice(expectedPrefix.length) : e.key
|
|
55
|
+
const val = this.#parse<TSchema[keyof TSchema]>(e.newValue)
|
|
56
|
+
const old = this.#parse<TSchema[keyof TSchema]>(e.oldValue)
|
|
57
|
+
|
|
58
|
+
emit(key, { key, val, old })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get<K extends keyof TSchema & string>(key: K): TSchema[K] | null {
|
|
62
|
+
if (typeof window === 'undefined') return null
|
|
63
|
+
|
|
64
|
+
return this.#parse<TSchema[K]>(window?.localStorage?.getItem(this.#buildKey(key)))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
set<K extends keyof TSchema & string>(key: K, val: TSchema[K]): void {
|
|
68
|
+
if (typeof window === 'undefined') return
|
|
69
|
+
|
|
70
|
+
const old = this.get(key)
|
|
71
|
+
window?.localStorage?.setItem(this.#buildKey(key), JSON.stringify(val))
|
|
72
|
+
|
|
73
|
+
emit(key, { key, val, old })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
remove<K extends keyof TSchema & string>(key: K): void {
|
|
77
|
+
if (typeof window === 'undefined') return
|
|
78
|
+
|
|
79
|
+
const old = this.get(key)
|
|
80
|
+
window?.localStorage?.removeItem(this.#buildKey(key))
|
|
81
|
+
emit(key, { key, val: null, old })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
subscribe<K extends keyof TSchema & string>(
|
|
85
|
+
key: K,
|
|
86
|
+
listener: IStoreListener<TSchema[K]>,
|
|
87
|
+
) {
|
|
88
|
+
return on(key, listener)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const local = new LocalStore()
|
|
93
|
+
|
|
94
|
+
export { LocalStore }
|
|
95
|
+
export type { IStoreChange }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { join, resolve } from 'node:path'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { resolveExtension } from './file'
|
|
4
|
+
|
|
5
|
+
export function getTsConfig(configPath = './tsconfig.json') {
|
|
6
|
+
const content = readFileSync(configPath, 'utf8')
|
|
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'))
|
|
12
|
+
const compilerOptions = tsconfig.compilerOptions || {}
|
|
13
|
+
const paths = Object.entries(compilerOptions.paths || {})
|
|
14
|
+
const baseUrl = compilerOptions.baseUrl || '.'
|
|
15
|
+
|
|
16
|
+
const aliases = {}
|
|
17
|
+
|
|
18
|
+
for (const [aliasPattern, targetPatterns] of paths) // @ts-ignore
|
|
19
|
+
aliases[aliasPattern.replace(/\/\*$/, '')] = resolve(process.cwd(), baseUrl, targetPatterns[0].replace(/\/\*$/, ''))
|
|
20
|
+
|
|
21
|
+
return aliases
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolveAlias(importPath: string, aliases: Record<string, string>) {
|
|
25
|
+
for (const [alias, realPath] of Object.entries(aliases)) {
|
|
26
|
+
if (importPath.startsWith(alias +'/') || importPath === alias) {
|
|
27
|
+
const subPath = importPath.substring(alias.length)
|
|
28
|
+
const cleanSubPath = subPath.startsWith('/') ? subPath.substring(1) : subPath
|
|
29
|
+
const resolved = join(realPath, cleanSubPath)
|
|
30
|
+
|
|
31
|
+
return resolveExtension(resolved) ?? resolved
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return resolveExtension(importPath) ?? importPath
|
|
36
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const distMap: Record<string, string> = {}
|
|
2
|
+
|
|
3
|
+
// export function getDist(){
|
|
4
|
+
// return distMap
|
|
5
|
+
// }
|
|
6
|
+
export function getAsset(id: string) {
|
|
7
|
+
const entry = getChunk(id, 1)
|
|
8
|
+
return distMap['\0'+ entry] || null
|
|
9
|
+
}
|
|
10
|
+
export function setAsset(id: string | null, val: string) {
|
|
11
|
+
distMap['\0'+ normalizeId(id)] = val
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// corririr isso...
|
|
15
|
+
export function getChunk(id: string, deep: number = 3, loop: number = 1) {
|
|
16
|
+
if (!distMap[id]) return id
|
|
17
|
+
|
|
18
|
+
const currentValue = distMap[id]
|
|
19
|
+
|
|
20
|
+
if (loop < deep && distMap[currentValue] && currentValue !== id)
|
|
21
|
+
return getChunk(currentValue, deep, loop + 1)
|
|
22
|
+
|
|
23
|
+
return currentValue
|
|
24
|
+
}
|
|
25
|
+
export function setChunk(id: string | null, val: string) {
|
|
26
|
+
distMap[normalizeId(id)] = val
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getEntry(id: string) {
|
|
30
|
+
if (id in distMap) return distMap[id]
|
|
31
|
+
const key = id in distMap ? id : normalizeId(id)
|
|
32
|
+
return distMap[key] || id
|
|
33
|
+
}
|
|
34
|
+
export function setEntry(id: string | null, val: string) {
|
|
35
|
+
if (!id) return
|
|
36
|
+
distMap[id] = normalizeId(val)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function normalizeId(id?: string | null) {
|
|
40
|
+
id = id?.replace(process.cwd(), '') || ''
|
|
41
|
+
if (id && !id.startsWith('/')) id = '/'+ id
|
|
42
|
+
return id
|
|
43
|
+
}
|