versacompiler 1.0.5 → 2.0.1

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 (48) hide show
  1. package/README.md +633 -145
  2. package/dist/compiler/compile.js +1362 -0
  3. package/dist/compiler/error-reporter.js +467 -0
  4. package/dist/compiler/linter.js +72 -0
  5. package/dist/compiler/minify.js +229 -0
  6. package/dist/compiler/module-resolution-optimizer.js +844 -0
  7. package/dist/compiler/parser.js +203 -0
  8. package/dist/compiler/performance-monitor.js +192 -0
  9. package/dist/compiler/tailwindcss.js +39 -0
  10. package/dist/compiler/transform-optimizer.js +287 -0
  11. package/dist/compiler/transformTStoJS.js +16 -0
  12. package/dist/compiler/transforms.js +578 -0
  13. package/dist/compiler/typescript-compiler.js +379 -0
  14. package/dist/compiler/typescript-error-parser.js +281 -0
  15. package/dist/compiler/typescript-manager.js +378 -0
  16. package/dist/compiler/typescript-sync-validator.js +228 -0
  17. package/dist/compiler/typescript-worker-pool.js +479 -0
  18. package/dist/compiler/typescript-worker-thread.cjs +457 -0
  19. package/dist/compiler/typescript-worker.js +339 -0
  20. package/dist/compiler/vuejs.js +390 -0
  21. package/dist/hrm/VueHRM.js +353 -0
  22. package/dist/hrm/errorScreen.js +23 -1
  23. package/dist/hrm/getInstanciaVue.js +313 -0
  24. package/dist/hrm/initHRM.js +140 -0
  25. package/dist/main.js +286 -0
  26. package/dist/servicios/browserSync.js +469 -0
  27. package/dist/servicios/file-watcher.js +316 -0
  28. package/dist/servicios/logger.js +34 -0
  29. package/dist/servicios/readConfig.js +430 -0
  30. package/dist/utils/module-resolver.js +495 -0
  31. package/dist/utils/promptUser.js +48 -0
  32. package/dist/utils/resolve-bin.js +48 -0
  33. package/dist/utils/utils.js +8 -35
  34. package/dist/wrappers/eslint-node.js +145 -0
  35. package/dist/wrappers/oxlint-node.js +120 -0
  36. package/dist/wrappers/tailwind-node.js +92 -0
  37. package/package.json +62 -17
  38. package/dist/hrm/devMode.js +0 -346
  39. package/dist/hrm/instanciaVue.js +0 -35
  40. package/dist/hrm/setupHMR.js +0 -57
  41. package/dist/index.js +0 -1010
  42. package/dist/services/acorn.js +0 -29
  43. package/dist/services/linter.js +0 -55
  44. package/dist/services/minify.js +0 -31
  45. package/dist/services/typescript.js +0 -89
  46. package/dist/services/vueLoader.js +0 -326
  47. package/dist/services/vuejs.js +0 -259
  48. package/dist/utils/transformWithAcorn.js +0 -316
