nuxt-openapi-hyperfetch 0.3.81-beta → 1.0.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 +218 -212
- package/dist/generators/components/connector-generator/templates.js +67 -17
- package/dist/generators/components/schema-analyzer/intent-detector.js +1 -12
- package/dist/generators/components/schema-analyzer/openapi-reader.js +10 -1
- package/dist/generators/components/schema-analyzer/resource-grouper.js +7 -0
- package/dist/generators/components/schema-analyzer/schema-field-mapper.js +1 -22
- package/dist/generators/components/schema-analyzer/types.d.ts +10 -0
- package/dist/generators/connectors/generator.d.ts +12 -0
- package/dist/generators/connectors/generator.js +115 -0
- package/dist/generators/connectors/runtime/connector-types.d.ts +147 -0
- package/dist/generators/connectors/runtime/connector-types.js +10 -0
- package/dist/generators/connectors/runtime/useCreateConnector.d.ts +26 -0
- package/dist/generators/connectors/runtime/useCreateConnector.js +156 -0
- package/dist/generators/connectors/runtime/useDeleteConnector.d.ts +30 -0
- package/dist/generators/connectors/runtime/useDeleteConnector.js +143 -0
- package/dist/generators/connectors/runtime/useGetAllConnector.d.ts +25 -0
- package/dist/generators/connectors/runtime/useGetAllConnector.js +127 -0
- package/dist/generators/connectors/runtime/useGetConnector.d.ts +15 -0
- package/dist/generators/connectors/runtime/useGetConnector.js +99 -0
- package/dist/generators/connectors/runtime/useUpdateConnector.d.ts +34 -0
- package/dist/generators/connectors/runtime/useUpdateConnector.js +211 -0
- package/dist/generators/connectors/runtime/zod-error-merger.d.ts +23 -0
- package/dist/generators/connectors/runtime/zod-error-merger.js +106 -0
- package/dist/generators/connectors/templates.d.ts +4 -0
- package/dist/generators/connectors/templates.js +376 -0
- package/dist/generators/connectors/types.d.ts +37 -0
- package/dist/generators/connectors/types.js +7 -0
- package/dist/generators/shared/runtime/useDeleteConnector.js +4 -2
- package/dist/generators/shared/runtime/useDetailConnector.d.ts +0 -1
- package/dist/generators/shared/runtime/useDetailConnector.js +9 -20
- package/dist/generators/shared/runtime/useFormConnector.js +4 -3
- package/dist/generators/use-async-data/runtime/useApiAsyncData.js +14 -5
- package/dist/generators/use-async-data/templates.js +20 -16
- package/dist/generators/use-fetch/templates.js +1 -1
- package/dist/index.js +1 -16
- package/dist/module/index.js +2 -3
- package/package.json +4 -3
- package/src/cli/prompts.ts +1 -7
- package/src/generators/components/connector-generator/templates.ts +97 -22
- package/src/generators/components/schema-analyzer/intent-detector.ts +1 -16
- package/src/generators/components/schema-analyzer/openapi-reader.ts +14 -1
- package/src/generators/components/schema-analyzer/resource-grouper.ts +9 -0
- package/src/generators/components/schema-analyzer/schema-field-mapper.ts +1 -26
- package/src/generators/components/schema-analyzer/types.ts +11 -0
- package/src/generators/connectors/generator.ts +137 -0
- package/src/generators/connectors/runtime/connector-types.ts +207 -0
- package/src/generators/connectors/runtime/useCreateConnector.ts +199 -0
- package/src/generators/connectors/runtime/useDeleteConnector.ts +179 -0
- package/src/generators/connectors/runtime/useGetAllConnector.ts +151 -0
- package/src/generators/connectors/runtime/useGetConnector.ts +120 -0
- package/src/generators/connectors/runtime/useUpdateConnector.ts +257 -0
- package/src/generators/connectors/runtime/zod-error-merger.ts +119 -0
- package/src/generators/connectors/templates.ts +481 -0
- package/src/generators/connectors/types.ts +39 -0
- package/src/generators/shared/runtime/useDeleteConnector.ts +4 -2
- package/src/generators/shared/runtime/useDetailConnector.ts +8 -19
- package/src/generators/shared/runtime/useFormConnector.ts +4 -3
- package/src/generators/use-async-data/runtime/useApiAsyncData.ts +16 -5
- package/src/generators/use-async-data/templates.ts +24 -16
- package/src/generators/use-fetch/templates.ts +1 -1
- package/src/index.ts +2 -19
- package/src/module/index.ts +2 -5
- package/docs/generated-components.md +0 -615
- package/docs/headless-composables-ui.md +0 -569
|
@@ -1,615 +0,0 @@
|
|
|
1
|
-
# Generated Vue Components (NuxtUI) — Feature Spec & Architecture
|
|
2
|
-
|
|
3
|
-
> **Status**: Planned — Capa 3 del sistema de generación de componentes Vue
|
|
4
|
-
> **Dependencia**: Requiere Capa 1 (Schema Analyzer) y Capa 2 (Connector Generator)
|
|
5
|
-
> **Objetivo**: Generar componentes `.vue` completamente funcionales listos para usar en producción, usando NuxtUI como librería de componentes, consumiendo los connectors headless generados en Capa 2
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Tabla de Contenidos
|
|
10
|
-
|
|
11
|
-
- [Qué es esta feature](#qué-es-esta-feature)
|
|
12
|
-
- [Estructura de archivos generados](#estructura-de-archivos-generados)
|
|
13
|
-
- [El archivo index.ts — punto de personalización](#el-archivo-indexts--punto-de-personalización)
|
|
14
|
-
- [Arquitectura de componentes por recurso](#arquitectura-de-componentes-por-recurso)
|
|
15
|
-
- [Componentes individuales](#componentes-individuales)
|
|
16
|
-
- [Reglas de generación y sobreescritura](#reglas-de-generación-y-sobreescritura)
|
|
17
|
-
- [Configuración en nxh.config / nuxt.config](#configuración-en-nxhconfig--nuxtconfig)
|
|
18
|
-
- [Estructura de archivos del generador en src/](#estructura-de-archivos-del-generador-en-src)
|
|
19
|
-
- [Plan de implementación](#plan-de-implementación)
|
|
20
|
-
- [Ejemplos de componentes generados](#ejemplos-de-componentes-generados)
|
|
21
|
-
- [Añadir soporte para otros UI frameworks](#añadir-soporte-para-otros-ui-frameworks)
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Qué es esta feature
|
|
26
|
-
|
|
27
|
-
El **Component Generator** es la Capa 3 del sistema. Toma el `ResourceMap` producido por el Schema Analyzer y los connectors headless generados por el Connector Generator, y produce **componentes `.vue` completamente funcionales** listos para ser usados en un proyecto Nuxt 3.
|
|
28
|
-
|
|
29
|
-
Primera implementación: **NuxtUI** (`@nuxt/ui`).
|
|
30
|
-
|
|
31
|
-
El desarrollador puede:
|
|
32
|
-
- Usar los componentes directamente con `<PetsCrud />` o `<PetsTable />`
|
|
33
|
-
- Personalizar labels, traducciones y overrides de campo en `index.ts` (generado una vez)
|
|
34
|
-
- Modificar cualquier `.vue` libremente después de generarlos (son archivos del proyecto del usuario)
|
|
35
|
-
- Importar subcomponentes individualmente (`<PetsCreate />` solo el form)
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Estructura de archivos generados
|
|
40
|
-
|
|
41
|
-
Por defecto, los componentes se generan en `components/nxh/{resource}/`. El developer puede cambiar el directorio base en la config.
|
|
42
|
-
|
|
43
|
-
Para un recurso `Pet` con CRUD completo:
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
components/nxh/
|
|
47
|
-
pets/
|
|
48
|
-
index.ts ← generado UNA VEZ, nunca sobreescrito
|
|
49
|
-
PetsCrud.vue ← componente principal CRUD completo
|
|
50
|
-
table/
|
|
51
|
-
index.vue ← tabla con columnas, paginación, botones de acción
|
|
52
|
-
forms/
|
|
53
|
-
PetsCreate.vue ← formulario de creación
|
|
54
|
-
PetsUpdate.vue ← formulario de edición (pre-rellena con GET /{id})
|
|
55
|
-
modals/
|
|
56
|
-
PetsCreate.vue ← modal que envuelve forms/PetsCreate.vue
|
|
57
|
-
PetsUpdate.vue ← modal que envuelve forms/PetsUpdate.vue
|
|
58
|
-
PetsDelete.vue ← modal de confirmación de borrado
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Para un recurso solo con GET list (sin CRUD):
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
components/nxh/
|
|
65
|
-
pets/
|
|
66
|
-
index.ts
|
|
67
|
-
table/
|
|
68
|
-
index.vue
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Para un recurso solo con POST (sin list):
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
components/nxh/
|
|
75
|
-
pets/
|
|
76
|
-
index.ts
|
|
77
|
-
forms/
|
|
78
|
-
PetsCreate.vue
|
|
79
|
-
modals/
|
|
80
|
-
PetsCreate.vue
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
El generador es inteligente: **solo genera los archivos que corresponden a los intents detectados**.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## El archivo index.ts — Punto de personalización
|
|
88
|
-
|
|
89
|
-
Este archivo es el contrato entre el generador y el desarrollador.
|
|
90
|
-
|
|
91
|
-
**Regla crítica: se genera UNA SOLA VEZ. Si ya existe, nunca se sobreescribe.**
|
|
92
|
-
|
|
93
|
-
```ts
|
|
94
|
-
// components/nxh/pets/index.ts
|
|
95
|
-
// Generated once by nxh — customize freely, this file will NOT be overwritten.
|
|
96
|
-
// Re-run `nxh components` to regenerate the .vue files without touching this file.
|
|
97
|
-
|
|
98
|
-
import type { NxhResourceConfig } from '#nxh/types'
|
|
99
|
-
|
|
100
|
-
export const config: NxhResourceConfig = {
|
|
101
|
-
|
|
102
|
-
// ─── Columnas de la tabla ────────────────────────────────────────────────
|
|
103
|
-
// Generadas automáticamente del response schema del GET list.
|
|
104
|
-
// Modifica 'label' para traducir, añade 'hidden: true' para ocultar.
|
|
105
|
-
columns: {
|
|
106
|
-
id: { label: 'ID', hidden: false },
|
|
107
|
-
name: { label: 'Name' },
|
|
108
|
-
status: { label: 'Status', type: 'badge' },
|
|
109
|
-
createdAt: { label: 'Created At', type: 'date' },
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
// ─── Campos del formulario ───────────────────────────────────────────────
|
|
113
|
-
// El tipo se infiere automáticamente del schema OpenAPI.
|
|
114
|
-
// Sobreescribe 'type', 'label' o añade 'options' para selects personalizados.
|
|
115
|
-
// 'errors' permite personalizar los mensajes de validación Zod por campo.
|
|
116
|
-
fields: {
|
|
117
|
-
name: {
|
|
118
|
-
label: 'Name',
|
|
119
|
-
type: 'input',
|
|
120
|
-
errors: {
|
|
121
|
-
required: 'Name is required', // sobreescribe el mensaje Zod
|
|
122
|
-
min: 'Name must be at least 1 character',
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
status: {
|
|
126
|
-
label: 'Status',
|
|
127
|
-
type: 'select',
|
|
128
|
-
options: [ // rellena las options
|
|
129
|
-
{ label: 'Available', value: 'available' },
|
|
130
|
-
{ label: 'Sold', value: 'sold' },
|
|
131
|
-
],
|
|
132
|
-
errors: {
|
|
133
|
-
invalid_enum_value: 'Select a valid status',
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
photoUrls: { label: 'Photos', type: 'input' },
|
|
137
|
-
// Los campos readOnly: true del schema están hidden: true por defecto
|
|
138
|
-
// id: { hidden: true }, ← generado así automáticamente
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
// ─── Opciones globales del recurso ───────────────────────────────────────
|
|
142
|
-
showReadonlyFields: false, // mostrar campos readOnly en formularios
|
|
143
|
-
|
|
144
|
-
// ─── Hooks de ciclo de vida ──────────────────────────────────────────────
|
|
145
|
-
// Retornar false en onBeforeCreate/onBeforeUpdate cancela la operación.
|
|
146
|
-
onBeforeCreate: (data) => data, // puede transformar el payload
|
|
147
|
-
onAfterCreate: (result) => {},
|
|
148
|
-
onBeforeUpdate: (id, data) => data,
|
|
149
|
-
onAfterUpdate: (result) => {},
|
|
150
|
-
onBeforeDelete: (item) => true, // return false = cancelar
|
|
151
|
-
onAfterDelete: (item) => {},
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Los `.vue` generados importan este `config` y lo aplican:
|
|
156
|
-
- `table/index.vue` usa `config.columns` para las columnas y labels
|
|
157
|
-
- `forms/PetsCreate.vue` usa `config.fields` para los inputs y labels
|
|
158
|
-
- Todos los `.vue` invocan los hooks correspondientes de `config`
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
## Arquitectura de componentes por recurso
|
|
163
|
-
|
|
164
|
-
### Jerarquía de dependencias
|
|
165
|
-
|
|
166
|
-
```
|
|
167
|
-
PetsCrud.vue
|
|
168
|
-
├── importa usePetsConnector (Capa 2)
|
|
169
|
-
├── importa config desde ./index.ts
|
|
170
|
-
├── renderiza table/index.vue
|
|
171
|
-
│ └── usa connector.table
|
|
172
|
-
├── renderiza modals/PetsCreate.vue
|
|
173
|
-
│ └── contiene forms/PetsCreate.vue
|
|
174
|
-
│ └── usa connector.createForm
|
|
175
|
-
├── renderiza modals/PetsUpdate.vue
|
|
176
|
-
│ └── contiene forms/PetsUpdate.vue
|
|
177
|
-
│ └── usa connector.updateForm (pre-rellena con connector.detail)
|
|
178
|
-
└── renderiza modals/PetsDelete.vue
|
|
179
|
-
└── usa connector.deleteAction
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### Comunicación entre componentes
|
|
183
|
-
|
|
184
|
-
Los subcomponentes **no se comunican entre sí directamente**. Todo pasa por `PetsCrud.vue` mediante el connector unificado:
|
|
185
|
-
|
|
186
|
-
- `table/index.vue` emite `@open-create`, `@open-update(row)`, `@open-delete(row)`
|
|
187
|
-
- `PetsCrud.vue` escucha esos eventos y abre el modal correspondiente
|
|
188
|
-
- Cuando un form hace submit con éxito, cierra el modal y llama `connector.table.refresh()`
|
|
189
|
-
|
|
190
|
-
Esto permite usar `table/index.vue` de forma independiente sin necesitar `PetsCrud.vue`.
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
## Componentes individuales
|
|
195
|
-
|
|
196
|
-
### `table/index.vue`
|
|
197
|
-
|
|
198
|
-
Responsabilidades:
|
|
199
|
-
- Mostrar `UTable` con las columnas de `config.columns`
|
|
200
|
-
- Columnas con `type: 'badge'` → `UBadge`; `type: 'date'` → fecha formateada
|
|
201
|
-
- Fila de acciones al final: botón Edit (abre modal update), botón Delete (abre modal delete)
|
|
202
|
-
- Paginación con `UPagination` si `connector.table.pagination` está activo
|
|
203
|
-
- Botón "New" en el header de la tabla (abre modal create)
|
|
204
|
-
- Loading state con skeleton rows
|
|
205
|
-
- Estado vacío con slot `empty` personalizable
|
|
206
|
-
|
|
207
|
-
Props:
|
|
208
|
-
```ts
|
|
209
|
-
defineProps<{
|
|
210
|
-
connector: ListConnectorReturn<any>
|
|
211
|
-
config: NxhResourceConfig
|
|
212
|
-
}>()
|
|
213
|
-
defineEmits(['open-create', 'open-update', 'open-delete'])
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### `forms/PetsCreate.vue` y `forms/PetsUpdate.vue`
|
|
217
|
-
|
|
218
|
-
Responsabilidades:
|
|
219
|
-
- Renderizar cada campo de `config.fields` con el componente NuxtUI correspondiente
|
|
220
|
-
- `type: 'input'` → `UInput`
|
|
221
|
-
- `type: 'textarea'` → `UTextarea`
|
|
222
|
-
- `type: 'select'` → `USelect`
|
|
223
|
-
- `type: 'checkbox'` → `UCheckbox`
|
|
224
|
-
- `type: 'number'` → `UInput type="number"`
|
|
225
|
-
- `type: 'datepicker'`→ `UInput type="date"` (o librería de fecha si disponible)
|
|
226
|
-
- Mostrar errores de validación por campo con `UFormField`
|
|
227
|
-
- Botón Submit con loading state
|
|
228
|
-
- `PetsUpdate.vue` usa `connector.updateForm` que pre-rellena automáticamente si existe `connector.detail`
|
|
229
|
-
|
|
230
|
-
Ejemplo de template generado con manejo de errores Zod vía `UFormField`:
|
|
231
|
-
|
|
232
|
-
```vue
|
|
233
|
-
<!-- forms/PetsCreate.vue (generado) -->
|
|
234
|
-
<template>
|
|
235
|
-
<UForm @submit="connector.submit()">
|
|
236
|
-
<template v-for="field in connector.fields" :key="field.name">
|
|
237
|
-
<UFormField
|
|
238
|
-
:label="field.label"
|
|
239
|
-
:error="connector.errors[field.name]"
|
|
240
|
-
>
|
|
241
|
-
<!-- el error viene de Zod.safeParse → mergeado con config.fields[name].errors -->
|
|
242
|
-
<UInput
|
|
243
|
-
v-if="field.type === 'input'"
|
|
244
|
-
v-model="connector.model[field.name]"
|
|
245
|
-
/>
|
|
246
|
-
<USelect
|
|
247
|
-
v-else-if="field.type === 'select'"
|
|
248
|
-
v-model="connector.model[field.name]"
|
|
249
|
-
:options="field.options"
|
|
250
|
-
/>
|
|
251
|
-
<!-- ...otros tipos... -->
|
|
252
|
-
</UFormField>
|
|
253
|
-
</template>
|
|
254
|
-
<UButton type="submit" :loading="connector.loading">Save</UButton>
|
|
255
|
-
</UForm>
|
|
256
|
-
</template>
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
`connector.errors` es `Ref<Record<string, string>>` expuesto por `useFormConnector` tras `schema.safeParse()`. Si el campo no tiene error, el valor es `undefined` y `UFormField` no muestra nada.
|
|
260
|
-
|
|
261
|
-
Props:
|
|
262
|
-
```ts
|
|
263
|
-
defineProps<{
|
|
264
|
-
connector: FormConnectorReturn<any>
|
|
265
|
-
config: NxhResourceConfig
|
|
266
|
-
}>()
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### `modals/PetsCreate.vue` y `modals/PetsUpdate.vue`
|
|
270
|
-
|
|
271
|
-
Wrapper simple de `UModal` + `UCard` que envuelve el form correspondiente.
|
|
272
|
-
|
|
273
|
-
```vue
|
|
274
|
-
<template>
|
|
275
|
-
<UModal v-model="isOpen">
|
|
276
|
-
<UCard>
|
|
277
|
-
<template #header>Create Pet</template>
|
|
278
|
-
<PetsCreateForm :connector="connector.createForm" :config="config" />
|
|
279
|
-
</UCard>
|
|
280
|
-
</UModal>
|
|
281
|
-
</template>
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
El estado `isOpen` es manejado por `PetsCrud.vue`, no por el modal.
|
|
285
|
-
|
|
286
|
-
### `modals/PetsDelete.vue`
|
|
287
|
-
|
|
288
|
-
Modal de confirmación. No usa form.
|
|
289
|
-
|
|
290
|
-
```vue
|
|
291
|
-
<template>
|
|
292
|
-
<UModal v-model="isOpen">
|
|
293
|
-
<UCard>
|
|
294
|
-
<template #header>Confirm Delete</template>
|
|
295
|
-
<p>Are you sure you want to delete this item?</p>
|
|
296
|
-
<template #footer>
|
|
297
|
-
<UButton color="red" :loading="connector.deleteAction.loading.value"
|
|
298
|
-
@click="connector.deleteAction.confirm()">
|
|
299
|
-
Delete
|
|
300
|
-
</UButton>
|
|
301
|
-
<UButton variant="ghost" @click="connector.deleteAction.cancel()">
|
|
302
|
-
Cancel
|
|
303
|
-
</UButton>
|
|
304
|
-
</template>
|
|
305
|
-
</UCard>
|
|
306
|
-
</UModal>
|
|
307
|
-
</template>
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### `PetsCrud.vue`
|
|
311
|
-
|
|
312
|
-
Componente orquestador. Gestiona:
|
|
313
|
-
- El estado de qué modal está abierto (`createOpen`, `updateOpen`, `deleteOpen`)
|
|
314
|
-
- Escucha eventos de `table/index.vue` para abrir modales
|
|
315
|
-
- Llama `table.refresh()` cuando un form tiene éxito
|
|
316
|
-
- Invoca hooks `config.onBeforeCreate`, `config.onAfterCreate`, etc.
|
|
317
|
-
|
|
318
|
-
```vue
|
|
319
|
-
<script setup>
|
|
320
|
-
import { ref } from 'vue'
|
|
321
|
-
import { usePetsConnector } from '~/composables/connectors/usePetsConnector'
|
|
322
|
-
import { config } from './index'
|
|
323
|
-
import PetsTable from './table/index.vue'
|
|
324
|
-
import PetsCreateModal from './modals/PetsCreate.vue'
|
|
325
|
-
import PetsUpdateModal from './modals/PetsUpdate.vue'
|
|
326
|
-
import PetsDeleteModal from './modals/PetsDelete.vue'
|
|
327
|
-
|
|
328
|
-
const connector = usePetsConnector()
|
|
329
|
-
|
|
330
|
-
const createOpen = ref(false)
|
|
331
|
-
const updateOpen = ref(false)
|
|
332
|
-
const deleteOpen = ref(false)
|
|
333
|
-
|
|
334
|
-
connector.createForm.onSuccess.value = () => {
|
|
335
|
-
createOpen.value = false
|
|
336
|
-
connector.table.refresh()
|
|
337
|
-
config.onAfterCreate?.(connector.createForm.model.value)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
connector.updateForm.onSuccess.value = () => {
|
|
341
|
-
updateOpen.value = false
|
|
342
|
-
connector.table.refresh()
|
|
343
|
-
config.onAfterUpdate?.(connector.updateForm.model.value)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
connector.deleteAction.onSuccess.value = () => {
|
|
347
|
-
deleteOpen.value = false
|
|
348
|
-
connector.table.refresh()
|
|
349
|
-
config.onAfterDelete?.(connector.deleteAction.target.value)
|
|
350
|
-
}
|
|
351
|
-
</script>
|
|
352
|
-
|
|
353
|
-
<template>
|
|
354
|
-
<PetsTable
|
|
355
|
-
:connector="connector.table"
|
|
356
|
-
:config="config"
|
|
357
|
-
@open-create="createOpen = true"
|
|
358
|
-
@open-update="(row) => { connector.updateForm.setValues(row); updateOpen = true }"
|
|
359
|
-
@open-delete="(row) => { connector.deleteAction.setTarget(row); deleteOpen = true }"
|
|
360
|
-
/>
|
|
361
|
-
<PetsCreateModal v-model="createOpen" :connector="connector" :config="config" />
|
|
362
|
-
<PetsUpdateModal v-model="updateOpen" :connector="connector" :config="config" />
|
|
363
|
-
<PetsDeleteModal v-model="deleteOpen" :connector="connector" :config="config" />
|
|
364
|
-
</template>
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
## Reglas de generación y sobreescritura
|
|
370
|
-
|
|
371
|
-
| Archivo | Se genera | Se sobreescribe en re-run |
|
|
372
|
-
|-----------------------------|------------------|---------------------------|
|
|
373
|
-
| `index.ts` | Solo si no existe | **NUNCA** |
|
|
374
|
-
| `PetsCrud.vue` | Siempre | Sí |
|
|
375
|
-
| `table/index.vue` | Siempre | Sí |
|
|
376
|
-
| `forms/PetsCreate.vue` | Siempre | Sí |
|
|
377
|
-
| `forms/PetsUpdate.vue` | Siempre | Sí |
|
|
378
|
-
| `modals/PetsCreate.vue` | Siempre | Sí |
|
|
379
|
-
| `modals/PetsUpdate.vue` | Siempre | Sí |
|
|
380
|
-
| `modals/PetsDelete.vue` | Siempre | Sí |
|
|
381
|
-
|
|
382
|
-
Si el developer modifica un `.vue` generado y no quiere que se sobreescriba: lo mueve a un directorio fuera de `components/nxh/` y actualiza sus imports.
|
|
383
|
-
|
|
384
|
-
---
|
|
385
|
-
|
|
386
|
-
## Configuración en nxh.config / nuxt.config
|
|
387
|
-
|
|
388
|
-
```js
|
|
389
|
-
// nxh.config.js
|
|
390
|
-
export default {
|
|
391
|
-
// ... config existente
|
|
392
|
-
|
|
393
|
-
components: {
|
|
394
|
-
// Override de intent para endpoints ambiguos
|
|
395
|
-
'GET /pets/search': { intent: 'list' },
|
|
396
|
-
|
|
397
|
-
// Configuración por recurso
|
|
398
|
-
pets: {
|
|
399
|
-
outputDir: 'components/admin/pets', // directorio custom
|
|
400
|
-
showReadonlyFields: true, // mostrar campos readOnly
|
|
401
|
-
ui: 'nuxtui', // framework UI (default: 'nuxtui')
|
|
402
|
-
},
|
|
403
|
-
|
|
404
|
-
// Excluir un recurso de la generación
|
|
405
|
-
internalLogs: { skip: true },
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
En `nuxt.config.ts` (cuando se usa como módulo Nuxt):
|
|
411
|
-
|
|
412
|
-
```ts
|
|
413
|
-
export default defineNuxtConfig({
|
|
414
|
-
nxh: {
|
|
415
|
-
components: {
|
|
416
|
-
'GET /pets/search': { intent: 'list' },
|
|
417
|
-
pets: {
|
|
418
|
-
outputDir: 'components/admin/pets',
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
})
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
---
|
|
426
|
-
|
|
427
|
-
## Estructura de archivos del generador en src/
|
|
428
|
-
|
|
429
|
-
```
|
|
430
|
-
src/
|
|
431
|
-
generators/
|
|
432
|
-
components/
|
|
433
|
-
schema-analyzer/ ← Capa 1 (ver headless-composables-ui.md)
|
|
434
|
-
connector-generator/ ← Capa 2 (ver headless-composables-ui.md)
|
|
435
|
-
vue-generator/ ← ESTA FEATURE (Capa 3)
|
|
436
|
-
index.ts ← entry point
|
|
437
|
-
types.ts ← ComponentPlan, ComponentFile, UIAdapter
|
|
438
|
-
generator.ts ← orquesta la generación de todos los .vue
|
|
439
|
-
config-generator.ts ← genera el index.ts (si no existe)
|
|
440
|
-
adapters/
|
|
441
|
-
nuxtui/
|
|
442
|
-
index.ts ← entry point del adaptador NuxtUI
|
|
443
|
-
table.ts ← template de table/index.vue con UTable
|
|
444
|
-
form-create.ts ← template de forms/PetsCreate.vue
|
|
445
|
-
form-update.ts ← template de forms/PetsUpdate.vue
|
|
446
|
-
modal-create.ts ← template de modals/PetsCreate.vue
|
|
447
|
-
modal-update.ts ← template de modals/PetsUpdate.vue
|
|
448
|
-
modal-delete.ts ← template de modals/PetsDelete.vue
|
|
449
|
-
crud.ts ← template de PetsCrud.vue
|
|
450
|
-
field-mapper.ts ← FormFieldDef → componente NuxtUI string
|
|
451
|
-
primevue/ ← para implementación futura
|
|
452
|
-
index.ts
|
|
453
|
-
...
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
Cada función en `adapters/nuxtui/*.ts` recibe un `ComponentPlan` (datos del recurso) y devuelve un `string` con el contenido del archivo `.vue`.
|
|
457
|
-
|
|
458
|
-
---
|
|
459
|
-
|
|
460
|
-
## Plan de implementación
|
|
461
|
-
|
|
462
|
-
### Fase 1 — Tipos y contratos del vue-generator
|
|
463
|
-
|
|
464
|
-
**Archivo:** `src/generators/components/vue-generator/types.ts`
|
|
465
|
-
|
|
466
|
-
```ts
|
|
467
|
-
interface ComponentPlan {
|
|
468
|
-
resourceName: string // 'Pet'
|
|
469
|
-
resourceNamePlural: string // 'Pets'
|
|
470
|
-
connectorImportPath: string // '~/composables/connectors/usePetsConnector'
|
|
471
|
-
configImportPath: string // './index'
|
|
472
|
-
columns: ColumnDef[]
|
|
473
|
-
formFields: FormFieldDef[]
|
|
474
|
-
intents: Intent[] // ['list', 'create', 'update', 'delete']
|
|
475
|
-
hasPagination: boolean
|
|
476
|
-
hasDetail: boolean
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
interface UIAdapter {
|
|
480
|
-
name: string
|
|
481
|
-
generateTable(plan: ComponentPlan): string
|
|
482
|
-
generateFormCreate(plan: ComponentPlan): string
|
|
483
|
-
generateFormUpdate(plan: ComponentPlan): string
|
|
484
|
-
generateModalCreate(plan: ComponentPlan): string
|
|
485
|
-
generateModalUpdate(plan: ComponentPlan): string
|
|
486
|
-
generateModalDelete(plan: ComponentPlan): string
|
|
487
|
-
generateCrud(plan: ComponentPlan): string
|
|
488
|
-
generateConfig(plan: ComponentPlan): string
|
|
489
|
-
}
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
### Fase 2 — Adaptador NuxtUI
|
|
493
|
-
|
|
494
|
-
**Archivos:** `src/generators/components/vue-generator/adapters/nuxtui/`
|
|
495
|
-
|
|
496
|
-
Implementar cada función de `UIAdapter` produciendo strings con el template Vue correcto. Cada función es pura: `(plan: ComponentPlan) => string`.
|
|
497
|
-
|
|
498
|
-
Orden de implementación:
|
|
499
|
-
1. `field-mapper.ts` — mapea `FormFieldDef.type` → componente NuxtUI correcto
|
|
500
|
-
2. `table.ts` — genera `table/index.vue` con `UTable`, `UPagination`, botones
|
|
501
|
-
3. `form-create.ts` — genera `forms/PetsCreate.vue` con `UForm`, `UFormField`
|
|
502
|
-
4. `form-update.ts` — igual que create pero con `loadWith`
|
|
503
|
-
5. `modal-create.ts`, `modal-update.ts`, `modal-delete.ts` — wrappers `UModal`
|
|
504
|
-
6. `crud.ts` — orquestador principal
|
|
505
|
-
7. `config-generator.ts` — genera `index.ts` (con columnas y campos inferidos como punto de partida)
|
|
506
|
-
|
|
507
|
-
### Fase 3 — Generator principal
|
|
508
|
-
|
|
509
|
-
**Archivo:** `src/generators/components/vue-generator/generator.ts`
|
|
510
|
-
|
|
511
|
-
```ts
|
|
512
|
-
export async function generateVueComponents(
|
|
513
|
-
resourceMap: ResourceMap,
|
|
514
|
-
outputBaseDir: string,
|
|
515
|
-
adapter: UIAdapter,
|
|
516
|
-
options: { overwriteConfig?: boolean } = {}
|
|
517
|
-
): Promise<void>
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
Por cada recurso en `resourceMap`:
|
|
521
|
-
1. Construye el `ComponentPlan`
|
|
522
|
-
2. Determina qué archivos generar según los intents
|
|
523
|
-
3. Para `index.ts`: escribe solo si no existe (a menos que `overwriteConfig: true`)
|
|
524
|
-
4. Formatea cada archivo con Prettier antes de escribir
|
|
525
|
-
5. Reporta progreso con `@clack/prompts`
|
|
526
|
-
|
|
527
|
-
### Fase 4 — Integración en CLI
|
|
528
|
-
|
|
529
|
-
Nuevo flag en el comando `generate` existente:
|
|
530
|
-
```
|
|
531
|
-
--components <ui> Generate Vue components with specified UI framework (nuxtui)
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
O subcomando separado (preferible para no sobrecargar `generate`):
|
|
535
|
-
```
|
|
536
|
-
nxh components --input swagger.yaml --output ./components/nxh --ui nuxtui
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
---
|
|
540
|
-
|
|
541
|
-
## Ejemplos de componentes generados
|
|
542
|
-
|
|
543
|
-
### Uso básico — solo importar PetsCrud
|
|
544
|
-
|
|
545
|
-
```vue
|
|
546
|
-
<!-- pages/admin/pets.vue -->
|
|
547
|
-
<template>
|
|
548
|
-
<div>
|
|
549
|
-
<h1>Pets Management</h1>
|
|
550
|
-
<PetsCrud />
|
|
551
|
-
</div>
|
|
552
|
-
</template>
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
### Solo la tabla, sin modales
|
|
556
|
-
|
|
557
|
-
```vue
|
|
558
|
-
<!-- pages/dashboard.vue -->
|
|
559
|
-
<script setup>
|
|
560
|
-
import PetsTable from '~/components/nxh/pets/table/index.vue'
|
|
561
|
-
import { usePetsConnector } from '~/composables/connectors/usePetsConnector'
|
|
562
|
-
import { config } from '~/components/nxh/pets/index'
|
|
563
|
-
|
|
564
|
-
const { table } = usePetsConnector()
|
|
565
|
-
</script>
|
|
566
|
-
|
|
567
|
-
<template>
|
|
568
|
-
<PetsTable :connector="table" :config="config" />
|
|
569
|
-
</template>
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### Solo el formulario de creación en una página dedicada
|
|
573
|
-
|
|
574
|
-
```vue
|
|
575
|
-
<!-- pages/pets/new.vue -->
|
|
576
|
-
<script setup>
|
|
577
|
-
import PetsCreateForm from '~/components/nxh/pets/forms/PetsCreate.vue'
|
|
578
|
-
import { usePetsConnector } from '~/composables/connectors/usePetsConnector'
|
|
579
|
-
import { config } from '~/components/nxh/pets/index'
|
|
580
|
-
|
|
581
|
-
const { createForm } = usePetsConnector()
|
|
582
|
-
|
|
583
|
-
createForm.onSuccess.value = () => navigateTo('/pets')
|
|
584
|
-
</script>
|
|
585
|
-
|
|
586
|
-
<template>
|
|
587
|
-
<PetsCreateForm :connector="createForm" :config="config" />
|
|
588
|
-
</template>
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## Añadir soporte para otros UI frameworks
|
|
594
|
-
|
|
595
|
-
Para añadir soporte para PrimeVue, Vuetify, Shadcn-vue, etc., se crea una nueva carpeta en `adapters/`:
|
|
596
|
-
|
|
597
|
-
```
|
|
598
|
-
adapters/
|
|
599
|
-
primevue/
|
|
600
|
-
index.ts ← exporta un objeto UIAdapter
|
|
601
|
-
table.ts ← usa DataTable, Column de PrimeVue
|
|
602
|
-
form-create.ts ← usa InputText, Dropdown, etc.
|
|
603
|
-
...
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
El `generator.ts` es idéntico para todos los adaptadores. Solo cambia qué `UIAdapter` se le pasa.
|
|
607
|
-
|
|
608
|
-
El CLI expondrá:
|
|
609
|
-
```
|
|
610
|
-
nxh components --ui primevue
|
|
611
|
-
nxh components --ui nuxtui (default)
|
|
612
|
-
nxh components --ui shadcn
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
Esto permite que la comunidad contribuya nuevos adaptadores sin tocar el core del generador.
|