@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.
Files changed (139) hide show
  1. package/README.md +21 -19
  2. package/dist/autoimports-ts.d.ts +4 -4
  3. package/dist/autoimports-ts.js +86 -30
  4. package/dist/autoimports-ts.js.map +1 -1
  5. package/dist/autoimports.d.ts +2 -2
  6. package/dist/autoimports.js +23 -7
  7. package/dist/autoimports.js.map +1 -1
  8. package/dist/check.js +39 -10
  9. package/dist/check.js.map +1 -1
  10. package/dist/cli.js +37 -4
  11. package/dist/cli.js.map +1 -1
  12. package/dist/compiler/events.d.ts +2 -0
  13. package/dist/compiler/events.js +6 -0
  14. package/dist/compiler/events.js.map +1 -0
  15. package/dist/compiler/props.d.ts +12 -0
  16. package/dist/compiler/props.js +32 -0
  17. package/dist/compiler/props.js.map +1 -0
  18. package/dist/compiler.js +55 -12
  19. package/dist/compiler.js.map +1 -1
  20. package/dist/component-errors.d.ts +18 -0
  21. package/dist/component-errors.js +65 -0
  22. package/dist/component-errors.js.map +1 -0
  23. package/dist/devtools.js +2 -4
  24. package/dist/devtools.js.map +1 -1
  25. package/dist/dom.d.ts +11 -5
  26. package/dist/dom.js +288 -88
  27. package/dist/dom.js.map +1 -1
  28. package/dist/error-observer.d.ts +6 -0
  29. package/dist/error-observer.js +41 -0
  30. package/dist/error-observer.js.map +1 -0
  31. package/dist/framework/check-app.js +160 -5
  32. package/dist/framework/check-app.js.map +1 -1
  33. package/dist/framework/check-project.d.ts +4 -0
  34. package/dist/framework/check-project.js +42 -0
  35. package/dist/framework/check-project.js.map +1 -0
  36. package/dist/framework/client.d.ts +3 -0
  37. package/dist/framework/client.js +136 -33
  38. package/dist/framework/client.js.map +1 -1
  39. package/dist/framework/clients.js +12 -4
  40. package/dist/framework/clients.js.map +1 -1
  41. package/dist/framework/contracts-generate.js +66 -3
  42. package/dist/framework/contracts-generate.js.map +1 -1
  43. package/dist/framework/init.js +21 -200
  44. package/dist/framework/init.js.map +1 -1
  45. package/dist/framework/middleware.d.ts +14 -0
  46. package/dist/framework/middleware.js +16 -0
  47. package/dist/framework/middleware.js.map +1 -0
  48. package/dist/framework/page-contracts-check.d.ts +8 -0
  49. package/dist/framework/page-contracts-check.js +110 -0
  50. package/dist/framework/page-contracts-check.js.map +1 -0
  51. package/dist/framework/page-contracts-generate.d.ts +2 -0
  52. package/dist/framework/page-contracts-generate.js +94 -0
  53. package/dist/framework/page-contracts-generate.js.map +1 -0
  54. package/dist/framework/page.d.ts +7 -3
  55. package/dist/framework/page.js +3 -1
  56. package/dist/framework/page.js.map +1 -1
  57. package/dist/framework/prerender.js +11 -5
  58. package/dist/framework/prerender.js.map +1 -1
  59. package/dist/framework/project-templates.d.ts +3 -0
  60. package/dist/framework/project-templates.js +119 -0
  61. package/dist/framework/project-templates.js.map +1 -0
  62. package/dist/framework/project.d.ts +9 -0
  63. package/dist/framework/project.js +272 -0
  64. package/dist/framework/project.js.map +1 -0
  65. package/dist/framework/router.d.ts +3 -1
  66. package/dist/framework/router.js +94 -8
  67. package/dist/framework/router.js.map +1 -1
  68. package/dist/framework/server.d.ts +17 -3
  69. package/dist/framework/server.js +71 -24
  70. package/dist/framework/server.js.map +1 -1
  71. package/dist/framework/socket-contracts-generate.js +8 -5
  72. package/dist/framework/socket-contracts-generate.js.map +1 -1
  73. package/dist/framework/socket.d.ts +2 -0
  74. package/dist/framework/socket.js +119 -17
  75. package/dist/framework/socket.js.map +1 -1
  76. package/dist/framework/standard-schema-types.d.ts +7 -0
  77. package/dist/framework/standard-schema-types.js +69 -0
  78. package/dist/framework/standard-schema-types.js.map +1 -0
  79. package/dist/framework/state.d.ts +7 -0
  80. package/dist/framework/state.js +78 -14
  81. package/dist/framework/state.js.map +1 -1
  82. package/dist/framework/styles.d.ts +2 -0
  83. package/dist/framework/styles.js +6 -0
  84. package/dist/framework/styles.js.map +1 -0
  85. package/dist/framework/type-declarations.d.ts +5 -0
  86. package/dist/framework/type-declarations.js +84 -0
  87. package/dist/framework/type-declarations.js.map +1 -0
  88. package/dist/framework-server/contracts.d.ts +11 -2
  89. package/dist/framework-server/contracts.js +62 -7
  90. package/dist/framework-server/contracts.js.map +1 -1
  91. package/dist/framework-server/discovery.d.ts +4 -1
  92. package/dist/framework-server/discovery.js +21 -16
  93. package/dist/framework-server/discovery.js.map +1 -1
  94. package/dist/framework-server/local.d.ts +2 -0
  95. package/dist/framework-server/local.js +5 -3
  96. package/dist/framework-server/local.js.map +1 -1
  97. package/dist/framework-server/middleware.d.ts +4 -0
  98. package/dist/framework-server/middleware.js +56 -0
  99. package/dist/framework-server/middleware.js.map +1 -0
  100. package/dist/framework-server/node-upgrade.js +27 -9
  101. package/dist/framework-server/node-upgrade.js.map +1 -1
  102. package/dist/framework-server/node-websocket.js +4 -2
  103. package/dist/framework-server/node-websocket.js.map +1 -1
  104. package/dist/framework-server/session-stores.d.ts +9 -2
  105. package/dist/framework-server/session-stores.js +37 -11
  106. package/dist/framework-server/session-stores.js.map +1 -1
  107. package/dist/framework-server/sessions.d.ts +6 -0
  108. package/dist/framework-server/sessions.js +41 -10
  109. package/dist/framework-server/sessions.js.map +1 -1
  110. package/dist/framework-server/socket.js +62 -27
  111. package/dist/framework-server/socket.js.map +1 -1
  112. package/dist/framework-server.d.ts +2 -0
  113. package/dist/framework-server.js +1 -0
  114. package/dist/framework-server.js.map +1 -1
  115. package/dist/framework.d.ts +3 -1
  116. package/dist/framework.js +1 -0
  117. package/dist/framework.js.map +1 -1
  118. package/dist/hmr.js +74 -24
  119. package/dist/hmr.js.map +1 -1
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +1 -0
  122. package/dist/index.js.map +1 -1
  123. package/dist/init.js +27 -1
  124. package/dist/init.js.map +1 -1
  125. package/dist/internal.d.ts +2 -2
  126. package/dist/internal.js +2 -2
  127. package/dist/internal.js.map +1 -1
  128. package/dist/node.d.ts +5 -1
  129. package/dist/node.js +80 -10
  130. package/dist/node.js.map +1 -1
  131. package/dist/reactivity.d.ts +12 -3
  132. package/dist/reactivity.js +94 -17
  133. package/dist/reactivity.js.map +1 -1
  134. package/dist/types.d.ts +2 -0
  135. package/dist/types.js +3 -1
  136. package/dist/types.js.map +1 -1
  137. package/dist/vite.js +29 -9
  138. package/dist/vite.js.map +1 -1
  139. 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. **La versión `0.0.4` que incluye este framework está preparada, pero aún no se ha publicado en npm.** Una vez publicada e instalada, crea una aplicación con:
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
- `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](examples/regions/Regions.meeko) muestra condiciones, listas anidadas, eventos y atributos dinámicos.
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
- 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](examples/nested/Parent.meeko) muestra hijos y nietos dentro de condiciones y listas.
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
 
@@ -1,7 +1,7 @@
1
1
  import type { AutoImport, ImportScope } from "./autoimports.js";
2
- export type TypeScriptScope = ImportScope;
3
- /** Selects the application scope of a source file without executing it. */
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;
@@ -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
- /** Selects the application scope of a source file without executing it. */
10
- export function typeScriptScope(root, filename) {
11
- const path = within(root, filename);
12
- if (!path || !/\.[cm]?tsx?$/.test(path) || /\.(?:test|spec|d)\.[cm]?tsx?$/.test(path))
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
- async function typeDeclaration(entry, specifier) {
50
- if (entry.specifier)
51
- return ` type ${entry.name} = import(${specifier}).${entry.imported};`;
52
- const source = await readFile(entry.file, "utf8");
53
- const file = ts.createSourceFile(entry.file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
54
- const declaration = file.statements.find((statement) => (ts.isTypeAliasDeclaration(statement) || ts.isInterfaceDeclaration(statement)) && statement.name.text === entry.imported);
55
- if (!declaration || (!ts.isTypeAliasDeclaration(declaration) && !ts.isInterfaceDeclaration(declaration)) || !declaration.typeParameters?.length) {
56
- return ` type ${entry.name} = import(${specifier}).${entry.imported};`;
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
- const parameters = `<${declaration.typeParameters.map((parameter) => parameter.getText(file)).join(", ")}>`;
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 declarations = await Promise.all(entries.sort((a, b) => a.name.localeCompare(b.name)).map(async (entry) => {
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
- return typeDeclaration(entry, specifier);
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
- // A shared module must resolve identically from both client and server views.
102
- const client = applyAutoImports(source, filename, registry, "client");
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"]}
@@ -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. */
@@ -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 "client";
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.push({ name, imported: "*", file, scope, typeOnly: false, component: true });
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.push({ name: statement.name.text, imported: statement.name.text, file, scope, typeOnly: ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement), component: false });
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.push({ name: declaration.name.text, imported: declaration.name.text, file, scope, typeOnly: false, component: false });
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.push({ name: element.name.text, imported: element.name.text, file, scope, typeOnly: statement.isTypeOnly || element.isTypeOnly, component: false });
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)