versacompiler 2.0.1 → 2.0.2

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