first commit
This commit is contained in:
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Dependencias
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# Archivos temporales de generación
|
||||||
|
.temp-generated/
|
||||||
|
temp-generated/
|
||||||
|
|
||||||
|
# Reportes
|
||||||
|
generation-report.json
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Sistema operativo
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Output de prueba
|
||||||
|
test-output/
|
||||||
33
.openapi-generator-ignore
Normal file
33
.openapi-generator-ignore
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# OpenAPI Generator Ignore File
|
||||||
|
# Archivos que no queremos generar
|
||||||
|
|
||||||
|
# Documentación
|
||||||
|
README.md
|
||||||
|
.gitignore
|
||||||
|
git_push.sh
|
||||||
|
|
||||||
|
# NPM
|
||||||
|
.npmignore
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# TypeScript config
|
||||||
|
tsconfig.json
|
||||||
|
tsconfig.spec.json
|
||||||
|
|
||||||
|
# Angular specific
|
||||||
|
angular.json
|
||||||
|
karma.conf.js
|
||||||
|
|
||||||
|
# Tests que no usamos
|
||||||
|
*.spec.ts
|
||||||
|
|
||||||
|
# Variables de entorno
|
||||||
|
variables.ts
|
||||||
|
configuration.ts
|
||||||
|
|
||||||
|
# Encoder
|
||||||
|
encoder.ts
|
||||||
|
|
||||||
|
# API base que usamos nuestra propia implementación
|
||||||
|
api.ts
|
||||||
157
QUICKSTART.md
Normal file
157
QUICKSTART.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# 🚀 Guía de Inicio Rápido
|
||||||
|
|
||||||
|
## Instalación en 3 pasos
|
||||||
|
|
||||||
|
### 1. Instalar dependencias
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Instalar OpenAPI Generator CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run setup
|
||||||
|
# O manualmente:
|
||||||
|
npm install -g @openapitools/openapi-generator-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Probar con el ejemplo incluido
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js -i example-swagger.yaml -o ./test-output --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uso con tu API
|
||||||
|
|
||||||
|
### Paso 1: Copia tu archivo Swagger/OpenAPI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /ruta/a/tu/api.yaml ./swagger.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Paso 2: Genera el código
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js -i swagger.yaml -o ./src/app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Paso 3: Revisa los archivos generados
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la ./src/app/data/
|
||||||
|
ls -la ./src/app/domain/
|
||||||
|
ls -la ./src/app/di/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Opciones Comunes
|
||||||
|
|
||||||
|
### Generar en otra carpeta
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js -i swagger.yaml -o ./frontend/src/app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usar templates personalizados
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edita los archivos en ./templates/
|
||||||
|
# Luego ejecuta:
|
||||||
|
node generate.js -i swagger.yaml -t ./templates
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modo de prueba (sin generar archivos)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js -i swagger.yaml --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integración con tu proyecto Angular
|
||||||
|
|
||||||
|
### 1. Registra los providers
|
||||||
|
|
||||||
|
En `app.config.ts` o `app.module.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { UserRepositoryProvider } from '@/di/repositories/user.repository.provider';
|
||||||
|
import { UserUseCasesProvider } from '@/di/use-cases/user.use-cases.provider';
|
||||||
|
|
||||||
|
export const appConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
// ... otros providers
|
||||||
|
UserRepositoryProvider,
|
||||||
|
UserUseCasesProvider
|
||||||
|
]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configura los path aliases
|
||||||
|
|
||||||
|
En `tsconfig.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/app/*"],
|
||||||
|
"@environment": ["src/environments/environment"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Usa en tus componentes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { USER_USE_CASES } from '@/domain/use-cases/user/user.use-cases.contract';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-users',
|
||||||
|
template: `...`
|
||||||
|
})
|
||||||
|
export class UsersComponent {
|
||||||
|
#userUseCases = inject(USER_USE_CASES);
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.#userUseCases.getUsers().subscribe(users => {
|
||||||
|
console.log(users);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### ❌ Error: openapi-generator-cli: command not found
|
||||||
|
|
||||||
|
**Solución:**
|
||||||
|
```bash
|
||||||
|
npm install -g @openapitools/openapi-generator-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Error: Cannot find module 'commander'
|
||||||
|
|
||||||
|
**Solución:**
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❌ Los archivos no se generan
|
||||||
|
|
||||||
|
**Solución:** Verifica que el directorio de salida existe o usa `--dry-run` para ver qué pasaría:
|
||||||
|
```bash
|
||||||
|
node generate.js --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Próximos pasos
|
||||||
|
|
||||||
|
1. ✅ Genera el código desde tu Swagger
|
||||||
|
2. 📝 Ajusta los templates según tus necesidades
|
||||||
|
3. 🔧 Configura los path aliases en tu tsconfig.json
|
||||||
|
4. 📦 Registra los providers en tu módulo Angular
|
||||||
|
5. 🚀 ¡Usa el código generado en tus componentes!
|
||||||
|
|
||||||
|
## ¿Necesitas ayuda?
|
||||||
|
|
||||||
|
Consulta el README.md completo para documentación detallada.
|
||||||
286
README.md
Normal file
286
README.md
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
# OpenAPI Clean Architecture Generator
|
||||||
|
|
||||||
|
Generador de código Angular con Clean Architecture desde archivos OpenAPI/Swagger.
|
||||||
|
|
||||||
|
## 🚀 Instalación
|
||||||
|
|
||||||
|
### Opción 1: Instalación Global
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g @openapitools/openapi-generator-cli
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opción 2: Usar directamente
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📖 Uso
|
||||||
|
|
||||||
|
### Comando básico
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js -i swagger.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opciones disponibles
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js [opciones]
|
||||||
|
|
||||||
|
Opciones:
|
||||||
|
-V, --version Mostrar versión
|
||||||
|
-i, --input <file> Archivo OpenAPI/Swagger (yaml o json) [default: swagger.yaml]
|
||||||
|
-o, --output <dir> Directorio de salida [default: ./src/app]
|
||||||
|
-t, --templates <dir> Directorio de templates personalizados [default: ./templates]
|
||||||
|
--skip-install No instalar dependencias
|
||||||
|
--dry-run Simular sin generar archivos
|
||||||
|
-h, --help Mostrar ayuda
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ejemplos
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generar desde swagger.yaml en src/app
|
||||||
|
node generate.js -i swagger.yaml -o ./src/app
|
||||||
|
|
||||||
|
# Usar templates personalizados
|
||||||
|
node generate.js -i api.yaml -t ./mis-templates
|
||||||
|
|
||||||
|
# Modo de prueba (no genera archivos)
|
||||||
|
node generate.js -i swagger.yaml --dry-run
|
||||||
|
|
||||||
|
# Especificar todos los parámetros
|
||||||
|
node generate.js -i ./docs/api.yaml -o ./frontend/src/app -t ./custom-templates
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📁 Estructura Generada
|
||||||
|
|
||||||
|
El generador crea la siguiente estructura siguiendo Clean Architecture:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/app/
|
||||||
|
├── data/ # Capa de datos
|
||||||
|
│ ├── dtos/ # Data Transfer Objects
|
||||||
|
│ │ ├── node/
|
||||||
|
│ │ │ └── node.dto.ts
|
||||||
|
│ │ ├── order-type/
|
||||||
|
│ │ │ └── order-type.dto.ts
|
||||||
|
│ │ └── supply-mode/
|
||||||
|
│ │ └── supply-mode.dto.ts
|
||||||
|
│ ├── repositories/ # Implementaciones de repositorios
|
||||||
|
│ │ ├── node.repository.impl.ts
|
||||||
|
│ │ ├── order-type.repository.impl.ts
|
||||||
|
│ │ └── supply-mode.repository.impl.ts
|
||||||
|
│ └── mappers/ # Transformadores DTO → Entidad
|
||||||
|
│ ├── node.mapper.ts
|
||||||
|
│ ├── order-type.mapper.ts
|
||||||
|
│ └── supply-mode.mapper.ts
|
||||||
|
├── domain/ # Capa de dominio
|
||||||
|
│ ├── repositories/ # Contratos de repositorios
|
||||||
|
│ │ ├── node.repository.contract.ts
|
||||||
|
│ │ ├── order-type.repository.contract.ts
|
||||||
|
│ │ └── supply-mode.repository.contract.ts
|
||||||
|
│ └── use-cases/ # Casos de uso
|
||||||
|
│ ├── node/
|
||||||
|
│ │ ├── node.use-cases.contract.ts
|
||||||
|
│ │ └── node.use-cases.impl.ts
|
||||||
|
│ ├── order-type/
|
||||||
|
│ │ ├── order-type.use-cases.contract.ts
|
||||||
|
│ │ └── order-type.use-cases.impl.ts
|
||||||
|
│ └── supply-mode/
|
||||||
|
│ ├── supply-mode.use-cases.contract.ts
|
||||||
|
│ └── supply-mode.use-cases.impl.ts
|
||||||
|
├── di/ # Inyección de dependencias
|
||||||
|
│ ├── repositories/ # Providers de repositorios
|
||||||
|
│ │ ├── node.repository.provider.ts
|
||||||
|
│ │ ├── order-type.repository.provider.ts
|
||||||
|
│ │ └── supply-mode.repository.provider.ts
|
||||||
|
│ └── use-cases/ # Providers de use cases
|
||||||
|
│ ├── node.use-cases.provider.ts
|
||||||
|
│ ├── order-type.use-cases.provider.ts
|
||||||
|
│ └── supply-mode.use-cases.provider.ts
|
||||||
|
└── entities/ # Entidades de dominio
|
||||||
|
└── models/
|
||||||
|
├── node.model.ts
|
||||||
|
├── order-type.model.ts
|
||||||
|
└── supply-mode.model.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 Personalización
|
||||||
|
|
||||||
|
### Modificar Templates
|
||||||
|
|
||||||
|
Los templates están en la carpeta `templates/`. Cada archivo `.mustache` define cómo se genera un tipo de archivo.
|
||||||
|
|
||||||
|
Templates disponibles:
|
||||||
|
- `model.mustache` - DTOs
|
||||||
|
- `model-entity.mustache` - Entidades del modelo
|
||||||
|
- `mapper.mustache` - Mappers
|
||||||
|
- `api.repository.contract.mustache` - Contratos de repositorio
|
||||||
|
- `api.repository.impl.mustache` - Implementaciones de repositorio
|
||||||
|
- `api.use-cases.contract.mustache` - Contratos de use cases
|
||||||
|
- `api.use-cases.impl.mustache` - Implementaciones de use cases
|
||||||
|
- `repository.provider.mustache` - Providers de repositorio
|
||||||
|
- `use-cases.provider.mustache` - Providers de use cases
|
||||||
|
|
||||||
|
### Variables Mustache Disponibles
|
||||||
|
|
||||||
|
```mustache
|
||||||
|
{{classname}} - Nombre de la clase (ej: "OrderType")
|
||||||
|
{{classVarName}} - Nombre en camelCase (ej: "orderType")
|
||||||
|
{{classFilename}} - Nombre del archivo (ej: "order-type")
|
||||||
|
{{constantName}} - Constante (ej: "ORDER_TYPE")
|
||||||
|
{{description}} - Descripción del schema
|
||||||
|
{{httpMethod}} - Método HTTP (get, post, etc)
|
||||||
|
{{path}} - Path del endpoint
|
||||||
|
{{nickname}} - Nombre del método
|
||||||
|
{{allParams}} - Todos los parámetros
|
||||||
|
{{returnType}} - Tipo de retorno
|
||||||
|
{{vars}} - Variables del modelo
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 Reporte de Generación
|
||||||
|
|
||||||
|
Después de cada generación, se crea un archivo `generation-report.json` con estadísticas:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"timestamp": "2025-01-15T10:30:00.000Z",
|
||||||
|
"tags": 3,
|
||||||
|
"endpoints": 8,
|
||||||
|
"outputDirectory": "./src/app",
|
||||||
|
"structure": {
|
||||||
|
"dtos": 15,
|
||||||
|
"repositories": 9,
|
||||||
|
"mappers": 3,
|
||||||
|
"useCases": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Ejemplo Completo
|
||||||
|
|
||||||
|
### 1. Preparar tu proyecto
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clonar o copiar el generador
|
||||||
|
cd mi-proyecto-angular
|
||||||
|
mkdir generator
|
||||||
|
cd generator
|
||||||
|
# Copiar archivos del generador aquí
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Copiar tu Swagger
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp ../docs/api.yaml ./swagger.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Generar código
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node generate.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Registrar providers en Angular
|
||||||
|
|
||||||
|
En tu `app.module.ts` o `app.config.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { NodeRepositoryProvider } from '@/di/repositories/node.repository.provider';
|
||||||
|
import { NodeUseCasesProvider } from '@/di/use-cases/node.use-cases.provider';
|
||||||
|
// ... importar otros providers
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [
|
||||||
|
// Repositories
|
||||||
|
NodeRepositoryProvider,
|
||||||
|
OrderTypeRepositoryProvider,
|
||||||
|
SupplyModeRepositoryProvider,
|
||||||
|
|
||||||
|
// Use Cases
|
||||||
|
NodeUseCasesProvider,
|
||||||
|
OrderTypeUseCasesProvider,
|
||||||
|
SupplyModeUseCasesProvider
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Usar en componentes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { NODE_USE_CASES, NodeUseCases } from '@/domain/use-cases/node/node.use-cases.contract';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-nodes',
|
||||||
|
template: `...`
|
||||||
|
})
|
||||||
|
export class NodesComponent {
|
||||||
|
#nodeUseCases = inject(NODE_USE_CASES);
|
||||||
|
|
||||||
|
loadNodes() {
|
||||||
|
this.#nodeUseCases.getNodes('TI').subscribe(nodes => {
|
||||||
|
console.log(nodes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Error: openapi-generator-cli no encontrado
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -g @openapitools/openapi-generator-cli
|
||||||
|
# o
|
||||||
|
npm run setup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error: Archivo swagger.yaml no encontrado
|
||||||
|
|
||||||
|
Asegúrate de especificar la ruta correcta:
|
||||||
|
```bash
|
||||||
|
node generate.js -i ./ruta/a/tu/swagger.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Los imports no se resuelven (@/ no funciona)
|
||||||
|
|
||||||
|
Configura los path aliases en tu `tsconfig.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/app/*"],
|
||||||
|
"@environment": ["src/environments/environment"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Los templates no generan el código esperado
|
||||||
|
|
||||||
|
1. Verifica que tus templates están en `./templates/`
|
||||||
|
2. Revisa la sintaxis Mustache
|
||||||
|
3. Usa `--dry-run` para verificar sin generar archivos
|
||||||
|
|
||||||
|
## 📝 Notas
|
||||||
|
|
||||||
|
- El generador crea archivos `.ts`, no los compila
|
||||||
|
- Los providers deben registrarse manualmente en tu módulo Angular
|
||||||
|
- Asegúrate de tener configurado `@mercadona/common` o ajusta los imports en los templates
|
||||||
|
- El generador asume Angular 17+ con inject() function
|
||||||
|
|
||||||
|
## 🤝 Contribuir
|
||||||
|
|
||||||
|
Si encuentras bugs o mejoras, siéntete libre de modificar los templates y el script según tus necesidades.
|
||||||
|
|
||||||
|
## 📄 Licencia
|
||||||
|
|
||||||
|
MIT
|
||||||
150
example-swagger.yaml
Normal file
150
example-swagger.yaml
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
openapi: 3.0.1
|
||||||
|
info:
|
||||||
|
title: Example API
|
||||||
|
description: API de ejemplo para probar el generador
|
||||||
|
version: 1.0.0
|
||||||
|
tags:
|
||||||
|
- name: User
|
||||||
|
description: Operaciones de usuario
|
||||||
|
- name: Product
|
||||||
|
description: Operaciones de productos
|
||||||
|
paths:
|
||||||
|
/v1/users:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
summary: Obtener lista de usuarios
|
||||||
|
operationId: getUsers
|
||||||
|
parameters:
|
||||||
|
- name: search
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserResponse'
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
summary: Crear usuario
|
||||||
|
operationId: createUser
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/CreateUserRequest'
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: Created
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserSchema'
|
||||||
|
/v1/users/{id}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
summary: Obtener usuario por ID
|
||||||
|
operationId: getUserById
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserSchema'
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
summary: Eliminar usuario
|
||||||
|
operationId: deleteUser
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: No Content
|
||||||
|
/v1/products:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Product
|
||||||
|
summary: Obtener lista de productos
|
||||||
|
operationId: getProducts
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ProductResponse'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
UserSchema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
example: 1
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Juan Pérez
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
example: juan@example.com
|
||||||
|
active:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
CreateUserRequest:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- email
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Juan Pérez
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
example: juan@example.com
|
||||||
|
UserResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
users:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserSchema'
|
||||||
|
ProductSchema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
example: 100
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Laptop HP
|
||||||
|
price:
|
||||||
|
type: number
|
||||||
|
format: float
|
||||||
|
example: 599.99
|
||||||
|
ProductResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
products:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ProductSchema'
|
||||||
311
generate.js
Executable file
311
generate.js
Executable file
@@ -0,0 +1,311 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const { program } = require('commander');
|
||||||
|
|
||||||
|
// Colores para console (sin dependencias externas)
|
||||||
|
const colors = {
|
||||||
|
reset: '\x1b[0m',
|
||||||
|
bright: '\x1b[1m',
|
||||||
|
green: '\x1b[32m',
|
||||||
|
blue: '\x1b[34m',
|
||||||
|
yellow: '\x1b[33m',
|
||||||
|
red: '\x1b[31m',
|
||||||
|
cyan: '\x1b[36m'
|
||||||
|
};
|
||||||
|
|
||||||
|
function log(message, color = 'reset') {
|
||||||
|
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logSuccess(message) {
|
||||||
|
log(`✅ ${message}`, 'green');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logInfo(message) {
|
||||||
|
log(`ℹ️ ${message}`, 'blue');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logWarning(message) {
|
||||||
|
log(`⚠️ ${message}`, 'yellow');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(message) {
|
||||||
|
log(`❌ ${message}`, 'red');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logStep(message) {
|
||||||
|
log(`\n🚀 ${message}`, 'cyan');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuración del CLI
|
||||||
|
program
|
||||||
|
.name('generate-clean-arch')
|
||||||
|
.description('Generador de código Angular con Clean Architecture desde OpenAPI/Swagger')
|
||||||
|
.version('1.0.0')
|
||||||
|
.option('-i, --input <file>', 'Archivo OpenAPI/Swagger (yaml o json)', 'swagger.yaml')
|
||||||
|
.option('-o, --output <dir>', 'Directorio de salida', './src/app')
|
||||||
|
.option('-t, --templates <dir>', 'Directorio de templates personalizados', './templates')
|
||||||
|
.option('--skip-install', 'No instalar dependencias')
|
||||||
|
.option('--dry-run', 'Simular sin generar archivos')
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
|
const options = program.opts();
|
||||||
|
|
||||||
|
// Validar que existe openapi-generator-cli
|
||||||
|
function checkOpenApiGenerator() {
|
||||||
|
try {
|
||||||
|
execSync('openapi-generator-cli version', { stdio: 'ignore' });
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instalar openapi-generator-cli
|
||||||
|
function installOpenApiGenerator() {
|
||||||
|
logStep('Instalando @openapitools/openapi-generator-cli...');
|
||||||
|
try {
|
||||||
|
execSync('npm install -g @openapitools/openapi-generator-cli', { stdio: 'inherit' });
|
||||||
|
logSuccess('OpenAPI Generator CLI instalado correctamente');
|
||||||
|
} catch (error) {
|
||||||
|
logError('Error al instalar OpenAPI Generator CLI');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear estructura de directorios
|
||||||
|
function createDirectoryStructure(baseDir) {
|
||||||
|
const dirs = [
|
||||||
|
path.join(baseDir, 'data/dtos'),
|
||||||
|
path.join(baseDir, 'data/repositories'),
|
||||||
|
path.join(baseDir, 'data/mappers'),
|
||||||
|
path.join(baseDir, 'domain/repositories'),
|
||||||
|
path.join(baseDir, 'domain/use-cases'),
|
||||||
|
path.join(baseDir, 'di/repositories'),
|
||||||
|
path.join(baseDir, 'di/use-cases'),
|
||||||
|
path.join(baseDir, 'entities/models')
|
||||||
|
];
|
||||||
|
|
||||||
|
dirs.forEach(dir => {
|
||||||
|
fs.ensureDirSync(dir);
|
||||||
|
});
|
||||||
|
|
||||||
|
logSuccess('Estructura de directorios creada');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analizar el swagger para extraer tags y dominios
|
||||||
|
function analyzeSwagger(swaggerFile) {
|
||||||
|
logStep('Analizando archivo OpenAPI...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileContent = fs.readFileSync(swaggerFile, 'utf8');
|
||||||
|
const swagger = yaml.load(fileContent);
|
||||||
|
|
||||||
|
const tags = swagger.tags || [];
|
||||||
|
const paths = swagger.paths || {};
|
||||||
|
|
||||||
|
logInfo(`Encontrados ${tags.length} tags en el API`);
|
||||||
|
logInfo(`Encontrados ${Object.keys(paths).length} endpoints`);
|
||||||
|
|
||||||
|
tags.forEach(tag => {
|
||||||
|
logInfo(` - ${tag.name}: ${tag.description || 'Sin descripción'}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return { tags, paths, swagger };
|
||||||
|
} catch (error) {
|
||||||
|
logError(`Error al leer el archivo Swagger: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generar código con OpenAPI Generator
|
||||||
|
function generateCode(swaggerFile, templatesDir) {
|
||||||
|
logStep('Generando código desde OpenAPI...');
|
||||||
|
|
||||||
|
const tempDir = path.join(process.cwd(), '.temp-generated');
|
||||||
|
|
||||||
|
// Limpiar directorio temporal
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
fs.removeSync(tempDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const command = `openapi-generator-cli generate \
|
||||||
|
-i "${swaggerFile}" \
|
||||||
|
-g typescript-angular \
|
||||||
|
-t "${templatesDir}" \
|
||||||
|
-o "${tempDir}" \
|
||||||
|
--additional-properties=ngVersion=17.0.0,withInterfaces=true,providedInRoot=false,supportsES6=true,modelPropertyNaming=camelCase`;
|
||||||
|
|
||||||
|
execSync(command, { stdio: 'inherit' });
|
||||||
|
logSuccess('Código generado correctamente');
|
||||||
|
|
||||||
|
return tempDir;
|
||||||
|
} catch (error) {
|
||||||
|
logError('Error al generar código');
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
fs.removeSync(tempDir);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organizar archivos según Clean Architecture
|
||||||
|
function organizeFiles(tempDir, outputDir) {
|
||||||
|
logStep('Organizando archivos en estructura Clean Architecture...');
|
||||||
|
|
||||||
|
const moves = [
|
||||||
|
{ from: 'model', to: path.join(outputDir, 'data/dtos'), pattern: '*.dto.ts' },
|
||||||
|
{ from: 'model', to: path.join(outputDir, 'entities/models'), pattern: '*.model.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'domain/repositories'), pattern: '*.repository.contract.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'data/repositories'), pattern: '*.repository.impl.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'data/repositories'), pattern: '*.repository.mock.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'data/mappers'), pattern: '*.mapper.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'domain/use-cases'), pattern: '*.use-cases.contract.ts' },
|
||||||
|
{ from: 'api', to: path.join(outputDir, 'domain/use-cases'), pattern: '*.use-cases.impl.ts' },
|
||||||
|
{ from: 'providers', to: path.join(outputDir, 'di/repositories'), pattern: '*.repository.provider.ts' },
|
||||||
|
{ from: 'providers', to: path.join(outputDir, 'di/use-cases'), pattern: '*.use-cases.provider.ts' }
|
||||||
|
];
|
||||||
|
|
||||||
|
let filesMoved = 0;
|
||||||
|
|
||||||
|
moves.forEach(({ from, to, pattern }) => {
|
||||||
|
const sourceDir = path.join(tempDir, from);
|
||||||
|
|
||||||
|
if (fs.existsSync(sourceDir)) {
|
||||||
|
fs.ensureDirSync(to);
|
||||||
|
|
||||||
|
const files = fs.readdirSync(sourceDir).filter(file => {
|
||||||
|
if (pattern.includes('*')) {
|
||||||
|
const regex = new RegExp(pattern.replace('*', '.*'));
|
||||||
|
return regex.test(file);
|
||||||
|
}
|
||||||
|
return file.endsWith(pattern);
|
||||||
|
});
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const sourcePath = path.join(sourceDir, file);
|
||||||
|
const destPath = path.join(to, file);
|
||||||
|
|
||||||
|
fs.copySync(sourcePath, destPath);
|
||||||
|
filesMoved++;
|
||||||
|
logInfo(` ${file} → ${path.relative(process.cwd(), destPath)}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
logSuccess(`${filesMoved} archivos organizados correctamente`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limpiar directorio temporal
|
||||||
|
function cleanup(tempDir) {
|
||||||
|
if (fs.existsSync(tempDir)) {
|
||||||
|
fs.removeSync(tempDir);
|
||||||
|
logInfo('Archivos temporales eliminados');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generar reporte
|
||||||
|
function generateReport(outputDir, analysis) {
|
||||||
|
logStep('Generando reporte de generación...');
|
||||||
|
|
||||||
|
const report = {
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
tags: analysis.tags.length,
|
||||||
|
endpoints: Object.keys(analysis.paths).length,
|
||||||
|
outputDirectory: outputDir,
|
||||||
|
structure: {
|
||||||
|
dtos: fs.readdirSync(path.join(outputDir, 'data/dtos')).length,
|
||||||
|
repositories: fs.readdirSync(path.join(outputDir, 'data/repositories')).length,
|
||||||
|
mappers: fs.readdirSync(path.join(outputDir, 'data/mappers')).length,
|
||||||
|
useCases: fs.readdirSync(path.join(outputDir, 'domain/use-cases')).length
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const reportPath = path.join(process.cwd(), 'generation-report.json');
|
||||||
|
fs.writeJsonSync(reportPath, report, { spaces: 2 });
|
||||||
|
|
||||||
|
logSuccess(`Reporte guardado en: ${reportPath}`);
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función principal
|
||||||
|
async function main() {
|
||||||
|
console.log('\n' + '='.repeat(60));
|
||||||
|
log(' OpenAPI Clean Architecture Generator', 'bright');
|
||||||
|
log(' Angular + Clean Architecture Code Generator', 'cyan');
|
||||||
|
console.log('='.repeat(60) + '\n');
|
||||||
|
|
||||||
|
// Validar archivo de entrada
|
||||||
|
if (!fs.existsSync(options.input)) {
|
||||||
|
logError(`Archivo no encontrado: ${options.input}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
logInfo(`Archivo de entrada: ${options.input}`);
|
||||||
|
logInfo(`Directorio de salida: ${options.output}`);
|
||||||
|
logInfo(`Templates: ${options.templates}`);
|
||||||
|
|
||||||
|
if (options.dryRun) {
|
||||||
|
logWarning('Modo DRY RUN - No se generarán archivos');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar/Instalar OpenAPI Generator
|
||||||
|
if (!checkOpenApiGenerator()) {
|
||||||
|
logWarning('OpenAPI Generator CLI no encontrado');
|
||||||
|
if (!options.skipInstall) {
|
||||||
|
installOpenApiGenerator();
|
||||||
|
} else {
|
||||||
|
logError('Instala openapi-generator-cli con: npm install -g @openapitools/openapi-generator-cli');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logSuccess('OpenAPI Generator CLI encontrado');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analizar Swagger
|
||||||
|
const analysis = analyzeSwagger(options.input);
|
||||||
|
|
||||||
|
if (options.dryRun) {
|
||||||
|
logInfo('Finalizando en modo DRY RUN');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear estructura de directorios
|
||||||
|
createDirectoryStructure(options.output);
|
||||||
|
|
||||||
|
// Generar código
|
||||||
|
const tempDir = generateCode(options.input, options.templates);
|
||||||
|
|
||||||
|
// Organizar archivos
|
||||||
|
organizeFiles(tempDir, options.output);
|
||||||
|
|
||||||
|
// Limpiar
|
||||||
|
cleanup(tempDir);
|
||||||
|
|
||||||
|
// Generar reporte
|
||||||
|
const report = generateReport(options.output, analysis);
|
||||||
|
|
||||||
|
// Resumen final
|
||||||
|
console.log('\n' + '='.repeat(60));
|
||||||
|
log(' ✨ Generación completada con éxito', 'green');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log(`\n📊 Resumen:`);
|
||||||
|
console.log(` - DTOs generados: ${report.structure.dtos}`);
|
||||||
|
console.log(` - Repositories: ${report.structure.repositories}`);
|
||||||
|
console.log(` - Mappers: ${report.structure.mappers}`);
|
||||||
|
console.log(` - Use Cases: ${report.structure.useCases}`);
|
||||||
|
console.log(`\n📁 Archivos generados en: ${colors.cyan}${options.output}${colors.reset}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ejecutar
|
||||||
|
main().catch(error => {
|
||||||
|
logError(`Error fatal: ${error.message}`);
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
23
openapitools.json
Normal file
23
openapitools.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||||
|
"spaces": 2,
|
||||||
|
"generator-cli": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"generators": {
|
||||||
|
"typescript-angular-clean": {
|
||||||
|
"generatorName": "typescript-angular",
|
||||||
|
"output": "./.temp-generated",
|
||||||
|
"glob": "**/*",
|
||||||
|
"additionalProperties": {
|
||||||
|
"ngVersion": "17.0.0",
|
||||||
|
"modelPropertyNaming": "camelCase",
|
||||||
|
"supportsES6": true,
|
||||||
|
"withInterfaces": true,
|
||||||
|
"providedInRoot": false,
|
||||||
|
"npmName": "api-client",
|
||||||
|
"npmVersion": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
package.json
Normal file
31
package.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "openapi-clean-arch-generator",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Generador de código Angular con Clean Architecture desde OpenAPI/Swagger",
|
||||||
|
"main": "generate.js",
|
||||||
|
"bin": {
|
||||||
|
"generate-clean-arch": "./generate.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"generate": "node generate.js",
|
||||||
|
"setup": "npm install -g @openapitools/openapi-generator-cli"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"openapi",
|
||||||
|
"swagger",
|
||||||
|
"angular",
|
||||||
|
"clean-architecture",
|
||||||
|
"code-generator"
|
||||||
|
],
|
||||||
|
"author": "Blas",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"commander": "^11.1.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
|
"js-yaml": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
34
templates/api.repository.contract.mustache
Normal file
34
templates/api.repository.contract.mustache
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
{{#imports}}
|
||||||
|
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Repository Contract
|
||||||
|
* Generated from OpenAPI tag: {{classname}}
|
||||||
|
*/
|
||||||
|
export interface {{classname}}Repository {
|
||||||
|
{{#operation}}
|
||||||
|
/**
|
||||||
|
* {{summary}}
|
||||||
|
{{#notes}}
|
||||||
|
* {{notes}}
|
||||||
|
{{/notes}}
|
||||||
|
{{#allParams}}
|
||||||
|
* @param {{paramName}} {{description}}
|
||||||
|
{{/allParams}}
|
||||||
|
*/
|
||||||
|
{{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{dataType}}{{^-last}}, {{/-last}}{{/allParams}}): Observable<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}>;
|
||||||
|
|
||||||
|
{{/operation}}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {{constantName}}_REPOSITORY = new InjectionToken<{{classname}}Repository>('{{constantName}}_REPOSITORY');
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
61
templates/api.repository.impl.mustache
Normal file
61
templates/api.repository.impl.mustache
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { environment } from '@environment';
|
||||||
|
|
||||||
|
import { MRepository } from '@mercadona/core/utils/repository';
|
||||||
|
|
||||||
|
import { {{classname}}Repository } from '../../../domain/repositories/{{classFilename}}.repository.contract';
|
||||||
|
{{#imports}}
|
||||||
|
import { {{classname}}Dto } from '@/dtos/{{classFilename}}/{{classFilename}}.dto';
|
||||||
|
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||||
|
import { {{classVarName}}Mapper } from '@/mappers/{{classFilename}}/{{classFilename}}.mapper';
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Repository Implementation
|
||||||
|
* Generated from OpenAPI tag: {{classname}}
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class {{classname}}RepositoryImpl extends MRepository implements {{classname}}Repository {
|
||||||
|
constructor() {
|
||||||
|
super(`${environment.modapApi.url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
{{#operation}}
|
||||||
|
{{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{dataType}}{{^-last}}, {{/-last}}{{/allParams}}): Observable<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}> {
|
||||||
|
{{#isListContainer}}
|
||||||
|
return this.{{httpMethod}}<{{returnBaseType}}Dto>('{{path}}'{{#hasQueryParams}}, {
|
||||||
|
params: { {{#queryParams}}{{paramName}}{{^-last}}, {{/-last}}{{/queryParams}} }
|
||||||
|
}{{/hasQueryParams}}{{#hasBodyParam}}, {{bodyParam}}{{/hasBodyParam}})
|
||||||
|
.pipe(
|
||||||
|
map((response) => response.{{#vendorExtensions}}{{x-response-property}}{{/vendorExtensions}}{{^vendorExtensions}}items{{/vendorExtensions}}.map({{returnBaseType}}Mapper))
|
||||||
|
);
|
||||||
|
{{/isListContainer}}
|
||||||
|
{{^isListContainer}}
|
||||||
|
{{#returnType}}
|
||||||
|
return this.{{httpMethod}}<{{returnType}}Dto>('{{path}}'{{#hasQueryParams}}, {
|
||||||
|
params: { {{#queryParams}}{{paramName}}{{^-last}}, {{/-last}}{{/queryParams}} }
|
||||||
|
}{{/hasQueryParams}}{{#hasBodyParam}}, {{bodyParam}}{{/hasBodyParam}})
|
||||||
|
.pipe(
|
||||||
|
map({{returnType}}Mapper)
|
||||||
|
);
|
||||||
|
{{/returnType}}
|
||||||
|
{{^returnType}}
|
||||||
|
return this.{{httpMethod}}<void>('{{path}}'{{#hasQueryParams}}, {
|
||||||
|
params: { {{#queryParams}}{{paramName}}{{^-last}}, {{/-last}}{{/queryParams}} }
|
||||||
|
}{{/hasQueryParams}}{{#hasBodyParam}}, {{bodyParam}}{{/hasBodyParam}});
|
||||||
|
{{/returnType}}
|
||||||
|
{{/isListContainer}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operation}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
34
templates/api.use-cases.contract.mustache
Normal file
34
templates/api.use-cases.contract.mustache
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
{{#imports}}
|
||||||
|
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Use Cases Contract
|
||||||
|
* Generated from OpenAPI tag: {{classname}}
|
||||||
|
*/
|
||||||
|
export interface {{classname}}UseCases {
|
||||||
|
{{#operation}}
|
||||||
|
/**
|
||||||
|
* {{summary}}
|
||||||
|
{{#notes}}
|
||||||
|
* {{notes}}
|
||||||
|
{{/notes}}
|
||||||
|
{{#allParams}}
|
||||||
|
* @param {{paramName}} {{description}}
|
||||||
|
{{/allParams}}
|
||||||
|
*/
|
||||||
|
{{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{dataType}}{{^-last}}, {{/-last}}{{/allParams}}): Observable<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}>;
|
||||||
|
|
||||||
|
{{/operation}}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {{constantName}}_USE_CASES = new InjectionToken<{{classname}}UseCases>('{{constantName}}_USE_CASES');
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
32
templates/api.use-cases.impl.mustache
Normal file
32
templates/api.use-cases.impl.mustache
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { {{classname}}UseCases } from './{{classFilename}}.use-cases.contract';
|
||||||
|
|
||||||
|
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
||||||
|
{{#imports}}
|
||||||
|
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Use Cases Implementation
|
||||||
|
* Generated from OpenAPI tag: {{classname}}
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class {{classname}}UseCasesImpl implements {{classname}}UseCases {
|
||||||
|
#{{classVarName}}Repository: {{classname}}Repository = inject({{constantName}}_REPOSITORY);
|
||||||
|
|
||||||
|
{{#operation}}
|
||||||
|
{{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{dataType}}{{^-last}}, {{/-last}}{{/allParams}}): Observable<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}void{{/returnType}}> {
|
||||||
|
return this.#{{classVarName}}Repository.{{nickname}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}});
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operation}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
28
templates/mapper.mustache
Normal file
28
templates/mapper.mustache
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { MapFromFn } from '@mercadona/common/public';
|
||||||
|
import { Builder } from '@mercadona/common/utils';
|
||||||
|
|
||||||
|
import { {{classname}}Dto } from '@/dtos/{{classFilename}}/{{classFilename}}.dto';
|
||||||
|
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Mapper
|
||||||
|
* Converts DTO to Domain Entity
|
||||||
|
* Generated from OpenAPI schema: {{classname}}
|
||||||
|
*/
|
||||||
|
export const {{classVarName}}Mapper: MapFromFn<{{classname}}Dto, {{classname}}> = (dto: {{classname}}Dto): {{classname}} =>
|
||||||
|
Builder.forModel({{classname}})
|
||||||
|
{{#allModels}}
|
||||||
|
{{#model}}
|
||||||
|
{{#vars}}
|
||||||
|
.{{name}}(dto.{{name}})
|
||||||
|
{{/vars}}
|
||||||
|
{{/model}}
|
||||||
|
{{/allModels}}
|
||||||
|
.build();
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
24
templates/model-entity.mustache
Normal file
24
templates/model-entity.mustache
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
{{#imports}}
|
||||||
|
import { {{classname}} } from './{{classFilename}}.model';
|
||||||
|
{{/imports}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Entity
|
||||||
|
* {{#description}}{{description}}{{/description}}
|
||||||
|
* Generated from OpenAPI schema
|
||||||
|
*/
|
||||||
|
export class {{classname}} {
|
||||||
|
{{#vars}}
|
||||||
|
{{#description}}
|
||||||
|
/**
|
||||||
|
* {{description}}
|
||||||
|
*/
|
||||||
|
{{/description}}
|
||||||
|
{{name}}{{^required}}?{{/required}}: {{dataType}};
|
||||||
|
{{/vars}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
20
templates/model.mustache
Normal file
20
templates/model.mustache
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{#models}}
|
||||||
|
{{#model}}
|
||||||
|
/**
|
||||||
|
* {{classname}} DTO
|
||||||
|
* {{#description}}{{description}}{{/description}}
|
||||||
|
* Generated from OpenAPI specification
|
||||||
|
*/
|
||||||
|
export interface {{classname}}Dto {
|
||||||
|
{{#vars}}
|
||||||
|
{{#description}}
|
||||||
|
/**
|
||||||
|
* {{description}}
|
||||||
|
*/
|
||||||
|
{{/description}}
|
||||||
|
{{name}}{{^required}}?{{/required}}: {{dataType}};
|
||||||
|
{{/vars}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{/model}}
|
||||||
|
{{/models}}
|
||||||
20
templates/repository.provider.mustache
Normal file
20
templates/repository.provider.mustache
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { Provider } from '@angular/core';
|
||||||
|
|
||||||
|
import { {{constantName}}_REPOSITORY } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
||||||
|
import { {{classname}}RepositoryImpl } from '@/data/repositories/{{classFilename}}.repository.impl';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Repository Provider
|
||||||
|
* Binds the repository contract with its implementation
|
||||||
|
*/
|
||||||
|
export const {{classname}}RepositoryProvider: Provider = {
|
||||||
|
provide: {{constantName}}_REPOSITORY,
|
||||||
|
useClass: {{classname}}RepositoryImpl
|
||||||
|
};
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
20
templates/use-cases.provider.mustache
Normal file
20
templates/use-cases.provider.mustache
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{#apiInfo}}
|
||||||
|
{{#apis}}
|
||||||
|
{{#operations}}
|
||||||
|
import { Provider } from '@angular/core';
|
||||||
|
|
||||||
|
import { {{constantName}}_USE_CASES } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.contract';
|
||||||
|
import { {{classname}}UseCasesImpl } from '@/domain/use-cases/{{classFilename}}/{{classFilename}}.use-cases.impl';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {{classname}} Use Cases Provider
|
||||||
|
* Binds the use cases contract with its implementation
|
||||||
|
*/
|
||||||
|
export const {{classname}}UseCasesProvider: Provider = {
|
||||||
|
provide: {{constantName}}_USE_CASES,
|
||||||
|
useClass: {{classname}}UseCasesImpl
|
||||||
|
};
|
||||||
|
|
||||||
|
{{/operations}}
|
||||||
|
{{/apis}}
|
||||||
|
{{/apiInfo}}
|
||||||
Reference in New Issue
Block a user