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.
@@ -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 = 10000; // 10 segundos por tarea
21
+ TASK_TIMEOUT = 15000; // 15 segundos por tarea (aumentado)
22
22
  WORKER_INIT_TIMEOUT = 5000; // 5 segundos para inicializar
23
- MAX_TASKS_PER_WORKER = 50; // Máximo de tareas por worker antes de reciclaje
24
- WORKER_MEMORY_CHECK_INTERVAL = 100; // Verificar cada 100 tareas
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
- */ async _performPoolInitialization() {
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
- */ async createWorker(workerId) {
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
- */ setupWorkerListeners(poolWorker) {
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
- } // Buscar la tarea pendiente
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
- // Procesar respuesta
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
- pendingTask.resolve({
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
- pendingTask.reject(new Error(errorMessage));
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
- */ async handleWorkerError(poolWorker, error) {
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
- */ async recreateWorker(failedWorker) {
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`); // 1. Esperar a que termine tareas pendientes (timeout corto)
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
- }, this.TASK_TIMEOUT);
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
- */ async terminate() {
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
- } // 2. Cerrar todos los workers con manejo de errores
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
- let scriptContent = content;
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 (let element of allElements) {
59
+ for (const element of allElements) {
60
60
  // Vue 3
61
61
  if (element.__vue_app__) {
62
62
  return element.__vue_app__;
@@ -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
  /**