versacompiler 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/compiler/compile.js +2520 -25
- package/dist/compiler/error-reporter.js +467 -38
- package/dist/compiler/linter.js +72 -1
- package/dist/compiler/minify.js +272 -1
- package/dist/compiler/minifyTemplate.js +230 -1
- package/dist/compiler/module-resolution-optimizer.js +888 -1
- package/dist/compiler/parser.js +336 -1
- package/dist/compiler/performance-monitor.js +204 -56
- package/dist/compiler/tailwindcss.js +39 -1
- package/dist/compiler/transform-optimizer.js +392 -1
- package/dist/compiler/transformTStoJS.js +16 -1
- package/dist/compiler/transforms.js +554 -1
- package/dist/compiler/typescript-compiler.js +172 -2
- package/dist/compiler/typescript-error-parser.js +281 -10
- package/dist/compiler/typescript-manager.js +304 -2
- package/dist/compiler/typescript-sync-validator.js +295 -31
- package/dist/compiler/typescript-worker-pool.js +936 -1
- package/dist/compiler/typescript-worker-thread.cjs +466 -22
- package/dist/compiler/typescript-worker.js +339 -1
- package/dist/compiler/vuejs.js +396 -37
- package/dist/hrm/VueHRM.js +359 -1
- package/dist/hrm/errorScreen.js +83 -1
- package/dist/hrm/getInstanciaVue.js +313 -1
- package/dist/hrm/initHRM.js +586 -1
- package/dist/main.js +353 -7
- package/dist/servicios/browserSync.js +589 -2
- package/dist/servicios/file-watcher.js +425 -4
- package/dist/servicios/logger.js +63 -3
- package/dist/servicios/readConfig.js +399 -53
- package/dist/utils/excluded-modules.js +37 -1
- package/dist/utils/module-resolver.js +552 -1
- package/dist/utils/promptUser.js +48 -2
- package/dist/utils/proxyValidator.js +68 -1
- package/dist/utils/resolve-bin.js +58 -1
- package/dist/utils/utils.js +21 -1
- package/dist/utils/vue-types-setup.js +435 -241
- package/dist/wrappers/eslint-node.js +1 -1
- package/dist/wrappers/oxlint-node.js +122 -1
- package/dist/wrappers/tailwind-node.js +94 -1
- package/package.json +109 -104
|
@@ -1,4 +1,425 @@
|
|
|
1
|
-
import{readdir
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { readdir, rm, stat, unlink } from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as process from 'node:process';
|
|
4
|
+
const { env } = process;
|
|
5
|
+
import * as chokidar from 'chokidar';
|
|
6
|
+
import { minimatch } from 'minimatch';
|
|
7
|
+
import { getOutputPath, initCompile, normalizeRuta } from '../compiler/compile.js';
|
|
8
|
+
import { promptUser } from '../utils/promptUser.js';
|
|
9
|
+
import { emitirCambios } from './browserSync.js';
|
|
10
|
+
import { logger } from './logger.js';
|
|
11
|
+
// Lazy loading para chalk
|
|
12
|
+
let chalk;
|
|
13
|
+
async function loadChalk() {
|
|
14
|
+
if (!chalk) {
|
|
15
|
+
chalk = (await import('chalk')).default;
|
|
16
|
+
}
|
|
17
|
+
return chalk;
|
|
18
|
+
}
|
|
19
|
+
class WatchDebouncer {
|
|
20
|
+
pendingChanges = new Map();
|
|
21
|
+
debounceTimer = null;
|
|
22
|
+
DEBOUNCE_DELAY = 50; // ✨ OPTIMIZACIÓN: 50ms para hot reload más responsive
|
|
23
|
+
BATCH_SIZE = 10; // Máximo archivos por batch
|
|
24
|
+
isProcessing = false;
|
|
25
|
+
browserSyncInstance = null; // ✨ Almacenar referencia a browserSync
|
|
26
|
+
/**
|
|
27
|
+
* Establece la instancia de browserSync
|
|
28
|
+
*/
|
|
29
|
+
setBrowserSyncInstance(bs) {
|
|
30
|
+
this.browserSyncInstance = bs;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ✨ FIX #3: Limpia todos los recursos del debouncer
|
|
34
|
+
*/
|
|
35
|
+
cleanup() {
|
|
36
|
+
if (this.debounceTimer) {
|
|
37
|
+
clearTimeout(this.debounceTimer);
|
|
38
|
+
this.debounceTimer = null;
|
|
39
|
+
}
|
|
40
|
+
this.pendingChanges.clear();
|
|
41
|
+
this.isProcessing = false;
|
|
42
|
+
this.browserSyncInstance = null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Añade un cambio al sistema de debouncing
|
|
46
|
+
*/
|
|
47
|
+
addChange(filePath, action, extensionAction, isAdditionalFile = false) {
|
|
48
|
+
// Normalizar ruta para evitar duplicados
|
|
49
|
+
const normalizedPath = normalizeRuta(filePath);
|
|
50
|
+
// Agregar o actualizar el cambio pendiente
|
|
51
|
+
this.pendingChanges.set(normalizedPath, {
|
|
52
|
+
filePath: normalizedPath,
|
|
53
|
+
action,
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
extensionAction,
|
|
56
|
+
isAdditionalFile,
|
|
57
|
+
});
|
|
58
|
+
// Reiniciar el timer de debounce
|
|
59
|
+
this.resetDebounceTimer();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reinicia el timer de debounce
|
|
63
|
+
*/
|
|
64
|
+
resetDebounceTimer() {
|
|
65
|
+
if (this.debounceTimer) {
|
|
66
|
+
clearTimeout(this.debounceTimer);
|
|
67
|
+
}
|
|
68
|
+
this.debounceTimer = setTimeout(() => {
|
|
69
|
+
this.processPendingChanges();
|
|
70
|
+
}, this.DEBOUNCE_DELAY);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Procesa todos los cambios pendientes en batch
|
|
74
|
+
*/
|
|
75
|
+
async processPendingChanges() {
|
|
76
|
+
if (this.isProcessing || this.pendingChanges.size === 0) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.isProcessing = true;
|
|
80
|
+
const changes = Array.from(this.pendingChanges.values());
|
|
81
|
+
this.pendingChanges.clear();
|
|
82
|
+
try {
|
|
83
|
+
// Agrupar por tipo de acción para optimización
|
|
84
|
+
const deleteChanges = changes.filter(c => c.action === 'unlink');
|
|
85
|
+
const compileChanges = changes.filter(c => c.action === 'add' || c.action === 'change');
|
|
86
|
+
// Procesar eliminaciones primero
|
|
87
|
+
if (deleteChanges.length > 0) {
|
|
88
|
+
await this.processDeleteChanges(deleteChanges);
|
|
89
|
+
}
|
|
90
|
+
// Procesar compilaciones en batches
|
|
91
|
+
if (compileChanges.length > 0) {
|
|
92
|
+
await this.processCompileChanges(compileChanges);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const chalkInstance = await loadChalk();
|
|
97
|
+
logger.error(chalkInstance.red(`🚩 Error procesando cambios en batch: ${error instanceof Error ? error.message : String(error)}`));
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
this.isProcessing = false;
|
|
101
|
+
// Si hay más cambios pendientes, procesarlos
|
|
102
|
+
if (this.pendingChanges.size > 0) {
|
|
103
|
+
this.resetDebounceTimer();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} /**
|
|
107
|
+
* Procesa cambios de eliminación
|
|
108
|
+
*/
|
|
109
|
+
async processDeleteChanges(deleteChanges) {
|
|
110
|
+
for (const change of deleteChanges) {
|
|
111
|
+
if (change.isAdditionalFile) {
|
|
112
|
+
// ✨ Archivos adicionales: solo reload, sin eliminar del output
|
|
113
|
+
logger.info(`\n🗑️ Archivo adicional eliminado: ${change.filePath}`);
|
|
114
|
+
emitirCambios(this.browserSyncInstance, 'reloadFull', change.filePath);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Archivos compilables: eliminar del output
|
|
118
|
+
logger.info(`\n🗑️ Eliminando archivo compilado: ${change.filePath}`);
|
|
119
|
+
const result = await deleteFile(getOutputPath(change.filePath));
|
|
120
|
+
if (result) {
|
|
121
|
+
logger.info(`Archivo eliminado: ${change.filePath}`);
|
|
122
|
+
emitirCambios(this.browserSyncInstance, 'reloadFull', change.filePath);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Procesa cambios de compilación en paralelo con límite de concurrencia
|
|
129
|
+
*/
|
|
130
|
+
async processCompileChanges(compileChanges) {
|
|
131
|
+
// ✨ NUEVO: Separar archivos adicionales de archivos compilables
|
|
132
|
+
const additionalFiles = compileChanges.filter(c => c.isAdditionalFile);
|
|
133
|
+
const compilableFiles = compileChanges.filter(c => !c.isAdditionalFile);
|
|
134
|
+
// ✨ Procesar archivos adicionales (solo reload, sin compilación)
|
|
135
|
+
if (additionalFiles.length > 0) {
|
|
136
|
+
await this.processAdditionalFiles(additionalFiles);
|
|
137
|
+
}
|
|
138
|
+
// Procesar archivos compilables normalmente
|
|
139
|
+
if (compilableFiles.length > 0) {
|
|
140
|
+
await this.processCompilableFiles(compilableFiles);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* ✨ RENOMBRADO: Procesa archivos compilables
|
|
145
|
+
*/
|
|
146
|
+
async processCompilableFiles(compilableFiles) {
|
|
147
|
+
const chalkInstance = await loadChalk();
|
|
148
|
+
// Procesar en batches para evitar sobrecarga
|
|
149
|
+
for (let i = 0; i < compilableFiles.length; i += this.BATCH_SIZE) {
|
|
150
|
+
const batch = compilableFiles.slice(i, i + this.BATCH_SIZE);
|
|
151
|
+
if (batch.length > 1) {
|
|
152
|
+
logger.info(chalkInstance.cyan(`📦 Procesando batch de ${batch.length} archivos compilables (${i + 1}-${Math.min(i + this.BATCH_SIZE, compilableFiles.length)} de ${compilableFiles.length})`));
|
|
153
|
+
}
|
|
154
|
+
const promises = batch.map(change => this.compileFile(change));
|
|
155
|
+
await Promise.allSettled(promises);
|
|
156
|
+
}
|
|
157
|
+
if (compilableFiles.length > 1) {
|
|
158
|
+
logger.info(chalkInstance.green(`✅ Batch completado: ${compilableFiles.length} archivos compilados`));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* ✨ NUEVO: Procesa archivos adicionales (solo reloadFull)
|
|
163
|
+
*/
|
|
164
|
+
async processAdditionalFiles(additionalFiles) {
|
|
165
|
+
const chalkInstance = await loadChalk();
|
|
166
|
+
logger.info(chalkInstance.blue(`🔄 Recargando ${additionalFiles.length} archivo(s) adicional(es) (sin compilación)`));
|
|
167
|
+
for (const change of additionalFiles) {
|
|
168
|
+
logger.info(`📄 Archivo adicional modificado: ${change.filePath}`);
|
|
169
|
+
// Solo hacer reloadFull, sin compilación
|
|
170
|
+
emitirCambios(this.browserSyncInstance, 'reloadFull', change.filePath);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Compila un archivo individual
|
|
175
|
+
*/
|
|
176
|
+
async compileFile(change) {
|
|
177
|
+
try {
|
|
178
|
+
const result = await initCompile(change.filePath, true, 'watch');
|
|
179
|
+
if (result.success) {
|
|
180
|
+
let accion = result.action || change.extensionAction;
|
|
181
|
+
accion =
|
|
182
|
+
accion === 'extension' ? change.extensionAction : accion;
|
|
183
|
+
emitirCambios(this.browserSyncInstance, accion || 'reloadFull', result.output);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const chalkInstance = await loadChalk();
|
|
188
|
+
logger.error(chalkInstance.red(`🚩 Error compilando ${change.filePath}: ${error instanceof Error ? error.message : String(error)}`));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Obtiene estadísticas del debouncer
|
|
193
|
+
*/
|
|
194
|
+
getStats() {
|
|
195
|
+
return {
|
|
196
|
+
pendingChanges: this.pendingChanges.size,
|
|
197
|
+
isProcessing: this.isProcessing,
|
|
198
|
+
hasTimer: this.debounceTimer !== null,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Instancia global del debouncer
|
|
203
|
+
const watchDebouncer = new WatchDebouncer();
|
|
204
|
+
// const cacheImportMap = new Map<string, string[]>();
|
|
205
|
+
// const cacheComponentMap = new Map<string, string[]>();
|
|
206
|
+
export async function cleanOutputDir(outputDir, primerInteraccion = true) {
|
|
207
|
+
try {
|
|
208
|
+
if (!outputDir) {
|
|
209
|
+
throw new Error('El directorio de salida no está definido');
|
|
210
|
+
}
|
|
211
|
+
if (primerInteraccion) {
|
|
212
|
+
const stats = await stat(outputDir).catch(() => null);
|
|
213
|
+
if (!stats || !stats.isDirectory()) {
|
|
214
|
+
logger.error(`🚩 El directorio de salida no existe o no es un directorio: ${outputDir}`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
if (env.yes === 'false') {
|
|
219
|
+
const chalkInstance = await loadChalk();
|
|
220
|
+
const answer = await promptUser('\n\n¿Estás seguro deseas limpiar la carpeta ' +
|
|
221
|
+
chalkInstance.yellow(outputDir) +
|
|
222
|
+
'? (s / N) : ');
|
|
223
|
+
if (answer.toLowerCase() !== 's') {
|
|
224
|
+
logger.info('🛑 Compilación cancelada por el usuario.');
|
|
225
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
226
|
+
process.exit(0);
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
logger.error(`Error en la entrada del usuario: ${error}`);
|
|
234
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const chalkInstance = await loadChalk();
|
|
241
|
+
logger.info(`🗑️ Limpiando directorio de salida: ${chalkInstance.yellow(outputDir)}\n`);
|
|
242
|
+
const items = await readdir(outputDir);
|
|
243
|
+
await Promise.all(items.map(async (item) => {
|
|
244
|
+
const itemPath = path.join(outputDir, item);
|
|
245
|
+
const itemStat = await stat(itemPath);
|
|
246
|
+
if (itemStat.isDirectory()) {
|
|
247
|
+
await rm(itemPath, { recursive: true });
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
await unlink(itemPath);
|
|
251
|
+
}
|
|
252
|
+
}));
|
|
253
|
+
logger.info(`✅ Directorio limpiado: ${outputDir}`);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
logger.error(`🚩 Error al limpiar directorio de salida: ${error instanceof Error ? error.message : String(error)}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async function deleteFile(filePath) {
|
|
260
|
+
try {
|
|
261
|
+
await unlink(filePath);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
logger.error(`🚩 Error eliminando archivo ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function getAction(ruta, extendsionWatch) {
|
|
270
|
+
const action = extendsionWatch
|
|
271
|
+
.filter((item) => item !== undefined)
|
|
272
|
+
.find(item => item.ext === ruta.split('.').pop())?.action;
|
|
273
|
+
return action || 'reloadFull';
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Verifica si un archivo pertenece a las rutas adicionales (no compilables)
|
|
277
|
+
*/
|
|
278
|
+
function isAdditionalWatchFile(filePath, additionalPatterns) {
|
|
279
|
+
if (!additionalPatterns || additionalPatterns.length === 0) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
const normalizedPath = normalizeRuta(filePath);
|
|
283
|
+
return additionalPatterns.some(pattern => {
|
|
284
|
+
// Normalizar el patrón también
|
|
285
|
+
const normalizedPattern = pattern.replace(/\\/g, '/');
|
|
286
|
+
return minimatch(normalizedPath, normalizedPattern);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
export async function initChokidar(bs) {
|
|
290
|
+
try {
|
|
291
|
+
if (!env.PATH_SOURCE) {
|
|
292
|
+
logger.error('Error: La variable de entorno PATH_SOURCE no está definida.');
|
|
293
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
throw new Error('PATH_SOURCE no está definida');
|
|
297
|
+
}
|
|
298
|
+
const watchJS = `${env.PATH_SOURCE}/**/*.js`;
|
|
299
|
+
const watchVue = `${env.PATH_SOURCE}/**/*.vue`;
|
|
300
|
+
const watchTS = `${env.PATH_SOURCE}/**/*.ts`;
|
|
301
|
+
const watchCJS = `${env.PATH_SOURCE}/**/*.cjs`;
|
|
302
|
+
const watchMJS = `${env.PATH_SOURCE}/**/*.mjs`;
|
|
303
|
+
//TODO: agregar watch para CSS
|
|
304
|
+
const watchAditional = JSON.parse(env.aditionalWatch || '[]');
|
|
305
|
+
let fileWatch = [
|
|
306
|
+
watchJS,
|
|
307
|
+
watchVue,
|
|
308
|
+
watchTS,
|
|
309
|
+
watchCJS,
|
|
310
|
+
watchMJS,
|
|
311
|
+
...watchAditional,
|
|
312
|
+
];
|
|
313
|
+
//extraer sólo las extesniones de fileWatch
|
|
314
|
+
const accionExtension = {
|
|
315
|
+
vue: 'HRMVue',
|
|
316
|
+
js: 'HRMHelper',
|
|
317
|
+
ts: 'HRMHelper',
|
|
318
|
+
cjs: 'HRMHelper',
|
|
319
|
+
mjs: 'HRMHelper',
|
|
320
|
+
};
|
|
321
|
+
const extendsionWatch = fileWatch.map(item => {
|
|
322
|
+
const ext = item.split('.').pop();
|
|
323
|
+
if (ext) {
|
|
324
|
+
return {
|
|
325
|
+
ext,
|
|
326
|
+
action: accionExtension[ext] ||
|
|
327
|
+
'reloadFull',
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
if (extendsionWatch.length === 0 || extendsionWatch[0] === undefined) {
|
|
332
|
+
throw new Error('No se encontraron extensiones para observar');
|
|
333
|
+
}
|
|
334
|
+
const regExtExtension = new RegExp(`\\.(?!${extendsionWatch
|
|
335
|
+
.filter(item => item !== undefined)
|
|
336
|
+
.map(item => item.ext)
|
|
337
|
+
.join('$|')}$).+$`);
|
|
338
|
+
fileWatch = fileWatch.map(item => item.replace(/\/\*\*\//g, '/'));
|
|
339
|
+
const directories = new Map();
|
|
340
|
+
fileWatch.forEach(item => {
|
|
341
|
+
const dir = item.substring(0, item.lastIndexOf('/'));
|
|
342
|
+
if (!directories.has(dir)) {
|
|
343
|
+
directories.set(dir, []);
|
|
344
|
+
}
|
|
345
|
+
directories.get(dir).push(item);
|
|
346
|
+
});
|
|
347
|
+
const DirWatch = Array.from(directories.keys());
|
|
348
|
+
const watcher = chokidar.watch(DirWatch, {
|
|
349
|
+
persistent: true,
|
|
350
|
+
ignoreInitial: true,
|
|
351
|
+
ignored: regExtExtension,
|
|
352
|
+
});
|
|
353
|
+
// ✨ OPTIMIZACIÓN: Pre-cargar módulos críticos al iniciar el watcher
|
|
354
|
+
watcher.on('ready', async () => {
|
|
355
|
+
const chalkInstance = await loadChalk();
|
|
356
|
+
logger.info(chalkInstance.green(`👀 : Listo para observar \n${fileWatch
|
|
357
|
+
.map((item) => `${item}`)
|
|
358
|
+
.join('\n')}\n`));
|
|
359
|
+
// Pre-cargar módulos críticos para primera compilación más rápida
|
|
360
|
+
setImmediate(async () => {
|
|
361
|
+
try {
|
|
362
|
+
// Pre-cargar módulos básicos que se usarán en compilación
|
|
363
|
+
await Promise.all([
|
|
364
|
+
import('../compiler/compile.js'),
|
|
365
|
+
import('../compiler/parser.js'),
|
|
366
|
+
]);
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// Ignorar errores de pre-carga, no son críticos
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
// ✨ CONFIGURAR: Establecer la instancia de browserSync en el debouncer
|
|
374
|
+
watchDebouncer.setBrowserSyncInstance(bs);
|
|
375
|
+
// ✨ OPTIMIZADO: Evento cuando se añade un archivo - Con debouncing
|
|
376
|
+
watcher.on('add', async (ruta) => {
|
|
377
|
+
const isAdditional = isAdditionalWatchFile(ruta, watchAditional);
|
|
378
|
+
const action = getAction(ruta, extendsionWatch.filter((item) => item !== undefined));
|
|
379
|
+
// Usar sistema de debouncing en lugar de compilación inmediata
|
|
380
|
+
watchDebouncer.addChange(ruta, 'add', action, isAdditional);
|
|
381
|
+
});
|
|
382
|
+
// ✨ OPTIMIZADO: Evento cuando se modifica un archivo - Con debouncing
|
|
383
|
+
watcher.on('change', async (ruta) => {
|
|
384
|
+
const isAdditional = isAdditionalWatchFile(ruta, watchAditional);
|
|
385
|
+
const action = getAction(ruta, extendsionWatch.filter((item) => item !== undefined));
|
|
386
|
+
// Usar sistema de debouncing en lugar de compilación inmediata
|
|
387
|
+
watchDebouncer.addChange(ruta, 'change', action, isAdditional);
|
|
388
|
+
});
|
|
389
|
+
// ✨ OPTIMIZADO: Evento cuando se elimina un archivo - Con debouncing
|
|
390
|
+
watcher.on('unlink', async (ruta) => {
|
|
391
|
+
const action = getAction(ruta, extendsionWatch.filter((item) => item !== undefined));
|
|
392
|
+
const isAdditional = isAdditionalWatchFile(ruta, watchAditional);
|
|
393
|
+
// Usar sistema de debouncing para eliminaciones también
|
|
394
|
+
watchDebouncer.addChange(ruta, 'unlink', action, isAdditional);
|
|
395
|
+
});
|
|
396
|
+
return watcher;
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
logger.error(`🚩 :Error al iniciar watch: ${error instanceof Error ? error.message : String(error)}`);
|
|
400
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* ✨ FIX #3: Limpia todos los recursos de watch mode
|
|
408
|
+
* Cierra watchers y limpia timers para evitar fugas de memoria
|
|
409
|
+
*/
|
|
410
|
+
export async function cleanupWatcher(watcher) {
|
|
411
|
+
try {
|
|
412
|
+
console.log('[FileWatcher] Limpiando recursos...');
|
|
413
|
+
// 1. Limpiar debouncer
|
|
414
|
+
watchDebouncer.cleanup();
|
|
415
|
+
// 2. Cerrar watcher de chokidar
|
|
416
|
+
if (watcher) {
|
|
417
|
+
await watcher.close();
|
|
418
|
+
}
|
|
419
|
+
console.log('[FileWatcher] Recursos limpiados correctamente');
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
console.error('[FileWatcher] Error al limpiar recursos:', error instanceof Error ? error.message : String(error));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=file-watcher.js.map
|
package/dist/servicios/logger.js
CHANGED
|
@@ -1,3 +1,63 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as process from 'node:process';
|
|
2
|
+
// Función para obtener ProgressManager (lazy import para evitar dependencias circulares)
|
|
3
|
+
let getProgressManager = null;
|
|
4
|
+
export function setProgressManagerGetter(getter) {
|
|
5
|
+
getProgressManager = getter;
|
|
6
|
+
}
|
|
7
|
+
class Logger {
|
|
8
|
+
constructor() {
|
|
9
|
+
// Bind console methods
|
|
10
|
+
process.stdout.write = process.stdout.write.bind(process.stdout);
|
|
11
|
+
process.stderr.write = process.stderr.write.bind(process.stderr);
|
|
12
|
+
}
|
|
13
|
+
writeMessage(message, useStderr = false, immediate = false) {
|
|
14
|
+
if (getProgressManager) {
|
|
15
|
+
const progressManager = getProgressManager();
|
|
16
|
+
if (progressManager && progressManager.isActive()) {
|
|
17
|
+
// Si el progreso está activo, usar el sistema de logs apropiado
|
|
18
|
+
if (immediate) {
|
|
19
|
+
progressManager.addImmediateLog(message);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
progressManager.addLog(message);
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Comportamiento normal si no hay progreso activo
|
|
28
|
+
if (useStderr) {
|
|
29
|
+
process.stderr.write(message + '\n');
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
process.stdout.write(message + '\n');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
log(...args) {
|
|
36
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '));
|
|
37
|
+
}
|
|
38
|
+
info(...args) {
|
|
39
|
+
// En modo verbose, mostrar logs inmediatamente
|
|
40
|
+
const isVerbose = process.env.VERBOSE === 'true';
|
|
41
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '), false, isVerbose);
|
|
42
|
+
}
|
|
43
|
+
error(...args) {
|
|
44
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '), true);
|
|
45
|
+
}
|
|
46
|
+
warn(...args) {
|
|
47
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '), true);
|
|
48
|
+
}
|
|
49
|
+
debug(...args) {
|
|
50
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '));
|
|
51
|
+
}
|
|
52
|
+
fatal(...args) {
|
|
53
|
+
this.writeMessage(args.map(arg => String(arg)).join(' '), true);
|
|
54
|
+
}
|
|
55
|
+
table(data, title) {
|
|
56
|
+
const tableString = title
|
|
57
|
+
? console.table(data, title)
|
|
58
|
+
: console.table(data);
|
|
59
|
+
this.writeMessage(String(tableString));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export const logger = new Logger();
|
|
63
|
+
//# sourceMappingURL=logger.js.map
|