@meekojs/meeko 0.0.4 → 0.1.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 +21 -19
- package/dist/autoimports-ts.d.ts +4 -4
- package/dist/autoimports-ts.js +86 -30
- package/dist/autoimports-ts.js.map +1 -1
- package/dist/autoimports.d.ts +2 -2
- package/dist/autoimports.js +23 -7
- package/dist/autoimports.js.map +1 -1
- package/dist/check.js +39 -10
- package/dist/check.js.map +1 -1
- package/dist/cli.js +37 -4
- package/dist/cli.js.map +1 -1
- package/dist/compiler/events.d.ts +2 -0
- package/dist/compiler/events.js +6 -0
- package/dist/compiler/events.js.map +1 -0
- package/dist/compiler/props.d.ts +12 -0
- package/dist/compiler/props.js +32 -0
- package/dist/compiler/props.js.map +1 -0
- package/dist/compiler.js +55 -12
- package/dist/compiler.js.map +1 -1
- package/dist/component-errors.d.ts +18 -0
- package/dist/component-errors.js +65 -0
- package/dist/component-errors.js.map +1 -0
- package/dist/devtools.js +2 -4
- package/dist/devtools.js.map +1 -1
- package/dist/dom.d.ts +11 -5
- package/dist/dom.js +288 -88
- package/dist/dom.js.map +1 -1
- package/dist/error-observer.d.ts +6 -0
- package/dist/error-observer.js +41 -0
- package/dist/error-observer.js.map +1 -0
- package/dist/framework/check-app.js +160 -5
- package/dist/framework/check-app.js.map +1 -1
- package/dist/framework/check-project.d.ts +4 -0
- package/dist/framework/check-project.js +42 -0
- package/dist/framework/check-project.js.map +1 -0
- package/dist/framework/client.d.ts +3 -0
- package/dist/framework/client.js +136 -33
- package/dist/framework/client.js.map +1 -1
- package/dist/framework/clients.js +12 -4
- package/dist/framework/clients.js.map +1 -1
- package/dist/framework/contracts-generate.js +66 -3
- package/dist/framework/contracts-generate.js.map +1 -1
- package/dist/framework/init.js +21 -200
- package/dist/framework/init.js.map +1 -1
- package/dist/framework/middleware.d.ts +14 -0
- package/dist/framework/middleware.js +16 -0
- package/dist/framework/middleware.js.map +1 -0
- package/dist/framework/page-contracts-check.d.ts +8 -0
- package/dist/framework/page-contracts-check.js +110 -0
- package/dist/framework/page-contracts-check.js.map +1 -0
- package/dist/framework/page-contracts-generate.d.ts +2 -0
- package/dist/framework/page-contracts-generate.js +94 -0
- package/dist/framework/page-contracts-generate.js.map +1 -0
- package/dist/framework/page.d.ts +7 -3
- package/dist/framework/page.js +3 -1
- package/dist/framework/page.js.map +1 -1
- package/dist/framework/prerender.js +11 -5
- package/dist/framework/prerender.js.map +1 -1
- package/dist/framework/project-templates.d.ts +3 -0
- package/dist/framework/project-templates.js +119 -0
- package/dist/framework/project-templates.js.map +1 -0
- package/dist/framework/project.d.ts +9 -0
- package/dist/framework/project.js +272 -0
- package/dist/framework/project.js.map +1 -0
- package/dist/framework/router.d.ts +3 -1
- package/dist/framework/router.js +94 -8
- package/dist/framework/router.js.map +1 -1
- package/dist/framework/server.d.ts +17 -3
- package/dist/framework/server.js +71 -24
- package/dist/framework/server.js.map +1 -1
- package/dist/framework/socket-contracts-generate.js +8 -5
- package/dist/framework/socket-contracts-generate.js.map +1 -1
- package/dist/framework/socket.d.ts +2 -0
- package/dist/framework/socket.js +119 -17
- package/dist/framework/socket.js.map +1 -1
- package/dist/framework/standard-schema-types.d.ts +7 -0
- package/dist/framework/standard-schema-types.js +69 -0
- package/dist/framework/standard-schema-types.js.map +1 -0
- package/dist/framework/state.d.ts +7 -0
- package/dist/framework/state.js +78 -14
- package/dist/framework/state.js.map +1 -1
- package/dist/framework/styles.d.ts +2 -0
- package/dist/framework/styles.js +6 -0
- package/dist/framework/styles.js.map +1 -0
- package/dist/framework/type-declarations.d.ts +5 -0
- package/dist/framework/type-declarations.js +84 -0
- package/dist/framework/type-declarations.js.map +1 -0
- package/dist/framework-server/contracts.d.ts +11 -2
- package/dist/framework-server/contracts.js +62 -7
- package/dist/framework-server/contracts.js.map +1 -1
- package/dist/framework-server/discovery.d.ts +4 -1
- package/dist/framework-server/discovery.js +21 -16
- package/dist/framework-server/discovery.js.map +1 -1
- package/dist/framework-server/local.d.ts +2 -0
- package/dist/framework-server/local.js +5 -3
- package/dist/framework-server/local.js.map +1 -1
- package/dist/framework-server/middleware.d.ts +4 -0
- package/dist/framework-server/middleware.js +56 -0
- package/dist/framework-server/middleware.js.map +1 -0
- package/dist/framework-server/node-upgrade.js +27 -9
- package/dist/framework-server/node-upgrade.js.map +1 -1
- package/dist/framework-server/node-websocket.js +4 -2
- package/dist/framework-server/node-websocket.js.map +1 -1
- package/dist/framework-server/session-stores.d.ts +9 -2
- package/dist/framework-server/session-stores.js +37 -11
- package/dist/framework-server/session-stores.js.map +1 -1
- package/dist/framework-server/sessions.d.ts +6 -0
- package/dist/framework-server/sessions.js +41 -10
- package/dist/framework-server/sessions.js.map +1 -1
- package/dist/framework-server/socket.js +62 -27
- package/dist/framework-server/socket.js.map +1 -1
- package/dist/framework-server.d.ts +2 -0
- package/dist/framework-server.js +1 -0
- package/dist/framework-server.js.map +1 -1
- package/dist/framework.d.ts +3 -1
- package/dist/framework.js +1 -0
- package/dist/framework.js.map +1 -1
- package/dist/hmr.js +74 -24
- package/dist/hmr.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init.js +27 -1
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +2 -2
- package/dist/internal.js.map +1 -1
- package/dist/node.d.ts +5 -1
- package/dist/node.js +80 -10
- package/dist/node.js.map +1 -1
- package/dist/reactivity.d.ts +12 -3
- package/dist/reactivity.js +94 -17
- package/dist/reactivity.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js +3 -1
- package/dist/types.js.map +1 -1
- package/dist/vite.js +29 -9
- package/dist/vite.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# Meeko
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src="assets/brand/meeko-logo.png" alt="Carita de Meeko, una gatita de ojos azules, orejas oscuras y pelaje crema" width="200" />
|
|
4
|
+
<img src="https://raw.githubusercontent.com/meekojs/meeko/main/assets/brand/meeko-logo.png" alt="Carita de Meeko, una gatita de ojos azules, orejas oscuras y pelaje crema" width="200" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
Este proyecto está dedicado a mi gatita Meeko. Su carita inspira el logo que lo acompaña.
|
|
8
8
|
|
|
9
9
|
**Meeko** es un motor experimental de componentes para TypeScript. Los archivos `.meeko` combinan lógica tipada, plantilla y estilos; el compilador produce HTML para SSR y conecta la reactividad al HTML existente durante la hidratación.
|
|
10
10
|
|
|
11
|
-
El código se distribuye bajo la [licencia MIT](LICENSE). El paquete público se llama `@meekojs/meeko`; la CLI se invoca como `meeko` y el plugin de Vite se importa desde `@meekojs/meeko/vite`.
|
|
11
|
+
El código se distribuye bajo la [licencia MIT](https://github.com/meekojs/meeko/blob/main/LICENSE). El paquete público se llama `@meekojs/meeko`; la CLI se invoca como `meeko` y el plugin de Vite se importa desde `@meekojs/meeko/vite`.
|
|
12
12
|
|
|
13
13
|
El proyecto está en etapa temprana. Ya funciona el recorrido completo de un contador renderizado en servidor, hidratado en navegador y actualizado por señales. La sintaxis y las API públicas pueden cambiar antes de la primera versión estable.
|
|
14
14
|
|
|
15
|
-
- [Arquitectura y contratos](docs/architecture.md)
|
|
16
|
-
- [API y límites de compatibilidad](docs/api.md)
|
|
17
|
-
- [Aplicaciones full-stack con Meeko](docs/framework.md)
|
|
18
|
-
- [Plan de desarrollo y criterios de aceptación](docs/roadmap.md)
|
|
19
|
-
- [Comparativa reproducible con Vue](docs/benchmarks.md)
|
|
20
|
-
- [DevTools para depurar componentes](docs/devtools.md)
|
|
21
|
-
- [Aplicación piloto SSR](examples/pilot/README.md)
|
|
22
|
-
- [Publicación y verificaciones](docs/releasing.md)
|
|
23
|
-
- [Historial de cambios](CHANGELOG.md)
|
|
24
|
-
- [Guía para contribuir](CONTRIBUTING.md)
|
|
15
|
+
- [Arquitectura y contratos](https://github.com/meekojs/meeko/blob/main/docs/architecture.md)
|
|
16
|
+
- [API y límites de compatibilidad](https://github.com/meekojs/meeko/blob/main/docs/api.md)
|
|
17
|
+
- [Aplicaciones full-stack con Meeko](https://github.com/meekojs/meeko/blob/main/docs/framework.md)
|
|
18
|
+
- [Plan de desarrollo y criterios de aceptación](https://github.com/meekojs/meeko/blob/main/docs/roadmap.md)
|
|
19
|
+
- [Comparativa reproducible con Vue](https://github.com/meekojs/meeko/blob/main/docs/benchmarks.md)
|
|
20
|
+
- [DevTools para depurar componentes](https://github.com/meekojs/meeko/blob/main/docs/devtools.md)
|
|
21
|
+
- [Aplicación piloto SSR](https://github.com/meekojs/meeko/blob/main/examples/pilot/README.md)
|
|
22
|
+
- [Publicación y verificaciones](https://github.com/meekojs/meeko/blob/main/docs/releasing.md)
|
|
23
|
+
- [Historial de cambios](https://github.com/meekojs/meeko/blob/main/CHANGELOG.md)
|
|
24
|
+
- [Guía para contribuir](https://github.com/meekojs/meeko/blob/main/CONTRIBUTING.md)
|
|
25
25
|
|
|
26
26
|
## Requisitos
|
|
27
27
|
|
|
@@ -64,7 +64,7 @@ Desde `0.0.3`, si ya ejecutaste `pnpm add @meekojs/meeko` en una carpeta sin có
|
|
|
64
64
|
|
|
65
65
|
### Crear una aplicación full-stack
|
|
66
66
|
|
|
67
|
-
Meeko Engine permite usar componentes `.meeko` de forma independiente. Meeko Framework añade rutas por archivos, layouts, SSR, estado por petición, API, RPC, sesiones y WebSocket con el mismo compilador y runtime.
|
|
67
|
+
Meeko Engine permite usar componentes `.meeko` de forma independiente. Meeko Framework añade rutas por archivos, layouts, middleware de `app/` y `server/`, SSR, estado por petición, API, RPC, sesiones y WebSocket con el mismo compilador y runtime. En este checkout, crea una aplicación con:
|
|
68
68
|
|
|
69
69
|
```powershell
|
|
70
70
|
pnpm exec meeko init-framework my-app
|
|
@@ -76,7 +76,7 @@ npm run build
|
|
|
76
76
|
npm start
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
`check` genera contratos y comprueba tipos; `build` produce cliente, servidor y prerender. `start` sirve SSR de producción con Node 24 y requiere configurar sesiones persistentes. La [guía del framework](docs/framework.md) explica configuración, autoimports, rutas, despliegue y seguridad.
|
|
79
|
+
`check` genera contratos y comprueba tipos; `build` produce cliente, servidor y prerender. `start` sirve SSR de producción con Node 24 y requiere configurar sesiones persistentes. La [guía del framework](https://github.com/meekojs/meeko/blob/main/docs/framework.md) explica configuración, autoimports, rutas, middleware, despliegue y seguridad. Los comandos simplificados del proyecto están disponibles desde `0.1.0`.
|
|
80
80
|
|
|
81
81
|
## Estructura
|
|
82
82
|
|
|
@@ -124,7 +124,7 @@ pnpm run vite:build
|
|
|
124
124
|
|
|
125
125
|
El plugin `@meekojs/meeko/vite` transforma imports de `.meeko` en cliente y SSR y procesa el CSS del componente. En desarrollo, HMR sustituye las instancias hidratadas sin recargar la página, conserva las señales editables que mantienen su nombre y aplica cambios de CSS. Un cambio en el runtime del motor provoca una recarga completa.
|
|
126
126
|
|
|
127
|
-
El ejemplo Vite muestra [Meeko DevTools](docs/devtools.md) durante el desarrollo: permite seleccionar cada instancia, revisar props y señales, seguir eventos y activar un punto de parada cuando cambia una señal. También hay un panel local para Chrome DevTools. La funcionalidad se incorpora al paquete a partir de `0.0.2`.
|
|
127
|
+
El ejemplo Vite muestra [Meeko DevTools](https://github.com/meekojs/meeko/blob/main/docs/devtools.md) durante el desarrollo: permite seleccionar cada instancia, revisar props y señales, seguir eventos y activar un punto de parada cuando cambia una señal. También hay un panel local para Chrome DevTools. La funcionalidad se incorpora al paquete a partir de `0.0.2`.
|
|
128
128
|
|
|
129
129
|
`vite:types` genera declaraciones `.d.meeko.ts` para los imports de la aplicación y comprueba el consumidor con TypeScript 7 y `allowArbitraryExtensions`. Las declaraciones del ejemplo se regeneran; no se versionan.
|
|
130
130
|
|
|
@@ -144,21 +144,23 @@ La aplicación debe pasar **las mismas props** al render y a `hydrate`. `renderW
|
|
|
144
144
|
|
|
145
145
|
## Aplicación piloto
|
|
146
146
|
|
|
147
|
-
[`examples/pilot`](examples/pilot/README.md) reúne SSR, hidratación, componentes anidados, listas, formularios, rutas y una API asíncrona. Se ejecuta con `pnpm run pilot:dev`; `pnpm run pilot:build` y `pnpm run pilot:serve` prueban los artefactos de producción sin middleware de Vite. La prueba `pnpm run pilot:e2e` recorre ambos modos en Chromium, Firefox y WebKit. WebKit de Playwright no equivale a una prueba en Safari real.
|
|
147
|
+
[`examples/pilot`](https://github.com/meekojs/meeko/blob/main/examples/pilot/README.md) reúne SSR, hidratación, componentes anidados, listas, formularios, rutas y una API asíncrona. Se ejecuta con `pnpm run pilot:dev`; `pnpm run pilot:build` y `pnpm run pilot:serve` prueban los artefactos de producción sin middleware de Vite. La prueba `pnpm run pilot:e2e` recorre ambos modos en Chromium, Firefox y WebKit. WebKit de Playwright no equivale a una prueba en Safari real.
|
|
148
148
|
|
|
149
149
|
## Sintaxis inicial
|
|
150
150
|
|
|
151
151
|
Un archivo tiene `<script lang="ts">`, `<template>` y un `<style>` opcional; `scoped` limita las reglas CSS al componente. `defineProps<Props>()` declara las props. La plantilla acepta expresiones de texto `{expression}`, eventos `on:click="handler"` y atributos dinámicos `bind:title="expression"`. Los atributos booleanos, como `bind:disabled`, se agregan o eliminan según el valor.
|
|
152
152
|
|
|
153
|
-
`
|
|
153
|
+
`defineProps<Props>({ count: 0 })` declara defaults sin otra macro: `count` será opcional al usar el componente y estará definido dentro de él. Consulta las reglas y límites en la [guía de la API](https://github.com/meekojs/meeko/blob/main/docs/api.md#valores-por-defecto-en-defineprops).
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
`if:when="expression"` muestra u oculta un elemento. Una lista usa `each:of="items"`, `each:as="item"` y `each:key="item.id"`; `each:index="position"` permite nombrar el índice, que se llama `index` por defecto. Las claves deben ser cadenas o números finitos y no pueden repetirse. Meeko conserva los nodos de las claves existentes al reordenar la lista. [Regions.meeko](https://github.com/meekojs/meeko/blob/main/examples/regions/Regions.meeko) muestra condiciones, listas anidadas, eventos y atributos dinámicos.
|
|
156
|
+
|
|
157
|
+
Un componente importado en el script se inserta con `<component is="Child" bind:label="expression"></component>`. Las props se comprueban con TypeScript y cada hijo se hidrata dentro de un rango de comentarios, sin un elemento envolvente. `is` también acepta un componente recibido como prop tipada `Component<Props>`; así se puede insertar contenido reutilizable y cambiarlo reactivamente. La comunicación hacia el padre usa callbacks tipados en las props, y `createContext<T>()` permite compartir valores con descendientes. El cierre explícito es obligatorio; la sintaxis autocerrada de HTML no se admite para `<component>`. [Parent.meeko](https://github.com/meekojs/meeko/blob/main/examples/nested/Parent.meeko) muestra hijos y nietos dentro de condiciones y listas.
|
|
156
158
|
|
|
157
159
|
Los errores de sintaxis de script, plantilla y CSS, así como los errores de tipos en declaraciones y expresiones, tienen ubicación en `.meeko`. Los errores atribuibles sólo al código auxiliar generado se identifican explícitamente.
|
|
158
160
|
|
|
159
161
|
Los nombres e identificadores de código se escriben en inglés. La API pública y sus contratos llevan JSDoc en español.
|
|
160
162
|
|
|
161
|
-
La [extensión local de VS Code](editors/vscode/README.md) comparte los diagnósticos del CLI y ofrece completado, navegación, hover, renombrado y formato en script y plantilla. El VSIX se validó en un host VS Code aislado con un proyecto consumidor externo; su README explica cómo repetir la prueba y las limitaciones actuales.
|
|
163
|
+
La [extensión local de VS Code](https://github.com/meekojs/meeko/blob/main/editors/vscode/README.md) comparte los diagnósticos del CLI y ofrece completado, navegación, hover, renombrado y formato en script y plantilla. El VSIX se validó en un host VS Code aislado con un proyecto consumidor externo; su README explica cómo repetir la prueba y las limitaciones actuales.
|
|
162
164
|
|
|
163
165
|
## Alcance actual
|
|
164
166
|
|
package/dist/autoimports-ts.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AutoImport, ImportScope } from "./autoimports.js";
|
|
2
|
-
export type TypeScriptScope = ImportScope
|
|
3
|
-
/** Selects
|
|
4
|
-
export declare function typeScriptScope(root: string, filename: string): TypeScriptScope | undefined;
|
|
2
|
+
export type TypeScriptScope = Exclude<ImportScope, "app">;
|
|
3
|
+
/** Selects a source scope without executing config; Vite may pass resolved roots for dynamic config. */
|
|
4
|
+
export declare function typeScriptScope(root: string, filename: string, sourceRoots?: readonly string[]): TypeScriptScope | undefined;
|
|
5
5
|
/** Produces global editor declarations for isolated app, server and shared TS projects. */
|
|
6
6
|
export declare function generateAutoImportTypes(projectRoot: string): Promise<{
|
|
7
7
|
client: string;
|
|
@@ -9,7 +9,7 @@ export declare function generateAutoImportTypes(projectRoot: string): Promise<{
|
|
|
9
9
|
shared: string;
|
|
10
10
|
}>;
|
|
11
11
|
/** Vite can call this for app/shared/server TypeScript before its normal TS transform. */
|
|
12
|
-
export declare function transformTypeScriptAutoImports(source: string, filename: string, root: string, registry: readonly AutoImport[]): string | undefined;
|
|
12
|
+
export declare function transformTypeScriptAutoImports(source: string, filename: string, root: string, registry: readonly AutoImport[], sourceRoots?: readonly string[]): string | undefined;
|
|
13
13
|
/** Maps the unchanged source body after imports inserted at the start of a TS module. */
|
|
14
14
|
export declare function typeScriptAutoImportMap(source: string, transformed: string, filename: string): {
|
|
15
15
|
version: 3;
|
package/dist/autoimports-ts.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import ts from "@typescript/typescript6";
|
|
4
4
|
import { applyAutoImports, discoverAutoImports } from "./autoimports.js";
|
|
5
|
+
import { readMeekoConfigSync } from "./framework/config.js";
|
|
5
6
|
function within(root, filename) {
|
|
6
7
|
const path = relative(resolve(root), resolve(filename));
|
|
7
8
|
return path === ".." || path.startsWith(`..${sep}`) || path.startsWith("/") ? undefined : path.replaceAll("\\", "/");
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
function scopeWithin(sourceRoot, filename) {
|
|
11
|
+
const path = within(sourceRoot, filename);
|
|
12
|
+
if (!path || !/\.[cm]?tsx?$/.test(path) || /\.(?:test|spec|d)\.[cm]?tsx?$/.test(path) ||
|
|
13
|
+
!/^(?:app|server|shared)\//.test(path))
|
|
13
14
|
return undefined;
|
|
14
15
|
if (/\.shared\.[cm]?tsx?$/.test(path))
|
|
15
16
|
return "shared";
|
|
@@ -27,6 +28,20 @@ export function typeScriptScope(root, filename) {
|
|
|
27
28
|
return "shared";
|
|
28
29
|
return undefined;
|
|
29
30
|
}
|
|
31
|
+
/** Selects a source scope without executing config; Vite may pass resolved roots for dynamic config. */
|
|
32
|
+
export function typeScriptScope(root, filename, sourceRoots) {
|
|
33
|
+
const config = sourceRoots ? undefined : readMeekoConfigSync(root);
|
|
34
|
+
const configured = sourceRoots ?? [
|
|
35
|
+
...(config?.extends ?? []),
|
|
36
|
+
...(config?.modules ?? []),
|
|
37
|
+
].map((entry) => resolve(root, entry));
|
|
38
|
+
for (const sourceRoot of [...configured, root].sort((a, b) => b.length - a.length)) {
|
|
39
|
+
const scope = scopeWithin(sourceRoot, filename);
|
|
40
|
+
if (scope)
|
|
41
|
+
return scope;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
30
45
|
function publicSpecifier(outputDirectory, entry) {
|
|
31
46
|
if (entry.specifier)
|
|
32
47
|
return entry.specifier;
|
|
@@ -35,7 +50,7 @@ function publicSpecifier(outputDirectory, entry) {
|
|
|
35
50
|
return entry.component ? prefixed : prefixed.replace(/\.[cm]?ts$/, (extension) => extension === ".mts" ? ".mjs" : extension === ".cts" ? ".cjs" : ".js");
|
|
36
51
|
}
|
|
37
52
|
function scopeEntries(registry, scope) {
|
|
38
|
-
return registry.filter((entry) => entry.scope === "shared" || (scope !== "shared" && entry.scope === scope));
|
|
53
|
+
return registry.filter((entry) => entry.scope === "shared" || (scope !== "shared" && (entry.scope === scope || entry.scope === "app")));
|
|
39
54
|
}
|
|
40
55
|
function assertNoCollisions(entries, scope) {
|
|
41
56
|
const symbols = new Map();
|
|
@@ -46,38 +61,83 @@ function assertNoCollisions(entries, scope) {
|
|
|
46
61
|
symbols.set(entry.name, entry);
|
|
47
62
|
}
|
|
48
63
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
function projectCompilerOptions(root) {
|
|
65
|
+
const config = ts.findConfigFile(root, ts.sys.fileExists, "tsconfig.json");
|
|
66
|
+
if (!config)
|
|
67
|
+
return {
|
|
68
|
+
target: ts.ScriptTarget.Latest,
|
|
69
|
+
module: ts.ModuleKind.NodeNext,
|
|
70
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
71
|
+
noEmit: true,
|
|
72
|
+
skipLibCheck: true,
|
|
73
|
+
};
|
|
74
|
+
const loaded = ts.readConfigFile(config, ts.sys.readFile);
|
|
75
|
+
if (loaded.error)
|
|
76
|
+
throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, "\n"));
|
|
77
|
+
return { ...ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options, noEmit: true };
|
|
78
|
+
}
|
|
79
|
+
function typeTargets(root, entries) {
|
|
80
|
+
const files = [...new Set(entries.filter((entry) => entry.typeOnly && !entry.specifier).map((entry) => entry.file))];
|
|
81
|
+
const targets = new Map();
|
|
82
|
+
if (files.length === 0)
|
|
83
|
+
return targets;
|
|
84
|
+
const program = ts.createProgram({ rootNames: files, options: projectCompilerOptions(root) });
|
|
85
|
+
const checker = program.getTypeChecker();
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (!entry.typeOnly || entry.specifier)
|
|
88
|
+
continue;
|
|
89
|
+
const file = program.getSourceFile(entry.file);
|
|
90
|
+
const moduleSymbol = file && checker.getSymbolAtLocation(file);
|
|
91
|
+
const exported = moduleSymbol && checker.getExportsOfModule(moduleSymbol).find((symbol) => symbol.name === entry.imported);
|
|
92
|
+
if (!exported)
|
|
93
|
+
continue;
|
|
94
|
+
const symbol = exported.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;
|
|
95
|
+
const declaration = symbol.declarations?.[0];
|
|
96
|
+
if (!declaration)
|
|
97
|
+
continue;
|
|
98
|
+
targets.set(`${entry.file}\0${entry.imported}`, {
|
|
99
|
+
file: declaration.getSourceFile().fileName,
|
|
100
|
+
imported: symbol.name,
|
|
101
|
+
});
|
|
57
102
|
}
|
|
58
|
-
|
|
59
|
-
const arguments_ = `<${declaration.typeParameters.map((parameter) => parameter.name.text).join(", ")}>`;
|
|
60
|
-
return ` type ${entry.name}${parameters} = import(${specifier}).${entry.imported}${arguments_};`;
|
|
103
|
+
return targets;
|
|
61
104
|
}
|
|
62
105
|
/** Produces global editor declarations for isolated app, server and shared TS projects. */
|
|
63
106
|
export async function generateAutoImportTypes(projectRoot) {
|
|
64
107
|
const root = resolve(projectRoot);
|
|
65
108
|
const outputDirectory = join(root, ".meeko", "types", "autoimports");
|
|
66
109
|
const registry = await discoverAutoImports(root);
|
|
110
|
+
const resolvedTypes = typeTargets(root, registry);
|
|
67
111
|
await mkdir(outputDirectory, { recursive: true });
|
|
68
112
|
const outputs = {};
|
|
69
113
|
for (const scope of ["client", "server", "shared"]) {
|
|
70
114
|
const entries = scopeEntries(registry, scope);
|
|
71
115
|
assertNoCollisions(entries, scope);
|
|
72
|
-
const
|
|
116
|
+
const typeModules = new Map();
|
|
117
|
+
const imports = [];
|
|
118
|
+
const declarations = entries.sort((a, b) => a.name.localeCompare(b.name)).map((entry) => {
|
|
73
119
|
const specifier = JSON.stringify(publicSpecifier(outputDirectory, entry));
|
|
74
|
-
if (entry.typeOnly)
|
|
75
|
-
|
|
120
|
+
if (entry.typeOnly) {
|
|
121
|
+
const resolvedTarget = resolvedTypes.get(`${entry.file}\0${entry.imported}`);
|
|
122
|
+
const target = resolvedTarget ?? entry;
|
|
123
|
+
const targetSpecifier = resolvedTarget
|
|
124
|
+
? JSON.stringify(publicSpecifier(outputDirectory, { ...entry, ...resolvedTarget }))
|
|
125
|
+
: specifier;
|
|
126
|
+
let namespace = typeModules.get(targetSpecifier);
|
|
127
|
+
if (!namespace) {
|
|
128
|
+
namespace = `__meeko_type_${typeModules.size}`;
|
|
129
|
+
typeModules.set(targetSpecifier, namespace);
|
|
130
|
+
// A declaration-only namespace alias preserves the original symbol's
|
|
131
|
+
// generic parameters, including private constraints and defaults.
|
|
132
|
+
imports.push(`import * as ${namespace} from ${targetSpecifier};`);
|
|
133
|
+
}
|
|
134
|
+
return ` export import ${entry.name} = ${namespace}.${target.imported};`;
|
|
135
|
+
}
|
|
76
136
|
const value = entry.component ? `typeof import(${specifier})` : `typeof import(${specifier})[${JSON.stringify(entry.imported)}]`;
|
|
77
137
|
return ` const ${entry.name}: ${value};`;
|
|
78
|
-
})
|
|
138
|
+
});
|
|
79
139
|
const path = join(outputDirectory, `${scope}.d.ts`);
|
|
80
|
-
const source = ["// Generated by Meeko. Scope-specific editor declarations.", "export {};", "declare global {", ...declarations, "}", ""].join("\n");
|
|
140
|
+
const source = ["// Generated by Meeko. Scope-specific editor declarations.", ...imports, "export {};", "declare global {", ...declarations, "}", ""].join("\n");
|
|
81
141
|
let previous;
|
|
82
142
|
try {
|
|
83
143
|
previous = await readFile(path, "utf8");
|
|
@@ -93,17 +153,13 @@ export async function generateAutoImportTypes(projectRoot) {
|
|
|
93
153
|
return outputs;
|
|
94
154
|
}
|
|
95
155
|
/** Vite can call this for app/shared/server TypeScript before its normal TS transform. */
|
|
96
|
-
export function transformTypeScriptAutoImports(source, filename, root, registry) {
|
|
97
|
-
const scope = typeScriptScope(root, filename);
|
|
156
|
+
export function transformTypeScriptAutoImports(source, filename, root, registry, sourceRoots) {
|
|
157
|
+
const scope = typeScriptScope(root, filename, sourceRoots);
|
|
98
158
|
if (!scope)
|
|
99
159
|
return undefined;
|
|
100
160
|
if (scope === "shared") {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const server = applyAutoImports(source, filename, registry, "server");
|
|
104
|
-
if (client !== server)
|
|
105
|
-
throw new Error(`Shared module ${filename} references an app or server autoimport`);
|
|
106
|
-
return client === source ? undefined : client;
|
|
161
|
+
const transformed = applyAutoImports(source, filename, registry, "shared");
|
|
162
|
+
return transformed === source ? undefined : transformed;
|
|
107
163
|
}
|
|
108
164
|
const transformed = applyAutoImports(source, filename, registry, scope);
|
|
109
165
|
return transformed === source ? undefined : transformed;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoimports-ts.js","sourceRoot":"","sources":["../src/autoimports-ts.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { applyAutoImports, discoverAutoImports } from \"./autoimports.js\";\nimport type { AutoImport, ImportScope } from \"./autoimports.js\";\n\nexport type TypeScriptScope = ImportScope;\n\nfunction within(root: string, filename: string): string | undefined {\n const path = relative(resolve(root), resolve(filename));\n return path === \"..\" || path.startsWith(`..${sep}`) || path.startsWith(\"/\") ? undefined : path.replaceAll(\"\\\\\", \"/\");\n}\n\n/** Selects the application scope of a source file without executing it. */\nexport function typeScriptScope(root: string, filename: string): TypeScriptScope | undefined {\n const path = within(root, filename);\n if (!path || !/\\.[cm]?tsx?$/.test(path) || /\\.(?:test|spec|d)\\.[cm]?tsx?$/.test(path)) return undefined;\n if (/\\.shared\\.[cm]?tsx?$/.test(path)) return \"shared\";\n if (/\\.server\\.[cm]?tsx?$/.test(path)) return \"server\";\n if (/\\.route\\.[cm]?tsx?$/.test(path) && /(?:^|\\/)app\\/pages\\//.test(path)) return \"server\";\n if (/\\.client\\.[cm]?tsx?$/.test(path)) return \"client\";\n if (path.startsWith(\"server/\")) return \"server\";\n if (path.startsWith(\"app/\")) return \"client\";\n if (path.startsWith(\"shared/\")) return \"shared\";\n return undefined;\n}\n\nfunction publicSpecifier(outputDirectory: string, entry: AutoImport): string {\n if (entry.specifier) return entry.specifier;\n const path = relative(outputDirectory, entry.file).replaceAll(\"\\\\\", \"/\");\n const prefixed = path.startsWith(\".\") ? path : `./${path}`;\n return entry.component ? prefixed : prefixed.replace(/\\.[cm]?ts$/, (extension) => extension === \".mts\" ? \".mjs\" : extension === \".cts\" ? \".cjs\" : \".js\");\n}\n\nfunction scopeEntries(registry: readonly AutoImport[], scope: TypeScriptScope): AutoImport[] {\n return registry.filter((entry) => entry.scope === \"shared\" || (scope !== \"shared\" && entry.scope === scope));\n}\n\nfunction assertNoCollisions(entries: readonly AutoImport[], scope: TypeScriptScope): void {\n const symbols = new Map<string, AutoImport>();\n for (const entry of entries) {\n const previous = symbols.get(entry.name);\n if (previous) throw new Error(`Ambiguous autoimport ${entry.name} in ${scope} scope: ${previous.file}, ${entry.file}`);\n symbols.set(entry.name, entry);\n }\n}\n\nasync function typeDeclaration(entry: AutoImport, specifier: string): Promise<string> {\n if (entry.specifier) return ` type ${entry.name} = import(${specifier}).${entry.imported};`;\n const source = await readFile(entry.file, \"utf8\");\n const file = ts.createSourceFile(entry.file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const declaration = file.statements.find((statement) =>\n (ts.isTypeAliasDeclaration(statement) || ts.isInterfaceDeclaration(statement)) && statement.name.text === entry.imported);\n if (!declaration || (!ts.isTypeAliasDeclaration(declaration) && !ts.isInterfaceDeclaration(declaration)) || !declaration.typeParameters?.length) {\n return ` type ${entry.name} = import(${specifier}).${entry.imported};`;\n }\n const parameters = `<${declaration.typeParameters.map((parameter) => parameter.getText(file)).join(\", \")}>`;\n const arguments_ = `<${declaration.typeParameters.map((parameter) => parameter.name.text).join(\", \")}>`;\n return ` type ${entry.name}${parameters} = import(${specifier}).${entry.imported}${arguments_};`;\n}\n\n/** Produces global editor declarations for isolated app, server and shared TS projects. */\nexport async function generateAutoImportTypes(projectRoot: string): Promise<{ client: string; server: string; shared: string }> {\n const root = resolve(projectRoot);\n const outputDirectory = join(root, \".meeko\", \"types\", \"autoimports\");\n const registry = await discoverAutoImports(root);\n await mkdir(outputDirectory, { recursive: true });\n const outputs = {} as { client: string; server: string; shared: string };\n for (const scope of [\"client\", \"server\", \"shared\"] as const) {\n const entries = scopeEntries(registry, scope);\n assertNoCollisions(entries, scope);\n const declarations = await Promise.all(entries.sort((a, b) => a.name.localeCompare(b.name)).map(async (entry) => {\n const specifier = JSON.stringify(publicSpecifier(outputDirectory, entry));\n if (entry.typeOnly) return typeDeclaration(entry, specifier);\n const value = entry.component ? `typeof import(${specifier})` : `typeof import(${specifier})[${JSON.stringify(entry.imported)}]`;\n return ` const ${entry.name}: ${value};`;\n }));\n const path = join(outputDirectory, `${scope}.d.ts`);\n const source = [\"// Generated by Meeko. Scope-specific editor declarations.\", \"export {};\", \"declare global {\", ...declarations, \"}\", \"\"].join(\"\\n\");\n let previous: string | undefined;\n try { previous = await readFile(path, \"utf8\"); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\n if (previous !== source) await writeFile(path, source, \"utf8\");\n outputs[scope] = path;\n }\n return outputs;\n}\n\n/** Vite can call this for app/shared/server TypeScript before its normal TS transform. */\nexport function transformTypeScriptAutoImports(source: string, filename: string, root: string, registry: readonly AutoImport[]): string | undefined {\n const scope = typeScriptScope(root, filename);\n if (!scope) return undefined;\n if (scope === \"shared\") {\n // A shared module must resolve identically from both client and server views.\n const client = applyAutoImports(source, filename, registry, \"client\");\n const server = applyAutoImports(source, filename, registry, \"server\");\n if (client !== server) throw new Error(`Shared module ${filename} references an app or server autoimport`);\n return client === source ? undefined : client;\n }\n const transformed = applyAutoImports(source, filename, registry, scope);\n return transformed === source ? undefined : transformed;\n}\n\n/** Maps the unchanged source body after imports inserted at the start of a TS module. */\nexport function typeScriptAutoImportMap(source: string, transformed: string, filename: string): {\n version: 3; sources: string[]; sourcesContent: string[]; names: string[]; mappings: string;\n} {\n if (!transformed.endsWith(source)) throw new TypeError(\"Autoimport transform must preserve the original TypeScript body\");\n const prefix = transformed.slice(0, -source.length);\n const insertedLines = (prefix.match(/\\n/g) ?? []).length;\n const sourceLines = source.split(/\\r\\n|\\r|\\n/).length;\n return {\n version: 3, sources: [filename], sourcesContent: [source], names: [],\n mappings: `${\";\".repeat(insertedLines)}AAAA${\";AACA\".repeat(Math.max(0, sourceLines - 1))}`,\n };\n}\n\n/** Convenience entrypoint for CLI generators. */\nexport async function generateTypeScriptAutoImports(projectRoot: string): Promise<{ client: string; server: string; shared: string }> {\n return generateAutoImportTypes(projectRoot);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"autoimports-ts.js","sourceRoot":"","sources":["../src/autoimports-ts.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport ts from \"@typescript/typescript6\";\nimport { applyAutoImports, discoverAutoImports } from \"./autoimports.js\";\nimport type { AutoImport, ImportScope } from \"./autoimports.js\";\nimport { readMeekoConfigSync } from \"./framework/config.js\";\n\nexport type TypeScriptScope = Exclude<ImportScope, \"app\">;\n\nfunction within(root: string, filename: string): string | undefined {\n const path = relative(resolve(root), resolve(filename));\n return path === \"..\" || path.startsWith(`..${sep}`) || path.startsWith(\"/\") ? undefined : path.replaceAll(\"\\\\\", \"/\");\n}\n\nfunction scopeWithin(sourceRoot: string, filename: string): TypeScriptScope | undefined {\n const path = within(sourceRoot, filename);\n if (!path || !/\\.[cm]?tsx?$/.test(path) || /\\.(?:test|spec|d)\\.[cm]?tsx?$/.test(path) ||\n !/^(?:app|server|shared)\\//.test(path)) return undefined;\n if (/\\.shared\\.[cm]?tsx?$/.test(path)) return \"shared\";\n if (/\\.server\\.[cm]?tsx?$/.test(path)) return \"server\";\n if (/\\.route\\.[cm]?tsx?$/.test(path) && /(?:^|\\/)app\\/pages\\//.test(path)) return \"server\";\n if (/\\.client\\.[cm]?tsx?$/.test(path)) return \"client\";\n if (path.startsWith(\"server/\")) return \"server\";\n if (path.startsWith(\"app/\")) return \"client\";\n if (path.startsWith(\"shared/\")) return \"shared\";\n return undefined;\n}\n\n/** Selects a source scope without executing config; Vite may pass resolved roots for dynamic config. */\nexport function typeScriptScope(root: string, filename: string, sourceRoots?: readonly string[]): TypeScriptScope | undefined {\n const config = sourceRoots ? undefined : readMeekoConfigSync(root);\n const configured = sourceRoots ?? [\n ...(config?.extends ?? []),\n ...(config?.modules ?? []),\n ].map((entry) => resolve(root, entry));\n for (const sourceRoot of [...configured, root].sort((a, b) => b.length - a.length)) {\n const scope = scopeWithin(sourceRoot, filename);\n if (scope) return scope;\n }\n return undefined;\n}\n\nfunction publicSpecifier(outputDirectory: string, entry: AutoImport): string {\n if (entry.specifier) return entry.specifier;\n const path = relative(outputDirectory, entry.file).replaceAll(\"\\\\\", \"/\");\n const prefixed = path.startsWith(\".\") ? path : `./${path}`;\n return entry.component ? prefixed : prefixed.replace(/\\.[cm]?ts$/, (extension) => extension === \".mts\" ? \".mjs\" : extension === \".cts\" ? \".cjs\" : \".js\");\n}\n\nfunction scopeEntries(registry: readonly AutoImport[], scope: TypeScriptScope): AutoImport[] {\n return registry.filter((entry) => entry.scope === \"shared\" || (scope !== \"shared\" && (entry.scope === scope || entry.scope === \"app\")));\n}\n\nfunction assertNoCollisions(entries: readonly AutoImport[], scope: TypeScriptScope): void {\n const symbols = new Map<string, AutoImport>();\n for (const entry of entries) {\n const previous = symbols.get(entry.name);\n if (previous) throw new Error(`Ambiguous autoimport ${entry.name} in ${scope} scope: ${previous.file}, ${entry.file}`);\n symbols.set(entry.name, entry);\n }\n}\n\ninterface TypeTarget {\n readonly file: string;\n readonly imported: string;\n}\n\nfunction projectCompilerOptions(root: string): ts.CompilerOptions {\n const config = ts.findConfigFile(root, ts.sys.fileExists, \"tsconfig.json\");\n if (!config) return {\n target: ts.ScriptTarget.Latest,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n noEmit: true,\n skipLibCheck: true,\n };\n const loaded = ts.readConfigFile(config, ts.sys.readFile);\n if (loaded.error) throw new Error(ts.flattenDiagnosticMessageText(loaded.error.messageText, \"\\n\"));\n return { ...ts.parseJsonConfigFileContent(loaded.config, ts.sys, dirname(config)).options, noEmit: true };\n}\n\nfunction typeTargets(root: string, entries: readonly AutoImport[]): Map<string, TypeTarget> {\n const files = [...new Set(entries.filter((entry) => entry.typeOnly && !entry.specifier).map((entry) => entry.file))];\n const targets = new Map<string, TypeTarget>();\n if (files.length === 0) return targets;\n const program = ts.createProgram({ rootNames: files, options: projectCompilerOptions(root) });\n const checker = program.getTypeChecker();\n for (const entry of entries) {\n if (!entry.typeOnly || entry.specifier) continue;\n const file = program.getSourceFile(entry.file);\n const moduleSymbol = file && checker.getSymbolAtLocation(file);\n const exported = moduleSymbol && checker.getExportsOfModule(moduleSymbol).find((symbol) => symbol.name === entry.imported);\n if (!exported) continue;\n const symbol = exported.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported;\n const declaration = symbol.declarations?.[0];\n if (!declaration) continue;\n targets.set(`${entry.file}\\0${entry.imported}`, {\n file: declaration.getSourceFile().fileName,\n imported: symbol.name,\n });\n }\n return targets;\n}\n\n/** Produces global editor declarations for isolated app, server and shared TS projects. */\nexport async function generateAutoImportTypes(projectRoot: string): Promise<{ client: string; server: string; shared: string }> {\n const root = resolve(projectRoot);\n const outputDirectory = join(root, \".meeko\", \"types\", \"autoimports\");\n const registry = await discoverAutoImports(root);\n const resolvedTypes = typeTargets(root, registry);\n await mkdir(outputDirectory, { recursive: true });\n const outputs = {} as { client: string; server: string; shared: string };\n for (const scope of [\"client\", \"server\", \"shared\"] as const) {\n const entries = scopeEntries(registry, scope);\n assertNoCollisions(entries, scope);\n const typeModules = new Map<string, string>();\n const imports: string[] = [];\n const declarations = entries.sort((a, b) => a.name.localeCompare(b.name)).map((entry) => {\n const specifier = JSON.stringify(publicSpecifier(outputDirectory, entry));\n if (entry.typeOnly) {\n const resolvedTarget = resolvedTypes.get(`${entry.file}\\0${entry.imported}`);\n const target = resolvedTarget ?? entry;\n const targetSpecifier = resolvedTarget\n ? JSON.stringify(publicSpecifier(outputDirectory, { ...entry, ...resolvedTarget }))\n : specifier;\n let namespace = typeModules.get(targetSpecifier);\n if (!namespace) {\n namespace = `__meeko_type_${typeModules.size}`;\n typeModules.set(targetSpecifier, namespace);\n // A declaration-only namespace alias preserves the original symbol's\n // generic parameters, including private constraints and defaults.\n imports.push(`import * as ${namespace} from ${targetSpecifier};`);\n }\n return ` export import ${entry.name} = ${namespace}.${target.imported};`;\n }\n const value = entry.component ? `typeof import(${specifier})` : `typeof import(${specifier})[${JSON.stringify(entry.imported)}]`;\n return ` const ${entry.name}: ${value};`;\n });\n const path = join(outputDirectory, `${scope}.d.ts`);\n const source = [\"// Generated by Meeko. Scope-specific editor declarations.\", ...imports, \"export {};\", \"declare global {\", ...declarations, \"}\", \"\"].join(\"\\n\");\n let previous: string | undefined;\n try { previous = await readFile(path, \"utf8\"); }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\n if (previous !== source) await writeFile(path, source, \"utf8\");\n outputs[scope] = path;\n }\n return outputs;\n}\n\n/** Vite can call this for app/shared/server TypeScript before its normal TS transform. */\nexport function transformTypeScriptAutoImports(source: string, filename: string, root: string, registry: readonly AutoImport[], sourceRoots?: readonly string[]): string | undefined {\n const scope = typeScriptScope(root, filename, sourceRoots);\n if (!scope) return undefined;\n if (scope === \"shared\") {\n const transformed = applyAutoImports(source, filename, registry, \"shared\");\n return transformed === source ? undefined : transformed;\n }\n const transformed = applyAutoImports(source, filename, registry, scope);\n return transformed === source ? undefined : transformed;\n}\n\n/** Maps the unchanged source body after imports inserted at the start of a TS module. */\nexport function typeScriptAutoImportMap(source: string, transformed: string, filename: string): {\n version: 3; sources: string[]; sourcesContent: string[]; names: string[]; mappings: string;\n} {\n if (!transformed.endsWith(source)) throw new TypeError(\"Autoimport transform must preserve the original TypeScript body\");\n const prefix = transformed.slice(0, -source.length);\n const insertedLines = (prefix.match(/\\n/g) ?? []).length;\n const sourceLines = source.split(/\\r\\n|\\r|\\n/).length;\n return {\n version: 3, sources: [filename], sourcesContent: [source], names: [],\n mappings: `${\";\".repeat(insertedLines)}AAAA${\";AACA\".repeat(Math.max(0, sourceLines - 1))}`,\n };\n}\n\n/** Convenience entrypoint for CLI generators. */\nexport async function generateTypeScriptAutoImports(projectRoot: string): Promise<{ client: string; server: string; shared: string }> {\n return generateAutoImportTypes(projectRoot);\n}\n"]}
|
package/dist/autoimports.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CompileOptions, CompileResult } from "./compiler.js";
|
|
2
|
-
export type ImportScope = "client" | "server" | "shared";
|
|
2
|
+
export type ImportScope = "client" | "server" | "shared" | "app";
|
|
3
3
|
export interface AutoImport {
|
|
4
4
|
name: string;
|
|
5
5
|
imported: string;
|
|
@@ -14,7 +14,7 @@ export declare function discoverAutoImports(root: string): Promise<AutoImport[]>
|
|
|
14
14
|
/** Same static registry used by the synchronous VS Code Language Service. */
|
|
15
15
|
export declare function discoverAutoImportsSync(root: string): AutoImport[];
|
|
16
16
|
/** Añade imports ESM para referencias libres del módulo generado. */
|
|
17
|
-
export declare function applyAutoImports(code: string, filename: string, registry: readonly AutoImport[], target: "client" | "server"): string;
|
|
17
|
+
export declare function applyAutoImports(code: string, filename: string, registry: readonly AutoImport[], target: "client" | "server" | "shared"): string;
|
|
18
18
|
/** Transforma un SFC usando exactamente el mismo compilador que el plugin Vite. */
|
|
19
19
|
export declare function transformAutoImports(source: string, filename: string, code: string, registry: readonly AutoImport[], target: "client" | "server"): string;
|
|
20
20
|
/** Compile result shared by Vite, CLI checks and declaration generation. */
|
package/dist/autoimports.js
CHANGED
|
@@ -20,8 +20,9 @@ function scopeOf(file) {
|
|
|
20
20
|
return "client";
|
|
21
21
|
if (file.includes(`${sep}server${sep}`))
|
|
22
22
|
return "server";
|
|
23
|
+
// App modules render on both sides during SSR, but are not available to shared/ sources.
|
|
23
24
|
if (file.includes(`${sep}app${sep}`))
|
|
24
|
-
return "
|
|
25
|
+
return "app";
|
|
25
26
|
return "shared";
|
|
26
27
|
}
|
|
27
28
|
async function filesIn(path) {
|
|
@@ -58,7 +59,7 @@ function filesInSync(path) {
|
|
|
58
59
|
}
|
|
59
60
|
function builtins(root) {
|
|
60
61
|
const entries = [
|
|
61
|
-
...["signal", "computed", "effect", "batch", "onCleanup", "provide", "inject", "createContext"].map((name) => ({ name, imported: name, file: "@meekojs/meeko", specifier: "@meekojs/meeko", scope: "shared", typeOnly: false, component: false })),
|
|
62
|
+
...["signal", "computed", "effect", "batch", "onCleanup", "provide", "inject", "createContext", "provideErrorHandler"].map((name) => ({ name, imported: name, file: "@meekojs/meeko", specifier: "@meekojs/meeko", scope: "shared", typeOnly: false, component: false })),
|
|
62
63
|
...["useState", "href"].map((name) => ({ name, imported: name, file: "@meekojs/meeko/framework", specifier: "@meekojs/meeko/framework", scope: "shared", typeOnly: false, component: false })),
|
|
63
64
|
];
|
|
64
65
|
for (const scope of ["client", "server"]) {
|
|
@@ -73,6 +74,21 @@ function builtins(root) {
|
|
|
73
74
|
}
|
|
74
75
|
return entries;
|
|
75
76
|
}
|
|
77
|
+
function addAutoImport(result, entry) {
|
|
78
|
+
const previous = result.find((candidate) => candidate.name === entry.name
|
|
79
|
+
&& candidate.imported === entry.imported
|
|
80
|
+
&& candidate.file === entry.file
|
|
81
|
+
&& candidate.scope === entry.scope
|
|
82
|
+
&& candidate.component === entry.component);
|
|
83
|
+
if (!previous) {
|
|
84
|
+
result.push(entry);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Function overloads and declaration merging describe one exported symbol.
|
|
88
|
+
// Prefer the value-bearing form when a type and value share that symbol.
|
|
89
|
+
if (previous.typeOnly && !entry.typeOnly)
|
|
90
|
+
previous.typeOnly = false;
|
|
91
|
+
}
|
|
76
92
|
function addFileImports(result, root, directory, file, source) {
|
|
77
93
|
const scope = scopeOf(file);
|
|
78
94
|
if (extname(file) === ".meeko") {
|
|
@@ -80,24 +96,24 @@ function addFileImports(result, root, directory, file, source) {
|
|
|
80
96
|
return;
|
|
81
97
|
const path = relative(join(root, directory), file).replace(/\.meeko$/, "");
|
|
82
98
|
const name = path.split(/[\\/]/).map((part) => part.replace(/(^|[-_])(\w)/g, (_, _dash, letter) => letter.toUpperCase())).join("");
|
|
83
|
-
result
|
|
99
|
+
addAutoImport(result, { name, imported: "*", file, scope, typeOnly: false, component: true });
|
|
84
100
|
return;
|
|
85
101
|
}
|
|
86
102
|
const ast = ts.createSourceFile(file, source ?? "", ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
87
103
|
for (const statement of ast.statements) {
|
|
88
104
|
const exported = ts.canHaveModifiers(statement) && ts.getModifiers(statement)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
89
105
|
if (exported && (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement) || ts.isEnumDeclaration(statement)) && statement.name) {
|
|
90
|
-
result
|
|
106
|
+
addAutoImport(result, { name: statement.name.text, imported: statement.name.text, file, scope, typeOnly: ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement), component: false });
|
|
91
107
|
}
|
|
92
108
|
if (exported && ts.isVariableStatement(statement)) {
|
|
93
109
|
for (const declaration of statement.declarationList.declarations)
|
|
94
110
|
if (ts.isIdentifier(declaration.name)) {
|
|
95
|
-
result
|
|
111
|
+
addAutoImport(result, { name: declaration.name.text, imported: declaration.name.text, file, scope, typeOnly: false, component: false });
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
if (ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
99
115
|
for (const element of statement.exportClause.elements)
|
|
100
|
-
result
|
|
116
|
+
addAutoImport(result, { name: element.name.text, imported: element.name.text, file, scope, typeOnly: statement.isTypeOnly || element.isTypeOnly, component: false });
|
|
101
117
|
}
|
|
102
118
|
}
|
|
103
119
|
}
|
|
@@ -247,7 +263,7 @@ export function applyAutoImports(code, filename, registry, target) {
|
|
|
247
263
|
const candidates = registry.filter((entry) => entry.name === name);
|
|
248
264
|
if (candidates.length === 0)
|
|
249
265
|
continue;
|
|
250
|
-
const allowed = candidates.filter((entry) => entry.scope === "shared" || entry.scope === target);
|
|
266
|
+
const allowed = candidates.filter((entry) => entry.scope === "shared" || entry.scope === target || (target !== "shared" && entry.scope === "app"));
|
|
251
267
|
if (allowed.length === 0)
|
|
252
268
|
throw new Error(`Autoimport ${name} is unavailable in ${target} scope`);
|
|
253
269
|
if (allowed.length > 1)
|