@@ -0,0 +1,1362 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { glob, mkdir, readFile, stat, unlink, writeFile, } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { cwd, env, stdout } from 'node:process';
6
+ // Lazy loading optimizations - Only import lightweight modules synchronously
7
+ import { logger } from '../servicios/logger.js';
8
+ import { promptUser } from '../utils/promptUser.js';
9
+ import { showTimingForHumans } from '../utils/utils.js';
10
+ // Heavy dependencies will be loaded dynamically when needed
11
+ let chalk;
12
+ let ESLint;
13
+ let OxLint;
14
+ let minifyJS;
15
+ let getCodeFile;
16
+ let generateTailwindCSS;
17
+ let estandarizaCode;
18
+ let preCompileTS;
19
+ let preCompileVue;
20
+ // 🚀 Importar optimizador de transformaciones
21
+ let TransformOptimizer;
22
+ // 🚀 Importar optimizador de resolución de módulos
23
+ let ModuleResolutionOptimizer;
24
+ // 🚀 Sistema de Carga Inteligente de Módulos - VERSIÓN OPTIMIZADA V2
25
+ class OptimizedModuleManager {
26
+ static instance;
27
+ isInitialized = false;
28
+ loadedModules = new Set();
29
+ // ✨ NUEVAS OPTIMIZACIONES
30
+ modulePool = new Map(); // Pool de instancias reutilizables
31
+ loadingPromises = new Map(); // Prevenir cargas duplicadas
32
+ usageStats = new Map(); // Estadísticas de uso
33
+ preloadQueue = new Set(); // Cola de precarga
34
+ backgroundLoader = null; // Cargador en background
35
+ // Módulos críticos que siempre se precargan
36
+ HOT_MODULES = ['chalk', 'parser'];
37
+ // Contexto actual para optimizar cargas
38
+ currentContext = null;
39
+ constructor() {
40
+ // Iniciar precarga en background inmediatamente
41
+ this.startBackgroundPreloading();
42
+ }
43
+ static getInstance() {
44
+ if (!OptimizedModuleManager.instance) {
45
+ OptimizedModuleManager.instance = new OptimizedModuleManager();
46
+ }
47
+ return OptimizedModuleManager.instance;
48
+ }
49
+ /**
50
+ * ✨ NUEVO: Precarga en background para módulos críticos
51
+ */
52
+ startBackgroundPreloading() {
53
+ this.backgroundLoader = this.preloadCriticalModules();
54
+ }
55
+ /**
56
+ * ✨ NUEVO: Precarga módulos críticos en background
57
+ */
58
+ async preloadCriticalModules() {
59
+ try {
60
+ // Precargar módulos críticos de forma asíncrona
61
+ const preloadPromises = this.HOT_MODULES.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
62
+ // Silenciar errores de precarga, se intentará cargar después
63
+ }));
64
+ await Promise.allSettled(preloadPromises);
65
+ }
66
+ catch {
67
+ // Fallos en precarga no deben afectar la funcionalidad principal
68
+ }
69
+ }
70
+ /**
71
+ * ✨ MEJORADO: Precarga contextual basada en tipos de archivo
72
+ */
73
+ async preloadForContext(context, fileTypes = new Set()) {
74
+ this.currentContext = context;
75
+ // Esperar que termine la precarga crítica si está en progreso
76
+ if (this.backgroundLoader) {
77
+ await this.backgroundLoader;
78
+ }
79
+ const toPreload = []; // Precarga basada en contexto
80
+ if (context === 'batch' || context === 'watch') {
81
+ // En batch/watch, precargar todos los módulos comunes
82
+ toPreload.push('transforms', 'vue', 'typescript', 'module-resolution-optimizer');
83
+ }
84
+ else {
85
+ // En individual, cargar solo según tipos de archivo detectados
86
+ if (fileTypes.has('.vue'))
87
+ toPreload.push('vue');
88
+ if (fileTypes.has('.ts') || fileTypes.has('.vue'))
89
+ toPreload.push('typescript');
90
+ if (!this.loadedModules.has('transforms'))
91
+ toPreload.push('transforms');
92
+ }
93
+ // Precargar en paralelo
94
+ const preloadPromises = toPreload.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
95
+ // Log warning pero no fallar
96
+ console.warn(`Warning: No se pudo precargar módulo ${moduleName}`);
97
+ }));
98
+ await Promise.allSettled(preloadPromises);
99
+ }
100
+ /**
101
+ * ✨ MEJORADO: Carga inteligente con pooling y deduplicación
102
+ */
103
+ async ensureModuleLoaded(moduleName) {
104
+ // 1. Verificar pool de módulos primero
105
+ if (this.modulePool.has(moduleName)) {
106
+ this.updateUsageStats(moduleName);
107
+ return this.modulePool.get(moduleName);
108
+ }
109
+ // 2. Verificar si ya está cargando (deduplicación)
110
+ if (this.loadingPromises.has(moduleName)) {
111
+ return this.loadingPromises.get(moduleName);
112
+ }
113
+ // 3. Iniciar carga
114
+ const loadPromise = this.loadModuleInternal(moduleName);
115
+ this.loadingPromises.set(moduleName, loadPromise);
116
+ try {
117
+ const moduleInstance = await loadPromise;
118
+ // 4. Almacenar en pool y estadísticas
119
+ this.modulePool.set(moduleName, moduleInstance);
120
+ this.loadedModules.add(moduleName);
121
+ this.updateUsageStats(moduleName);
122
+ return moduleInstance;
123
+ }
124
+ finally {
125
+ // 5. Limpiar promesa de carga
126
+ this.loadingPromises.delete(moduleName);
127
+ }
128
+ }
129
+ /**
130
+ * ✨ NUEVO: Actualiza estadísticas de uso para optimizaciones futuras
131
+ */
132
+ updateUsageStats(moduleName) {
133
+ const currentCount = this.usageStats.get(moduleName) || 0;
134
+ this.usageStats.set(moduleName, currentCount + 1);
135
+ }
136
+ /**
137
+ * ✨ MEJORADO: Carga interna de módulos con mejor manejo de errores
138
+ */ async loadModuleInternal(moduleName) {
139
+ switch (moduleName) {
140
+ case 'chalk':
141
+ return this.loadChalk();
142
+ case 'parser':
143
+ return this.loadParser();
144
+ case 'transforms':
145
+ return this.loadTransforms();
146
+ case 'vue':
147
+ return this.loadVue();
148
+ case 'typescript':
149
+ return this.loadTypeScript();
150
+ case 'minify':
151
+ return this.loadMinify();
152
+ case 'tailwind':
153
+ return this.loadTailwind();
154
+ case 'linter':
155
+ return this.loadLinter();
156
+ case 'transform-optimizer':
157
+ return this.loadTransformOptimizer();
158
+ case 'module-resolution-optimizer':
159
+ return this.loadModuleResolutionOptimizer();
160
+ default:
161
+ throw new Error(`Módulo desconocido: ${moduleName}`);
162
+ }
163
+ }
164
+ // ✨ Métodos de carga específicos optimizados
165
+ async loadChalk() {
166
+ if (!chalk) {
167
+ chalk = (await import('chalk')).default;
168
+ }
169
+ return chalk;
170
+ }
171
+ async loadParser() {
172
+ if (!getCodeFile) {
173
+ const parserModule = await import('./parser.js');
174
+ getCodeFile = parserModule.getCodeFile;
175
+ }
176
+ return getCodeFile;
177
+ }
178
+ async loadTransforms() {
179
+ if (!estandarizaCode) {
180
+ const transformsModule = await import('./transforms.js');
181
+ estandarizaCode = transformsModule.estandarizaCode;
182
+ }
183
+ return estandarizaCode;
184
+ }
185
+ async loadVue() {
186
+ if (!preCompileVue) {
187
+ const vueModule = await import('./vuejs.js');
188
+ preCompileVue = vueModule.preCompileVue;
189
+ }
190
+ return preCompileVue;
191
+ }
192
+ async loadTypeScript() {
193
+ if (!preCompileTS) {
194
+ const typescriptModule = await import('./typescript-manager.js');
195
+ preCompileTS = typescriptModule.preCompileTS;
196
+ }
197
+ return preCompileTS;
198
+ }
199
+ async loadMinify() {
200
+ if (!minifyJS) {
201
+ const minifyModule = await import('./minify.js');
202
+ minifyJS = minifyModule.minifyJS;
203
+ }
204
+ return minifyJS;
205
+ }
206
+ async loadTailwind() {
207
+ if (!generateTailwindCSS) {
208
+ const tailwindModule = await import('./tailwindcss.js');
209
+ generateTailwindCSS = tailwindModule.generateTailwindCSS;
210
+ }
211
+ return generateTailwindCSS;
212
+ }
213
+ async loadLinter() {
214
+ if (!ESLint || !OxLint) {
215
+ const linterModule = await import('./linter.js');
216
+ ESLint = linterModule.ESLint;
217
+ OxLint = linterModule.OxLint;
218
+ }
219
+ return { ESLint, OxLint };
220
+ }
221
+ async loadTransformOptimizer() {
222
+ if (!TransformOptimizer) {
223
+ const transformModule = await import('./transform-optimizer.js');
224
+ TransformOptimizer =
225
+ transformModule.TransformOptimizer.getInstance();
226
+ }
227
+ return TransformOptimizer;
228
+ }
229
+ async loadModuleResolutionOptimizer() {
230
+ if (!ModuleResolutionOptimizer) {
231
+ const resolutionModule = await import('./module-resolution-optimizer.js');
232
+ ModuleResolutionOptimizer =
233
+ resolutionModule.ModuleResolutionOptimizer.getInstance();
234
+ }
235
+ return ModuleResolutionOptimizer;
236
+ }
237
+ /**
238
+ * ✨ NUEVO: Obtiene estadísticas de performance del manager
239
+ */
240
+ getPerformanceStats() {
241
+ const sortedByUsage = Array.from(this.usageStats.entries())
242
+ .sort((a, b) => b[1] - a[1])
243
+ .slice(0, 5)
244
+ .map(([name]) => name);
245
+ return {
246
+ loadedModules: Array.from(this.loadedModules),
247
+ usageStats: Object.fromEntries(this.usageStats),
248
+ poolSize: this.modulePool.size,
249
+ loadingInProgress: Array.from(this.loadingPromises.keys()),
250
+ mostUsedModules: sortedByUsage,
251
+ };
252
+ }
253
+ /**
254
+ * ✨ NUEVO: Limpia módulos no utilizados para liberar memoria
255
+ */
256
+ cleanupUnusedModules() {
257
+ const threshold = 1; // Mínimo de usos para mantener en pool
258
+ for (const [moduleName, usageCount] of this.usageStats) {
259
+ if (usageCount < threshold &&
260
+ !this.HOT_MODULES.includes(moduleName)) {
261
+ this.modulePool.delete(moduleName);
262
+ this.loadedModules.delete(moduleName);
263
+ this.usageStats.delete(moduleName);
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * Resetea el estado del manager (útil para tests)
269
+ */
270
+ reset() {
271
+ this.isInitialized = false;
272
+ this.loadedModules.clear();
273
+ this.modulePool.clear();
274
+ this.loadingPromises.clear();
275
+ this.usageStats.clear();
276
+ this.preloadQueue.clear();
277
+ this.currentContext = null;
278
+ this.backgroundLoader = null;
279
+ // Reiniciar precarga crítica
280
+ this.startBackgroundPreloading();
281
+ }
282
+ }
283
+ // Lazy loading helper functions
284
+ async function loadChalk() {
285
+ if (!chalk) {
286
+ chalk = (await import('chalk')).default;
287
+ }
288
+ return chalk;
289
+ }
290
+ async function loadLinter() {
291
+ if (!ESLint || !OxLint) {
292
+ const linterModule = await import('./linter.js');
293
+ ESLint = linterModule.ESLint;
294
+ OxLint = linterModule.OxLint;
295
+ }
296
+ return { ESLint, OxLint };
297
+ }
298
+ async function loadMinify() {
299
+ if (!minifyJS) {
300
+ const minifyModule = await import('./minify.js');
301
+ minifyJS = minifyModule.minifyJS;
302
+ }
303
+ return minifyJS;
304
+ }
305
+ async function loadParser() {
306
+ if (!getCodeFile) {
307
+ const parserModule = await import('./parser.js');
308
+ getCodeFile = parserModule.getCodeFile;
309
+ }
310
+ return getCodeFile;
311
+ }
312
+ async function loadTailwind() {
313
+ if (!generateTailwindCSS) {
314
+ const tailwindModule = await import('./tailwindcss.js');
315
+ generateTailwindCSS = tailwindModule.generateTailwindCSS;
316
+ }
317
+ return generateTailwindCSS;
318
+ }
319
+ async function loadTransforms() {
320
+ if (!estandarizaCode) {
321
+ const transformsModule = await import('./transforms.js');
322
+ estandarizaCode = transformsModule.estandarizaCode;
323
+ }
324
+ return estandarizaCode;
325
+ }
326
+ async function loadTypeScript() {
327
+ if (!preCompileTS) {
328
+ const typescriptModule = await import('./typescript-manager.js');
329
+ preCompileTS = typescriptModule.preCompileTS;
330
+ }
331
+ return preCompileTS;
332
+ }
333
+ async function loadVue() {
334
+ if (!preCompileVue) {
335
+ const vueModule = await import('./vuejs.js');
336
+ preCompileVue = vueModule.preCompileVue;
337
+ }
338
+ return preCompileVue;
339
+ }
340
+ // Almacenamiento global de errores y resultados
341
+ const compilationErrors = [];
342
+ const compilationResults = [];
343
+ class SmartCompilationCache {
344
+ cache = new Map();
345
+ maxEntries = 500; // Máximo archivos en cache
346
+ maxMemory = 100 * 1024 * 1024; // 100MB límite
347
+ currentMemoryUsage = 0;
348
+ /**
349
+ * Genera hash SHA-256 del contenido del archivo
350
+ */ async generateContentHash(filePath) {
351
+ try {
352
+ const content = await readFile(filePath, 'utf8');
353
+ return createHash('sha256').update(content).digest('hex');
354
+ }
355
+ catch {
356
+ // Si no se puede leer el archivo, generar hash único basado en la ruta y timestamp
357
+ const fallback = `${filePath}-${Date.now()}`;
358
+ return createHash('sha256').update(fallback).digest('hex');
359
+ }
360
+ }
361
+ /**
362
+ * Verifica si una entrada de cache es válida
363
+ */
364
+ async isValid(filePath) {
365
+ const entry = this.cache.get(filePath);
366
+ if (!entry)
367
+ return false;
368
+ try {
369
+ // Verificar si el archivo de salida existe
370
+ await stat(entry.outputPath);
371
+ // Verificar si el contenido ha cambiado
372
+ const currentHash = await this.generateContentHash(filePath);
373
+ if (entry.contentHash !== currentHash) {
374
+ this.cache.delete(filePath);
375
+ return false;
376
+ }
377
+ // Verificar tiempo de modificación como backup
378
+ const stats = await stat(filePath);
379
+ if (stats.mtimeMs > entry.mtime) {
380
+ this.cache.delete(filePath);
381
+ return false;
382
+ }
383
+ // Actualizar tiempo de uso para LRU
384
+ entry.lastUsed = Date.now();
385
+ return true;
386
+ }
387
+ catch {
388
+ // Si hay error verificando, eliminar del cache
389
+ this.cache.delete(filePath);
390
+ return false;
391
+ }
392
+ }
393
+ /**
394
+ * Añade una entrada al cache
395
+ */
396
+ async set(filePath, outputPath) {
397
+ try {
398
+ const stats = await stat(filePath);
399
+ const contentHash = await this.generateContentHash(filePath);
400
+ const entry = {
401
+ contentHash,
402
+ mtime: stats.mtimeMs,
403
+ outputPath,
404
+ lastUsed: Date.now(),
405
+ size: stats.size,
406
+ };
407
+ // Aplicar límites de memoria y entradas antes de agregar
408
+ this.evictIfNeeded(entry.size);
409
+ this.cache.set(filePath, entry);
410
+ this.currentMemoryUsage += entry.size;
411
+ }
412
+ catch (error) {
413
+ // Si hay error, no cachear
414
+ console.warn(`Warning: No se pudo cachear ${filePath}:`, error);
415
+ }
416
+ }
417
+ /**
418
+ * Aplica política LRU para liberar espacio
419
+ */
420
+ evictIfNeeded(newEntrySize) {
421
+ // Verificar límite de entradas
422
+ while (this.cache.size >= this.maxEntries) {
423
+ this.evictLRU();
424
+ }
425
+ // Verificar límite de memoria
426
+ while (this.currentMemoryUsage + newEntrySize > this.maxMemory &&
427
+ this.cache.size > 0) {
428
+ this.evictLRU();
429
+ }
430
+ }
431
+ /**
432
+ * Elimina la entrada menos recientemente usada
433
+ */
434
+ evictLRU() {
435
+ let oldestKey = '';
436
+ let oldestTime = Infinity;
437
+ for (const [key, entry] of this.cache) {
438
+ if (entry.lastUsed < oldestTime) {
439
+ oldestTime = entry.lastUsed;
440
+ oldestKey = key;
441
+ }
442
+ }
443
+ if (oldestKey) {
444
+ const entry = this.cache.get(oldestKey);
445
+ if (entry) {
446
+ this.currentMemoryUsage -= entry.size;
447
+ this.cache.delete(oldestKey);
448
+ }
449
+ }
450
+ }
451
+ /**
452
+ * Carga el cache desde disco
453
+ */
454
+ async load(cacheFile) {
455
+ try {
456
+ if (env.cleanCache === 'true') {
457
+ this.cache.clear();
458
+ this.currentMemoryUsage = 0;
459
+ try {
460
+ await unlink(cacheFile);
461
+ }
462
+ catch {
463
+ // Ignorar errores al eliminar el archivo
464
+ }
465
+ return;
466
+ }
467
+ const cacheData = await readFile(cacheFile, 'utf-8');
468
+ const parsed = JSON.parse(cacheData);
469
+ // Validar y cargar entradas del cache
470
+ for (const [key, value] of Object.entries(parsed)) {
471
+ const entry = value;
472
+ if (entry.contentHash && entry.outputPath && entry.mtime) {
473
+ this.cache.set(key, entry);
474
+ this.currentMemoryUsage += entry.size || 0;
475
+ }
476
+ }
477
+ }
478
+ catch {
479
+ // Cache file doesn't exist or is invalid, start fresh
480
+ this.cache.clear();
481
+ this.currentMemoryUsage = 0;
482
+ }
483
+ }
484
+ /**
485
+ * Guarda el cache a disco
486
+ */
487
+ async save(cacheFile, cacheDir) {
488
+ try {
489
+ await mkdir(cacheDir, { recursive: true });
490
+ const cacheData = Object.fromEntries(this.cache);
491
+ await writeFile(cacheFile, JSON.stringify(cacheData, null, 2));
492
+ }
493
+ catch (error) {
494
+ console.warn('Warning: No se pudo guardar el cache:', error);
495
+ }
496
+ }
497
+ /**
498
+ * Limpia completamente el cache
499
+ */
500
+ clear() {
501
+ this.cache.clear();
502
+ this.currentMemoryUsage = 0;
503
+ } /**
504
+ * Obtiene la ruta de salida para un archivo cacheado
505
+ */
506
+ getOutputPath(filePath) {
507
+ const entry = this.cache.get(filePath);
508
+ return entry?.outputPath || '';
509
+ }
510
+ /**
511
+ * Obtiene estadísticas del cache
512
+ */
513
+ getStats() {
514
+ return {
515
+ entries: this.cache.size,
516
+ memoryUsage: this.currentMemoryUsage,
517
+ hitRate: 0, // Se calculará externamente
518
+ };
519
+ }
520
+ }
521
+ // Instancia global del cache inteligente
522
+ const smartCache = new SmartCompilationCache();
523
+ const CACHE_DIR = path.join(path.resolve(env.PATH_PROY || cwd(), 'compiler'), '.cache');
524
+ const CACHE_FILE = path.join(CACHE_DIR, 'versacompile-cache.json');
525
+ async function loadCache() {
526
+ await smartCache.load(CACHE_FILE);
527
+ }
528
+ async function saveCache() {
529
+ await smartCache.save(CACHE_FILE, CACHE_DIR);
530
+ }
531
+ // 🎯 Funciones del Sistema Unificado de Manejo de Errores
532
+ /**
533
+ * Registra un error de compilación en el sistema unificado
534
+ */
535
+ function registerCompilationError(file, stage, message, severity = 'error', details, help) {
536
+ compilationErrors.push({
537
+ file,
538
+ stage,
539
+ message,
540
+ severity,
541
+ details,
542
+ help,
543
+ timestamp: Date.now(),
544
+ });
545
+ }
546
+ /**
547
+ * Registra un resultado de compilación (éxitos/errores por etapa)
548
+ */
549
+ function registerCompilationResult(stage, errors, success, files = []) {
550
+ const existingResult = compilationResults.find(r => r.stage === stage);
551
+ if (existingResult) {
552
+ existingResult.errors += errors;
553
+ existingResult.success += success;
554
+ existingResult.files.push(...files);
555
+ }
556
+ else {
557
+ compilationResults.push({
558
+ stage,
559
+ errors,
560
+ success,
561
+ files: [...files],
562
+ });
563
+ }
564
+ }
565
+ /**
566
+ * Maneja errores según el modo de compilación
567
+ */
568
+ async function handleCompilationError(error, fileName, stage, mode, isVerbose = false) {
569
+ const errorMessage = error instanceof Error ? error.message : error;
570
+ const errorDetails = error instanceof Error ? error.stack : undefined;
571
+ // Registrar el error en el sistema unificado
572
+ registerCompilationError(fileName, stage, errorMessage, 'error', errorDetails);
573
+ registerCompilationResult(stage, 1, 0, [fileName]); // Mostrar error inmediatamente solo en modo individual y watch
574
+ if (mode === 'individual' || mode === 'watch') {
575
+ const chalk = await loadChalk();
576
+ const baseName = path.basename(fileName);
577
+ const stageColor = await getStageColor(stage);
578
+ if (isVerbose) {
579
+ // Modo verbose: Mostrar error completo con contexto
580
+ logger.error(chalk.red(`❌ Error en etapa ${stageColor(stage)} - ${baseName}:`));
581
+ logger.error(chalk.red(errorMessage));
582
+ if (errorDetails && (stage === 'typescript' || stage === 'vue')) {
583
+ // Mostrar stack trace limitado para TypeScript y Vue
584
+ const stackLines = errorDetails.split('\n').slice(0, 5);
585
+ stackLines.forEach(line => {
586
+ if (line.trim()) {
587
+ logger.error(chalk.gray(` ${line.trim()}`));
588
+ }
589
+ });
590
+ }
591
+ }
592
+ else {
593
+ // Modo normal: Mostrar error simplificado
594
+ const firstLine = errorMessage.split('\n')[0];
595
+ logger.error(chalk.red(`❌ Error en ${stageColor(stage)}: ${baseName}`));
596
+ logger.error(chalk.red(` ${firstLine}`));
597
+ logger.info(chalk.yellow(`💡 Usa --verbose para ver detalles completos`));
598
+ }
599
+ }
600
+ // En modo 'all', los errores se acumulan silenciosamente para el resumen final
601
+ }
602
+ /**
603
+ * Registra un éxito de compilación
604
+ */
605
+ function registerCompilationSuccess(fileName, stage) {
606
+ registerCompilationResult(stage, 0, 1, [fileName]);
607
+ }
608
+ /**
609
+ * Limpia todos los errores y resultados acumulados
610
+ */
611
+ function clearCompilationState() {
612
+ compilationErrors.length = 0;
613
+ compilationResults.length = 0;
614
+ }
615
+ /**
616
+ * Muestra un resumen detallado de todos los errores de compilación
617
+ */
618
+ async function displayCompilationSummary(isVerbose = false) {
619
+ const chalk = await loadChalk();
620
+ if (compilationErrors.length === 0 && compilationResults.length === 0) {
621
+ logger.info(chalk.green('✅ No hay errores de compilación para mostrar.'));
622
+ return;
623
+ }
624
+ logger.info(chalk.bold('\n--- 📊 RESUMEN DE COMPILACIÓN ---'));
625
+ // Mostrar estadísticas por etapa
626
+ if (compilationResults.length > 0) {
627
+ logger.info(chalk.blue('\n🔍 Estadísticas por etapa:'));
628
+ for (const result of compilationResults) {
629
+ const totalFiles = result.success + result.errors;
630
+ const successRate = totalFiles > 0
631
+ ? Math.round((result.success / totalFiles) * 100)
632
+ : 0;
633
+ const statusIcon = result.errors === 0 ? '✅' : '❌';
634
+ const stageColor = await getStageColor(result.stage);
635
+ const statusText = `${result.success} éxitos, ${result.errors} errores`;
636
+ const coloredStatusText = result.errors === 0
637
+ ? chalk.green(statusText)
638
+ : chalk.red(statusText);
639
+ logger.info(`${statusIcon} ${stageColor(result.stage)}: ${coloredStatusText} (${successRate}% éxito)`);
640
+ }
641
+ }
642
+ // Mostrar errores detallados
643
+ if (compilationErrors.length > 0) {
644
+ logger.info(chalk.red(`\n❌ Se encontraron ${compilationErrors.length} errores:`));
645
+ // Agrupar errores por archivo para mejor organización
646
+ const errorsByFile = new Map();
647
+ compilationErrors.forEach(error => {
648
+ if (!errorsByFile.has(error.file)) {
649
+ errorsByFile.set(error.file, []);
650
+ }
651
+ errorsByFile.get(error.file).push(error);
652
+ });
653
+ // Mostrar errores por archivo
654
+ let fileIndex = 1;
655
+ for (const [filePath, fileErrors] of errorsByFile) {
656
+ const baseName = path.basename(filePath);
657
+ const errorCount = fileErrors.filter(e => e.severity === 'error').length;
658
+ const warningCount = fileErrors.filter(e => e.severity === 'warning').length;
659
+ logger.info(chalk.cyan(`\n📄 ${fileIndex}. ${baseName}`));
660
+ logger.info(chalk.gray(` Ruta: ${filePath}`));
661
+ logger.info(chalk.yellow(` ${errorCount} errores, ${warningCount} advertencias`));
662
+ for (const error of fileErrors) {
663
+ const icon = error.severity === 'error' ? '❌' : '⚠️';
664
+ const stageColor = await getStageColor(error.stage);
665
+ logger.info(` ${icon} [${stageColor(error.stage)}] ${error.message}`);
666
+ if (isVerbose && error.details) {
667
+ // En modo verbose, mostrar detalles adicionales
668
+ const detailLines = error.details.split('\n').slice(0, 5);
669
+ detailLines.forEach(line => {
670
+ if (line.trim()) {
671
+ logger.info(chalk.gray(` ${line.trim()}`));
672
+ }
673
+ });
674
+ }
675
+ if (error.help) {
676
+ logger.info(chalk.blue(` 💡 ${error.help}`));
677
+ }
678
+ }
679
+ fileIndex++;
680
+ }
681
+ // Mostrar totales finales
682
+ const totalErrors = compilationErrors.filter(e => e.severity === 'error').length;
683
+ const totalWarnings = compilationErrors.filter(e => e.severity === 'warning').length;
684
+ const totalFiles = errorsByFile.size;
685
+ logger.info(chalk.bold('\n--- 📈 ESTADÍSTICAS FINALES ---'));
686
+ logger.info(`📁 Archivos con errores: ${totalFiles}`);
687
+ logger.info(`❌ Total de errores: ${totalErrors}`);
688
+ logger.info(`⚠️ Total de advertencias: ${totalWarnings}`);
689
+ if (totalErrors > 0) {
690
+ logger.info(chalk.red('🚨 Compilación completada con errores que requieren atención.'));
691
+ }
692
+ else {
693
+ logger.info(chalk.yellow('✅ Compilación completada con solo advertencias.'));
694
+ }
695
+ }
696
+ else {
697
+ logger.info(chalk.green('✅ ¡Compilación exitosa sin errores!'));
698
+ }
699
+ logger.info(chalk.bold('--- FIN DEL RESUMEN ---\n'));
700
+ }
701
+ /**
702
+ * Muestra errores del linter de forma detallada
703
+ */
704
+ async function displayLinterErrors(errors) {
705
+ const chalk = await loadChalk();
706
+ logger.info(chalk.bold('--- Errores y Advertencias de Linting ---'));
707
+ const errorsByFile = new Map();
708
+ errors.forEach(error => {
709
+ if (!errorsByFile.has(error.file)) {
710
+ errorsByFile.set(error.file, []);
711
+ }
712
+ errorsByFile.get(error.file).push(error);
713
+ });
714
+ const totalErrors = errors.filter(e => e.severity === 'error').length;
715
+ const totalWarnings = errors.filter(e => e.severity === 'warning').length;
716
+ const totalFiles = errorsByFile.size;
717
+ logger.info(chalk.yellow(`📊 Resumen: ${totalErrors} errores, ${totalWarnings} advertencias en ${totalFiles} archivos\n`));
718
+ errorsByFile.forEach((fileErrors, filePath) => {
719
+ const baseName = path.basename(filePath);
720
+ logger.info(chalk.cyan(`\n📄 ${baseName}`));
721
+ fileErrors.forEach(error => {
722
+ const icon = error.severity === 'error' ? '❌' : '⚠️';
723
+ logger.info(`${icon} ${error.message}`);
724
+ if (error.help) {
725
+ logger.info(` └─ ${error.help}`);
726
+ }
727
+ });
728
+ });
729
+ logger.info(chalk.bold('--- Fin de Errores y Advertencias ---\n'));
730
+ }
731
+ /**
732
+ * Obtiene el color apropiado para cada etapa de compilación
733
+ */
734
+ async function getStageColor(stage) {
735
+ const chalk = await loadChalk();
736
+ switch (stage) {
737
+ case 'vue':
738
+ return chalk.green;
739
+ case 'typescript':
740
+ return chalk.blue;
741
+ case 'standardization':
742
+ return chalk.yellow;
743
+ case 'minification':
744
+ return chalk.red;
745
+ case 'tailwind':
746
+ return chalk.magenta;
747
+ case 'file-read':
748
+ return chalk.gray;
749
+ default:
750
+ return chalk.white;
751
+ }
752
+ }
753
+ export function normalizeRuta(ruta) {
754
+ if (path.isAbsolute(ruta)) {
755
+ return path.normalize(ruta).replace(/\\/g, '/');
756
+ }
757
+ const file = path
758
+ .normalize(!ruta.startsWith('.') ? './' + ruta : ruta)
759
+ .replace(/\\/g, '/');
760
+ const sourceForDist = file.startsWith('./') ? file : `./${file}`;
761
+ return sourceForDist;
762
+ }
763
+ export function getOutputPath(ruta) {
764
+ const pathSource = env.PATH_SOURCE ?? '';
765
+ const pathDist = env.PATH_DIST ?? '';
766
+ if (!pathSource || !pathDist) {
767
+ return ruta.replace(/\.(vue|ts)$/, '.js');
768
+ }
769
+ const normalizedRuta = path.normalize(ruta).replace(/\\/g, '/');
770
+ const normalizedSource = path.normalize(pathSource).replace(/\\/g, '/');
771
+ const normalizedDist = path.normalize(pathDist).replace(/\\/g, '/');
772
+ let outputPath;
773
+ if (normalizedRuta.includes(normalizedSource)) {
774
+ const relativePath = normalizedRuta
775
+ .substring(normalizedRuta.indexOf(normalizedSource) +
776
+ normalizedSource.length)
777
+ .replace(/^[/\\]/, '');
778
+ outputPath = path
779
+ .join(normalizedDist, relativePath)
780
+ .replace(/\\/g, '/');
781
+ }
782
+ else {
783
+ const fileName = path.basename(normalizedRuta);
784
+ outputPath = path.join(normalizedDist, fileName).replace(/\\/g, '/');
785
+ }
786
+ if (outputPath.includes('vue') || outputPath.includes('ts')) {
787
+ return outputPath.replace(/\.(vue|ts)$/, '.js');
788
+ }
789
+ else {
790
+ return outputPath;
791
+ }
792
+ }
793
+ // Optimización para modo watch: debouncing y cache de archivos
794
+ class WatchModeOptimizer {
795
+ static instance;
796
+ fileSystemCache = new Map();
797
+ debounceTimers = new Map();
798
+ DEBOUNCE_DELAY = 100; // 100ms debounce
799
+ static getInstance() {
800
+ if (!WatchModeOptimizer.instance) {
801
+ WatchModeOptimizer.instance = new WatchModeOptimizer();
802
+ }
803
+ return WatchModeOptimizer.instance;
804
+ }
805
+ async compileForWatch(filePath, compileFn) {
806
+ return new Promise(resolve => {
807
+ const existingTimer = this.debounceTimers.get(filePath);
808
+ if (existingTimer) {
809
+ clearTimeout(existingTimer);
810
+ }
811
+ const timer = setTimeout(async () => {
812
+ this.debounceTimers.delete(filePath);
813
+ try {
814
+ const stats = await stat(filePath);
815
+ const cached = this.fileSystemCache.get(filePath);
816
+ if (cached && cached.mtime >= stats.mtimeMs) {
817
+ resolve({ success: true, cached: true });
818
+ return;
819
+ } // Configurar worker pool para modo watch
820
+ const { TypeScriptWorkerPool } = await import('./typescript-worker-pool.js');
821
+ const workerPool = TypeScriptWorkerPool.getInstance();
822
+ workerPool.setMode('watch');
823
+ const result = await compileFn(filePath);
824
+ this.fileSystemCache.set(filePath, {
825
+ mtime: stats.mtimeMs,
826
+ });
827
+ resolve(result);
828
+ }
829
+ catch (error) {
830
+ resolve({ success: false, error });
831
+ }
832
+ }, this.DEBOUNCE_DELAY);
833
+ this.debounceTimers.set(filePath, timer);
834
+ });
835
+ }
836
+ cleanup() {
837
+ this.debounceTimers.forEach(timer => clearTimeout(timer));
838
+ this.debounceTimers.clear();
839
+ this.fileSystemCache.clear();
840
+ }
841
+ }
842
+ async function compileJS(inPath, outPath, mode = 'individual') {
843
+ const timings = {};
844
+ // Si la ruta ya es absoluta, no la resolvamos de nuevo
845
+ inPath = path.isAbsolute(inPath)
846
+ ? normalizeRuta(inPath)
847
+ : normalizeRuta(path.resolve(inPath)); // 🚀 Usar OptimizedModuleManager para carga optimizada
848
+ const moduleManager = OptimizedModuleManager.getInstance();
849
+ // Timing de lectura
850
+ let start = Date.now();
851
+ const extension = path.extname(inPath);
852
+ // Asegurar que el parser esté cargado
853
+ await moduleManager.ensureModuleLoaded('parser');
854
+ const getCodeFile = await loadParser();
855
+ let { code, error } = await getCodeFile(inPath);
856
+ timings.fileRead = Date.now() - start;
857
+ if (error) {
858
+ await handleCompilationError(error instanceof Error ? error : new Error(String(error)), inPath, 'file-read', mode, env.VERBOSE === 'true');
859
+ throw new Error(error instanceof Error ? error.message : String(error));
860
+ }
861
+ if (!code ||
862
+ code.trim().length === 0 ||
863
+ code === 'undefined' ||
864
+ code === 'null') {
865
+ await handleCompilationError(new Error('El archivo está vacío o no se pudo leer.'), inPath, 'file-read', mode, env.VERBOSE === 'true');
866
+ throw new Error('El archivo está vacío o no se pudo leer.');
867
+ }
868
+ // Logs detallados solo en modo verbose + all
869
+ const shouldShowDetailedLogs = env.VERBOSE === 'true' && mode === 'all';
870
+ // Compilación de Vue
871
+ let vueResult;
872
+ if (extension === '.vue') {
873
+ start = Date.now();
874
+ if (shouldShowDetailedLogs) {
875
+ logger.info(chalk.green(`💚 Precompilando VUE: ${inPath}`));
876
+ }
877
+ // Asegurar que el módulo Vue esté cargado
878
+ await moduleManager.ensureModuleLoaded('vue');
879
+ const preCompileVue = await loadVue();
880
+ if (typeof preCompileVue !== 'function') {
881
+ throw new Error(`loadVue devolvió ${typeof preCompileVue} en lugar de una función para archivo: ${inPath}`);
882
+ }
883
+ vueResult = await preCompileVue(code, inPath, env.isPROD === 'true');
884
+ timings.vueCompile = Date.now() - start;
885
+ if (vueResult === undefined || vueResult === null) {
886
+ throw new Error(`preCompileVue devolvió ${vueResult} para archivo: ${inPath}`);
887
+ }
888
+ if (vueResult.error) {
889
+ await handleCompilationError(vueResult.error instanceof Error
890
+ ? vueResult.error
891
+ : new Error(String(vueResult.error)), inPath, 'vue', mode, env.VERBOSE === 'true');
892
+ throw new Error(vueResult.error instanceof Error
893
+ ? vueResult.error.message
894
+ : String(vueResult.error));
895
+ }
896
+ registerCompilationSuccess(inPath, 'vue');
897
+ code = vueResult.data;
898
+ }
899
+ if (!code || code.trim().length === 0) {
900
+ await handleCompilationError(new Error('El código Vue compilado está vacío.'), inPath, 'vue', mode, env.VERBOSE === 'true');
901
+ throw new Error('El código Vue compilado está vacío.');
902
+ }
903
+ // Compilación de TypeScript
904
+ let tsResult;
905
+ if (extension === '.ts' || vueResult?.lang === 'ts') {
906
+ start = Date.now();
907
+ if (shouldShowDetailedLogs) {
908
+ logger.info(chalk.blue(`🔄️ Precompilando TS: ${inPath}`));
909
+ }
910
+ // Asegurar que el módulo TypeScript esté cargado
911
+ await moduleManager.ensureModuleLoaded('typescript');
912
+ const preCompileTS = await loadTypeScript();
913
+ if (typeof preCompileTS !== 'function') {
914
+ throw new Error(`loadTypeScript devolvió ${typeof preCompileTS} en lugar de una función para archivo: ${inPath}`);
915
+ }
916
+ tsResult = await preCompileTS(code, inPath);
917
+ timings.tsCompile = Date.now() - start;
918
+ if (tsResult === undefined || tsResult === null) {
919
+ throw new Error(`preCompileTS devolvió ${tsResult} para archivo: ${inPath}`);
920
+ }
921
+ if (tsResult.error) {
922
+ if (mode === 'all') {
923
+ // En modo --all, registrar el error pero continuar la compilación
924
+ registerCompilationError(inPath, 'typescript', tsResult.error instanceof Error
925
+ ? tsResult.error.message
926
+ : String(tsResult.error), 'error');
927
+ }
928
+ else {
929
+ await handleCompilationError(tsResult.error, inPath, 'typescript', mode, env.VERBOSE === 'true');
930
+ throw new Error(tsResult.error instanceof Error
931
+ ? tsResult.error.message
932
+ : String(tsResult.error));
933
+ }
934
+ }
935
+ else {
936
+ registerCompilationSuccess(inPath, 'typescript');
937
+ code = tsResult.data;
938
+ }
939
+ }
940
+ if (!code || code.trim().length === 0) {
941
+ await handleCompilationError(new Error('El código TypeScript compilado está vacío.'), inPath, 'typescript', mode, env.VERBOSE === 'true');
942
+ throw new Error('El código TypeScript compilado está vacío.');
943
+ }
944
+ // Estandarización
945
+ if (shouldShowDetailedLogs) {
946
+ logger.info(chalk.yellow(`💛 Estandarizando: ${inPath}`));
947
+ }
948
+ start = Date.now();
949
+ // Asegurar que el módulo de transformaciones esté cargado
950
+ await moduleManager.ensureModuleLoaded('transforms');
951
+ const estandarizaCode = await loadTransforms();
952
+ const resultSTD = await estandarizaCode(code, inPath);
953
+ timings.standardization = Date.now() - start;
954
+ if (resultSTD === undefined || resultSTD === null) {
955
+ throw new Error(`estandarizaCode devolvió ${resultSTD} para archivo: ${inPath}`);
956
+ }
957
+ if (resultSTD.error) {
958
+ await handleCompilationError(new Error(resultSTD.error), inPath, 'standardization', mode, env.VERBOSE === 'true');
959
+ throw new Error(resultSTD.error);
960
+ }
961
+ registerCompilationSuccess(inPath, 'standardization');
962
+ code = resultSTD.code;
963
+ if (!code || code.trim().length === 0) {
964
+ await handleCompilationError(new Error('El código estandarizado está vacío.'), inPath, 'standardization', mode, env.VERBOSE === 'true');
965
+ throw new Error('El código estandarizado está vacío.');
966
+ }
967
+ // Minificación (solo en producción)
968
+ if (env.isPROD === 'true') {
969
+ start = Date.now();
970
+ if (shouldShowDetailedLogs) {
971
+ logger.info(chalk.red(`🤖 Minificando: ${inPath}`));
972
+ }
973
+ // Asegurar que el módulo de minificación esté cargado
974
+ await moduleManager.ensureModuleLoaded('minify');
975
+ const minifyJS = await loadMinify();
976
+ const resultMinify = await minifyJS(code, inPath, true);
977
+ timings.minification = Date.now() - start;
978
+ if (resultMinify === undefined || resultMinify === null) {
979
+ throw new Error(`minifyJS devolvió ${resultMinify} para archivo: ${inPath}`);
980
+ }
981
+ if (resultMinify.error) {
982
+ await handleCompilationError(resultMinify.error instanceof Error
983
+ ? resultMinify.error
984
+ : new Error(String(resultMinify.error)), inPath, 'minification', mode, env.VERBOSE === 'true');
985
+ throw new Error(resultMinify.error instanceof Error
986
+ ? resultMinify.error.message
987
+ : String(resultMinify.error));
988
+ }
989
+ registerCompilationSuccess(inPath, 'minification');
990
+ code = resultMinify.code;
991
+ }
992
+ // Escribir archivo final
993
+ const destinationDir = path.dirname(outPath);
994
+ await mkdir(destinationDir, { recursive: true });
995
+ await writeFile(outPath, code, 'utf-8');
996
+ return {
997
+ error: null,
998
+ action: 'extension',
999
+ };
1000
+ }
1001
+ export async function initCompile(ruta, compileTailwind = true, mode = 'individual') {
1002
+ try {
1003
+ // 🚀 Sistema de Carga Inteligente de Módulos
1004
+ const moduleManager = OptimizedModuleManager.getInstance();
1005
+ const fileExtension = path.extname(ruta);
1006
+ const fileExtensions = new Set([fileExtension]);
1007
+ // Inicializar módulos según el contexto
1008
+ await moduleManager.preloadForContext(mode === 'all' ? 'batch' : mode, fileExtensions);
1009
+ // Generar TailwindCSS si está habilitado
1010
+ if (compileTailwind && Boolean(env.TAILWIND)) {
1011
+ await moduleManager.ensureModuleLoaded('tailwind');
1012
+ const generateTailwindCSS = await loadTailwind();
1013
+ const resultTW = await generateTailwindCSS();
1014
+ if (typeof resultTW !== 'boolean') {
1015
+ if (resultTW?.success) {
1016
+ logger.info(`🎨 ${resultTW.message}`);
1017
+ }
1018
+ else {
1019
+ const errorMsg = `${resultTW.message}${resultTW.details ? '\n' + resultTW.details : ''}`;
1020
+ await handleCompilationError(new Error(errorMsg), 'tailwind.config.js', 'tailwind', mode, env.VERBOSE === 'true');
1021
+ // No hacer throw aquí, permitir que la compilación continúe
1022
+ }
1023
+ }
1024
+ }
1025
+ const startTime = Date.now();
1026
+ const file = normalizeRuta(ruta);
1027
+ const outFile = getOutputPath(file);
1028
+ if (mode === 'individual' && env.VERBOSE === 'true') {
1029
+ logger.info(`🔜 Fuente: ${file}`);
1030
+ }
1031
+ const result = await compileJS(file, outFile, mode);
1032
+ if (result.error) {
1033
+ throw new Error(result.error);
1034
+ }
1035
+ const endTime = Date.now();
1036
+ const elapsedTime = showTimingForHumans(endTime - startTime);
1037
+ if (mode === 'individual') {
1038
+ if (env.VERBOSE === 'true') {
1039
+ logger.info(`🔚 Destino: ${outFile}`);
1040
+ logger.info(`⏱️ Tiempo: ${elapsedTime}`);
1041
+ }
1042
+ const chalk = await loadChalk();
1043
+ logger.info(chalk.green(`✅ Compilación exitosa: ${path.basename(file)}`));
1044
+ }
1045
+ return {
1046
+ success: true,
1047
+ output: outFile,
1048
+ action: result.action,
1049
+ };
1050
+ }
1051
+ catch (error) {
1052
+ const errorMessage = error instanceof Error ? error.message : String(error);
1053
+ if (env.VERBOSE === 'true') {
1054
+ logger.error(`❌ Error en compilación de ${path.basename(ruta)}: ${errorMessage}`);
1055
+ }
1056
+ return {
1057
+ success: false,
1058
+ output: '',
1059
+ error: errorMessage,
1060
+ };
1061
+ }
1062
+ }
1063
+ // Variable para el último progreso mostrado (evitar spam)
1064
+ let lastProgressUpdate = 0;
1065
+ // Función para ejecutar el linter antes de la compilación
1066
+ export async function runLinter(showResult = false) {
1067
+ const linterENV = env.linter;
1068
+ const linterPromises = [];
1069
+ const linterErrors = [];
1070
+ let proceedWithCompilation = true;
1071
+ if (env.ENABLE_LINTER !== 'true') {
1072
+ return true;
1073
+ }
1074
+ if (typeof linterENV === 'string' && linterENV.trim() !== '') {
1075
+ logger.info('🔍 Ejecutando linting...');
1076
+ try {
1077
+ const parsedLinterEnv = JSON.parse(linterENV);
1078
+ if (Array.isArray(parsedLinterEnv)) {
1079
+ // Cargar dependencias de linting de forma lazy
1080
+ const { ESLint, OxLint } = await loadLinter();
1081
+ for (const item of parsedLinterEnv) {
1082
+ if (item.name.toLowerCase() === 'eslint') {
1083
+ logger.info(`🔧 Ejecutando ESLint con config: ${item.configFile || 'por defecto'}`);
1084
+ const eslintPromise = ESLint(item)
1085
+ .then((eslintResult) => {
1086
+ if (eslintResult && eslintResult.json) {
1087
+ // Procesar resultados de ESLint
1088
+ if (Array.isArray(eslintResult.json)) {
1089
+ eslintResult.json.forEach((result) => {
1090
+ linterErrors.push({
1091
+ file: result.filePath ||
1092
+ 'archivo no especificado',
1093
+ message: result.message,
1094
+ severity: result.severity === 2
1095
+ ? 'error'
1096
+ : 'warning',
1097
+ help: result.ruleId
1098
+ ? `Regla ESLint: ${result.ruleId}`
1099
+ : undefined,
1100
+ });
1101
+ });
1102
+ }
1103
+ else if (eslintResult.json.results &&
1104
+ Array.isArray(eslintResult.json.results)) {
1105
+ eslintResult.json.results.forEach((fileResult) => {
1106
+ if (fileResult.messages &&
1107
+ Array.isArray(fileResult.messages)) {
1108
+ fileResult.messages.forEach((msg) => {
1109
+ linterErrors.push({
1110
+ file: fileResult.filePath ||
1111
+ 'archivo no especificado',
1112
+ message: msg.message,
1113
+ severity: msg.severity ===
1114
+ 2
1115
+ ? 'error'
1116
+ : 'warning',
1117
+ help: msg.ruleId
1118
+ ? `Regla ESLint: ${msg.ruleId}`
1119
+ : undefined,
1120
+ });
1121
+ });
1122
+ }
1123
+ });
1124
+ }
1125
+ }
1126
+ })
1127
+ .catch((err) => {
1128
+ logger.error(`❌ Error durante la ejecución de ESLint: ${err.message}`);
1129
+ linterErrors.push({
1130
+ file: item.configFile || 'ESLint Config',
1131
+ message: `Fallo al ejecutar ESLint: ${err.message}`,
1132
+ severity: 'error',
1133
+ });
1134
+ });
1135
+ linterPromises.push(eslintPromise);
1136
+ }
1137
+ else if (item.name.toLowerCase() === 'oxlint') {
1138
+ logger.info(`🔧 Ejecutando OxLint con config: ${item.configFile || 'por defecto'}`);
1139
+ const oxlintPromise = OxLint(item)
1140
+ .then((oxlintResult) => {
1141
+ if (oxlintResult &&
1142
+ oxlintResult['json'] &&
1143
+ Array.isArray(oxlintResult['json'])) {
1144
+ oxlintResult['json'].forEach((result) => {
1145
+ linterErrors.push({
1146
+ file: result.filename ||
1147
+ result.file ||
1148
+ 'archivo no especificado',
1149
+ message: result.message,
1150
+ severity: typeof result.severity ===
1151
+ 'string'
1152
+ ? result.severity.toLowerCase()
1153
+ : 'error',
1154
+ help: result.help ||
1155
+ (result.rule_id
1156
+ ? `Regla Oxlint: ${result.rule_id}`
1157
+ : undefined),
1158
+ });
1159
+ });
1160
+ }
1161
+ })
1162
+ .catch((err) => {
1163
+ logger.error(`❌ Error durante la ejecución de OxLint: ${err.message}`);
1164
+ linterErrors.push({
1165
+ file: item.configFile || 'Oxlint Config',
1166
+ message: `Fallo al ejecutar Oxlint: ${err.message}`,
1167
+ severity: 'error',
1168
+ });
1169
+ });
1170
+ linterPromises.push(oxlintPromise);
1171
+ }
1172
+ }
1173
+ }
1174
+ else {
1175
+ logger.warn('⚠️ La configuración de linter no es un array válido.');
1176
+ }
1177
+ await Promise.all(linterPromises);
1178
+ if (showResult) {
1179
+ if (linterErrors.length > 0) {
1180
+ await displayLinterErrors(linterErrors);
1181
+ }
1182
+ else {
1183
+ const chalk = await loadChalk();
1184
+ logger.info(chalk.green('✅ No se encontraron errores ni advertencias de linting.'));
1185
+ }
1186
+ }
1187
+ }
1188
+ catch (parseError) {
1189
+ logger.warn(`Error parseando configuración de linter: ${parseError instanceof Error ? parseError.message : 'Error desconocido'}, omitiendo...`);
1190
+ }
1191
+ if (!showResult && linterErrors.length > 0) {
1192
+ await displayLinterErrors(linterErrors);
1193
+ logger.warn('🚨 Se encontraron errores o advertencias durante el linting.');
1194
+ if (env.yes === 'false') {
1195
+ const result = await promptUser('¿Deseas continuar con la compilación a pesar de los errores de linting? (s/N): ');
1196
+ if (result.toLowerCase() !== 's') {
1197
+ logger.info('🛑 Compilación cancelada por el usuario.');
1198
+ proceedWithCompilation = false;
1199
+ }
1200
+ }
1201
+ }
1202
+ }
1203
+ return proceedWithCompilation;
1204
+ }
1205
+ // Función para crear una barra de progreso visual
1206
+ function createProgressBar(current, total, width = 30) {
1207
+ const percentage = Math.round((current / total) * 100);
1208
+ const filled = Math.round((percentage / 100) * width);
1209
+ const empty = width - filled;
1210
+ return `[${'█'.repeat(filled)}${' '.repeat(empty)}] ${percentage}% (${current}/${total})`;
1211
+ }
1212
+ // Función helper para verificar si un archivo debe ser omitido por cache
1213
+ async function shouldSkipFile(filePath) {
1214
+ return await smartCache.isValid(filePath);
1215
+ }
1216
+ // Función para compilar archivos con límite de concurrencia
1217
+ async function compileWithConcurrencyLimit(files, maxConcurrency = 8) {
1218
+ const results = [];
1219
+ const executing = [];
1220
+ const total = files.length;
1221
+ let completed = 0;
1222
+ let skipped = 0;
1223
+ let failed = 0; // Función para mostrar progreso
1224
+ function showProgress() {
1225
+ const currentTotal = completed + skipped + failed;
1226
+ const progressBar = createProgressBar(currentTotal, total);
1227
+ const progressPercent = Math.round((currentTotal / total) * 100);
1228
+ if (progressPercent > lastProgressUpdate + 1 ||
1229
+ currentTotal === total) {
1230
+ stdout.write(`\r🚀 ${progressBar} [✅ ${completed} | ⏭️ ${skipped} | ❌ ${failed}]`);
1231
+ lastProgressUpdate = progressPercent;
1232
+ }
1233
+ }
1234
+ for (const file of files) {
1235
+ const promise = (async () => {
1236
+ try {
1237
+ // Verificar cache antes de compilar
1238
+ if (await shouldSkipFile(file)) {
1239
+ skipped++;
1240
+ showProgress();
1241
+ return {
1242
+ success: true,
1243
+ cached: true,
1244
+ output: smartCache.getOutputPath(file),
1245
+ };
1246
+ }
1247
+ const result = await initCompile(file, false, 'batch'); // Actualizar cache si la compilación fue exitosa
1248
+ if (result.success && result.output) {
1249
+ await smartCache.set(file, result.output);
1250
+ }
1251
+ completed++;
1252
+ showProgress();
1253
+ return result;
1254
+ }
1255
+ catch (error) {
1256
+ failed++;
1257
+ showProgress();
1258
+ return {
1259
+ success: false,
1260
+ error: error instanceof Error ? error.message : String(error),
1261
+ };
1262
+ }
1263
+ })();
1264
+ results.push(promise);
1265
+ executing.push(promise);
1266
+ if (executing.length >= maxConcurrency) {
1267
+ await Promise.race(executing);
1268
+ executing.splice(executing.findIndex(p => p === promise), 1);
1269
+ }
1270
+ }
1271
+ await Promise.all(results);
1272
+ console.log('\n'); // Nueva línea después de la barra de progreso
1273
+ }
1274
+ export async function initCompileAll() {
1275
+ try {
1276
+ // Limpiar estado de compilación anterior
1277
+ clearCompilationState();
1278
+ // Cargar cache al inicio
1279
+ await loadCache();
1280
+ lastProgressUpdate = 0;
1281
+ const shouldContinue = await runLinter();
1282
+ if (!shouldContinue) {
1283
+ // await displayCompilationSummary(env.VERBOSE === 'true');
1284
+ return;
1285
+ }
1286
+ const startTime = Date.now();
1287
+ const rawPathSource = env.PATH_SOURCE ?? '';
1288
+ const pathDist = env.PATH_DIST ?? '';
1289
+ const normalizedGlobPathSource = rawPathSource.replace(/\\/g, '/');
1290
+ const patterns = [
1291
+ `${normalizedGlobPathSource}/**/*.js`,
1292
+ `${normalizedGlobPathSource}/**/*.vue`,
1293
+ `${normalizedGlobPathSource}/**/*.ts`,
1294
+ `${normalizedGlobPathSource}/**/*.mjs`,
1295
+ `${normalizedGlobPathSource}/**/*.cjs`,
1296
+ ];
1297
+ logger.info(`📝 Compilando todos los archivos...`);
1298
+ logger.info(`🔜 Fuente: ${rawPathSource}`);
1299
+ logger.info(`🔚 Destino: ${pathDist}\n`); // Generar TailwindCSS
1300
+ const generateTailwindCSS = await loadTailwind();
1301
+ const resultTW = await generateTailwindCSS();
1302
+ if (typeof resultTW !== 'boolean') {
1303
+ if (resultTW?.success) {
1304
+ logger.info(`🎨 ${resultTW.message}\n`);
1305
+ }
1306
+ else {
1307
+ await handleCompilationError(new Error(`${resultTW.message}${resultTW.details ? '\n' + resultTW.details : ''}`), 'tailwind.config.js', 'tailwind', 'all', env.VERBOSE === 'true');
1308
+ }
1309
+ } // Recopilar todos los archivos
1310
+ const filesToCompile = [];
1311
+ for await (const file of glob(patterns)) {
1312
+ if (file.endsWith('.d.ts')) {
1313
+ continue;
1314
+ }
1315
+ // Usar la ruta tal como viene de glob, sin modificar
1316
+ filesToCompile.push(file);
1317
+ }
1318
+ // Determinar concurrencia óptima
1319
+ const cpuCount = os.cpus().length;
1320
+ const fileCount = filesToCompile.length;
1321
+ let maxConcurrency;
1322
+ if (fileCount < 10) {
1323
+ maxConcurrency = Math.min(fileCount, cpuCount);
1324
+ }
1325
+ else if (fileCount < 50) {
1326
+ maxConcurrency = Math.min(cpuCount * 2, 12);
1327
+ }
1328
+ else {
1329
+ maxConcurrency = Math.min(cpuCount * 2, 16);
1330
+ }
1331
+ logger.info(`🚀 Compilando ${fileCount} archivos con concurrencia optimizada (${maxConcurrency} hilos)...`); // Configurar worker pool para modo batch
1332
+ try {
1333
+ const { TypeScriptWorkerPool } = await import('./typescript-worker-pool.js');
1334
+ const workerPool = TypeScriptWorkerPool.getInstance();
1335
+ workerPool.setMode('batch');
1336
+ }
1337
+ catch {
1338
+ // Error silencioso en configuración del pool
1339
+ }
1340
+ await compileWithConcurrencyLimit(filesToCompile, maxConcurrency);
1341
+ // Guardar cache al final
1342
+ await saveCache();
1343
+ const endTime = Date.now();
1344
+ const elapsedTime = showTimingForHumans(endTime - startTime);
1345
+ logger.info(`⏱️ Tiempo total de compilación: ${elapsedTime}\n`); // Mostrar resumen de compilación
1346
+ await displayCompilationSummary(env.VERBOSE === 'true');
1347
+ }
1348
+ catch (error) {
1349
+ const errorMessage = error instanceof Error ? error.message : String(error);
1350
+ logger.error(`🚩 Error al compilar todos los archivos: ${errorMessage}`);
1351
+ // Registrar el error en el sistema unificado
1352
+ await handleCompilationError(error instanceof Error ? error : new Error(String(error)), 'compilación general', 'all', 'all', env.VERBOSE === 'true');
1353
+ // Mostrar resumen incluso si hay errores generales
1354
+ await displayCompilationSummary(env.VERBOSE === 'true');
1355
+ }
1356
+ }
1357
+ // Función wrapper para compatibilidad con tests
1358
+ export async function compileFile(filePath) {
1359
+ return await initCompile(filePath, true, 'individual');
1360
+ }
1361
+ export { WatchModeOptimizer };
1362
+ //# sourceMappingURL=compile.js.map