versacompiler 2.0.7 → 2.0.8

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.
Files changed (39) hide show
  1. package/dist/compiler/compile.js +26 -2332
  2. package/dist/compiler/error-reporter.js +38 -467
  3. package/dist/compiler/linter.js +1 -72
  4. package/dist/compiler/minify.js +1 -229
  5. package/dist/compiler/module-resolution-optimizer.js +1 -821
  6. package/dist/compiler/parser.js +1 -203
  7. package/dist/compiler/performance-monitor.js +56 -192
  8. package/dist/compiler/tailwindcss.js +1 -39
  9. package/dist/compiler/transform-optimizer.js +1 -392
  10. package/dist/compiler/transformTStoJS.js +1 -16
  11. package/dist/compiler/transforms.js +1 -550
  12. package/dist/compiler/typescript-compiler.js +2 -172
  13. package/dist/compiler/typescript-error-parser.js +10 -281
  14. package/dist/compiler/typescript-manager.js +2 -273
  15. package/dist/compiler/typescript-sync-validator.js +31 -295
  16. package/dist/compiler/typescript-worker-pool.js +1 -842
  17. package/dist/compiler/typescript-worker-thread.cjs +41 -466
  18. package/dist/compiler/typescript-worker.js +1 -339
  19. package/dist/compiler/vuejs.js +37 -392
  20. package/dist/hrm/VueHRM.js +1 -353
  21. package/dist/hrm/errorScreen.js +1 -83
  22. package/dist/hrm/getInstanciaVue.js +1 -313
  23. package/dist/hrm/initHRM.js +1 -141
  24. package/dist/main.js +7 -347
  25. package/dist/servicios/browserSync.js +5 -501
  26. package/dist/servicios/file-watcher.js +4 -379
  27. package/dist/servicios/logger.js +3 -63
  28. package/dist/servicios/readConfig.js +105 -430
  29. package/dist/utils/excluded-modules.js +1 -36
  30. package/dist/utils/module-resolver.js +1 -466
  31. package/dist/utils/promptUser.js +2 -48
  32. package/dist/utils/proxyValidator.js +1 -68
  33. package/dist/utils/resolve-bin.js +1 -48
  34. package/dist/utils/utils.js +1 -21
  35. package/dist/utils/vue-types-setup.js +241 -435
  36. package/dist/wrappers/eslint-node.js +1 -145
  37. package/dist/wrappers/oxlint-node.js +1 -120
  38. package/dist/wrappers/tailwind-node.js +1 -92
  39. package/package.json +36 -35
