jerkjs 2.4.0 → 2.5.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/CHANGELOG.md +19 -0
- package/README.md +82 -5
- package/docs/ROUTE_DIRECTORY_LOADER_MANUAL.md +277 -0
- package/example-directory-loader.js +46 -0
- package/index.js +3 -1
- package/lib/loader/routeDirectoryLoader.js +294 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v2.5.0 - 6 de febrero de 2026
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **RouteDirectoryLoader**: Nuevo componente `RouteDirectoryLoader` que permite cargar rutas desde múltiples archivos JSON ubicados en un directorio específico
|
|
7
|
+
- **Detección de rutas duplicadas**: El sistema ahora detecta automáticamente cuando una ruta sobrescribe otra y muestra mensajes de advertencia
|
|
8
|
+
- **Mensajes de log coloreados**: Mensajes en rojo para rutas sobreescritas y en amarillo para rutas que prevalecen
|
|
9
|
+
- **Integración con sistema de hooks**: El nuevo componente dispara eventos en momentos clave del proceso de carga de rutas
|
|
10
|
+
- **Recarga automática de rutas**: Funcionalidad para observar cambios en los archivos de rutas y recargar automáticamente
|
|
11
|
+
- **Manual de uso**: Documentación completa para el nuevo componente RouteDirectoryLoader
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **Actualización de la versión a 2.5.0**: Debido a la implementación significativa del componente RouteDirectoryLoader
|
|
15
|
+
- **Exportaciones del framework actualizadas**: Se ha añadido la nueva exportación de RouteDirectoryLoader en el archivo principal index.js
|
|
16
|
+
|
|
17
|
+
## v2.4.1 - 22 de enero de 2026
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **QueryBuilder ahora como dependencia externa**: El componente QueryBuilder ha sido removido como parte interna del framework y ahora es una dependencia externa llamada `qbuilderjs`. Esto permite una mayor modularidad y mantenimiento independiente del componente.
|
|
21
|
+
|
|
3
22
|
## v2.3.1 - 21 de enero de 2026
|
|
4
23
|
|
|
5
24
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# JERK Framework v2.
|
|
1
|
+
# JERK Framework v2.5.0
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
**¿Nuevo en JERK? Comienza tu proyecto rápidamente con nuestro Starter Kit**
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ Nuestro Starter Kit en `standard/server.js` es la forma más rápida de comenzar
|
|
|
13
13
|
- Middlewares esenciales ya integrados (autenticación, CORS, compresión, firewall, etc.)
|
|
14
14
|
- Sistema de logging y manejo de errores implementado
|
|
15
15
|
- **NUEVO: Arquitectura completa MVC con modelos y soporte para bases de datos**
|
|
16
|
-
- **NUEVO:
|
|
16
|
+
- **NUEVO: Compatible con qbuilderjs para consultas SQL seguras y eficientes**
|
|
17
17
|
|
|
18
18
|
**Cómo comenzar:**
|
|
19
19
|
1. Edita el archivo `routes.json` para definir tus rutas y asociarlas a tus controladores
|
|
@@ -106,6 +106,84 @@ server.addRoute('GET', '/assets', {
|
|
|
106
106
|
});
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
## Carga de Rutas desde Múltiples Archivos (v2.5.0)
|
|
110
|
+
|
|
111
|
+
Desde la versión 2.5.0, JERK Framework incluye el componente `RouteDirectoryLoader` que permite cargar rutas desde múltiples archivos JSON ubicados en un directorio específico. Esta funcionalidad mejora la organización y mantenibilidad de aplicaciones grandes al permitir dividir las rutas en varios archivos en lugar de tener un único archivo `routes.json`.
|
|
112
|
+
|
|
113
|
+
### Ventajas del RouteDirectoryLoader:
|
|
114
|
+
- Organización por funcionalidad (usuarios, autenticación, API, etc.)
|
|
115
|
+
- Mayor mantenibilidad en proyectos grandes
|
|
116
|
+
- Detección automática de rutas duplicadas
|
|
117
|
+
- Mensajes de advertencia coloreados para rutas sobreescritas
|
|
118
|
+
- Recarga automática de rutas en desarrollo
|
|
119
|
+
|
|
120
|
+
### Uso del RouteDirectoryLoader:
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
const { APIServer, RouteDirectoryLoader } = require('jerkjs');
|
|
124
|
+
|
|
125
|
+
const server = new APIServer({ port: 3000 });
|
|
126
|
+
const routeDirectoryLoader = new RouteDirectoryLoader();
|
|
127
|
+
|
|
128
|
+
// Cargar rutas desde un directorio que contiene múltiples archivos JSON
|
|
129
|
+
routeDirectoryLoader.loadRoutesFromDirectory(server, './routes')
|
|
130
|
+
.then(routes => {
|
|
131
|
+
console.log(`${routes.length} rutas cargadas exitosamente`);
|
|
132
|
+
server.start();
|
|
133
|
+
})
|
|
134
|
+
.catch(error => {
|
|
135
|
+
console.error('Error cargando rutas desde directorio:', error.message);
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Estructura de directorio recomendada:
|
|
140
|
+
```
|
|
141
|
+
routes/
|
|
142
|
+
├── api-routes.json
|
|
143
|
+
├── auth-routes.json
|
|
144
|
+
├── static-routes.json
|
|
145
|
+
└── user-routes.json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Ejemplo de archivo api-routes.json:
|
|
149
|
+
```json
|
|
150
|
+
[
|
|
151
|
+
{
|
|
152
|
+
"path": "/api/users",
|
|
153
|
+
"method": "GET",
|
|
154
|
+
"controller": "./controllers/userController.js",
|
|
155
|
+
"handler": "getAllUsers",
|
|
156
|
+
"contentType": "application/json"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"path": "/api/users/:id",
|
|
160
|
+
"method": "GET",
|
|
161
|
+
"controller": "./controllers/userController.js",
|
|
162
|
+
"handler": "getUserById",
|
|
163
|
+
"contentType": "application/json"
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Detección de rutas duplicadas:
|
|
169
|
+
Cuando el sistema detecta que una ruta ya ha sido definida previamente, muestra mensajes de advertencia:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
[RUTA SOBREESCRITA] Archivo: ./routes/api-routes.json, Ruta: GET /users
|
|
173
|
+
[RUTA ACTUAL] Archivo: ./routes/other-routes.json, Ruta: GET /users
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- El mensaje en **rojo** indica la ruta que será sobreescrita
|
|
177
|
+
- El mensaje en **amarillo** indica la ruta que prevalece
|
|
178
|
+
|
|
179
|
+
### Recarga automática de rutas:
|
|
180
|
+
Durante el desarrollo, puedes habilitar la recarga automática cuando se modifican los archivos de rutas:
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
// Observar cambios en el directorio de rutas
|
|
184
|
+
routeDirectoryLoader.watchRoutesDirectory(server, './routes', 1000); // 1000ms debounce
|
|
185
|
+
```
|
|
186
|
+
|
|
109
187
|
Visita nuestra página web: https://jerk.page.gd/
|
|
110
188
|
Repositorio oficial: https://gitlab.com/bytedogssyndicate1/jerk/
|
|
111
189
|
|
|
@@ -126,8 +204,7 @@ Repositorio oficial: https://gitlab.com/bytedogssyndicate1/jerk/
|
|
|
126
204
|
- **Motor de Plantillas MVC**: Sistema profesional de vistas con soporte para filtros, helpers y hooks
|
|
127
205
|
- **Arquitectura de Modelos Completa (MVC)**: Capa de modelos para la lógica de negocio y acceso a datos
|
|
128
206
|
- **Sistema de Adaptadores de Base de Datos**: Soporte para múltiples motores de base de datos (MariaDB, MySQL, etc.)
|
|
129
|
-
- **
|
|
130
|
-
- **Middleware de QueryBuilder**: Sistema para inyectar QueryBuilder en solicitudes HTTP con soporte para hooks
|
|
207
|
+
- **Compatible con qbuilderjs**: Soporte para integrar el QueryBuilder externo qbuilderjs para construir consultas SQL complejas de manera segura y eficiente
|
|
131
208
|
- **Servicio de Archivos Estáticos**: Soporte para servir archivos desde directorios locales con configuración flexible
|
|
132
209
|
- **Extensibilidad**: Sistema de hooks y filters para personalización
|
|
133
210
|
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Manual de Uso de la Extensión RouteDirectoryLoader
|
|
2
|
+
|
|
3
|
+
## Descripción General
|
|
4
|
+
|
|
5
|
+
El componente `RouteDirectoryLoader` es una extensión del framework JerkJS que permite cargar rutas desde múltiples archivos JSON ubicados en un directorio específico. Esta extensión mejora la organización y mantenibilidad de aplicaciones grandes al permitir dividir las rutas en varios archivos en lugar de tener un único archivo `routes.json`.
|
|
6
|
+
|
|
7
|
+
## Características Principales
|
|
8
|
+
|
|
9
|
+
### 1. Carga de Rutas desde Directorio
|
|
10
|
+
- Carga múltiples archivos JSON de rutas desde un directorio
|
|
11
|
+
- Compatible con la estructura estándar de rutas de JerkJS
|
|
12
|
+
- Soporta todas las funcionalidades disponibles en `routes.json`
|
|
13
|
+
|
|
14
|
+
### 2. Detección de Rutas Duplicadas
|
|
15
|
+
- Identifica automáticamente rutas que se sobrescriben
|
|
16
|
+
- Muestra mensajes de advertencia en colores distintivos:
|
|
17
|
+
- **Rojo**: Ruta que será sobreescrita
|
|
18
|
+
- **Amarillo**: Ruta que prevalece
|
|
19
|
+
|
|
20
|
+
### 3. Integración con el Sistema de Hooks
|
|
21
|
+
- Dispara eventos en momentos clave del proceso de carga
|
|
22
|
+
- Permite extender la funcionalidad mediante hooks personalizados
|
|
23
|
+
|
|
24
|
+
### 4. Recarga Automática
|
|
25
|
+
- Opción para observar cambios en los archivos de rutas
|
|
26
|
+
- Recarga automática cuando se detectan modificaciones
|
|
27
|
+
|
|
28
|
+
## Instalación y Configuración
|
|
29
|
+
|
|
30
|
+
### Importación del Componente
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const { APIServer, RouteDirectoryLoader } = require('jerkjs');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Creación de Instancia
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
const routeDirectoryLoader = new RouteDirectoryLoader();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Uso Básico
|
|
43
|
+
|
|
44
|
+
### Cargar Rutas desde un Directorio
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
const server = new APIServer({ port: 3000 });
|
|
48
|
+
const routeDirectoryLoader = new RouteDirectoryLoader();
|
|
49
|
+
|
|
50
|
+
// Directorio que contiene los archivos JSON de rutas
|
|
51
|
+
const routesDirectory = './routes';
|
|
52
|
+
|
|
53
|
+
// Cargar rutas desde el directorio
|
|
54
|
+
routeDirectoryLoader.loadRoutesFromDirectory(server, routesDirectory)
|
|
55
|
+
.then(routes => {
|
|
56
|
+
console.log(`${routes.length} rutas cargadas exitosamente`);
|
|
57
|
+
server.start();
|
|
58
|
+
})
|
|
59
|
+
.catch(error => {
|
|
60
|
+
console.error('Error cargando rutas desde directorio:', error.message);
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Estructura de Directorio de Rutas
|
|
65
|
+
|
|
66
|
+
Organiza tus archivos de rutas en un directorio como este:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
routes/
|
|
70
|
+
├── api-routes.json
|
|
71
|
+
├── auth-routes.json
|
|
72
|
+
├── static-routes.json
|
|
73
|
+
└── user-routes.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Cada archivo contiene rutas en el formato estándar de JerkJS:
|
|
77
|
+
|
|
78
|
+
**api-routes.json:**
|
|
79
|
+
```json
|
|
80
|
+
[
|
|
81
|
+
{
|
|
82
|
+
"path": "/api/users",
|
|
83
|
+
"method": "GET",
|
|
84
|
+
"controller": "./controllers/userController.js",
|
|
85
|
+
"handler": "getAllUsers",
|
|
86
|
+
"contentType": "application/json"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"path": "/api/users/:id",
|
|
90
|
+
"method": "GET",
|
|
91
|
+
"controller": "./controllers/userController.js",
|
|
92
|
+
"handler": "getUserById",
|
|
93
|
+
"contentType": "application/json"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**auth-routes.json:**
|
|
99
|
+
```json
|
|
100
|
+
[
|
|
101
|
+
{
|
|
102
|
+
"path": "/login",
|
|
103
|
+
"method": "GET",
|
|
104
|
+
"controller": "./controllers/authController.js",
|
|
105
|
+
"handler": "showLoginPage",
|
|
106
|
+
"contentType": "text/html"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"path": "/api/login",
|
|
110
|
+
"method": "POST",
|
|
111
|
+
"controller": "./controllers/authController.js",
|
|
112
|
+
"handler": "processLogin",
|
|
113
|
+
"contentType": "application/json"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Detección de Rutas Duplicadas
|
|
119
|
+
|
|
120
|
+
Cuando el sistema detecta que una ruta ya ha sido definida previamente, muestra mensajes de advertencia:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
[RUTA SOBREESCRITA] Archivo: ./routes/api-routes.json, Ruta: GET /users
|
|
124
|
+
[RUTA ACTUAL] Archivo: ./routes/other-routes.json, Ruta: GET /users
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- El mensaje en **rojo** indica la ruta que será sobreescrita
|
|
128
|
+
- El mensaje en **amarillo** indica la ruta que prevalece
|
|
129
|
+
|
|
130
|
+
## Integración con Hooks
|
|
131
|
+
|
|
132
|
+
El componente dispara varios eventos que puedes interceptar:
|
|
133
|
+
|
|
134
|
+
### Hooks Disponibles
|
|
135
|
+
|
|
136
|
+
- `pre_directory_route_load`: Antes de cargar rutas desde un directorio
|
|
137
|
+
- `pre_file_route_load`: Antes de cargar rutas desde un archivo
|
|
138
|
+
- `route_duplicate_detected`: Cuando se detecta una ruta duplicada
|
|
139
|
+
- `route_loaded_from_directory`: Después de cargar una ruta desde un archivo
|
|
140
|
+
- `post_directory_route_load`: Después de cargar todas las rutas del directorio
|
|
141
|
+
- `pre_directory_routes_reload`: Antes de recargar rutas desde directorio
|
|
142
|
+
- `post_directory_routes_reload`: Después de recargar rutas desde directorio
|
|
143
|
+
|
|
144
|
+
### Ejemplo de Uso de Hooks
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
const { hooks } = require('jerkjs');
|
|
148
|
+
|
|
149
|
+
// Registrar un hook para detectar rutas duplicadas
|
|
150
|
+
hooks.addAction('route_duplicate_detected', (data) => {
|
|
151
|
+
console.log('Ruta duplicada detectada:');
|
|
152
|
+
console.log('Ruta sobreescrita:', data.overwrittenRoute);
|
|
153
|
+
console.log('Nueva ruta:', data.newRoute);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Registrar un hook para rutas cargadas
|
|
157
|
+
hooks.addAction('route_loaded_from_directory', (data) => {
|
|
158
|
+
console.log('Ruta cargada:', data.route.path, data.route.method);
|
|
159
|
+
console.log('Desde archivo:', data.sourceFile);
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Recarga Automática de Rutas
|
|
164
|
+
|
|
165
|
+
Para habilitar la recarga automática cuando se modifican los archivos de rutas:
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// Observar cambios en el directorio de rutas
|
|
169
|
+
routeDirectoryLoader.watchRoutesDirectory(server, routesDirectory, 1000); // 1000ms debounce
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Métodos Disponibles
|
|
173
|
+
|
|
174
|
+
### `loadRoutesFromDirectory(server, directoryPath)`
|
|
175
|
+
Carga todas las rutas desde un directorio que contiene archivos JSON.
|
|
176
|
+
|
|
177
|
+
**Parámetros:**
|
|
178
|
+
- `server`: Instancia del servidor APIServer
|
|
179
|
+
- `directoryPath`: Ruta al directorio que contiene los archivos JSON de rutas
|
|
180
|
+
|
|
181
|
+
**Retorna:** Promise<Array> - Array de rutas cargadas
|
|
182
|
+
|
|
183
|
+
### `reloadRoutesFromDirectory(server, directoryPath)`
|
|
184
|
+
Recarga todas las rutas desde un directorio.
|
|
185
|
+
|
|
186
|
+
**Parámetros:**
|
|
187
|
+
- `server`: Instancia del servidor APIServer
|
|
188
|
+
- `directoryPath`: Ruta al directorio que contiene los archivos JSON de rutas
|
|
189
|
+
|
|
190
|
+
**Retorna:** Promise<Array> - Array de rutas recargadas
|
|
191
|
+
|
|
192
|
+
### `getLoadedRoutes()`
|
|
193
|
+
Obtiene las rutas que han sido cargadas.
|
|
194
|
+
|
|
195
|
+
**Retorna:** Array - Array de rutas cargadas
|
|
196
|
+
|
|
197
|
+
### `watchRoutesDirectory(server, directoryPath, debounceTime)`
|
|
198
|
+
Observa cambios en los archivos de rutas del directorio y recarga automáticamente.
|
|
199
|
+
|
|
200
|
+
**Parámetros:**
|
|
201
|
+
- `server`: Instancia del servidor APIServer
|
|
202
|
+
- `directoryPath`: Ruta al directorio que contiene los archivos JSON de rutas
|
|
203
|
+
- `debounceTime`: Tiempo de espera entre recargas en milisegundos (opcional, por defecto 1000)
|
|
204
|
+
|
|
205
|
+
## Ejemplo Completo
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
const { APIServer, RouteDirectoryLoader, hooks } = require('jerkjs');
|
|
209
|
+
|
|
210
|
+
// Crear instancia del servidor
|
|
211
|
+
const server = new APIServer({
|
|
212
|
+
port: 3000,
|
|
213
|
+
host: 'localhost'
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Crear instancia del cargador de rutas desde directorio
|
|
217
|
+
const routeDirectoryLoader = new RouteDirectoryLoader();
|
|
218
|
+
|
|
219
|
+
// Registrar hooks para ver eventos
|
|
220
|
+
hooks.addAction('route_duplicate_detected', (data) => {
|
|
221
|
+
console.log('Evento: Ruta duplicada detectada');
|
|
222
|
+
console.log('Ruta sobreescrita:', data.overwrittenRoute);
|
|
223
|
+
console.log('Nueva ruta:', data.newRoute);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
hooks.addAction('route_loaded_from_directory', (data) => {
|
|
227
|
+
console.log('Evento: Ruta cargada desde directorio');
|
|
228
|
+
console.log('Ruta:', data.route.path, data.route.method);
|
|
229
|
+
console.log('Archivo:', data.sourceFile);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Directorio que contiene los archivos JSON de rutas
|
|
233
|
+
const routesDirectory = './routes';
|
|
234
|
+
|
|
235
|
+
// Cargar rutas desde el directorio
|
|
236
|
+
routeDirectoryLoader.loadRoutesFromDirectory(server, routesDirectory)
|
|
237
|
+
.then(routes => {
|
|
238
|
+
console.log(`${routes.length} rutas cargadas exitosamente desde el directorio`);
|
|
239
|
+
|
|
240
|
+
// Iniciar el servidor
|
|
241
|
+
server.start();
|
|
242
|
+
|
|
243
|
+
// Opcional: Observar cambios en el directorio de rutas
|
|
244
|
+
routeDirectoryLoader.watchRoutesDirectory(server, routesDirectory);
|
|
245
|
+
})
|
|
246
|
+
.catch(error => {
|
|
247
|
+
console.error('Error cargando rutas desde directorio:', error.message);
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Buenas Prácticas
|
|
252
|
+
|
|
253
|
+
1. **Organización por Funcionalidad**: Divide tus rutas en archivos según su funcionalidad (usuarios, autenticación, API, etc.)
|
|
254
|
+
|
|
255
|
+
2. **Evitar Rutas Duplicadas**: Asegúrate de que no haya rutas duplicadas a menos que sea intencional
|
|
256
|
+
|
|
257
|
+
3. **Uso de Hooks**: Utiliza los hooks para registrar eventos y monitorizar la carga de rutas
|
|
258
|
+
|
|
259
|
+
4. **Recarga en Desarrollo**: Usa la funcionalidad de recarga automática durante el desarrollo para mejorar la experiencia de desarrollo
|
|
260
|
+
|
|
261
|
+
5. **Estructura Consistente**: Mantén una estructura consistente en todos tus archivos de rutas
|
|
262
|
+
|
|
263
|
+
## Consideraciones de Seguridad
|
|
264
|
+
|
|
265
|
+
- Asegúrate de que el directorio de rutas esté protegido contra escritura no autorizada
|
|
266
|
+
- Valida que los archivos JSON tengan la estructura correcta antes de cargarlos
|
|
267
|
+
- Considera usar permisos restrictivos en producción para los archivos de configuración
|
|
268
|
+
|
|
269
|
+
## Compatibilidad
|
|
270
|
+
|
|
271
|
+
- Compatible con todas las funcionalidades de `routes.json`
|
|
272
|
+
- Compatible con autenticación por ruta
|
|
273
|
+
- Compatible con content-type por ruta
|
|
274
|
+
- Compatible con rutas estáticas
|
|
275
|
+
- Compatible con el sistema de hooks del framework
|
|
276
|
+
|
|
277
|
+
Esta extensión proporciona una solución robusta y escalable para gestionar rutas en aplicaciones JerkJS de gran tamaño, manteniendo la organización y facilitando la detección de conflictos.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de uso del componente RouteDirectoryLoader
|
|
3
|
+
* Este ejemplo demuestra cómo cargar rutas desde un directorio con múltiples archivos JSON
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { APIServer, RouteDirectoryLoader, hooks } = require('./index.js');
|
|
7
|
+
|
|
8
|
+
// Crear instancia del servidor
|
|
9
|
+
const server = new APIServer({
|
|
10
|
+
port: 3000,
|
|
11
|
+
host: 'localhost'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Crear instancia del cargador de rutas desde directorio
|
|
15
|
+
const routeDirectoryLoader = new RouteDirectoryLoader();
|
|
16
|
+
|
|
17
|
+
// Registrar hooks para ver eventos
|
|
18
|
+
hooks.addAction('route_duplicate_detected', (data) => {
|
|
19
|
+
console.log('Evento: Ruta duplicada detectada');
|
|
20
|
+
console.log('Ruta sobreescrita:', data.overwrittenRoute);
|
|
21
|
+
console.log('Nueva ruta:', data.newRoute);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
hooks.addAction('route_loaded_from_directory', (data) => {
|
|
25
|
+
console.log('Evento: Ruta cargada desde directorio');
|
|
26
|
+
console.log('Ruta:', data.route.path, data.route.method);
|
|
27
|
+
console.log('Archivo:', data.sourceFile);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Directorio que contiene los archivos JSON de rutas
|
|
31
|
+
const routesDirectory = './routes';
|
|
32
|
+
|
|
33
|
+
// Cargar rutas desde el directorio
|
|
34
|
+
routeDirectoryLoader.loadRoutesFromDirectory(server, routesDirectory)
|
|
35
|
+
.then(routes => {
|
|
36
|
+
console.log(`${routes.length} rutas cargadas exitosamente desde el directorio`);
|
|
37
|
+
|
|
38
|
+
// Iniciar el servidor
|
|
39
|
+
server.start();
|
|
40
|
+
})
|
|
41
|
+
.catch(error => {
|
|
42
|
+
console.error('Error cargando rutas desde directorio:', error.message);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Opcional: Observar cambios en el directorio de rutas
|
|
46
|
+
// routeDirectoryLoader.watchRoutesDirectory(server, routesDirectory);
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Punto de entrada del framework JERK
|
|
3
|
-
* JERK Framework 2.
|
|
3
|
+
* JERK Framework 2.5.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Mostrar mensaje de versión al iniciar
|
|
@@ -13,6 +13,7 @@ const HandlerManager = require('./lib/core/handler');
|
|
|
13
13
|
const Authenticator = require('./lib/middleware/authenticator');
|
|
14
14
|
const Validator = require('./lib/middleware/validator');
|
|
15
15
|
const RouteLoader = require('./lib/loader/routeLoader');
|
|
16
|
+
const RouteDirectoryLoader = require('./lib/loader/routeDirectoryLoader');
|
|
16
17
|
const ControllerLoader = require('./lib/loader/controllerLoader');
|
|
17
18
|
const ConfigParser = require('./lib/utils/configParser');
|
|
18
19
|
const { Logger } = require('./lib/utils/logger');
|
|
@@ -61,6 +62,7 @@ module.exports = {
|
|
|
61
62
|
Authenticator,
|
|
62
63
|
Validator,
|
|
63
64
|
RouteLoader,
|
|
65
|
+
RouteDirectoryLoader,
|
|
64
66
|
ControllerLoader,
|
|
65
67
|
ConfigParser,
|
|
66
68
|
Logger,
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Carga de rutas desde múltiples archivos JSON en un directorio para el framework JERK
|
|
3
|
+
* Implementación del componente loader/routeDirectoryLoader.js
|
|
4
|
+
* JERK Framework v2.5.0 - Con detección de rutas duplicadas y mensajes de log coloreados
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const RouteLoader = require('./routeLoader');
|
|
10
|
+
|
|
11
|
+
class RouteDirectoryLoader {
|
|
12
|
+
/**
|
|
13
|
+
* Constructor del cargador de rutas desde directorio
|
|
14
|
+
*/
|
|
15
|
+
constructor() {
|
|
16
|
+
this.loadedRoutes = [];
|
|
17
|
+
this.routeMap = new Map(); // Para detectar rutas duplicadas
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Método para cargar rutas desde un directorio que contiene múltiples archivos JSON
|
|
22
|
+
* @param {Object} server - Instancia del servidor
|
|
23
|
+
* @param {string} directoryPath - Ruta al directorio que contiene los archivos JSON de rutas
|
|
24
|
+
* @returns {Promise<Array>} - Array de rutas cargadas
|
|
25
|
+
*/
|
|
26
|
+
async loadRoutesFromDirectory(server, directoryPath) {
|
|
27
|
+
try {
|
|
28
|
+
// Disparar hook antes de cargar rutas desde directorio
|
|
29
|
+
const hooks = require('../../index.js').hooks;
|
|
30
|
+
if (hooks) {
|
|
31
|
+
const hookResult = hooks.applyFilters('pre_directory_route_load', {
|
|
32
|
+
directoryPath,
|
|
33
|
+
server,
|
|
34
|
+
shouldContinue: true
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!hookResult.shouldContinue) {
|
|
38
|
+
return []; // Cancelar proceso si el filtro lo indica
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
directoryPath = hookResult.directoryPath || directoryPath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Verificar si el directorio existe
|
|
45
|
+
if (!fs.existsSync(directoryPath)) {
|
|
46
|
+
throw new Error(`Directorio de rutas no encontrado: ${directoryPath}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Obtener todos los archivos JSON del directorio
|
|
50
|
+
const files = fs.readdirSync(directoryPath).filter(file =>
|
|
51
|
+
path.extname(file).toLowerCase() === '.json'
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (files.length === 0) {
|
|
55
|
+
console.log(`No se encontraron archivos JSON en el directorio: ${directoryPath}`);
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Cargar cada archivo JSON
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const filePath = path.join(directoryPath, file);
|
|
62
|
+
await this.loadRoutesFromFile(server, filePath);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Disparar hook después de cargar rutas desde directorio
|
|
66
|
+
if (hooks) {
|
|
67
|
+
hooks.doAction('post_directory_route_load', this.loadedRoutes, server);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return this.loadedRoutes;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error(`Error cargando rutas desde directorio ${directoryPath}: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Método para cargar rutas desde un archivo JSON individual
|
|
78
|
+
* @param {Object} server - Instancia del servidor
|
|
79
|
+
* @param {string} filePath - Ruta al archivo JSON de rutas
|
|
80
|
+
*/
|
|
81
|
+
async loadRoutesFromFile(server, filePath) {
|
|
82
|
+
try {
|
|
83
|
+
// Disparar hook antes de cargar archivo
|
|
84
|
+
const hooks = require('../../index.js').hooks;
|
|
85
|
+
if (hooks) {
|
|
86
|
+
const hookResult = hooks.applyFilters('pre_file_route_load', {
|
|
87
|
+
filePath,
|
|
88
|
+
server,
|
|
89
|
+
shouldContinue: true
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!hookResult.shouldContinue) {
|
|
93
|
+
return; // Cancelar proceso si el filtro lo indica
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
filePath = hookResult.filePath || filePath;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Verificar si el archivo existe
|
|
100
|
+
if (!fs.existsSync(filePath)) {
|
|
101
|
+
throw new Error(`Archivo de rutas no encontrado: ${filePath}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Leer y parsear el archivo JSON
|
|
105
|
+
const routeData = fs.readFileSync(filePath, 'utf8');
|
|
106
|
+
const routes = JSON.parse(routeData);
|
|
107
|
+
|
|
108
|
+
// Validar estructura del archivo de rutas
|
|
109
|
+
this.validateRoutesStructure(routes);
|
|
110
|
+
|
|
111
|
+
// Cargar cada ruta, verificando duplicados
|
|
112
|
+
for (const route of routes) {
|
|
113
|
+
await this.loadSingleRoute(server, route, filePath);
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new Error(`Error cargando rutas desde ${filePath}: ${error.message}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Método para validar la estructura del archivo de rutas
|
|
122
|
+
* @param {Array} routes - Array de rutas a validar
|
|
123
|
+
*/
|
|
124
|
+
validateRoutesStructure(routes) {
|
|
125
|
+
if (!Array.isArray(routes)) {
|
|
126
|
+
throw new Error('El archivo de rutas debe contener un array de rutas');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < routes.length; i++) {
|
|
130
|
+
const route = routes[i];
|
|
131
|
+
|
|
132
|
+
if (typeof route !== 'object' || route === null) {
|
|
133
|
+
throw new Error(`La ruta en la posición ${i} no es un objeto válido`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!route.path) {
|
|
137
|
+
throw new Error(`La ruta en la posición ${i} no tiene propiedad 'path'`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!route.method) {
|
|
141
|
+
throw new Error(`La ruta en la posición ${i} no tiene propiedad 'method'`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Verificar si es una ruta estática
|
|
145
|
+
if (route.static) {
|
|
146
|
+
if (typeof route.static !== 'object' || route.static === null) {
|
|
147
|
+
throw new Error(`La ruta en la posición ${i} tiene una propiedad 'static' inválida`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!route.static.dir) {
|
|
151
|
+
throw new Error(`La ruta en la posición ${i} tiene una configuración 'static' sin directorio 'dir'`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// El método debe ser GET para rutas estáticas
|
|
155
|
+
if (route.method.toUpperCase() !== 'GET') {
|
|
156
|
+
throw new Error(`Las rutas estáticas deben usar el método GET, no ${route.method}`);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
// Validación normal para rutas dinámicas
|
|
160
|
+
if (!route.controller) {
|
|
161
|
+
throw new Error(`La ruta en la posición ${i} no tiene propiedad 'controller'`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!route.handler) {
|
|
165
|
+
throw new Error(`La ruta en la posición ${i} no tiene propiedad 'handler'`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validar que el content-type sea un string si está presente
|
|
170
|
+
if (route.contentType && typeof route.contentType !== 'string') {
|
|
171
|
+
throw new Error(`La ruta en la posición ${i} tiene un 'contentType' inválido, debe ser un string`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Método para cargar una sola ruta, verificando si ya existe
|
|
178
|
+
* @param {Object} server - Instancia del servidor
|
|
179
|
+
* @param {Object} route - Objeto de ruta a cargar
|
|
180
|
+
* @param {string} sourceFile - Archivo del que proviene la ruta
|
|
181
|
+
*/
|
|
182
|
+
async loadSingleRoute(server, route, sourceFile) {
|
|
183
|
+
// Crear un identificador único para la ruta (método + path)
|
|
184
|
+
const routeKey = `${route.method.toUpperCase()}-${route.path}`;
|
|
185
|
+
|
|
186
|
+
// Verificar si ya existe una ruta con el mismo método y path
|
|
187
|
+
if (this.routeMap.has(routeKey)) {
|
|
188
|
+
const existingRouteInfo = this.routeMap.get(routeKey);
|
|
189
|
+
|
|
190
|
+
// Disparar hook antes de sobrescribir ruta
|
|
191
|
+
const hooks = require('../../index.js').hooks;
|
|
192
|
+
if (hooks) {
|
|
193
|
+
hooks.doAction('route_duplicate_detected', {
|
|
194
|
+
overwrittenRoute: existingRouteInfo,
|
|
195
|
+
newRoute: { route, sourceFile },
|
|
196
|
+
server
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Mostrar mensaje de advertencia con colores
|
|
201
|
+
console.log('\x1b[31m%s\x1b[0m', `[RUTA SOBREESCRITA] Archivo: ${existingRouteInfo.sourceFile}, Ruta: ${route.method.toUpperCase()} ${route.path}`);
|
|
202
|
+
console.log('\x1b[33m%s\x1b[0m', `[RUTA ACTUAL] Archivo: ${sourceFile}, Ruta: ${route.method.toUpperCase()} ${route.path}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Agregar la ruta al mapa con su archivo de origen
|
|
206
|
+
this.routeMap.set(routeKey, {
|
|
207
|
+
route: { ...route },
|
|
208
|
+
sourceFile
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Cargar la ruta en el servidor
|
|
212
|
+
const routeLoader = new RouteLoader();
|
|
213
|
+
await routeLoader.loadSingleRoute(server, route);
|
|
214
|
+
|
|
215
|
+
// Disparar hook después de cargar la ruta
|
|
216
|
+
const hooks = require('../../index.js').hooks;
|
|
217
|
+
if (hooks) {
|
|
218
|
+
hooks.doAction('route_loaded_from_directory', { route, sourceFile, server });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Agregar la ruta a las rutas cargadas
|
|
222
|
+
this.loadedRoutes.push({
|
|
223
|
+
...route,
|
|
224
|
+
sourceFile
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Método para recargar rutas desde un directorio
|
|
230
|
+
* @param {Object} server - Instancia del servidor
|
|
231
|
+
* @param {string} directoryPath - Ruta al directorio que contiene los archivos JSON de rutas
|
|
232
|
+
* @returns {Promise<Array>} - Array de rutas recargadas
|
|
233
|
+
*/
|
|
234
|
+
async reloadRoutesFromDirectory(server, directoryPath) {
|
|
235
|
+
// Limpiar rutas previamente cargadas
|
|
236
|
+
this.loadedRoutes = [];
|
|
237
|
+
this.routeMap.clear();
|
|
238
|
+
|
|
239
|
+
// Cargar rutas nuevamente
|
|
240
|
+
return await this.loadRoutesFromDirectory(server, directoryPath);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Método para obtener las rutas cargadas
|
|
245
|
+
* @returns {Array} - Array de rutas cargadas
|
|
246
|
+
*/
|
|
247
|
+
getLoadedRoutes() {
|
|
248
|
+
return this.loadedRoutes;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Método para observar cambios en los archivos de rutas del directorio y recargar automáticamente
|
|
253
|
+
* @param {Object} server - Instancia del servidor
|
|
254
|
+
* @param {string} directoryPath - Ruta al directorio que contiene los archivos JSON de rutas
|
|
255
|
+
* @param {number} debounceTime - Tiempo de espera entre recargas (milisegundos)
|
|
256
|
+
*/
|
|
257
|
+
watchRoutesDirectory(server, directoryPath, debounceTime = 1000) {
|
|
258
|
+
if (!fs.existsSync(directoryPath)) {
|
|
259
|
+
throw new Error(`Directorio de rutas no encontrado: ${directoryPath}`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let timeoutId;
|
|
263
|
+
|
|
264
|
+
// Observar cambios en el directorio
|
|
265
|
+
fs.watch(directoryPath, (eventType, filename) => {
|
|
266
|
+
if (filename && path.extname(filename).toLowerCase() === '.json') {
|
|
267
|
+
clearTimeout(timeoutId);
|
|
268
|
+
timeoutId = setTimeout(async () => {
|
|
269
|
+
try {
|
|
270
|
+
console.log(`Recargando rutas desde directorio: ${directoryPath}`);
|
|
271
|
+
|
|
272
|
+
// Disparar hook antes de recargar
|
|
273
|
+
const hooks = require('../../index.js').hooks;
|
|
274
|
+
if (hooks) {
|
|
275
|
+
hooks.doAction('pre_directory_routes_reload', directoryPath, server);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
await this.reloadRoutesFromDirectory(server, directoryPath);
|
|
279
|
+
console.log('Rutas recargadas exitosamente');
|
|
280
|
+
|
|
281
|
+
// Disparar hook después de recargar
|
|
282
|
+
if (hooks) {
|
|
283
|
+
hooks.doAction('post_directory_routes_reload', this.loadedRoutes, server);
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error('Error recargando rutas:', error.message);
|
|
287
|
+
}
|
|
288
|
+
}, debounceTime);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
module.exports = RouteDirectoryLoader;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jerkjs",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "JERK Framework v2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
|
+
"description": "JERK Framework v2.5.0 - A comprehensive framework for building secure and scalable APIs with frontend support, sessions, template engine, integration with qbuilderjs, complete MVC architecture with models, and enhanced route loading from directory",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|