versacompiler 2.0.1 → 2.0.3
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/dist/compiler/compile.js +1086 -116
- package/dist/compiler/module-resolution-optimizer.js +17 -40
- package/dist/compiler/transform-optimizer.js +111 -6
- package/dist/compiler/transforms.js +3 -31
- package/dist/compiler/typescript-error-parser.js +1 -1
- package/dist/compiler/typescript-sync-validator.js +1 -1
- package/dist/compiler/typescript-worker-pool.js +387 -24
- package/dist/compiler/typescript-worker-thread.cjs +1 -2
- package/dist/hrm/getInstanciaVue.js +1 -1
- package/dist/hrm/initHRM.js +1 -1
- package/dist/main.js +64 -17
- package/dist/servicios/browserSync.js +1 -1
- package/dist/servicios/file-watcher.js +85 -22
- package/dist/servicios/logger.js +36 -7
- package/dist/servicios/readConfig.js +1 -1
- package/dist/utils/excluded-modules.js +36 -0
- package/dist/utils/module-resolver.js +4 -33
- package/package.json +2 -1
|
@@ -18,10 +18,10 @@ export class TypeScriptWorkerPool {
|
|
|
18
18
|
workerPath;
|
|
19
19
|
initPromise = null;
|
|
20
20
|
isInitialized = false; // Configuración optimizada con reciclaje de workers
|
|
21
|
-
TASK_TIMEOUT =
|
|
21
|
+
TASK_TIMEOUT = 15000; // 15 segundos por tarea (aumentado)
|
|
22
22
|
WORKER_INIT_TIMEOUT = 5000; // 5 segundos para inicializar
|
|
23
|
-
MAX_TASKS_PER_WORKER =
|
|
24
|
-
WORKER_MEMORY_CHECK_INTERVAL =
|
|
23
|
+
MAX_TASKS_PER_WORKER = 25; // Reducido para liberar memoria más frecuentemente
|
|
24
|
+
WORKER_MEMORY_CHECK_INTERVAL = 50; // Verificar cada 50 tareas (más frecuente)
|
|
25
25
|
// Métricas de rendimiento
|
|
26
26
|
totalTasks = 0;
|
|
27
27
|
completedTasks = 0;
|
|
@@ -31,6 +31,128 @@ export class TypeScriptWorkerPool {
|
|
|
31
31
|
const cpuCount = os.cpus().length;
|
|
32
32
|
this.poolSize = Math.min(Math.max(cpuCount - 1, 2), 8); // Entre 2 y 8 workers
|
|
33
33
|
this.workerPath = path.join(process.env.PATH_PROY || path.join(process.cwd(), 'src'), 'compiler', 'typescript-worker-thread.cjs');
|
|
34
|
+
// ✨ ISSUE #4: Configurar monitoreo de memoria automático this.startMemoryMonitoring();
|
|
35
|
+
}
|
|
36
|
+
// ✨ ISSUE #4: Métodos de control de memoria y timeouts
|
|
37
|
+
/**
|
|
38
|
+
* Inicia el monitoreo automático de memoria de workers
|
|
39
|
+
*/
|
|
40
|
+
startMemoryMonitoring() {
|
|
41
|
+
// Monitoreo cada 15 segundos (más frecuente)
|
|
42
|
+
setInterval(() => {
|
|
43
|
+
this.checkWorkersMemory();
|
|
44
|
+
}, 15000);
|
|
45
|
+
// Limpieza de workers inactivos cada 2 minutos (más frecuente)
|
|
46
|
+
setInterval(() => {
|
|
47
|
+
this.cleanupInactiveWorkers();
|
|
48
|
+
}, 120000);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Verifica el uso de memoria de todos los workers con medición real
|
|
52
|
+
*/
|
|
53
|
+
async checkWorkersMemory() {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
for (const poolWorker of this.workers) {
|
|
56
|
+
// Actualizar tiempo de última verificación
|
|
57
|
+
poolWorker.lastMemoryCheck = now;
|
|
58
|
+
try {
|
|
59
|
+
// ✨ ISSUE #4: Obtener memoria real del worker
|
|
60
|
+
const memoryInfo = await this.getWorkerMemoryUsage(poolWorker);
|
|
61
|
+
poolWorker.memoryUsage = memoryInfo.heapUsed;
|
|
62
|
+
// Verificar límites de memoria y reciclaje automático
|
|
63
|
+
if (this.shouldRecycleWorker(poolWorker)) {
|
|
64
|
+
const reason = this.getRecycleReason(poolWorker);
|
|
65
|
+
console.warn(`[WorkerPool] Worker ${poolWorker.id} requiere reciclaje: ${reason}`);
|
|
66
|
+
await this.recycleWorker(poolWorker);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.warn(`[WorkerPool] Error verificando memoria del worker ${poolWorker.id}:`, error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Obtiene el uso real de memoria de un worker
|
|
76
|
+
*/
|
|
77
|
+
async getWorkerMemoryUsage(poolWorker) {
|
|
78
|
+
return new Promise(resolve => {
|
|
79
|
+
const timeout = setTimeout(() => {
|
|
80
|
+
// Fallback con estimación si no hay respuesta
|
|
81
|
+
resolve({
|
|
82
|
+
heapUsed: poolWorker.tasksProcessed * 2048, // 2KB por tarea
|
|
83
|
+
heapTotal: poolWorker.tasksProcessed * 3072, // 3KB total estimado
|
|
84
|
+
rss: poolWorker.tasksProcessed * 4096, // 4KB RSS estimado
|
|
85
|
+
});
|
|
86
|
+
}, 1000);
|
|
87
|
+
// Solicitar memoria real del worker
|
|
88
|
+
const memoryRequestId = `memory-${poolWorker.id}-${Date.now()}`;
|
|
89
|
+
const handler = (response) => {
|
|
90
|
+
if (response.id === memoryRequestId &&
|
|
91
|
+
response.type === 'memory-usage') {
|
|
92
|
+
clearTimeout(timeout);
|
|
93
|
+
poolWorker.worker.off('message', handler);
|
|
94
|
+
resolve({
|
|
95
|
+
heapUsed: response.memoryUsage?.heapUsed ||
|
|
96
|
+
poolWorker.tasksProcessed * 2048,
|
|
97
|
+
heapTotal: response.memoryUsage?.heapTotal ||
|
|
98
|
+
poolWorker.tasksProcessed * 3072,
|
|
99
|
+
rss: response.memoryUsage?.rss ||
|
|
100
|
+
poolWorker.tasksProcessed * 4096,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
poolWorker.worker.on('message', handler);
|
|
105
|
+
poolWorker.worker.postMessage({
|
|
106
|
+
type: 'get-memory-usage',
|
|
107
|
+
id: memoryRequestId,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Obtiene la razón por la cual un worker debe ser reciclado
|
|
113
|
+
*/
|
|
114
|
+
getRecycleReason(poolWorker) {
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
const MEMORY_LIMIT = 50 * 1024 * 1024; // 50MB
|
|
117
|
+
const TIME_LIMIT = 30 * 60 * 1000; // 30 minutos
|
|
118
|
+
const TASK_LIMIT = this.MAX_TASKS_PER_WORKER;
|
|
119
|
+
const reasons = [];
|
|
120
|
+
if (poolWorker.memoryUsage > MEMORY_LIMIT) {
|
|
121
|
+
reasons.push(`memoria excede ${Math.round(MEMORY_LIMIT / 1024 / 1024)}MB (actual: ${Math.round(poolWorker.memoryUsage / 1024 / 1024)}MB)`);
|
|
122
|
+
}
|
|
123
|
+
if (now - poolWorker.creationTime > TIME_LIMIT) {
|
|
124
|
+
reasons.push(`tiempo de vida excede ${Math.round(TIME_LIMIT / 60000)} minutos`);
|
|
125
|
+
}
|
|
126
|
+
if (poolWorker.tasksProcessed >= TASK_LIMIT) {
|
|
127
|
+
reasons.push(`tareas procesadas exceden ${TASK_LIMIT} (actual: ${poolWorker.tasksProcessed})`);
|
|
128
|
+
}
|
|
129
|
+
return reasons.join(', ');
|
|
130
|
+
} /**
|
|
131
|
+
* Limpia workers que han estado inactivos por mucho tiempo
|
|
132
|
+
*/
|
|
133
|
+
async cleanupInactiveWorkers() {
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
const INACTIVE_TIMEOUT = 5 * 60 * 1000; // 5 minutos (reducido)
|
|
136
|
+
for (const poolWorker of this.workers) {
|
|
137
|
+
const timeSinceLastActivity = now - poolWorker.lastActivityTime;
|
|
138
|
+
if (timeSinceLastActivity > INACTIVE_TIMEOUT &&
|
|
139
|
+
!poolWorker.busy &&
|
|
140
|
+
poolWorker.pendingTasks.size === 0) {
|
|
141
|
+
console.info(`[WorkerPool] Worker ${poolWorker.id} inactivo por ${Math.round(timeSinceLastActivity / 60000)} minutos, reciclando...`);
|
|
142
|
+
await this.recycleWorker(poolWorker);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} /**
|
|
146
|
+
* Verifica si un worker debe ser reciclado por límites de memoria/tiempo
|
|
147
|
+
*/
|
|
148
|
+
shouldRecycleWorker(poolWorker) {
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const MEMORY_LIMIT = 30 * 1024 * 1024; // 30MB (reducido)
|
|
151
|
+
const TIME_LIMIT = 15 * 60 * 1000; // 15 minutos (reducido)
|
|
152
|
+
const TASK_LIMIT = this.MAX_TASKS_PER_WORKER;
|
|
153
|
+
return (poolWorker.memoryUsage > MEMORY_LIMIT ||
|
|
154
|
+
now - poolWorker.creationTime > TIME_LIMIT ||
|
|
155
|
+
poolWorker.tasksProcessed >= TASK_LIMIT);
|
|
34
156
|
}
|
|
35
157
|
/**
|
|
36
158
|
* Obtiene la instancia singleton del Worker Pool
|
|
@@ -40,7 +162,8 @@ export class TypeScriptWorkerPool {
|
|
|
40
162
|
TypeScriptWorkerPool.instance = new TypeScriptWorkerPool();
|
|
41
163
|
}
|
|
42
164
|
return TypeScriptWorkerPool.instance;
|
|
43
|
-
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
44
167
|
* Configura el modo de operación del pool
|
|
45
168
|
*/
|
|
46
169
|
setMode(mode) {
|
|
@@ -72,7 +195,8 @@ export class TypeScriptWorkerPool {
|
|
|
72
195
|
}
|
|
73
196
|
/**
|
|
74
197
|
* Realiza la inicialización del pool de workers
|
|
75
|
-
*/
|
|
198
|
+
*/
|
|
199
|
+
async _performPoolInitialization() {
|
|
76
200
|
try {
|
|
77
201
|
// Verificar que el archivo del worker existe
|
|
78
202
|
const fs = await import('node:fs');
|
|
@@ -92,7 +216,8 @@ export class TypeScriptWorkerPool {
|
|
|
92
216
|
}
|
|
93
217
|
/**
|
|
94
218
|
* Crea un worker individual
|
|
95
|
-
*/
|
|
219
|
+
*/
|
|
220
|
+
async createWorker(workerId) {
|
|
96
221
|
return new Promise((resolve, reject) => {
|
|
97
222
|
try {
|
|
98
223
|
const worker = new Worker(this.workerPath, {
|
|
@@ -108,6 +233,12 @@ export class TypeScriptWorkerPool {
|
|
|
108
233
|
busy: false,
|
|
109
234
|
pendingTasks: new Map(),
|
|
110
235
|
taskCounter: 0,
|
|
236
|
+
// ✨ ISSUE #4: Inicializar controles de memoria
|
|
237
|
+
memoryUsage: 0,
|
|
238
|
+
lastMemoryCheck: Date.now(),
|
|
239
|
+
tasksProcessed: 0,
|
|
240
|
+
creationTime: Date.now(),
|
|
241
|
+
lastActivityTime: Date.now(),
|
|
111
242
|
};
|
|
112
243
|
// Configurar listeners
|
|
113
244
|
this.setupWorkerListeners(poolWorker);
|
|
@@ -141,7 +272,8 @@ export class TypeScriptWorkerPool {
|
|
|
141
272
|
}
|
|
142
273
|
/**
|
|
143
274
|
* Configura los listeners para un worker individual
|
|
144
|
-
*/
|
|
275
|
+
*/
|
|
276
|
+
setupWorkerListeners(poolWorker) {
|
|
145
277
|
const { worker } = poolWorker;
|
|
146
278
|
worker.on('message', (response) => {
|
|
147
279
|
try {
|
|
@@ -149,7 +281,12 @@ export class TypeScriptWorkerPool {
|
|
|
149
281
|
if (response.id === 'worker-ready' ||
|
|
150
282
|
response.message === 'pong') {
|
|
151
283
|
return;
|
|
152
|
-
}
|
|
284
|
+
}
|
|
285
|
+
// ✨ ISSUE #4: Manejar reportes de memoria del worker
|
|
286
|
+
if (response.type === 'memory-usage') {
|
|
287
|
+
return; // Ya manejado en getWorkerMemoryUsage
|
|
288
|
+
}
|
|
289
|
+
// Buscar la tarea pendiente
|
|
153
290
|
const pendingTask = poolWorker.pendingTasks.get(response.id);
|
|
154
291
|
if (!pendingTask) {
|
|
155
292
|
return;
|
|
@@ -161,20 +298,26 @@ export class TypeScriptWorkerPool {
|
|
|
161
298
|
if (poolWorker.pendingTasks.size === 0) {
|
|
162
299
|
poolWorker.busy = false;
|
|
163
300
|
}
|
|
164
|
-
//
|
|
301
|
+
// Actualizar actividad del worker
|
|
302
|
+
poolWorker.lastActivityTime = Date.now();
|
|
303
|
+
// ✨ ISSUE #4: Manejo mejorado de errores de TypeScript
|
|
165
304
|
if (response.success &&
|
|
166
305
|
response.diagnostics !== undefined &&
|
|
167
306
|
response.hasErrors !== undefined) {
|
|
168
307
|
this.completedTasks++;
|
|
169
|
-
|
|
308
|
+
// Analizar y categorizar errores de TypeScript
|
|
309
|
+
const categorizedResult = this.categorizeTypeScriptErrors({
|
|
170
310
|
diagnostics: response.diagnostics,
|
|
171
311
|
hasErrors: response.hasErrors,
|
|
172
|
-
});
|
|
312
|
+
}, pendingTask.fileName);
|
|
313
|
+
pendingTask.resolve(categorizedResult);
|
|
173
314
|
}
|
|
174
315
|
else {
|
|
175
316
|
this.failedTasks++;
|
|
176
317
|
const errorMessage = response.error || 'Error desconocido del worker';
|
|
177
|
-
|
|
318
|
+
// ✨ Crear error categorizado
|
|
319
|
+
const categorizedError = this.createCategorizedError(errorMessage, pendingTask.fileName, response);
|
|
320
|
+
pendingTask.reject(categorizedError);
|
|
178
321
|
}
|
|
179
322
|
}
|
|
180
323
|
catch {
|
|
@@ -190,7 +333,8 @@ export class TypeScriptWorkerPool {
|
|
|
190
333
|
}
|
|
191
334
|
/**
|
|
192
335
|
* Maneja errores de un worker específico con cleanup completo
|
|
193
|
-
*/
|
|
336
|
+
*/
|
|
337
|
+
async handleWorkerError(poolWorker, error) {
|
|
194
338
|
console.warn(`[WorkerPool] Manejando error del worker ${poolWorker.id}:`, error.message);
|
|
195
339
|
// 1. Rechazar todas las tareas pendientes con cleanup de timeouts
|
|
196
340
|
poolWorker.pendingTasks.forEach(task => {
|
|
@@ -222,7 +366,8 @@ export class TypeScriptWorkerPool {
|
|
|
222
366
|
console.error(`[WorkerPool] No se pudo recrear worker ${poolWorker.id}:`, recreateError);
|
|
223
367
|
}
|
|
224
368
|
}
|
|
225
|
-
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
226
371
|
* Maneja la salida inesperada de un worker con cleanup completo
|
|
227
372
|
*/
|
|
228
373
|
async handleWorkerExit(poolWorker, code) {
|
|
@@ -254,7 +399,8 @@ export class TypeScriptWorkerPool {
|
|
|
254
399
|
}
|
|
255
400
|
/**
|
|
256
401
|
* Recrea un worker que falló
|
|
257
|
-
*/
|
|
402
|
+
*/
|
|
403
|
+
async recreateWorker(failedWorker) {
|
|
258
404
|
try {
|
|
259
405
|
const newWorker = await this.createWorker(failedWorker.id);
|
|
260
406
|
// Reemplazar en el array
|
|
@@ -272,7 +418,8 @@ export class TypeScriptWorkerPool {
|
|
|
272
418
|
*/
|
|
273
419
|
async recycleWorker(poolWorker) {
|
|
274
420
|
try {
|
|
275
|
-
console.log(`[WorkerPool] Reciclando worker ${poolWorker.id} después de ${poolWorker.taskCounter} tareas`);
|
|
421
|
+
console.log(`[WorkerPool] Reciclando worker ${poolWorker.id} después de ${poolWorker.taskCounter} tareas`);
|
|
422
|
+
// 1. Esperar a que termine tareas pendientes (timeout corto)
|
|
276
423
|
const maxWait = 2000; // 2 segundos máximo
|
|
277
424
|
const startTime = Date.now();
|
|
278
425
|
await new Promise(resolve => {
|
|
@@ -353,7 +500,8 @@ export class TypeScriptWorkerPool {
|
|
|
353
500
|
catch {
|
|
354
501
|
return this.typeCheckWithSyncFallback(fileName, content, compilerOptions);
|
|
355
502
|
}
|
|
356
|
-
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
357
505
|
* Realiza type checking usando un worker específico con reciclaje automático
|
|
358
506
|
*/
|
|
359
507
|
async typeCheckWithWorker(poolWorker, fileName, content, compilerOptions) {
|
|
@@ -363,16 +511,20 @@ export class TypeScriptWorkerPool {
|
|
|
363
511
|
}
|
|
364
512
|
return new Promise((resolve, reject) => {
|
|
365
513
|
const taskId = `task-${poolWorker.id}-${++poolWorker.taskCounter}-${Date.now()}`;
|
|
366
|
-
// Marcar worker como ocupado
|
|
514
|
+
// Marcar worker como ocupado y actualizar actividad
|
|
367
515
|
poolWorker.busy = true;
|
|
516
|
+
poolWorker.lastActivityTime = Date.now();
|
|
517
|
+
poolWorker.tasksProcessed++;
|
|
518
|
+
// ✨ ISSUE #4: Timeout dinámico basado en complejidad del archivo
|
|
519
|
+
const dynamicTimeout = this.calculateDynamicTimeout(fileName, content, compilerOptions);
|
|
368
520
|
// Configurar timeout para la tarea
|
|
369
521
|
const timeout = setTimeout(() => {
|
|
370
522
|
poolWorker.pendingTasks.delete(taskId);
|
|
371
523
|
if (poolWorker.pendingTasks.size === 0) {
|
|
372
524
|
poolWorker.busy = false;
|
|
373
525
|
}
|
|
374
|
-
reject(new Error(`Timeout en type checking para ${fileName}`));
|
|
375
|
-
},
|
|
526
|
+
reject(new Error(`Timeout (${dynamicTimeout}ms) en type checking para ${fileName} - archivo complejo detectado`));
|
|
527
|
+
}, dynamicTimeout);
|
|
376
528
|
// Agregar tarea a la lista de pendientes del worker
|
|
377
529
|
poolWorker.pendingTasks.set(taskId, {
|
|
378
530
|
resolve,
|
|
@@ -382,12 +534,16 @@ export class TypeScriptWorkerPool {
|
|
|
382
534
|
startTime: Date.now(),
|
|
383
535
|
});
|
|
384
536
|
try {
|
|
385
|
-
// Crear mensaje para el worker
|
|
537
|
+
// Crear mensaje para el worker con configuración de timeout
|
|
386
538
|
const message = {
|
|
387
539
|
id: taskId,
|
|
388
540
|
fileName,
|
|
389
541
|
content,
|
|
390
|
-
compilerOptions
|
|
542
|
+
compilerOptions: {
|
|
543
|
+
...compilerOptions,
|
|
544
|
+
// ✨ Añadir timeout al worker para manejo interno
|
|
545
|
+
_workerTimeout: dynamicTimeout - 1000, // 1 segundo menos para cleanup interno
|
|
546
|
+
},
|
|
391
547
|
};
|
|
392
548
|
// Enviar mensaje al worker
|
|
393
549
|
poolWorker.worker.postMessage(message);
|
|
@@ -403,6 +559,59 @@ export class TypeScriptWorkerPool {
|
|
|
403
559
|
}
|
|
404
560
|
});
|
|
405
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* Calcula un timeout dinámico basado en la complejidad del archivo TypeScript
|
|
564
|
+
*/
|
|
565
|
+
calculateDynamicTimeout(fileName, content, compilerOptions) {
|
|
566
|
+
const baseTimeout = this.TASK_TIMEOUT; // 10 segundos base
|
|
567
|
+
let complexityMultiplier = 1;
|
|
568
|
+
// Factor 1: Tamaño del archivo
|
|
569
|
+
const contentLength = content.length;
|
|
570
|
+
if (contentLength > 100000) {
|
|
571
|
+
// Archivos > 100KB
|
|
572
|
+
complexityMultiplier += 1.5;
|
|
573
|
+
}
|
|
574
|
+
else if (contentLength > 50000) {
|
|
575
|
+
// Archivos > 50KB
|
|
576
|
+
complexityMultiplier += 1;
|
|
577
|
+
}
|
|
578
|
+
else if (contentLength > 20000) {
|
|
579
|
+
// Archivos > 20KB
|
|
580
|
+
complexityMultiplier += 0.5;
|
|
581
|
+
}
|
|
582
|
+
// Factor 2: Complejidad sintáctica
|
|
583
|
+
const importCount = (content.match(/^import\s+/gm) || []).length;
|
|
584
|
+
const typeCount = (content.match(/\btype\s+\w+/g) || []).length;
|
|
585
|
+
const interfaceCount = (content.match(/\binterface\s+\w+/g) || [])
|
|
586
|
+
.length;
|
|
587
|
+
const genericCount = (content.match(/<[^>]*>/g) || []).length;
|
|
588
|
+
const complexConstructs = importCount + typeCount + interfaceCount + genericCount * 0.5;
|
|
589
|
+
if (complexConstructs > 100) {
|
|
590
|
+
complexityMultiplier += 2;
|
|
591
|
+
}
|
|
592
|
+
else if (complexConstructs > 50) {
|
|
593
|
+
complexityMultiplier += 1;
|
|
594
|
+
}
|
|
595
|
+
else if (complexConstructs > 20) {
|
|
596
|
+
complexityMultiplier += 0.5;
|
|
597
|
+
}
|
|
598
|
+
// Factor 3: Configuración de TypeScript estricta
|
|
599
|
+
if (compilerOptions?.strict || compilerOptions?.noImplicitAny) {
|
|
600
|
+
complexityMultiplier += 0.3;
|
|
601
|
+
}
|
|
602
|
+
// Factor 4: Extensión de archivo compleja (.d.ts, .vue.ts, etc.)
|
|
603
|
+
if (fileName.includes('.d.ts')) {
|
|
604
|
+
complexityMultiplier += 1; // Los archivos de definición son más complejos
|
|
605
|
+
}
|
|
606
|
+
else if (fileName.includes('.vue')) {
|
|
607
|
+
complexityMultiplier += 0.5; // Los archivos Vue requieren procesamiento adicional
|
|
608
|
+
}
|
|
609
|
+
// Aplicar límites razonables
|
|
610
|
+
complexityMultiplier = Math.min(complexityMultiplier, 5); // Máximo 5x el timeout base
|
|
611
|
+
complexityMultiplier = Math.max(complexityMultiplier, 0.5); // Mínimo 0.5x el timeout base
|
|
612
|
+
const finalTimeout = Math.round(baseTimeout * complexityMultiplier);
|
|
613
|
+
return Math.min(finalTimeout, 60000); // Máximo absoluto de 60 segundos
|
|
614
|
+
}
|
|
406
615
|
/**
|
|
407
616
|
* Fallback síncrono para type checking
|
|
408
617
|
*/
|
|
@@ -419,7 +628,8 @@ export class TypeScriptWorkerPool {
|
|
|
419
628
|
}
|
|
420
629
|
/**
|
|
421
630
|
* Cierra todos los workers del pool con cleanup completo
|
|
422
|
-
*/
|
|
631
|
+
*/
|
|
632
|
+
async terminate() {
|
|
423
633
|
console.log('[WorkerPool] Cerrando pool de workers...');
|
|
424
634
|
// 1. Rechazar todas las tareas pendientes con cleanup
|
|
425
635
|
let totalPendingTasks = 0;
|
|
@@ -440,7 +650,8 @@ export class TypeScriptWorkerPool {
|
|
|
440
650
|
}
|
|
441
651
|
if (totalPendingTasks > 0) {
|
|
442
652
|
console.log(`[WorkerPool] Se cancelaron ${totalPendingTasks} tareas pendientes`);
|
|
443
|
-
}
|
|
653
|
+
}
|
|
654
|
+
// 2. Cerrar todos los workers con manejo de errores
|
|
444
655
|
const terminatePromises = this.workers.map(async (poolWorker) => {
|
|
445
656
|
try {
|
|
446
657
|
await poolWorker.worker.terminate();
|
|
@@ -475,5 +686,157 @@ export class TypeScriptWorkerPool {
|
|
|
475
686
|
successRate,
|
|
476
687
|
};
|
|
477
688
|
}
|
|
689
|
+
// ✨ ISSUE #4: Métodos de categorización de errores de TypeScript
|
|
690
|
+
/**
|
|
691
|
+
* Categoriza y mejora los errores de TypeScript para mejor debugging
|
|
692
|
+
*/
|
|
693
|
+
categorizeTypeScriptErrors(result, fileName) {
|
|
694
|
+
if (!result.hasErrors || !result.diagnostics?.length) {
|
|
695
|
+
return result;
|
|
696
|
+
}
|
|
697
|
+
const categorizedDiagnostics = result.diagnostics.map(diagnostic => {
|
|
698
|
+
// Añadir metadatos útiles para debugging
|
|
699
|
+
const enhanced = {
|
|
700
|
+
...diagnostic,
|
|
701
|
+
_category: this.getErrorCategory(diagnostic),
|
|
702
|
+
_severity: this.getErrorSeverity(diagnostic),
|
|
703
|
+
_fileName: fileName,
|
|
704
|
+
_timestamp: Date.now(),
|
|
705
|
+
};
|
|
706
|
+
return enhanced;
|
|
707
|
+
});
|
|
708
|
+
return {
|
|
709
|
+
...result,
|
|
710
|
+
diagnostics: categorizedDiagnostics,
|
|
711
|
+
// Añadir estadísticas de errores
|
|
712
|
+
_errorStats: this.calculateErrorStats(categorizedDiagnostics),
|
|
713
|
+
};
|
|
714
|
+
} /**
|
|
715
|
+
* Determina la categoría de un error de TypeScript
|
|
716
|
+
*/
|
|
717
|
+
getErrorCategory(diagnostic) {
|
|
718
|
+
const code = diagnostic.code;
|
|
719
|
+
// Categorización basada en códigos de error comunes
|
|
720
|
+
if ([2304, 2339, 2346].includes(code)) {
|
|
721
|
+
return 'MISSING_DECLARATION'; // No puede encontrar nombre/propiedad
|
|
722
|
+
}
|
|
723
|
+
else if ([2322, 2322, 2345].includes(code)) {
|
|
724
|
+
return 'TYPE_MISMATCH'; // Error de tipos
|
|
725
|
+
}
|
|
726
|
+
else if ([2307, 2317].includes(code)) {
|
|
727
|
+
return 'MODULE_RESOLUTION'; // Error de resolución de módulos
|
|
728
|
+
}
|
|
729
|
+
else if ([2552, 2551].includes(code)) {
|
|
730
|
+
return 'PROPERTY_ACCESS'; // Error de acceso a propiedades
|
|
731
|
+
}
|
|
732
|
+
else if (code >= 1000 && code < 2000) {
|
|
733
|
+
return 'SYNTAX_ERROR'; // Errores de sintaxis
|
|
734
|
+
}
|
|
735
|
+
else if (code >= 2000 && code < 3000) {
|
|
736
|
+
return 'SEMANTIC_ERROR'; // Errores semánticos
|
|
737
|
+
}
|
|
738
|
+
else if (code >= 4000) {
|
|
739
|
+
return 'CONFIG_ERROR'; // Errores de configuración
|
|
740
|
+
}
|
|
741
|
+
return 'OTHER';
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Determina la severidad de un error de TypeScript
|
|
745
|
+
*/
|
|
746
|
+
getErrorSeverity(diagnostic) {
|
|
747
|
+
const category = diagnostic.category;
|
|
748
|
+
switch (category) {
|
|
749
|
+
case 1:
|
|
750
|
+
return 'ERROR'; // typescript.DiagnosticCategory.Error
|
|
751
|
+
case 2:
|
|
752
|
+
return 'WARNING'; // typescript.DiagnosticCategory.Warning
|
|
753
|
+
case 3:
|
|
754
|
+
return 'INFO'; // typescript.DiagnosticCategory.Message
|
|
755
|
+
default:
|
|
756
|
+
return 'ERROR';
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Calcula estadísticas de errores para análisis
|
|
761
|
+
*/
|
|
762
|
+
calculateErrorStats(diagnostics) {
|
|
763
|
+
const stats = {
|
|
764
|
+
totalErrors: diagnostics.length,
|
|
765
|
+
errorsByCategory: {},
|
|
766
|
+
errorsBySeverity: {},
|
|
767
|
+
mostCommonError: null,
|
|
768
|
+
};
|
|
769
|
+
// Contar por categoría y severidad
|
|
770
|
+
diagnostics.forEach(diag => {
|
|
771
|
+
const category = diag._category || 'OTHER';
|
|
772
|
+
const severity = diag._severity || 'ERROR';
|
|
773
|
+
stats.errorsByCategory[category] =
|
|
774
|
+
(stats.errorsByCategory[category] || 0) + 1;
|
|
775
|
+
stats.errorsBySeverity[severity] =
|
|
776
|
+
(stats.errorsBySeverity[severity] || 0) + 1;
|
|
777
|
+
}); // Encontrar el error más común
|
|
778
|
+
const errorCounts = {};
|
|
779
|
+
diagnostics.forEach(diag => {
|
|
780
|
+
const code = String(diag.code);
|
|
781
|
+
errorCounts[code] = (errorCounts[code] || 0) + 1;
|
|
782
|
+
});
|
|
783
|
+
const errorCountKeys = Object.keys(errorCounts);
|
|
784
|
+
if (errorCountKeys.length > 0) {
|
|
785
|
+
const mostCommonCode = errorCountKeys.reduce((a, b) => (errorCounts[a] || 0) > (errorCounts[b] || 0) ? a : b);
|
|
786
|
+
stats.mostCommonError = {
|
|
787
|
+
code: mostCommonCode,
|
|
788
|
+
count: errorCounts[mostCommonCode],
|
|
789
|
+
message: diagnostics.find(d => String(d.code) === mostCommonCode)?.messageText,
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
return stats;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Crea un error categorizado con información de contexto
|
|
796
|
+
*/
|
|
797
|
+
createCategorizedError(errorMessage, fileName, response) {
|
|
798
|
+
const error = new Error(errorMessage);
|
|
799
|
+
// Añadir metadatos del error
|
|
800
|
+
error.fileName = fileName;
|
|
801
|
+
error.timestamp = Date.now();
|
|
802
|
+
error.workerResponse = response;
|
|
803
|
+
error.category = this.categorizeGenericError(errorMessage);
|
|
804
|
+
error.isRecoverable = this.isRecoverableError(errorMessage);
|
|
805
|
+
return error;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Categoriza errores genéricos del worker
|
|
809
|
+
*/
|
|
810
|
+
categorizeGenericError(errorMessage) {
|
|
811
|
+
if (errorMessage.includes('timeout') ||
|
|
812
|
+
errorMessage.includes('Timeout')) {
|
|
813
|
+
return 'TIMEOUT';
|
|
814
|
+
}
|
|
815
|
+
else if (errorMessage.includes('memory') ||
|
|
816
|
+
errorMessage.includes('Memory')) {
|
|
817
|
+
return 'MEMORY';
|
|
818
|
+
}
|
|
819
|
+
else if (errorMessage.includes('Worker') &&
|
|
820
|
+
errorMessage.includes('exited')) {
|
|
821
|
+
return 'WORKER_CRASH';
|
|
822
|
+
}
|
|
823
|
+
else if (errorMessage.includes('initialization') ||
|
|
824
|
+
errorMessage.includes('init')) {
|
|
825
|
+
return 'INITIALIZATION';
|
|
826
|
+
}
|
|
827
|
+
return 'UNKNOWN';
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Determina si un error es recuperable
|
|
831
|
+
*/
|
|
832
|
+
isRecoverableError(errorMessage) {
|
|
833
|
+
const recoverablePatterns = [
|
|
834
|
+
'timeout',
|
|
835
|
+
'Worker being recycled',
|
|
836
|
+
'Worker pool cerrado',
|
|
837
|
+
'temporary',
|
|
838
|
+
];
|
|
839
|
+
return recoverablePatterns.some(pattern => errorMessage.toLowerCase().includes(pattern.toLowerCase()));
|
|
840
|
+
}
|
|
478
841
|
}
|
|
479
842
|
//# sourceMappingURL=typescript-worker-pool.js.map
|
|
@@ -158,9 +158,8 @@ class WorkerTypeScriptLanguageServiceHost {
|
|
|
158
158
|
*/
|
|
159
159
|
function validateTypesInWorker(fileName, content, compilerOptions) {
|
|
160
160
|
let actualFileName = fileName;
|
|
161
|
-
|
|
162
161
|
try {
|
|
163
|
-
|
|
162
|
+
const scriptContent = content;
|
|
164
163
|
|
|
165
164
|
// Si el script está vacío o es solo espacios en blanco, no validar
|
|
166
165
|
if (!scriptContent.trim()) {
|
|
@@ -56,7 +56,7 @@ function getVueInstanceFromElement(selector = '#app') {
|
|
|
56
56
|
function findVueInstanceInDOM() {
|
|
57
57
|
const allElements = document.querySelectorAll('*');
|
|
58
58
|
|
|
59
|
-
for (
|
|
59
|
+
for (const element of allElements) {
|
|
60
60
|
// Vue 3
|
|
61
61
|
if (element.__vue_app__) {
|
|
62
62
|
return element.__vue_app__;
|
package/dist/hrm/initHRM.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { hideErrorOverlay, showErrorOverlay } from './errorScreen.js';
|
|
13
|
-
import obtenerInstanciaVue from './getInstanciaVue.js';
|
|
13
|
+
import { obtenerInstanciaVue } from './getInstanciaVue.js';
|
|
14
14
|
import { reloadComponent } from './VueHRM.js';
|
|
15
15
|
|
|
16
16
|
/**
|