@@ -1,842 +1 @@
1
- /**
2
- * TypeScript Worker Pool - Pool de workers para compilación paralela
3
- * Reemplaza el worker único con múltiples workers para aprovecha la concurrencia real
4
- */
5
- import * as os from 'node:os';
6
- import * as path from 'node:path';
7
- import * as process from 'node:process';
8
- import { Worker } from 'node:worker_threads';
9
- import { validateTypesWithLanguageService } from './typescript-sync-validator.js';
10
- /**
11
- * Pool de workers para compilación TypeScript paralela
12
- * Distribuye las tareas entre múltiples workers para mayor rendimiento
13
- */
14
- export class TypeScriptWorkerPool {
15
- static instance;
16
- workers = [];
17
- poolSize;
18
- workerPath;
19
- initPromise = null;
20
- isInitialized = false; // Configuración optimizada con reciclaje de workers
21
- TASK_TIMEOUT = 15000; // 15 segundos por tarea (aumentado)
22
- WORKER_INIT_TIMEOUT = 5000; // 5 segundos para inicializar
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
- // Métricas de rendimiento
26
- totalTasks = 0;
27
- completedTasks = 0;
28
- failedTasks = 0;
29
- constructor() {
30
- // Determinar tamaño óptimo del pool
31
- const cpuCount = os.cpus().length;
32
- this.poolSize = Math.min(Math.max(cpuCount - 1, 2), 8); // Entre 2 y 8 workers
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);
156
- }
157
- /**
158
- * Obtiene la instancia singleton del Worker Pool
159
- */
160
- static getInstance() {
161
- if (!TypeScriptWorkerPool.instance) {
162
- TypeScriptWorkerPool.instance = new TypeScriptWorkerPool();
163
- }
164
- return TypeScriptWorkerPool.instance;
165
- }
166
- /**
167
- * Configura el modo de operación del pool
168
- */
169
- setMode(mode) {
170
- // Ajustar configuración según el modo
171
- switch (mode) {
172
- case 'batch':
173
- // Para modo batch, optimizar para throughput
174
- this.poolSize = Math.min(os.cpus().length, 12);
175
- break;
176
- case 'watch':
177
- // Para modo watch, menos workers pero más responsivos
178
- this.poolSize = Math.min(Math.max(os.cpus().length / 2, 2), 6);
179
- break;
180
- case 'individual':
181
- // Para individual, pool pequeño
182
- this.poolSize = Math.min(4, os.cpus().length);
183
- break;
184
- }
185
- }
186
- /**
187
- * Inicializa el pool de workers
188
- */
189
- async initializePool() {
190
- if (this.initPromise) {
191
- return this.initPromise;
192
- }
193
- this.initPromise = this._performPoolInitialization();
194
- return this.initPromise;
195
- }
196
- /**
197
- * Realiza la inicialización del pool de workers
198
- */
199
- async _performPoolInitialization() {
200
- try {
201
- // Verificar que el archivo del worker existe
202
- const fs = await import('node:fs');
203
- const exists = fs.existsSync(this.workerPath);
204
- if (!exists) {
205
- throw new Error(`Worker thread file not found: ${this.workerPath}`);
206
- }
207
- // Crear workers en paralelo
208
- const workerPromises = Array.from({ length: this.poolSize }, (_, index) => this.createWorker(index));
209
- this.workers = await Promise.all(workerPromises);
210
- this.isInitialized = true;
211
- }
212
- catch (error) {
213
- this.isInitialized = false;
214
- throw error;
215
- }
216
- }
217
- /**
218
- * Crea un worker individual
219
- */
220
- async createWorker(workerId) {
221
- return new Promise((resolve, reject) => {
222
- try {
223
- const worker = new Worker(this.workerPath, {
224
- env: {
225
- ...process.env,
226
- NODE_OPTIONS: '',
227
- WORKER_ID: workerId.toString(),
228
- },
229
- });
230
- const poolWorker = {
231
- worker,
232
- id: workerId,
233
- busy: false,
234
- pendingTasks: new Map(),
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(),
242
- };
243
- // Configurar listeners
244
- this.setupWorkerListeners(poolWorker);
245
- // Timeout para inicialización
246
- const initTimeout = setTimeout(() => {
247
- reject(new Error(`Worker ${workerId} initialization timeout`));
248
- }, this.WORKER_INIT_TIMEOUT);
249
- // Esperar que el worker esté listo
250
- const checkReady = () => {
251
- worker.postMessage({ type: 'ping' });
252
- };
253
- worker.on('message', function readyHandler(response) {
254
- if (response.id === 'worker-ready' ||
255
- response.message === 'pong') {
256
- clearTimeout(initTimeout);
257
- worker.off('message', readyHandler);
258
- resolve(poolWorker);
259
- }
260
- });
261
- worker.on('error', error => {
262
- clearTimeout(initTimeout);
263
- reject(error);
264
- });
265
- // Intentar conectar
266
- checkReady();
267
- }
268
- catch (error) {
269
- reject(error);
270
- }
271
- });
272
- }
273
- /**
274
- * Configura los listeners para un worker individual
275
- */
276
- setupWorkerListeners(poolWorker) {
277
- const { worker } = poolWorker;
278
- worker.on('message', (response) => {
279
- try {
280
- // Ignorar mensajes de control
281
- if (response.id === 'worker-ready' ||
282
- response.message === 'pong') {
283
- return;
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
290
- const pendingTask = poolWorker.pendingTasks.get(response.id);
291
- if (!pendingTask) {
292
- return;
293
- }
294
- // Limpiar timeout y eliminar tarea
295
- clearTimeout(pendingTask.timeout);
296
- poolWorker.pendingTasks.delete(response.id);
297
- // Marcar worker como disponible si no tiene más tareas
298
- if (poolWorker.pendingTasks.size === 0) {
299
- poolWorker.busy = false;
300
- }
301
- // Actualizar actividad del worker
302
- poolWorker.lastActivityTime = Date.now();
303
- // ✨ ISSUE #4: Manejo mejorado de errores de TypeScript
304
- if (response.success &&
305
- response.diagnostics !== undefined &&
306
- response.hasErrors !== undefined) {
307
- this.completedTasks++;
308
- // Analizar y categorizar errores de TypeScript
309
- const categorizedResult = this.categorizeTypeScriptErrors({
310
- diagnostics: response.diagnostics,
311
- hasErrors: response.hasErrors,
312
- }, pendingTask.fileName);
313
- pendingTask.resolve(categorizedResult);
314
- }
315
- else {
316
- this.failedTasks++;
317
- const errorMessage = response.error || 'Error desconocido del worker';
318
- // ✨ Crear error categorizado
319
- const categorizedError = this.createCategorizedError(errorMessage, pendingTask.fileName, response);
320
- pendingTask.reject(categorizedError);
321
- }
322
- }
323
- catch {
324
- // Error silencioso - no imprimir cada error
325
- }
326
- });
327
- worker.on('error', async (error) => {
328
- await this.handleWorkerError(poolWorker, error);
329
- });
330
- worker.on('exit', async (code) => {
331
- await this.handleWorkerExit(poolWorker, code);
332
- });
333
- }
334
- /**
335
- * Maneja errores de un worker específico con cleanup completo
336
- */
337
- async handleWorkerError(poolWorker, error) {
338
- console.warn(`[WorkerPool] Manejando error del worker ${poolWorker.id}:`, error.message);
339
- // 1. Rechazar todas las tareas pendientes con cleanup de timeouts
340
- poolWorker.pendingTasks.forEach(task => {
341
- clearTimeout(task.timeout);
342
- this.failedTasks++;
343
- task.reject(new Error(`Worker ${poolWorker.id} failed: ${error.message}`));
344
- });
345
- poolWorker.pendingTasks.clear();
346
- // 2. Terminar worker correctamente para evitar memory leaks
347
- try {
348
- poolWorker.worker.removeAllListeners();
349
- await poolWorker.worker.terminate();
350
- }
351
- catch (terminateError) {
352
- console.error(`[WorkerPool] Error terminando worker ${poolWorker.id}:`, terminateError);
353
- }
354
- // 3. Marcar como no disponible
355
- poolWorker.busy = false;
356
- // 4. Recrear worker si el pool está activo
357
- if (this.isInitialized && this.workers.length > 0) {
358
- try {
359
- const newWorker = await this.createWorker(poolWorker.id);
360
- const index = this.workers.findIndex(w => w.id === poolWorker.id);
361
- if (index !== -1) {
362
- this.workers[index] = newWorker;
363
- }
364
- }
365
- catch (recreateError) {
366
- console.error(`[WorkerPool] No se pudo recrear worker ${poolWorker.id}:`, recreateError);
367
- }
368
- }
369
- }
370
- /**
371
- * Maneja la salida inesperada de un worker con cleanup completo
372
- */
373
- async handleWorkerExit(poolWorker, code) {
374
- console.warn(`[WorkerPool] Worker ${poolWorker.id} salió con código ${code}`);
375
- // 1. Rechazar tareas pendientes con cleanup
376
- poolWorker.pendingTasks.forEach(task => {
377
- clearTimeout(task.timeout);
378
- this.failedTasks++;
379
- task.reject(new Error(`Worker ${poolWorker.id} exited with code ${code}`));
380
- });
381
- poolWorker.pendingTasks.clear();
382
- poolWorker.busy = false;
383
- // 2. Limpiar listeners para evitar memory leaks
384
- try {
385
- poolWorker.worker.removeAllListeners();
386
- }
387
- catch {
388
- // Error silencioso en cleanup
389
- }
390
- // 3. Recrear worker si es necesario y el pool está activo
391
- if (this.isInitialized && this.workers.length > 0) {
392
- try {
393
- await this.recreateWorker(poolWorker);
394
- }
395
- catch (recreateError) {
396
- console.error(`[WorkerPool] Error recreando worker ${poolWorker.id}:`, recreateError);
397
- }
398
- }
399
- }
400
- /**
401
- * Recrea un worker que falló
402
- */
403
- async recreateWorker(failedWorker) {
404
- try {
405
- const newWorker = await this.createWorker(failedWorker.id);
406
- // Reemplazar en el array
407
- const index = this.workers.findIndex(w => w.id === failedWorker.id);
408
- if (index !== -1) {
409
- this.workers[index] = newWorker;
410
- }
411
- }
412
- catch {
413
- // Error silencioso en recreación
414
- }
415
- }
416
- /**
417
- * Recicla un worker para prevenir memory leaks
418
- */
419
- async recycleWorker(poolWorker) {
420
- try {
421
- console.log(`[WorkerPool] Reciclando worker ${poolWorker.id} después de ${poolWorker.taskCounter} tareas`);
422
- // 1. Esperar a que termine tareas pendientes (timeout corto)
423
- const maxWait = 2000; // 2 segundos máximo
424
- const startTime = Date.now();
425
- await new Promise(resolve => {
426
- const checkPending = () => {
427
- if (poolWorker.pendingTasks.size === 0 ||
428
- Date.now() - startTime >= maxWait) {
429
- resolve();
430
- }
431
- else {
432
- setTimeout(checkPending, 100);
433
- }
434
- };
435
- checkPending();
436
- });
437
- // 2. Si aún hay tareas pendientes, rechazarlas
438
- if (poolWorker.pendingTasks.size > 0) {
439
- poolWorker.pendingTasks.forEach(task => {
440
- clearTimeout(task.timeout);
441
- task.reject(new Error('Worker being recycled'));
442
- });
443
- poolWorker.pendingTasks.clear();
444
- }
445
- // 3. Terminar worker actual
446
- poolWorker.worker.removeAllListeners();
447
- await poolWorker.worker.terminate();
448
- // 4. Crear nuevo worker
449
- const newWorker = await this.createWorker(poolWorker.id);
450
- // 5. Reemplazar en el array
451
- const index = this.workers.findIndex(w => w.id === poolWorker.id);
452
- if (index !== -1) {
453
- this.workers[index] = newWorker;
454
- }
455
- }
456
- catch (error) {
457
- console.error(`[WorkerPool] Error reciclando worker ${poolWorker.id}:`, error);
458
- }
459
- }
460
- /**
461
- * Encuentra el worker menos ocupado
462
- */
463
- findAvailableWorker() {
464
- // Buscar worker completamente libre
465
- const freeWorker = this.workers.find(w => !w.busy && w.pendingTasks.size === 0);
466
- if (freeWorker) {
467
- return freeWorker;
468
- }
469
- // Si no hay workers libres, buscar el menos ocupado
470
- const leastBusyWorker = this.workers.reduce((least, current) => {
471
- if (current.pendingTasks.size < least.pendingTasks.size) {
472
- return current;
473
- }
474
- return least;
475
- });
476
- // Solo devolver si no está demasiado ocupado
477
- if (leastBusyWorker.pendingTasks.size < 5) {
478
- return leastBusyWorker;
479
- }
480
- return null; // Todos los workers están muy ocupados
481
- }
482
- /**
483
- * Realiza type checking usando el pool de workers
484
- */
485
- async typeCheck(fileName, content, compilerOptions) {
486
- // Asegurar que el pool esté inicializado
487
- await this.initializePool();
488
- if (!this.isInitialized) {
489
- return this.typeCheckWithSyncFallback(fileName, content, compilerOptions);
490
- }
491
- // Buscar worker disponible
492
- const availableWorker = this.findAvailableWorker();
493
- if (!availableWorker) {
494
- return this.typeCheckWithSyncFallback(fileName, content, compilerOptions);
495
- }
496
- try {
497
- this.totalTasks++;
498
- return await this.typeCheckWithWorker(availableWorker, fileName, content, compilerOptions);
499
- }
500
- catch {
501
- return this.typeCheckWithSyncFallback(fileName, content, compilerOptions);
502
- }
503
- }
504
- /**
505
- * Realiza type checking usando un worker específico con reciclaje automático
506
- */
507
- async typeCheckWithWorker(poolWorker, fileName, content, compilerOptions) {
508
- // Verificar si el worker necesita reciclaje por número de tareas
509
- if (poolWorker.taskCounter >= this.MAX_TASKS_PER_WORKER) {
510
- await this.recycleWorker(poolWorker);
511
- }
512
- return new Promise((resolve, reject) => {
513
- const taskId = `task-${poolWorker.id}-${++poolWorker.taskCounter}-${Date.now()}`;
514
- // Marcar worker como ocupado y actualizar actividad
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);
520
- // Configurar timeout para la tarea
521
- const timeout = setTimeout(() => {
522
- poolWorker.pendingTasks.delete(taskId);
523
- if (poolWorker.pendingTasks.size === 0) {
524
- poolWorker.busy = false;
525
- }
526
- reject(new Error(`Timeout (${dynamicTimeout}ms) en type checking para ${fileName} - archivo complejo detectado`));
527
- }, dynamicTimeout);
528
- // Agregar tarea a la lista de pendientes del worker
529
- poolWorker.pendingTasks.set(taskId, {
530
- resolve,
531
- reject,
532
- timeout,
533
- fileName,
534
- startTime: Date.now(),
535
- });
536
- try {
537
- // Crear mensaje para el worker con configuración de timeout
538
- const message = {
539
- id: taskId,
540
- fileName,
541
- content,
542
- compilerOptions: {
543
- ...compilerOptions,
544
- // ✨ Añadir timeout al worker para manejo interno
545
- _workerTimeout: dynamicTimeout - 1000, // 1 segundo menos para cleanup interno
546
- },
547
- };
548
- // Enviar mensaje al worker
549
- poolWorker.worker.postMessage(message);
550
- }
551
- catch (error) {
552
- // Limpiar en caso de error
553
- clearTimeout(timeout);
554
- poolWorker.pendingTasks.delete(taskId);
555
- if (poolWorker.pendingTasks.size === 0) {
556
- poolWorker.busy = false;
557
- }
558
- reject(error);
559
- }
560
- });
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
- }
615
- /**
616
- * Fallback síncrono para type checking
617
- */
618
- typeCheckWithSyncFallback(fileName, content, compilerOptions) {
619
- try {
620
- return validateTypesWithLanguageService(fileName, content, compilerOptions);
621
- }
622
- catch {
623
- return {
624
- diagnostics: [],
625
- hasErrors: false,
626
- };
627
- }
628
- }
629
- /**
630
- * Cierra todos los workers del pool con cleanup completo
631
- */
632
- async terminate() {
633
- console.log('[WorkerPool] Cerrando pool de workers...');
634
- // 1. Rechazar todas las tareas pendientes con cleanup
635
- let totalPendingTasks = 0;
636
- for (const poolWorker of this.workers) {
637
- totalPendingTasks += poolWorker.pendingTasks.size;
638
- poolWorker.pendingTasks.forEach(task => {
639
- clearTimeout(task.timeout);
640
- task.reject(new Error('Worker pool cerrado'));
641
- });
642
- poolWorker.pendingTasks.clear();
643
- // Limpiar listeners para evitar memory leaks
644
- try {
645
- poolWorker.worker.removeAllListeners();
646
- }
647
- catch {
648
- // Error silencioso en cleanup
649
- }
650
- }
651
- if (totalPendingTasks > 0) {
652
- console.log(`[WorkerPool] Se cancelaron ${totalPendingTasks} tareas pendientes`);
653
- }
654
- // 2. Cerrar todos los workers con manejo de errores
655
- const terminatePromises = this.workers.map(async (poolWorker) => {
656
- try {
657
- await poolWorker.worker.terminate();
658
- }
659
- catch (error) {
660
- console.warn(`[WorkerPool] Error terminando worker ${poolWorker.id}:`, error);
661
- }
662
- });
663
- await Promise.allSettled(terminatePromises);
664
- // 3. Limpiar estado
665
- this.workers = [];
666
- this.isInitialized = false;
667
- this.initPromise = null;
668
- console.log(`[WorkerPool] Pool cerrado. Estadísticas finales: ${this.completedTasks} completadas, ${this.failedTasks} fallidas`);
669
- }
670
- /**
671
- * Obtiene estadísticas del pool
672
- */
673
- getStats() {
674
- const busyWorkers = this.workers.filter(w => w.busy).length;
675
- const totalPendingTasks = this.workers.reduce((sum, w) => sum + w.pendingTasks.size, 0);
676
- const successRate = this.totalTasks > 0
677
- ? Math.round((this.completedTasks / this.totalTasks) * 100)
678
- : 0;
679
- return {
680
- poolSize: this.workers.length,
681
- busyWorkers,
682
- totalPendingTasks,
683
- totalTasks: this.totalTasks,
684
- completedTasks: this.completedTasks,
685
- failedTasks: this.failedTasks,
686
- successRate,
687
- };
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
- }
841
- }
842
- //# sourceMappingURL=typescript-worker-pool.js.map
1
+ import*as e from"node:os";import*as t from"node:path";import*as n from"node:process";import{Worker as r}from"node:worker_threads";import{validateTypesWithLanguageService as i}from"./typescript-sync-validator.js";export class TypeScriptWorkerPool{static instance;workers=[];poolSize;workerPath;initPromise=null;isInitialized=!1;TASK_TIMEOUT=15e3;WORKER_INIT_TIMEOUT=5e3;MAX_TASKS_PER_WORKER=25;WORKER_MEMORY_CHECK_INTERVAL=50;totalTasks=0;completedTasks=0;failedTasks=0;constructor(){let r=e.cpus().length;this.poolSize=Math.min(Math.max(r-1,2),8),this.workerPath=t.join(n.env.PATH_PROY||t.join(n.cwd(),`src`),`compiler`,`typescript-worker-thread.cjs`)}startMemoryMonitoring(){setInterval(()=>{this.checkWorkersMemory()},15e3),setInterval(()=>{this.cleanupInactiveWorkers()},12e4)}async checkWorkersMemory(){let e=Date.now();for(let t of this.workers){t.lastMemoryCheck=e;try{let e=await this.getWorkerMemoryUsage(t);if(t.memoryUsage=e.heapUsed,this.shouldRecycleWorker(t)){let e=this.getRecycleReason(t);console.warn(`[WorkerPool] Worker ${t.id} requiere reciclaje: ${e}`),await this.recycleWorker(t)}}catch(e){console.warn(`[WorkerPool] Error verificando memoria del worker ${t.id}:`,e)}}}async getWorkerMemoryUsage(e){return new Promise(t=>{let n=setTimeout(()=>{t({heapUsed:e.tasksProcessed*2048,heapTotal:e.tasksProcessed*3072,rss:e.tasksProcessed*4096})},1e3),r=`memory-${e.id}-${Date.now()}`,i=a=>{a.id===r&&a.type===`memory-usage`&&(clearTimeout(n),e.worker.off(`message`,i),t({heapUsed:a.memoryUsage?.heapUsed||e.tasksProcessed*2048,heapTotal:a.memoryUsage?.heapTotal||e.tasksProcessed*3072,rss:a.memoryUsage?.rss||e.tasksProcessed*4096}))};e.worker.on(`message`,i),e.worker.postMessage({type:`get-memory-usage`,id:r})})}getRecycleReason(e){let t=Date.now(),n=50*1024*1024,r=1800*1e3,i=this.MAX_TASKS_PER_WORKER,a=[];return e.memoryUsage>n&&a.push(`memoria excede ${Math.round(n/1024/1024)}MB (actual: ${Math.round(e.memoryUsage/1024/1024)}MB)`),t-e.creationTime>r&&a.push(`tiempo de vida excede ${Math.round(r/6e4)} minutos`),e.tasksProcessed>=i&&a.push(`tareas procesadas exceden ${i} (actual: ${e.tasksProcessed})`),a.join(`, `)}async cleanupInactiveWorkers(){let e=Date.now(),t=300*1e3;for(let t of this.workers){let n=e-t.lastActivityTime;n>3e5&&!t.busy&&t.pendingTasks.size===0&&(console.info(`[WorkerPool] Worker ${t.id} inactivo por ${Math.round(n/6e4)} minutos, reciclando...`),await this.recycleWorker(t))}}shouldRecycleWorker(e){let t=Date.now(),n=30*1024*1024,r=900*1e3,i=this.MAX_TASKS_PER_WORKER;return e.memoryUsage>31457280||t-e.creationTime>9e5||e.tasksProcessed>=i}static getInstance(){return TypeScriptWorkerPool.instance||=new TypeScriptWorkerPool,TypeScriptWorkerPool.instance}setMode(t){switch(t){case`batch`:this.poolSize=Math.min(e.cpus().length,12);break;case`watch`:this.poolSize=Math.min(Math.max(e.cpus().length/2,2),6);break;case`individual`:this.poolSize=Math.min(4,e.cpus().length);break}}async initializePool(){return this.initPromise||=this._performPoolInitialization(),this.initPromise}async _performPoolInitialization(){try{let e=await import(`node:fs`),t=e.existsSync(this.workerPath);if(!t)throw Error(`Worker thread file not found: ${this.workerPath}`);let n=Array.from({length:this.poolSize},(e,t)=>this.createWorker(t));this.workers=await Promise.all(n),this.isInitialized=!0}catch(e){throw this.isInitialized=!1,e}}async createWorker(e){return new Promise((t,i)=>{try{let a=new r(this.workerPath,{env:{...n.env,NODE_OPTIONS:``,WORKER_ID:e.toString()}}),o={worker:a,id:e,busy:!1,pendingTasks:new Map,taskCounter:0,memoryUsage:0,lastMemoryCheck:Date.now(),tasksProcessed:0,creationTime:Date.now(),lastActivityTime:Date.now()};this.setupWorkerListeners(o);let s=setTimeout(()=>{i(Error(`Worker ${e} initialization timeout`))},this.WORKER_INIT_TIMEOUT),c=()=>{a.postMessage({type:`ping`})};a.on(`message`,function e(n){(n.id===`worker-ready`||n.message===`pong`)&&(clearTimeout(s),a.off(`message`,e),t(o))}),a.on(`error`,e=>{clearTimeout(s),i(e)}),c()}catch(e){i(e)}})}setupWorkerListeners(e){let{worker:t}=e;t.on(`message`,t=>{try{if(t.id===`worker-ready`||t.message===`pong`||t.type===`memory-usage`)return;let n=e.pendingTasks.get(t.id);if(!n)return;if(clearTimeout(n.timeout),e.pendingTasks.delete(t.id),e.pendingTasks.size===0&&(e.busy=!1),e.lastActivityTime=Date.now(),t.success&&t.diagnostics!==void 0&&t.hasErrors!==void 0){this.completedTasks++;let e=this.categorizeTypeScriptErrors({diagnostics:t.diagnostics,hasErrors:t.hasErrors},n.fileName);n.resolve(e)}else{this.failedTasks++;let e=t.error||`Error desconocido del worker`,r=this.createCategorizedError(e,n.fileName,t);n.reject(r)}}catch{}}),t.on(`error`,async t=>{await this.handleWorkerError(e,t)}),t.on(`exit`,async t=>{await this.handleWorkerExit(e,t)})}async handleWorkerError(e,t){console.warn(`[WorkerPool] Manejando error del worker ${e.id}:`,t.message),e.pendingTasks.forEach(n=>{clearTimeout(n.timeout),this.failedTasks++,n.reject(Error(`Worker ${e.id} failed: ${t.message}`))}),e.pendingTasks.clear();try{e.worker.removeAllListeners(),await e.worker.terminate()}catch(t){console.error(`[WorkerPool] Error terminando worker ${e.id}:`,t)}if(e.busy=!1,this.isInitialized&&this.workers.length>0)try{let t=await this.createWorker(e.id),n=this.workers.findIndex(t=>t.id===e.id);n!==-1&&(this.workers[n]=t)}catch(t){console.error(`[WorkerPool] No se pudo recrear worker ${e.id}:`,t)}}async handleWorkerExit(e,t){console.warn(`[WorkerPool] Worker ${e.id} salió con código ${t}`),e.pendingTasks.forEach(n=>{clearTimeout(n.timeout),this.failedTasks++,n.reject(Error(`Worker ${e.id} exited with code ${t}`))}),e.pendingTasks.clear(),e.busy=!1;try{e.worker.removeAllListeners()}catch{}if(this.isInitialized&&this.workers.length>0)try{await this.recreateWorker(e)}catch(t){console.error(`[WorkerPool] Error recreando worker ${e.id}:`,t)}}async recreateWorker(e){try{let t=await this.createWorker(e.id),n=this.workers.findIndex(t=>t.id===e.id);n!==-1&&(this.workers[n]=t)}catch{}}async recycleWorker(e){try{console.log(`[WorkerPool] Reciclando worker ${e.id} después de ${e.taskCounter} tareas`);let t=2e3,n=Date.now();await new Promise(t=>{let r=()=>{e.pendingTasks.size===0||Date.now()-n>=2e3?t():setTimeout(r,100)};r()}),e.pendingTasks.size>0&&(e.pendingTasks.forEach(e=>{clearTimeout(e.timeout),e.reject(Error(`Worker being recycled`))}),e.pendingTasks.clear()),e.worker.removeAllListeners(),await e.worker.terminate();let r=await this.createWorker(e.id),i=this.workers.findIndex(t=>t.id===e.id);i!==-1&&(this.workers[i]=r)}catch(t){console.error(`[WorkerPool] Error reciclando worker ${e.id}:`,t)}}findAvailableWorker(){let e=this.workers.find(e=>!e.busy&&e.pendingTasks.size===0);if(e)return e;let t=this.workers.reduce((e,t)=>t.pendingTasks.size<e.pendingTasks.size?t:e);return t.pendingTasks.size<5?t:null}async typeCheck(e,t,n){if(await this.initializePool(),!this.isInitialized)return this.typeCheckWithSyncFallback(e,t,n);let r=this.findAvailableWorker();if(!r)return this.typeCheckWithSyncFallback(e,t,n);try{return this.totalTasks++,await this.typeCheckWithWorker(r,e,t,n)}catch{return this.typeCheckWithSyncFallback(e,t,n)}}async typeCheckWithWorker(e,t,n,r){return e.taskCounter>=this.MAX_TASKS_PER_WORKER&&await this.recycleWorker(e),new Promise((i,a)=>{let o=`task-${e.id}-${++e.taskCounter}-${Date.now()}`;e.busy=!0,e.lastActivityTime=Date.now(),e.tasksProcessed++;let s=this.calculateDynamicTimeout(t,n,r),c=setTimeout(()=>{e.pendingTasks.delete(o),e.pendingTasks.size===0&&(e.busy=!1),a(Error(`Timeout (${s}ms) en type checking para ${t} - archivo complejo detectado`))},s);e.pendingTasks.set(o,{resolve:i,reject:a,timeout:c,fileName:t,startTime:Date.now()});try{let i={id:o,fileName:t,content:n,compilerOptions:{...r,_workerTimeout:s-1e3}};e.worker.postMessage(i)}catch(t){clearTimeout(c),e.pendingTasks.delete(o),e.pendingTasks.size===0&&(e.busy=!1),a(t)}})}calculateDynamicTimeout(e,t,n){let r=this.TASK_TIMEOUT,i=1,a=t.length;a>1e5?i+=1.5:a>5e4?i+=1:a>2e4&&(i+=.5);let o=(t.match(/^import\s+/gm)||[]).length,s=(t.match(/\btype\s+\w+/g)||[]).length,c=(t.match(/\binterface\s+\w+/g)||[]).length,l=(t.match(/<[^>]*>/g)||[]).length,u=o+s+c+l*.5;u>100?i+=2:u>50?i+=1:u>20&&(i+=.5),(n?.strict||n?.noImplicitAny)&&(i+=.3),e.includes(`.d.ts`)?i+=1:e.includes(`.vue`)&&(i+=.5),i=Math.min(i,5),i=Math.max(i,.5);let d=Math.round(r*i);return Math.min(d,6e4)}typeCheckWithSyncFallback(e,t,n){try{return i(e,t,n)}catch{return{diagnostics:[],hasErrors:!1}}}async terminate(){console.log(`[WorkerPool] Cerrando pool de workers...`);let e=0;for(let t of this.workers){e+=t.pendingTasks.size,t.pendingTasks.forEach(e=>{clearTimeout(e.timeout),e.reject(Error(`Worker pool cerrado`))}),t.pendingTasks.clear();try{t.worker.removeAllListeners()}catch{}}e>0&&console.log(`[WorkerPool] Se cancelaron ${e} tareas pendientes`);let t=this.workers.map(async e=>{try{await e.worker.terminate()}catch(t){console.warn(`[WorkerPool] Error terminando worker ${e.id}:`,t)}});await Promise.allSettled(t),this.workers=[],this.isInitialized=!1,this.initPromise=null,console.log(`[WorkerPool] Pool cerrado. Estadísticas finales: ${this.completedTasks} completadas, ${this.failedTasks} fallidas`)}getStats(){let e=this.workers.filter(e=>e.busy).length,t=this.workers.reduce((e,t)=>e+t.pendingTasks.size,0),n=this.totalTasks>0?Math.round(this.completedTasks/this.totalTasks*100):0;return{poolSize:this.workers.length,busyWorkers:e,totalPendingTasks:t,totalTasks:this.totalTasks,completedTasks:this.completedTasks,failedTasks:this.failedTasks,successRate:n}}categorizeTypeScriptErrors(e,t){if(!e.hasErrors||!e.diagnostics?.length)return e;let n=e.diagnostics.map(e=>{let n={...e,_category:this.getErrorCategory(e),_severity:this.getErrorSeverity(e),_fileName:t,_timestamp:Date.now()};return n});return{...e,diagnostics:n,_errorStats:this.calculateErrorStats(n)}}getErrorCategory(e){let t=e.code;return[2304,2339,2346].includes(t)?`MISSING_DECLARATION`:[2322,2322,2345].includes(t)?`TYPE_MISMATCH`:[2307,2317].includes(t)?`MODULE_RESOLUTION`:[2552,2551].includes(t)?`PROPERTY_ACCESS`:t>=1e3&&t<2e3?`SYNTAX_ERROR`:t>=2e3&&t<3e3?`SEMANTIC_ERROR`:t>=4e3?`CONFIG_ERROR`:`OTHER`}getErrorSeverity(e){let t=e.category;switch(t){case 1:return`ERROR`;case 2:return`WARNING`;case 3:return`INFO`;default:return`ERROR`}}calculateErrorStats(e){let t={totalErrors:e.length,errorsByCategory:{},errorsBySeverity:{},mostCommonError:null};e.forEach(e=>{let n=e._category||`OTHER`,r=e._severity||`ERROR`;t.errorsByCategory[n]=(t.errorsByCategory[n]||0)+1,t.errorsBySeverity[r]=(t.errorsBySeverity[r]||0)+1});let n={};e.forEach(e=>{let t=String(e.code);n[t]=(n[t]||0)+1});let r=Object.keys(n);if(r.length>0){let i=r.reduce((e,t)=>(n[e]||0)>(n[t]||0)?e:t);t.mostCommonError={code:i,count:n[i],message:e.find(e=>String(e.code)===i)?.messageText}}return t}createCategorizedError(e,t,n){let r=Error(e);return r.fileName=t,r.timestamp=Date.now(),r.workerResponse=n,r.category=this.categorizeGenericError(e),r.isRecoverable=this.isRecoverableError(e),r}categorizeGenericError(e){return e.includes(`timeout`)||e.includes(`Timeout`)?`TIMEOUT`:e.includes(`memory`)||e.includes(`Memory`)?`MEMORY`:e.includes(`Worker`)&&e.includes(`exited`)?`WORKER_CRASH`:e.includes(`initialization`)||e.includes(`init`)?`INITIALIZATION`:`UNKNOWN`}isRecoverableError(e){let t=[`timeout`,`Worker being recycled`,`Worker pool cerrado`,`temporary`];return t.some(t=>e.toLowerCase().includes(t.toLowerCase()))}}