utn-cli 2.0.58 → 2.0.59

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.
@@ -249,6 +249,7 @@ export async function addServiceBackend(nombreServicio = null, opciones = { cerr
249
249
  function generarCRUDBackend(servicioPath, rutaPath, nombreServicio, tableInfo) {
250
250
  const { dbName, tableName, columns, primaryKey } = tableInfo;
251
251
  const dbNameSinDB = dbName.endsWith('-db') ? dbName.slice(0, -3) : dbName;
252
+ const tituloServicio = tableInfo.serviceTitle || nombreServicio;
252
253
 
253
254
  // 1. Generar funciones en el Servicio
254
255
  let contenidoServicio = fs.readFileSync(servicioPath, 'utf-8');
@@ -303,7 +304,7 @@ Router.get('/listar', async (solicitud, respuesta, next) => {
303
304
  try {
304
305
  return respuesta.json({ body: await ${nombreServicio}.listar(), error: undefined });
305
306
  } catch (error) {
306
- const MensajeDeError = 'No fue posible listar los registros';
307
+ const MensajeDeError = 'No fue posible listar los registros de ${tituloServicio}';
307
308
  console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, \`Dirección IP: \${solicitud.ip}\`));
308
309
  return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
309
310
  }
@@ -322,7 +323,7 @@ Router.post('/agregar', async (solicitud, respuesta, next) => {
322
323
  Datos.LastUser = await Miscelaneo.generarLastUser(solicitud);
323
324
  return respuesta.json({ body: await ${nombreServicio}.agregar(Datos), error: undefined });
324
325
  } catch (error) {
325
- const MensajeDeError = 'No fue posible agregar el registro';
326
+ const MensajeDeError = 'No fue posible agregar el registro de ${tituloServicio}';
326
327
  console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, \`Dirección IP: \${solicitud.ip}\`));
327
328
  return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
328
329
  }
@@ -341,7 +342,7 @@ Router.post('/actualizar', async (solicitud, respuesta, next) => {
341
342
  Datos.LastUser = await Miscelaneo.generarLastUser(solicitud);
342
343
  return respuesta.json({ body: await ${nombreServicio}.actualizar(Datos), error: undefined });
343
344
  } catch (error) {
344
- const MensajeDeError = 'No fue posible actualizar el registro';
345
+ const MensajeDeError = 'No fue posible actualizar el registro de ${tituloServicio}';
345
346
  console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, \`Dirección IP: \${solicitud.ip}\`));
346
347
  return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
347
348
  }
@@ -358,7 +359,7 @@ Router.post('/borrar', async (solicitud, respuesta, next) => {
358
359
  try {
359
360
  return respuesta.json({ body: await ${nombreServicio}.borrar(solicitud.body), error: undefined });
360
361
  } catch (error) {
361
- const MensajeDeError = 'No fue posible borrar el registro';
362
+ const MensajeDeError = 'No fue posible borrar el registro de ${tituloServicio}';
362
363
  console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, \`Dirección IP: \${solicitud.ip}\`));
363
364
  return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
364
365
  }
@@ -377,7 +378,7 @@ Router.get('/reporte', async (solicitud, respuesta, next) => {
377
378
  respuesta.attachment('Datos.csv');
378
379
  return respuesta.send(encodeURI(await ${nombreServicio}.reporte()));
379
380
  } catch (error) {
380
- const MensajeDeError = 'No fue posible generar el reporte';
381
+ const MensajeDeError = 'No fue posible generar el reporte de ${tituloServicio}';
381
382
  console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, \`Dirección IP: \${solicitud.ip}\`));
382
383
  return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
383
384
  }
@@ -86,6 +86,8 @@ export async function cloneFrontendComponent(nombreComponente = null, tituloCard
86
86
  const nombreCapitalizado = nombre.charAt(0).toUpperCase() + nombre.slice(1);
87
87
  const nombreClase = `GestionTabla${nombreCapitalizado}Component`;
88
88
  const nombreRuta = `gestion-tabla-${nombreLower}`;
89
+ const nombreModal = `Guardar${nombreCapitalizado}Component`;
90
+ const nombreCarpetaModal = `guardar-${nombreLower}`;
89
91
 
90
92
  const rutaFuente = path.join(__dirname, '../templates/frontend', 'src', 'app', 'Paginas', 'gestion-tabla-XYZ');
91
93
  const rutaDestino = path.join(process.cwd(), 'src', 'app', 'Paginas', nombreRuta);
@@ -102,103 +104,96 @@ export async function cloneFrontendComponent(nombreComponente = null, tituloCard
102
104
  process.exit(1);
103
105
  }
104
106
 
105
- console.log(`Clonando carpeta...`);
106
-
107
- function copiarYReemplazar(fuente, destino) {
108
- if (!fs.existsSync(destino)) {
109
- fs.mkdirSync(destino, { recursive: true });
107
+ console.log(`Clonando carpeta de gestión...`);
108
+ copiarYReemplazar(rutaFuente, rutaDestino, nombreLower, nombreClase, tableInfo, nombreModal, nombreCarpetaModal);
109
+
110
+ // Clonar el modal si tenemos tableInfo
111
+ if (tableInfo) {
112
+ const rutaFuenteModal = path.join(__dirname, '../templates/frontend', 'src', 'app', 'Componentes', 'guardar-incapacidad');
113
+ const rutaDestinoModal = path.join(process.cwd(), 'src', 'app', 'Componentes', nombreCarpetaModal);
114
+
115
+ if (fs.existsSync(rutaFuenteModal)) {
116
+ console.log(`Clonando carpeta del modal...`);
117
+ copiarYReemplazarModal(rutaFuenteModal, rutaDestinoModal, nombreLower, nombreModal, tableInfo);
110
118
  }
111
- const entradas = fs.readdirSync(fuente, { withFileTypes: true });
112
- entradas.forEach((entrada) => {
113
- const nombreOriginal = entrada.name;
114
- const nombreNuevo = nombreOriginal.replace(/XYZ/g, nombreLower);
115
- const rutaFuente = path.join(fuente, nombreOriginal);
116
- const rutaDestino = path.join(destino, nombreNuevo);
117
-
118
- if (entrada.isDirectory()) {
119
- copiarYReemplazar(rutaFuente, rutaDestino);
120
- } else if (entrada.isFile()) {
121
- let contenido = fs.readFileSync(rutaFuente, 'utf-8');
122
-
123
- // Reemplazos base
124
- contenido = contenido.replace(/GestionTablaXYZComponent/g, nombreClase);
125
- contenido = contenido.replace(/XYZ/g, nombreLower);
126
-
127
- // Si tenemos información de la tabla, personalizamos el componente
128
- if (tableInfo && entrada.name.endsWith('.ts')) {
129
- contenido = personalizarComponenteFrontend(contenido, tableInfo, nombreLower);
130
- }
131
-
132
- fs.writeFileSync(rutaDestino, contenido);
133
- }
134
- });
135
119
  }
136
120
 
137
- copiarYReemplazar(rutaFuente, rutaDestino);
138
121
  console.log(`Componente creado en: ${rutaDestino}`);
139
122
 
140
123
  // --- Modificar app.routes.ts ---
141
- console.log('Actualizando app.routes.ts...');
142
- const rutaRoutes = path.join(process.cwd(), 'src', 'app', 'app.routes.ts');
143
- if (fs.existsSync(rutaRoutes)) {
144
- let contenidoRoutes = fs.readFileSync(rutaRoutes, 'utf-8');
145
-
146
- const lineaImport = `import { ${nombreClase} } from './Paginas/${nombreRuta}/${nombreRuta}.component';`;
147
- const ultimoImportIndex = contenidoRoutes.lastIndexOf('import {');
148
- const finUltimoImport = contenidoRoutes.indexOf(';', ultimoImportIndex);
149
-
150
- if (finUltimoImport !== -1) {
151
- contenidoRoutes = contenidoRoutes.slice(0, finUltimoImport + 1) + '\n' + lineaImport + contenidoRoutes.slice(finUltimoImport + 1);
152
- } else {
153
- contenidoRoutes = lineaImport + '\n' + contenidoRoutes;
154
- }
124
+ // ... (rest of the code for routes and html update remains similar, but using nombreClase and nombreRuta)
125
+ actualizarArchivosConfiguracion(nombreClase, nombreRuta, titulo, descripcion);
155
126
 
156
- const cierreArray = contenidoRoutes.lastIndexOf('];');
157
- if (cierreArray !== -1) {
158
- const nuevaRuta = ` { path: '${nombreRuta}', component: ${nombreClase} },`;
159
- const textoAntesDeCierre = contenidoRoutes.slice(0, cierreArray).trimEnd();
160
- const necesitaComa = !textoAntesDeCierre.endsWith(',') && !textoAntesDeCierre.endsWith('[');
161
-
162
- contenidoRoutes = contenidoRoutes.slice(0, cierreArray) +
163
- (necesitaComa ? ',' : '') + '\n' +
164
- nuevaRuta + '\n' +
165
- contenidoRoutes.slice(cierreArray);
166
-
167
- fs.writeFileSync(rutaRoutes, contenidoRoutes);
168
- console.log('Ruta agregada exitosamente.');
169
- } else {
170
- console.error('No se pudo encontrar el array de rutas en app.routes.ts');
171
- }
172
- } else {
173
- console.error(`No se encontró el archivo de rutas en: ${rutaRoutes}`);
127
+ if (opciones.cerrarAlFinalizar) {
128
+ closeReadLine();
174
129
  }
130
+ }
175
131
 
176
- // --- Modificar contenedor-principal.component.html ---
177
- console.log('Actualizando contenedor-principal.component.html...');
178
- const rutaHtml = path.join(process.cwd(), 'src', 'app', 'Paginas', 'contenedor-principal', 'contenedor-principal.component.html');
179
- if (fs.existsSync(rutaHtml)) {
180
- let contenidoHtml = fs.readFileSync(rutaHtml, 'utf-8');
181
-
182
- const nuevaTarjeta = ` <app-tarjeta [rutaASeguir]="'${nombreRuta}'" titulo="${titulo}" descripcion="${descripcion}" icono="table_chart"></app-tarjeta>`;
183
-
184
- const ultimoDiv = contenidoHtml.lastIndexOf('</div>');
132
+ function copiarYReemplazar(fuente, destino, nombreLower, nombreClase, tableInfo, nombreModal, nombreCarpetaModal) {
133
+ if (!fs.existsSync(destino)) {
134
+ fs.mkdirSync(destino, { recursive: true });
135
+ }
136
+ const entradas = fs.readdirSync(fuente, { withFileTypes: true });
137
+ entradas.forEach((entrada) => {
138
+ const nombreOriginal = entrada.name;
139
+ const nombreNuevo = nombreOriginal.replace(/XYZ/g, nombreLower);
140
+ const rutaFuente = path.join(fuente, nombreOriginal);
141
+ const rutaDestino = path.join(destino, nombreNuevo);
142
+
143
+ if (entrada.isDirectory()) {
144
+ copiarYReemplazar(rutaFuente, rutaDestino, nombreLower, nombreClase, tableInfo, nombreModal, nombreCarpetaModal);
145
+ } else if (entrada.isFile()) {
146
+ let contenido = fs.readFileSync(rutaFuente, 'utf-8');
147
+
148
+ // Reemplazos base
149
+ contenido = contenido.replace(/GestionTablaXYZComponent/g, nombreClase);
150
+ contenido = contenido.replace(/XYZ/g, nombreLower);
151
+
152
+ // Si tenemos información de la tabla, personalizamos el componente
153
+ if (tableInfo) {
154
+ if (entrada.name.endsWith('.ts')) {
155
+ contenido = personalizarComponenteFrontend(contenido, tableInfo, nombreLower, nombreModal, nombreCarpetaModal);
156
+ } else if (entrada.name.endsWith('.html')) {
157
+ contenido = contenido.replace(/app-gestion-tabla-XYZ/g, `app-gestion-tabla-${nombreLower}`);
158
+ }
159
+ }
185
160
 
186
- if (ultimoDiv !== -1) {
187
- contenidoHtml = contenidoHtml.slice(0, ultimoDiv) + '\n' + nuevaTarjeta + '\n' + contenidoHtml.slice(ultimoDiv);
188
- fs.writeFileSync(rutaHtml, contenidoHtml);
189
- console.log('Tarjeta agregada exitosamente.');
190
- } else {
191
- console.error('No se encontró un </div> de cierre en el HTML del contenedor principal.');
161
+ fs.writeFileSync(rutaDestino, contenido);
192
162
  }
193
- } else {
194
- console.error(`No se encontró el archivo HTML en: ${rutaHtml}`);
195
- }
196
- if (opciones.cerrarAlFinalizar) {
197
- closeReadLine();
163
+ });
164
+ }
165
+
166
+ function copiarYReemplazarModal(fuente, destino, nombreLower, nombreModal, tableInfo) {
167
+ if (!fs.existsSync(destino)) {
168
+ fs.mkdirSync(destino, { recursive: true });
198
169
  }
170
+ const entradas = fs.readdirSync(fuente, { withFileTypes: true });
171
+ entradas.forEach((entrada) => {
172
+ const nombreOriginal = entrada.name;
173
+ const nombreNuevo = nombreOriginal.replace(/guardar-incapacidad/g, `guardar-${nombreLower}`);
174
+ const rutaFuente = path.join(fuente, nombreOriginal);
175
+ const rutaDestino = path.join(destino, nombreNuevo);
176
+
177
+ if (entrada.isDirectory()) {
178
+ copiarYReemplazarModal(rutaFuente, rutaDestino, nombreLower, nombreModal, tableInfo);
179
+ } else if (entrada.isFile()) {
180
+ let contenido = fs.readFileSync(rutaFuente, 'utf-8');
181
+
182
+ // Reemplazos base
183
+ contenido = contenido.replace(/GuardarIncapacidadComponent/g, nombreModal);
184
+ contenido = contenido.replace(/guardar-incapacidad/g, `guardar-${nombreLower}`);
185
+ contenido = contenido.replace(/Incapacidad/g, nombreLower.charAt(0).toUpperCase() + nombreLower.slice(1));
186
+ contenido = contenido.replace(/incapacidad/g, nombreLower);
187
+
188
+ // Personalización basada en tableInfo
189
+ contenido = personalizarModalFrontend(contenido, tableInfo, entrada.name);
190
+
191
+ fs.writeFileSync(rutaDestino, contenido);
192
+ }
193
+ });
199
194
  }
200
195
 
201
- function personalizarComponenteFrontend(contenido, tableInfo, nombreServicioLower) {
196
+ function personalizarComponenteFrontend(contenido, tableInfo, nombreServicioLower, nombreModal, nombreCarpetaModal) {
202
197
  const { columns, primaryKey } = tableInfo;
203
198
 
204
199
  // 1. Reemplazar columnas
@@ -216,9 +211,123 @@ function personalizarComponenteFrontend(contenido, tableInfo, nombreServicioLowe
216
211
  const endpointRegex = new RegExp('licencias/', 'g');
217
212
  contenido = contenido.replace(endpointRegex, `${nombreServicioLower}/`);
218
213
 
214
+ // 4. Reemplazar el Import y uso del modal
215
+ contenido = contenido.replace(/import \{ GuardarIncapacidadComponent \} from '\.\.\/\.\.\/Componentes\/guardar-incapacidad\/guardar-incapacidad\.component';/g,
216
+ `import { ${nombreModal} } from '../../Componentes/${nombreCarpetaModal}/${nombreCarpetaModal}.component';`);
217
+ contenido = contenido.replace(/GuardarIncapacidadComponent/g, nombreModal);
218
+
219
+ // Usar 'Registro' como clave en el modal
220
+ contenido = contenido.replace(/Incapacidad: incapacidad/g, 'Registro: incapacidad');
221
+
222
+ // 5. Limpiar cosas específicas de Incapacidades si existen
223
+ contenido = contenido.replace(/this\.obtenerTiposLicencias\(\);/g, '');
224
+ contenido = contenido.replace(/obtenerTiposLicencias\(\) \{[\s\S]*?\}/g, '');
225
+ contenido = contenido.replace(/public tiposDeLicencias: any\[\] = \[\];/g, '');
226
+ contenido = contenido.replace(/TiposDeLicencias: this\.tiposDeLicencias/g, '');
227
+
219
228
  return contenido;
220
229
  }
221
230
 
231
+ function personalizarModalFrontend(contenido, tableInfo, fileName) {
232
+ const { columns, primaryKey } = tableInfo;
233
+
234
+ if (fileName.endsWith('.ts')) {
235
+ // Generar controles del formulario
236
+ const controles = columns.map(col => {
237
+ return ` ${col.name}Control: [this.data.Registro?.${col.name}, Validators.required]`;
238
+ }).join(',\n');
239
+
240
+ contenido = contenido.replace(/grupoFormulario = this\._formBuilder\.group\(\{[\s\S]*?\}\);/,
241
+ `grupoFormulario = this._formBuilder.group({\n${controles}\n });`);
242
+
243
+ // Generar objeto de retorno en Guardar()
244
+ const objetoRetorno = columns.map(col => {
245
+ return ` ${col.name}: controles.${col.name}Control.value`;
246
+ }).join(',\n');
247
+
248
+ contenido = contenido.replace(/let incapacidad = this\.grupoFormulario\.controls;[\s\S]*?this\.dialogRef\.close\(\{[\s\S]*?\}\);/,
249
+ `let controles = this.grupoFormulario.controls;\n this.dialogRef.close({\n${objetoRetorno},\n ${primaryKey}: this.data.Registro?.${primaryKey}\n });`);
250
+
251
+ // Quitar TiposDeLicencias si existe
252
+ contenido = contenido.replace(/TiposDeLicencias = this\.data\.TiposDeLicencias;/g, '');
253
+ contenido = contenido.replace(/readonly Incapacidad = this\.data\.Incapacidad \?\? \{\};/g, '');
254
+ }
255
+
256
+ if (fileName.endsWith('.html')) {
257
+ // Generar campos del formulario
258
+ const campos = columns.map(col => {
259
+ const type = col.type.includes('INT') ? 'number' : (col.type.includes('DATE') ? 'date' : 'text');
260
+ return ` <mat-form-field class="campo_mitad">
261
+ <mat-label>${col.alias}</mat-label>
262
+ <input matInput ${type !== 'text' ? 'type="' + type + '"' : ''} formControlName="${col.name}Control" required />
263
+ </mat-form-field>`;
264
+ }).join('\n');
265
+
266
+ contenido = contenido.replace(/<form \[formGroup\]="grupoFormulario">[\s\S]*?<\/form>/,
267
+ `<form [formGroup]="grupoFormulario">\n <div class="fila">\n${campos}\n </div>\n </form>`);
268
+
269
+ // Reemplazar el título
270
+ const titulo = tableInfo.serviceTitle || 'Registro';
271
+ contenido = contenido.replace(/<h2>[\s\S]*?<\/h2>/, `<h2>{{data.Registro ? 'Editar' : 'Agregar'}} ${titulo}</h2>`);
272
+ contenido = contenido.replace(/{{Incapacidad\.NumeroBoleta\?'Guardar':'Agregar'}}/, `{{data.Registro ? 'Guardar' : 'Agregar'}}`);
273
+ }
274
+
275
+ return contenido;
276
+ }
277
+
278
+ function actualizarArchivosConfiguracion(nombreClase, nombreRuta, titulo, descripcion) {
279
+ // --- Modificar app.routes.ts ---
280
+ console.log('Actualizando app.routes.ts...');
281
+ const rutaRoutes = path.join(process.cwd(), 'src', 'app', 'app.routes.ts');
282
+ if (fs.existsSync(rutaRoutes)) {
283
+ let contenidoRoutes = fs.readFileSync(rutaRoutes, 'utf-8');
284
+
285
+ const lineaImport = `import { ${nombreClase} } from './Paginas/${nombreRuta}/${nombreRuta}.component';`;
286
+ if (!contenidoRoutes.includes(lineaImport)) {
287
+ const ultimoImportIndex = contenidoRoutes.lastIndexOf('import {');
288
+ const finUltimoImport = contenidoRoutes.indexOf(';', ultimoImportIndex);
289
+
290
+ if (finUltimoImport !== -1) {
291
+ contenidoRoutes = contenidoRoutes.slice(0, finUltimoImport + 1) + '\n' + lineaImport + contenidoRoutes.slice(finUltimoImport + 1);
292
+ } else {
293
+ contenidoRoutes = lineaImport + '\n' + contenidoRoutes;
294
+ }
295
+ }
296
+
297
+ if (!contenidoRoutes.includes(`path: '${nombreRuta}'`)) {
298
+ const cierreArray = contenidoRoutes.lastIndexOf('];');
299
+ if (cierreArray !== -1) {
300
+ const nuevaRuta = ` { path: '${nombreRuta}', component: ${nombreClase} },`;
301
+ const textoAntesDeCierre = contenidoRoutes.slice(0, cierreArray).trimEnd();
302
+ const necesitaComa = !textoAntesDeCierre.endsWith(',') && !textoAntesDeCierre.endsWith('[');
303
+
304
+ contenidoRoutes = contenidoRoutes.slice(0, cierreArray) +
305
+ (necesitaComa ? ',' : '') + '\n' +
306
+ nuevaRuta + '\n' +
307
+ contenidoRoutes.slice(cierreArray);
308
+
309
+ fs.writeFileSync(rutaRoutes, contenidoRoutes);
310
+ }
311
+ }
312
+ }
313
+
314
+ // --- Modificar contenedor-principal.component.html ---
315
+ console.log('Actualizando contenedor-principal.component.html...');
316
+ const rutaHtml = path.join(process.cwd(), 'src', 'app', 'Paginas', 'contenedor-principal', 'contenedor-principal.component.html');
317
+ if (fs.existsSync(rutaHtml)) {
318
+ let contenidoHtml = fs.readFileSync(rutaHtml, 'utf-8');
319
+ if (!contenidoHtml.includes(`rutaASeguir]="'${nombreRuta}'"`)) {
320
+ const nuevaTarjeta = ` <app-tarjeta [rutaASeguir]="'${nombreRuta}'" titulo="${titulo}" descripcion="${descripcion}" icono="table_chart"></app-tarjeta>`;
321
+ const ultimoDiv = contenidoHtml.lastIndexOf('</div>');
322
+ if (ultimoDiv !== -1) {
323
+ contenidoHtml = contenidoHtml.slice(0, ultimoDiv) + '\n' + nuevaTarjeta + '\n' + contenidoHtml.slice(ultimoDiv);
324
+ fs.writeFileSync(rutaHtml, contenidoHtml);
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+
222
331
  export function showFrontendVersion() {
223
332
  mostrarVersion(path.join(__dirname, '../package.json'));
224
333
  closeReadLine();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utn-cli",
3
- "version": "2.0.58",
3
+ "version": "2.0.59",
4
4
  "description": "Herramienta CLI unificada para la gestión de plantillas en SIGU.",
5
5
  "main": "index.js",
6
6
  "type": "module",