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 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.3.1
1
+ # JERK Framework v2.5.0
2
2
 
3
- ![JERK Framework Logo](jerk.webg)
3
+ ![JERK Framework Logo](jerk.webp)
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: QueryBuilder con API fluida para consultas SQL seguras y eficientes**
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
- - **QueryBuilder con API Fluida**: Interfaz para construir consultas SQL complejas de manera segura y eficiente
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.1.8
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.0",
4
- "description": "JERK Framework v2.3.1 - A comprehensive framework for building secure and scalable APIs with frontend support, sessions, template engine, QueryBuilder, and complete MVC architecture with models",
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",