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,2332 +1,26 @@
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 process, { argv, cwd, env } from 'node:process';
6
- // Lazy loading optimizations - Only import lightweight modules synchronously
7
- import { logger, setProgressManagerGetter } from '../servicios/logger.js';
8
- import { promptUser } from '../utils/promptUser.js';
9
- import { showTimingForHumans } from '../utils/utils.js';
10
- // Configurar el getter del ProgressManager para el logger
11
- setProgressManagerGetter(() => ProgressManager.getInstance());
12
- // Heavy dependencies will be loaded dynamically when needed
13
- let chalk;
14
- let ESLint;
15
- let OxLint;
16
- let minifyJS;
17
- let getCodeFile;
18
- let generateTailwindCSS;
19
- let estandarizaCode;
20
- let preCompileTS;
21
- let preCompileVue;
22
- // 🚀 Importar optimizador de transformaciones
23
- let TransformOptimizer;
24
- // 🚀 Importar optimizador de resolución de módulos
25
- let ModuleResolutionOptimizer;
26
- // 🚀 Sistema de Carga Inteligente de Módulos - VERSIÓN OPTIMIZADA V2
27
- class OptimizedModuleManager {
28
- static instance;
29
- isInitialized = false;
30
- loadedModules = new Set();
31
- // ✨ NUEVAS OPTIMIZACIONES
32
- modulePool = new Map(); // Pool de instancias reutilizables
33
- loadingPromises = new Map(); // Prevenir cargas duplicadas
34
- usageStats = new Map(); // Estadísticas de uso
35
- preloadQueue = new Set(); // Cola de precarga
36
- backgroundLoader = null; // Cargador en background
37
- // Módulos críticos que siempre se precargan
38
- HOT_MODULES = ['chalk', 'parser'];
39
- // Contexto actual para optimizar cargas
40
- currentContext = null;
41
- constructor() {
42
- // Iniciar precarga en background inmediatamente
43
- this.startBackgroundPreloading();
44
- }
45
- static getInstance() {
46
- if (!OptimizedModuleManager.instance) {
47
- OptimizedModuleManager.instance = new OptimizedModuleManager();
48
- }
49
- return OptimizedModuleManager.instance;
50
- }
51
- /**
52
- * ✨ NUEVO: Precarga en background para módulos críticos
53
- */
54
- startBackgroundPreloading() {
55
- this.backgroundLoader = this.preloadCriticalModules();
56
- }
57
- /**
58
- * ✨ NUEVO: Precarga módulos críticos en background
59
- */
60
- async preloadCriticalModules() {
61
- try {
62
- // Precargar módulos críticos de forma asíncrona
63
- const preloadPromises = this.HOT_MODULES.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
64
- // Silenciar errores de precarga, se intentará cargar después
65
- }));
66
- await Promise.allSettled(preloadPromises);
67
- }
68
- catch {
69
- // Fallos en precarga no deben afectar la funcionalidad principal
70
- }
71
- }
72
- /**
73
- * ✨ MEJORADO: Precarga contextual basada en tipos de archivo
74
- */
75
- async preloadForContext(context, fileTypes = new Set()) {
76
- this.currentContext = context;
77
- // Esperar que termine la precarga crítica si está en progreso
78
- if (this.backgroundLoader) {
79
- await this.backgroundLoader;
80
- }
81
- const toPreload = []; // Precarga basada en contexto
82
- if (context === 'batch' || context === 'watch') {
83
- // En batch/watch, precargar todos los módulos comunes
84
- toPreload.push('transforms', 'vue', 'typescript', 'module-resolution-optimizer');
85
- }
86
- else {
87
- // En individual, cargar solo según tipos de archivo detectados
88
- if (fileTypes.has('.vue'))
89
- toPreload.push('vue');
90
- if (fileTypes.has('.ts') || fileTypes.has('.vue'))
91
- toPreload.push('typescript');
92
- if (!this.loadedModules.has('transforms'))
93
- toPreload.push('transforms');
94
- }
95
- // Precargar en paralelo
96
- const preloadPromises = toPreload.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
97
- // Log warning pero no fallar
98
- console.warn(`Warning: No se pudo precargar módulo ${moduleName}`);
99
- }));
100
- await Promise.allSettled(preloadPromises);
101
- }
102
- /**
103
- * ✨ MEJORADO: Carga inteligente con pooling y deduplicación
104
- */
105
- async ensureModuleLoaded(moduleName) {
106
- // 1. Verificar pool de módulos primero
107
- if (this.modulePool.has(moduleName)) {
108
- this.updateUsageStats(moduleName);
109
- return this.modulePool.get(moduleName);
110
- }
111
- // 2. Verificar si ya está cargando (deduplicación)
112
- if (this.loadingPromises.has(moduleName)) {
113
- return this.loadingPromises.get(moduleName);
114
- }
115
- // 3. Iniciar carga
116
- const loadPromise = this.loadModuleInternal(moduleName);
117
- this.loadingPromises.set(moduleName, loadPromise);
118
- try {
119
- const moduleInstance = await loadPromise;
120
- // 4. Almacenar en pool y estadísticas
121
- this.modulePool.set(moduleName, moduleInstance);
122
- this.loadedModules.add(moduleName);
123
- this.updateUsageStats(moduleName);
124
- return moduleInstance;
125
- }
126
- finally {
127
- // 5. Limpiar promesa de carga
128
- this.loadingPromises.delete(moduleName);
129
- }
130
- }
131
- /**
132
- * ✨ NUEVO: Actualiza estadísticas de uso para optimizaciones futuras
133
- */
134
- updateUsageStats(moduleName) {
135
- const currentCount = this.usageStats.get(moduleName) || 0;
136
- this.usageStats.set(moduleName, currentCount + 1);
137
- }
138
- /**
139
- * ✨ MEJORADO: Carga interna de módulos con mejor manejo de errores
140
- */ async loadModuleInternal(moduleName) {
141
- switch (moduleName) {
142
- case 'chalk':
143
- return this.loadChalk();
144
- case 'parser':
145
- return this.loadParser();
146
- case 'transforms':
147
- return this.loadTransforms();
148
- case 'vue':
149
- return this.loadVue();
150
- case 'typescript':
151
- return this.loadTypeScript();
152
- case 'minify':
153
- return this.loadMinify();
154
- case 'tailwind':
155
- return this.loadTailwind();
156
- case 'linter':
157
- return this.loadLinter();
158
- case 'transform-optimizer':
159
- return this.loadTransformOptimizer();
160
- case 'module-resolution-optimizer':
161
- return this.loadModuleResolutionOptimizer();
162
- default:
163
- throw new Error(`Módulo desconocido: ${moduleName}`);
164
- }
165
- }
166
- // ✨ Métodos de carga específicos optimizados
167
- async loadChalk() {
168
- if (!chalk) {
169
- chalk = (await import('chalk')).default;
170
- }
171
- return chalk;
172
- }
173
- async loadParser() {
174
- if (!getCodeFile) {
175
- const parserModule = await import('./parser.js');
176
- getCodeFile = parserModule.getCodeFile;
177
- }
178
- return getCodeFile;
179
- }
180
- async loadTransforms() {
181
- if (!estandarizaCode) {
182
- const transformsModule = await import('./transforms.js');
183
- estandarizaCode = transformsModule.estandarizaCode;
184
- }
185
- return estandarizaCode;
186
- }
187
- async loadVue() {
188
- if (!preCompileVue) {
189
- const vueModule = await import('./vuejs.js');
190
- preCompileVue = vueModule.preCompileVue;
191
- }
192
- return preCompileVue;
193
- }
194
- async loadTypeScript() {
195
- if (!preCompileTS) {
196
- const typescriptModule = await import('./typescript-manager.js');
197
- preCompileTS = typescriptModule.preCompileTS;
198
- }
199
- return preCompileTS;
200
- }
201
- async loadMinify() {
202
- if (!minifyJS) {
203
- const minifyModule = await import('./minify.js');
204
- minifyJS = minifyModule.minifyJS;
205
- }
206
- return minifyJS;
207
- }
208
- async loadTailwind() {
209
- if (!generateTailwindCSS) {
210
- const tailwindModule = await import('./tailwindcss.js');
211
- generateTailwindCSS = tailwindModule.generateTailwindCSS;
212
- }
213
- return generateTailwindCSS;
214
- }
215
- async loadLinter() {
216
- if (!ESLint || !OxLint) {
217
- const linterModule = await import('./linter.js');
218
- ESLint = linterModule.ESLint;
219
- OxLint = linterModule.OxLint;
220
- }
221
- return { ESLint, OxLint };
222
- }
223
- async loadTransformOptimizer() {
224
- if (!TransformOptimizer) {
225
- const transformModule = await import('./transform-optimizer.js');
226
- TransformOptimizer =
227
- transformModule.TransformOptimizer.getInstance();
228
- }
229
- return TransformOptimizer;
230
- }
231
- async loadModuleResolutionOptimizer() {
232
- if (!ModuleResolutionOptimizer) {
233
- const resolutionModule = await import('./module-resolution-optimizer.js');
234
- ModuleResolutionOptimizer =
235
- resolutionModule.ModuleResolutionOptimizer.getInstance();
236
- }
237
- return ModuleResolutionOptimizer;
238
- }
239
- /**
240
- * ✨ NUEVO: Obtiene estadísticas de performance del manager
241
- */
242
- getPerformanceStats() {
243
- const sortedByUsage = Array.from(this.usageStats.entries())
244
- .sort((a, b) => b[1] - a[1])
245
- .slice(0, 5)
246
- .map(([name]) => name);
247
- return {
248
- loadedModules: Array.from(this.loadedModules),
249
- usageStats: Object.fromEntries(this.usageStats),
250
- poolSize: this.modulePool.size,
251
- loadingInProgress: Array.from(this.loadingPromises.keys()),
252
- mostUsedModules: sortedByUsage,
253
- };
254
- }
255
- /**
256
- * ✨ NUEVO: Limpia módulos no utilizados para liberar memoria
257
- */
258
- cleanupUnusedModules() {
259
- const threshold = 1; // Mínimo de usos para mantener en pool
260
- for (const [moduleName, usageCount] of this.usageStats) {
261
- if (usageCount < threshold &&
262
- !this.HOT_MODULES.includes(moduleName)) {
263
- this.modulePool.delete(moduleName);
264
- this.loadedModules.delete(moduleName);
265
- this.usageStats.delete(moduleName);
266
- }
267
- }
268
- }
269
- /**
270
- * Resetea el estado del manager (útil para tests)
271
- */
272
- reset() {
273
- this.isInitialized = false;
274
- this.loadedModules.clear();
275
- this.modulePool.clear();
276
- this.loadingPromises.clear();
277
- this.usageStats.clear();
278
- this.preloadQueue.clear();
279
- this.currentContext = null;
280
- this.backgroundLoader = null;
281
- // Reiniciar precarga crítica
282
- this.startBackgroundPreloading();
283
- }
284
- }
285
- // Lazy loading helper functions
286
- async function loadChalk() {
287
- if (!chalk) {
288
- chalk = (await import('chalk')).default;
289
- }
290
- return chalk;
291
- }
292
- async function loadLinter() {
293
- if (!ESLint || !OxLint) {
294
- const linterModule = await import('./linter.js');
295
- ESLint = linterModule.ESLint;
296
- OxLint = linterModule.OxLint;
297
- }
298
- return { ESLint, OxLint };
299
- }
300
- async function loadMinify() {
301
- if (!minifyJS) {
302
- const minifyModule = await import('./minify.js');
303
- minifyJS = minifyModule.minifyJS;
304
- }
305
- return minifyJS;
306
- }
307
- async function loadParser() {
308
- if (!getCodeFile) {
309
- const parserModule = await import('./parser.js');
310
- getCodeFile = parserModule.getCodeFile;
311
- }
312
- return getCodeFile;
313
- }
314
- async function loadTailwind() {
315
- if (!generateTailwindCSS) {
316
- const tailwindModule = await import('./tailwindcss.js');
317
- generateTailwindCSS = tailwindModule.generateTailwindCSS;
318
- }
319
- return generateTailwindCSS;
320
- }
321
- async function loadTransforms() {
322
- if (!estandarizaCode) {
323
- const transformsModule = await import('./transforms.js');
324
- estandarizaCode = transformsModule.estandarizaCode;
325
- }
326
- return estandarizaCode;
327
- }
328
- async function loadTypeScript() {
329
- if (!preCompileTS) {
330
- const typescriptModule = await import('./typescript-manager.js');
331
- preCompileTS = typescriptModule.preCompileTS;
332
- }
333
- return preCompileTS;
334
- }
335
- async function loadVue() {
336
- if (!preCompileVue) {
337
- const vueModule = await import('./vuejs.js');
338
- preCompileVue = vueModule.preCompileVue;
339
- }
340
- return preCompileVue;
341
- }
342
- // Almacenamiento global de errores y resultados
343
- const compilationErrors = [];
344
- const compilationResults = [];
345
- // Variables de entorno relevantes para compilación
346
- const COMPILATION_ENV_VARS = [
347
- 'NODE_ENV',
348
- 'isPROD',
349
- 'TAILWIND',
350
- 'ENABLE_LINTER',
351
- 'VERBOSE',
352
- 'typeCheck',
353
- 'PATH_ALIAS',
354
- 'tailwindcss',
355
- 'linter',
356
- 'tsconfigFile',
357
- ];
358
- class SmartCompilationCache {
359
- cache = new Map();
360
- maxEntries = 200; // Reducido para tests de estrés
361
- maxMemory = 50 * 1024 * 1024; // 50MB límite (reducido)
362
- currentMemoryUsage = 0;
363
- // ✨ ISSUE #3: Sistema de vigilancia de dependencias
364
- fileWatchers = new Map(); // chokidar watchers
365
- dependencyGraph = new Map(); // archivo -> dependencias
366
- reverseDependencyGraph = new Map(); // dependencia -> archivos que la usan
367
- packageJsonPath = path.join(cwd(), 'package.json');
368
- nodeModulesPath = path.join(cwd(), 'node_modules');
369
- isWatchingDependencies = false;
370
- /**
371
- * Genera hash SHA-256 del contenido del archivo
372
- */ async generateContentHash(filePath) {
373
- try {
374
- const content = await readFile(filePath, 'utf8');
375
- return createHash('sha256').update(content).digest('hex');
376
- }
377
- catch {
378
- // Si no se puede leer el archivo, generar hash único basado en la ruta y timestamp
379
- const fallback = `${filePath}-${Date.now()}`;
380
- return createHash('sha256').update(fallback).digest('hex');
381
- }
382
- }
383
- /**
384
- * Genera hash de la configuración del compilador
385
- */
386
- generateConfigHash() {
387
- try {
388
- // Recopilar configuración relevante de variables de entorno
389
- const config = {
390
- isPROD: env.isPROD || 'false',
391
- TAILWIND: env.TAILWIND || 'false',
392
- ENABLE_LINTER: env.ENABLE_LINTER || 'false',
393
- PATH_ALIAS: env.PATH_ALIAS || '{}',
394
- tailwindcss: env.tailwindcss || 'false',
395
- linter: env.linter || 'false',
396
- tsconfigFile: env.tsconfigFile || './tsconfig.json',
397
- };
398
- const configStr = JSON.stringify(config, Object.keys(config).sort());
399
- return createHash('sha256')
400
- .update(configStr)
401
- .digest('hex')
402
- .substring(0, 12);
403
- }
404
- catch {
405
- return 'no-config';
406
- }
407
- }
408
- /**
409
- * Genera hash de variables de entorno relevantes
410
- */
411
- generateEnvHash() {
412
- try {
413
- const envVars = COMPILATION_ENV_VARS.map(key => `${key}=${env[key] || ''}`).join('|');
414
- return createHash('sha256')
415
- .update(envVars)
416
- .digest('hex')
417
- .substring(0, 12);
418
- }
419
- catch {
420
- return 'no-env';
421
- }
422
- } /**
423
- * ✨ ISSUE #3: Genera hash avanzado de dependencias del proyecto
424
- * Incluye vigilancia de package.json, node_modules y versiones instaladas
425
- */
426
- async generateDependencyHash() {
427
- try {
428
- const hash = createHash('sha256');
429
- // 1. Hash del package.json con versiones
430
- const packagePath = path.join(cwd(), 'package.json');
431
- const packageContent = await readFile(packagePath, 'utf8');
432
- const pkg = JSON.parse(packageContent);
433
- const deps = {
434
- ...pkg.dependencies,
435
- ...pkg.devDependencies,
436
- };
437
- const depsStr = JSON.stringify(deps, Object.keys(deps).sort());
438
- hash.update(`package:${depsStr}`);
439
- // 2. Hash del package-lock.json si existe (versiones exactas instaladas)
440
- try {
441
- const lockPath = path.join(cwd(), 'package-lock.json');
442
- const lockContent = await readFile(lockPath, 'utf8');
443
- const lockData = JSON.parse(lockContent);
444
- // Solo incluir las versiones instaladas, no todo el lockfile
445
- const installedVersions = {};
446
- if (lockData.packages) {
447
- for (const [pkgPath, pkgInfo] of Object.entries(lockData.packages)) {
448
- if (pkgPath &&
449
- pkgPath !== '' &&
450
- typeof pkgInfo === 'object' &&
451
- pkgInfo !== null) {
452
- const pkgName = pkgPath.replace('node_modules/', '');
453
- if (pkgInfo.version) {
454
- installedVersions[pkgName] = pkgInfo.version;
455
- }
456
- }
457
- }
458
- }
459
- hash.update(`lock:${JSON.stringify(installedVersions, Object.keys(installedVersions).sort())}`);
460
- }
461
- catch {
462
- // Ignorar si no existe package-lock.json
463
- }
464
- // 3. ✨ NUEVO: Hash de timestamps críticos de node_modules
465
- try {
466
- const nodeModulesPath = path.join(cwd(), 'node_modules');
467
- const nodeModulesStat = await stat(nodeModulesPath);
468
- hash.update(`nmtime:${nodeModulesStat.mtimeMs}`);
469
- // Verificar timestamps de dependencias críticas instaladas
470
- const criticalDeps = Object.keys(deps).slice(0, 10); // Top 10 para performance
471
- for (const dep of criticalDeps) {
472
- try {
473
- const depPath = path.join(nodeModulesPath, dep);
474
- const depStat = await stat(depPath);
475
- hash.update(`${dep}:${depStat.mtimeMs}`);
476
- }
477
- catch {
478
- // Dependencia no instalada o error
479
- hash.update(`${dep}:missing`);
480
- }
481
- }
482
- }
483
- catch {
484
- // node_modules no existe
485
- hash.update('nmtime:none');
486
- }
487
- return hash.digest('hex').substring(0, 16);
488
- }
489
- catch (error) {
490
- // Incluir información del error en el hash para debugging
491
- return createHash('sha256')
492
- .update(`error:${error instanceof Error ? error.message : 'unknown'}`)
493
- .digest('hex')
494
- .substring(0, 16);
495
- }
496
- }
497
- /**
498
- * Genera clave de cache granular que incluye todos los factores
499
- */
500
- async generateCacheKey(filePath) {
501
- const contentHash = await this.generateContentHash(filePath);
502
- const configHash = this.generateConfigHash();
503
- const envHash = this.generateEnvHash();
504
- const dependencyHash = await this.generateDependencyHash();
505
- // Usar | como separador para evitar problemas con rutas de Windows
506
- return `${filePath}|${contentHash.substring(0, 12)}|${configHash}|${envHash}|${dependencyHash}`;
507
- } /**
508
- * Verifica si una entrada de cache es válida
509
- */
510
- async isValid(filePath) {
511
- const entry = this.cache.get(filePath);
512
- if (!entry)
513
- return false;
514
- try {
515
- // Verificar si el archivo de salida existe
516
- await stat(entry.outputPath);
517
- // Verificar si el contenido ha cambiado
518
- const currentContentHash = await this.generateContentHash(filePath);
519
- if (entry.contentHash !== currentContentHash) {
520
- this.cache.delete(filePath);
521
- return false;
522
- }
523
- // Verificar si la configuración ha cambiado
524
- const currentConfigHash = this.generateConfigHash();
525
- if (entry.configHash !== currentConfigHash) {
526
- this.cache.delete(filePath);
527
- return false;
528
- }
529
- // Verificar si las variables de entorno han cambiado
530
- const currentEnvHash = this.generateEnvHash();
531
- if (entry.envHash !== currentEnvHash) {
532
- this.cache.delete(filePath);
533
- return false;
534
- }
535
- // Verificar si las dependencias han cambiado
536
- const currentDependencyHash = await this.generateDependencyHash();
537
- if (entry.dependencyHash !== currentDependencyHash) {
538
- this.cache.delete(filePath);
539
- return false;
540
- }
541
- // Verificar tiempo de modificación como backup
542
- const stats = await stat(filePath);
543
- if (stats.mtimeMs > entry.mtime) {
544
- this.cache.delete(filePath);
545
- return false;
546
- }
547
- // Actualizar tiempo de uso para LRU
548
- entry.lastUsed = Date.now();
549
- return true;
550
- }
551
- catch {
552
- // Si hay error verificando, eliminar del cache
553
- this.cache.delete(filePath);
554
- return false;
555
- }
556
- } /**
557
- * Añade una entrada al cache
558
- */
559
- async set(filePath, outputPath) {
560
- try {
561
- const stats = await stat(filePath);
562
- const contentHash = await this.generateContentHash(filePath);
563
- const configHash = this.generateConfigHash();
564
- const envHash = this.generateEnvHash();
565
- const dependencyHash = await this.generateDependencyHash();
566
- const entry = {
567
- contentHash,
568
- configHash,
569
- envHash,
570
- dependencyHash,
571
- mtime: stats.mtimeMs,
572
- outputPath,
573
- lastUsed: Date.now(),
574
- size: stats.size,
575
- };
576
- // Aplicar límites de memoria y entradas antes de agregar
577
- this.evictIfNeeded(entry.size);
578
- this.cache.set(filePath, entry);
579
- this.currentMemoryUsage += entry.size;
580
- }
581
- catch (error) {
582
- // Si hay error, no cachear
583
- console.warn(`Warning: No se pudo cachear ${filePath}:`, error);
584
- }
585
- } /**
586
- * Aplica política LRU para liberar espacio
587
- */
588
- evictIfNeeded(newEntrySize) {
589
- // Verificar límite de entradas más agresivamente
590
- while (this.cache.size >= this.maxEntries * 0.8) {
591
- // Limpiar cuando llegue al 80%
592
- this.evictLRU();
593
- }
594
- // Verificar límite de memoria más agresivamente
595
- while (this.currentMemoryUsage + newEntrySize > this.maxMemory * 0.8 && // Limpiar cuando llegue al 80%
596
- this.cache.size > 0) {
597
- this.evictLRU();
598
- }
599
- // Eviction adicional si la memoria total del proceso es alta
600
- const memUsage = process.memoryUsage();
601
- const heapUsedMB = memUsage.heapUsed / (1024 * 1024);
602
- if (heapUsedMB > 200 && this.cache.size > 50) {
603
- // Si heap > 200MB, limpiar más agresivamente
604
- const entriesToRemove = Math.min(this.cache.size - 50, 10);
605
- for (let i = 0; i < entriesToRemove; i++) {
606
- this.evictLRU();
607
- }
608
- }
609
- } /**
610
- * Elimina la entrada menos recientemente usada
611
- */
612
- evictLRU() {
613
- let oldestKey = '';
614
- let oldestTime = Infinity;
615
- for (const [key, entry] of this.cache) {
616
- if (entry.lastUsed < oldestTime) {
617
- oldestTime = entry.lastUsed;
618
- oldestKey = key;
619
- }
620
- }
621
- if (oldestKey) {
622
- const entry = this.cache.get(oldestKey);
623
- if (entry) {
624
- this.currentMemoryUsage -= entry.size;
625
- this.cache.delete(oldestKey);
626
- }
627
- }
628
- }
629
- /**
630
- * Método público para limpiar entradas del cache cuando sea necesario
631
- */
632
- cleanOldEntries(maxEntriesToRemove = 20) {
633
- let removedCount = 0;
634
- for (let i = 0; i < maxEntriesToRemove && this.cache.size > 0; i++) {
635
- const sizeBefore = this.cache.size;
636
- this.evictLRU();
637
- if (this.cache.size < sizeBefore) {
638
- removedCount++;
639
- }
640
- else {
641
- break; // No se pudo remover más entradas
642
- }
643
- }
644
- return removedCount;
645
- }
646
- /**
647
- * Carga el cache desde disco
648
- */
649
- async load(cacheFile) {
650
- try {
651
- if (env.cleanCache === 'true') {
652
- this.cache.clear();
653
- this.currentMemoryUsage = 0;
654
- try {
655
- await unlink(cacheFile);
656
- }
657
- catch {
658
- // Ignorar errores al eliminar el archivo
659
- }
660
- return;
661
- }
662
- const cacheData = await readFile(cacheFile, 'utf-8');
663
- const parsed = JSON.parse(cacheData);
664
- // Validar y cargar entradas del cache
665
- for (const [key, value] of Object.entries(parsed)) {
666
- const entry = value;
667
- if (entry.contentHash && entry.outputPath && entry.mtime) {
668
- this.cache.set(key, entry);
669
- this.currentMemoryUsage += entry.size || 0;
670
- }
671
- }
672
- }
673
- catch {
674
- // Cache file doesn't exist or is invalid, start fresh
675
- this.cache.clear();
676
- this.currentMemoryUsage = 0;
677
- }
678
- }
679
- /**
680
- * Guarda el cache a disco
681
- */
682
- async save(cacheFile, cacheDir) {
683
- try {
684
- await mkdir(cacheDir, { recursive: true });
685
- const cacheData = Object.fromEntries(this.cache);
686
- await writeFile(cacheFile, JSON.stringify(cacheData, null, 2));
687
- }
688
- catch (error) {
689
- console.warn('Warning: No se pudo guardar el cache:', error);
690
- }
691
- }
692
- /**
693
- * Limpia completamente el cache
694
- */
695
- clear() {
696
- this.cache.clear();
697
- this.currentMemoryUsage = 0;
698
- } /**
699
- * Obtiene la ruta de salida para un archivo cacheado
700
- */
701
- getOutputPath(filePath) {
702
- const entry = this.cache.get(filePath);
703
- return entry?.outputPath || '';
704
- } /**
705
- * Obtiene estadísticas del cache
706
- */
707
- getStats() {
708
- return {
709
- entries: this.cache.size,
710
- memoryUsage: this.currentMemoryUsage,
711
- hitRate: 0, // Se calculará externamente
712
- };
713
- }
714
- // ✨ ISSUE #3: Métodos de vigilancia y invalidación cascada
715
- /**
716
- * Inicializa vigilancia de package.json y node_modules
717
- */
718
- async startDependencyWatching() {
719
- if (this.isWatchingDependencies)
720
- return;
721
- try {
722
- // Lazy load chokidar para evitar problemas de importación
723
- const chokidar = await import('chokidar');
724
- // Vigilar package.json
725
- if (await this.fileExists(this.packageJsonPath)) {
726
- const packageWatcher = chokidar.watch(this.packageJsonPath, {
727
- persistent: false, // No mantener el proceso vivo
728
- ignoreInitial: true,
729
- });
730
- packageWatcher.on('change', () => {
731
- logger.info('📦 package.json modificado - invalidando cache de dependencias');
732
- this.invalidateByDependencyChange();
733
- });
734
- this.fileWatchers.set('package.json', packageWatcher);
735
- }
736
- // Vigilar node_modules (solo cambios en el directorio raíz para performance)
737
- if (await this.fileExists(this.nodeModulesPath)) {
738
- const nodeModulesWatcher = chokidar.watch(this.nodeModulesPath, {
739
- persistent: false,
740
- ignoreInitial: true,
741
- depth: 1, // Solo primer nivel para performance
742
- ignored: /(^|[/\\])\../, // Ignorar archivos ocultos
743
- });
744
- nodeModulesWatcher.on('addDir', (path) => {
745
- logger.info(`📦 Nueva dependencia instalada: ${path.split(/[/\\]/).pop()}`);
746
- this.invalidateByDependencyChange();
747
- });
748
- nodeModulesWatcher.on('unlinkDir', (path) => {
749
- logger.info(`📦 Dependencia eliminada: ${path.split(/[/\\]/).pop()}`);
750
- this.invalidateByDependencyChange();
751
- });
752
- this.fileWatchers.set('node_modules', nodeModulesWatcher);
753
- }
754
- this.isWatchingDependencies = true;
755
- logger.info('🔍 Vigilancia de dependencias iniciada');
756
- }
757
- catch (error) {
758
- logger.warn('⚠️ No se pudo iniciar vigilancia de dependencias:', error);
759
- }
760
- }
761
- /**
762
- * Detiene la vigilancia de dependencias
763
- */
764
- async stopDependencyWatching() {
765
- for (const [name, watcher] of this.fileWatchers) {
766
- try {
767
- await watcher.close();
768
- logger.info(`🛑 Vigilancia detenida: ${name}`);
769
- }
770
- catch (error) {
771
- logger.warn(`⚠️ Error cerrando watcher ${name}:`, error);
772
- }
773
- }
774
- this.fileWatchers.clear();
775
- this.isWatchingDependencies = false;
776
- }
777
- /**
778
- * Registra dependencias de un archivo para invalidación cascada
779
- */
780
- registerDependencies(filePath, dependencies) {
781
- // Limpiar dependencias anteriores
782
- const oldDeps = this.dependencyGraph.get(filePath);
783
- if (oldDeps) {
784
- for (const dep of oldDeps) {
785
- const reverseDeps = this.reverseDependencyGraph.get(dep);
786
- if (reverseDeps) {
787
- reverseDeps.delete(filePath);
788
- if (reverseDeps.size === 0) {
789
- this.reverseDependencyGraph.delete(dep);
790
- }
791
- }
792
- }
793
- }
794
- // Registrar nuevas dependencias
795
- const newDeps = new Set(dependencies);
796
- this.dependencyGraph.set(filePath, newDeps);
797
- for (const dep of newDeps) {
798
- if (!this.reverseDependencyGraph.has(dep)) {
799
- this.reverseDependencyGraph.set(dep, new Set());
800
- }
801
- this.reverseDependencyGraph.get(dep).add(filePath);
802
- }
803
- }
804
- /**
805
- * Invalida cache por cambios en dependencias
806
- */
807
- invalidateByDependencyChange() {
808
- let invalidatedCount = 0;
809
- // Invalidar todos los archivos que dependen de dependencias externas
810
- for (const [filePath] of this.cache) {
811
- this.cache.delete(filePath);
812
- invalidatedCount++;
813
- }
814
- // Limpiar grafos de dependencias
815
- this.dependencyGraph.clear();
816
- this.reverseDependencyGraph.clear();
817
- this.currentMemoryUsage = 0;
818
- logger.info(`🗑️ Cache invalidado: ${invalidatedCount} archivos (cambio en dependencias)`);
819
- }
820
- /**
821
- * Invalida cascada cuando un archivo específico cambia
822
- */
823
- invalidateCascade(changedFile) {
824
- const invalidated = [];
825
- const toInvalidate = new Set([changedFile]);
826
- // BFS para encontrar todos los archivos afectados
827
- const queue = [changedFile];
828
- while (queue.length > 0) {
829
- const current = queue.shift();
830
- const dependents = this.reverseDependencyGraph.get(current);
831
- if (dependents) {
832
- for (const dependent of dependents) {
833
- if (!toInvalidate.has(dependent)) {
834
- toInvalidate.add(dependent);
835
- queue.push(dependent);
836
- }
837
- }
838
- }
839
- }
840
- // Invalidar archivos
841
- for (const filePath of toInvalidate) {
842
- if (this.cache.has(filePath)) {
843
- const entry = this.cache.get(filePath);
844
- this.currentMemoryUsage -= entry.size;
845
- this.cache.delete(filePath);
846
- invalidated.push(filePath);
847
- }
848
- }
849
- if (invalidated.length > 0) {
850
- logger.info(`🔄 Invalidación cascada: ${invalidated.length} archivos afectados por ${changedFile}`);
851
- }
852
- return invalidated;
853
- }
854
- /**
855
- * Verifica si un archivo existe
856
- */
857
- async fileExists(filePath) {
858
- try {
859
- await stat(filePath);
860
- return true;
861
- }
862
- catch {
863
- return false;
864
- }
865
- }
866
- /**
867
- * Obtiene estadísticas avanzadas del cache
868
- */
869
- getAdvancedStats() {
870
- return {
871
- entries: this.cache.size,
872
- memoryUsage: this.currentMemoryUsage,
873
- hitRate: 0,
874
- dependencyNodes: this.dependencyGraph.size,
875
- watchingDependencies: this.isWatchingDependencies,
876
- activeWatchers: this.fileWatchers.size,
877
- };
878
- }
879
- }
880
- // Instancia global del cache inteligente
881
- const smartCache = new SmartCompilationCache();
882
- const CACHE_DIR = path.join(path.resolve(env.PATH_PROY || cwd(), 'compiler'), '.cache');
883
- const CACHE_FILE = path.join(CACHE_DIR, 'versacompile-cache.json');
884
- async function loadCache() {
885
- await smartCache.load(CACHE_FILE);
886
- // ✨ ISSUE #3: Iniciar vigilancia de dependencias en modo watch
887
- if (env.WATCH_MODE === 'true' ||
888
- argv.includes('--watch') ||
889
- argv.includes('-w')) {
890
- await smartCache.startDependencyWatching();
891
- }
892
- }
893
- async function saveCache() {
894
- await smartCache.save(CACHE_FILE, CACHE_DIR);
895
- }
896
- // 🎯 Funciones del Sistema Unificado de Manejo de Errores
897
- /**
898
- * Registra un error de compilación en el sistema unificado
899
- */
900
- function registerCompilationError(file, stage, message, severity = 'error', details, help) {
901
- compilationErrors.push({
902
- file,
903
- stage,
904
- message,
905
- severity,
906
- details,
907
- help,
908
- timestamp: Date.now(),
909
- });
910
- }
911
- /**
912
- * Registra un resultado de compilación (éxitos/errores por etapa)
913
- */
914
- function registerCompilationResult(stage, errors, success, files = []) {
915
- const existingResult = compilationResults.find(r => r.stage === stage);
916
- if (existingResult) {
917
- existingResult.errors += errors;
918
- existingResult.success += success;
919
- existingResult.files.push(...files);
920
- }
921
- else {
922
- compilationResults.push({
923
- stage,
924
- errors,
925
- success,
926
- files: [...files],
927
- });
928
- }
929
- }
930
- /**
931
- * Maneja errores según el modo de compilación
932
- */
933
- async function handleCompilationError(error, fileName, stage, mode, isVerbose = false) {
934
- const errorMessage = error instanceof Error ? error.message : error;
935
- const errorDetails = error instanceof Error ? error.stack : undefined;
936
- // Registrar el error en el sistema unificado
937
- registerCompilationError(fileName, stage, errorMessage, 'error', errorDetails);
938
- registerCompilationResult(stage, 1, 0, [fileName]); // Mostrar error inmediatamente solo en modo individual y watch
939
- if (mode === 'individual' || mode === 'watch') {
940
- const chalk = await loadChalk();
941
- const baseName = path.basename(fileName);
942
- const stageColor = await getStageColor(stage);
943
- if (isVerbose) {
944
- // Modo verbose: Mostrar error completo con contexto
945
- logger.error(chalk.red(`❌ Error en etapa ${stageColor(stage)} - ${baseName}:`));
946
- logger.error(chalk.red(errorMessage));
947
- if (errorDetails && (stage === 'typescript' || stage === 'vue')) {
948
- // Mostrar stack trace limitado para TypeScript y Vue
949
- const stackLines = errorDetails.split('\n').slice(0, 5);
950
- stackLines.forEach(line => {
951
- if (line.trim()) {
952
- logger.error(chalk.gray(` ${line.trim()}`));
953
- }
954
- });
955
- }
956
- }
957
- else {
958
- // Modo normal: Mostrar error simplificado
959
- const firstLine = errorMessage.split('\n')[0];
960
- logger.error(chalk.red(`❌ Error en ${stageColor(stage)}: ${baseName}`));
961
- logger.error(chalk.red(` ${firstLine}`));
962
- logger.info(chalk.yellow(`💡 Usa --verbose para ver detalles completos`));
963
- }
964
- }
965
- // En modo 'all', los errores se acumulan silenciosamente para el resumen final
966
- }
967
- /**
968
- * Registra un éxito de compilación
969
- */
970
- function registerCompilationSuccess(fileName, stage) {
971
- registerCompilationResult(stage, 0, 1, [fileName]);
972
- }
973
- /**
974
- * Limpia todos los errores y resultados acumulados
975
- */
976
- function clearCompilationState() {
977
- compilationErrors.length = 0;
978
- compilationResults.length = 0;
979
- }
980
- /**
981
- * Muestra un resumen detallado de todos los errores de compilación
982
- */
983
- async function displayCompilationSummary(isVerbose = false, totalTime) {
984
- const chalk = await loadChalk();
985
- if (compilationErrors.length === 0 && compilationResults.length === 0) {
986
- logger.info(chalk.green('✅ No hay errores de compilación para mostrar.'));
987
- if (totalTime) {
988
- logger.info(chalk.bold(`\n⏱️ TIEMPO TOTAL DE COMPILACIÓN: ${totalTime}`));
989
- }
990
- return;
991
- }
992
- // 🎨 Header moderno del resumen
993
- const summaryLine = '━'.repeat(40);
994
- logger.info('');
995
- logger.info(chalk.bold.cyan('📊 Resumen de Compilación'));
996
- logger.info(chalk.gray(summaryLine)); // ⏱️ Tiempo total con formato elegante
997
- if (totalTime) {
998
- logger.info(chalk.bold(`⏱️ Tiempo Total: ${chalk.green(totalTime)}`));
999
- logger.info('');
1000
- } // 🔧 Estadísticas por etapa con mejor formato
1001
- if (compilationResults.length > 0) {
1002
- logger.info(chalk.bold.blue('🔧 Estadísticas por Etapa:'));
1003
- for (const result of compilationResults) {
1004
- const totalFiles = result.success + result.errors;
1005
- const successRate = totalFiles > 0
1006
- ? Math.round((result.success / totalFiles) * 100)
1007
- : 0;
1008
- // Iconos y colores dinámicos por etapa
1009
- const stageIcon = getStageIcon(result.stage);
1010
- const statusColor = result.errors === 0 ? chalk.green : chalk.red;
1011
- const progressBar = createProgressBarWithPercentage(successRate, 20);
1012
- logger.info(` ${stageIcon} ${chalk.bold(result.stage)}`);
1013
- logger.info(` ${statusColor('●')} ${result.success}/${totalFiles} archivos ${statusColor(`(${successRate}%)`)}`);
1014
- logger.info(` ${progressBar}`);
1015
- if (result.errors > 0) {
1016
- logger.info(` ${chalk.red('⚠')} ${result.errors} ${result.errors === 1 ? 'error' : 'errores'}`);
1017
- }
1018
- logger.info('');
1019
- }
1020
- }
1021
- // Mostrar errores detallados
1022
- if (compilationErrors.length > 0) {
1023
- logger.info(chalk.red(`\n❌ Se encontraron ${compilationErrors.length} errores:`));
1024
- // Agrupar errores por archivo para mejor organización
1025
- const errorsByFile = new Map();
1026
- compilationErrors.forEach(error => {
1027
- if (!errorsByFile.has(error.file)) {
1028
- errorsByFile.set(error.file, []);
1029
- }
1030
- errorsByFile.get(error.file).push(error);
1031
- });
1032
- // Mostrar errores por archivo
1033
- let fileIndex = 1;
1034
- for (const [filePath, fileErrors] of errorsByFile) {
1035
- const baseName = path.basename(filePath);
1036
- const errorCount = fileErrors.filter(e => e.severity === 'error').length;
1037
- const warningCount = fileErrors.filter(e => e.severity === 'warning').length;
1038
- logger.info(chalk.cyan(`\n📄 ${fileIndex}. ${baseName}`));
1039
- logger.info(chalk.gray(` Ruta: ${filePath}`));
1040
- logger.info(chalk.yellow(` ${errorCount} errores, ${warningCount} advertencias`));
1041
- for (const error of fileErrors) {
1042
- const icon = error.severity === 'error' ? '❌' : '⚠️';
1043
- const stageColor = await getStageColor(error.stage);
1044
- logger.info(` ${icon} [${stageColor(error.stage)}] ${error.message}`);
1045
- if (isVerbose && error.details) {
1046
- // En modo verbose, mostrar detalles adicionales
1047
- const detailLines = error.details.split('\n').slice(0, 5);
1048
- detailLines.forEach(line => {
1049
- if (line.trim()) {
1050
- logger.info(chalk.gray(` ${line.trim()}`));
1051
- }
1052
- });
1053
- }
1054
- if (error.help) {
1055
- logger.info(chalk.blue(` 💡 ${error.help}`));
1056
- }
1057
- }
1058
- fileIndex++;
1059
- } // 📊 Mostrar totales finales con diseño moderno
1060
- const totalErrors = compilationErrors.filter(e => e.severity === 'error').length;
1061
- const totalWarnings = compilationErrors.filter(e => e.severity === 'warning').length;
1062
- const totalFiles = errorsByFile.size;
1063
- // Header elegante para estadísticas finales
1064
- const statLine = '═'.repeat(50);
1065
- logger.info('');
1066
- logger.info(chalk.bold.cyan(statLine));
1067
- logger.info(chalk.bold.cyan(' 📊 RESUMEN FINAL'));
1068
- logger.info(chalk.bold.cyan(statLine));
1069
- // Estadísticas con iconos y colores modernos
1070
- logger.info('');
1071
- logger.info(chalk.bold('🎯 Resultados:'));
1072
- logger.info(` 📁 Archivos afectados: ${chalk.cyan.bold(totalFiles)}`);
1073
- logger.info(` ${totalErrors > 0 ? chalk.red('●') : chalk.green('○')} Errores: ${totalErrors > 0 ? chalk.red.bold(totalErrors) : chalk.green.bold('0')}`);
1074
- logger.info(` ${totalWarnings > 0 ? chalk.yellow('●') : chalk.green('○')} Advertencias: ${totalWarnings > 0 ? chalk.yellow.bold(totalWarnings) : chalk.green.bold('0')}`);
1075
- logger.info('');
1076
- // Estado final con diseño visual atractivo
1077
- if (totalErrors > 0) {
1078
- logger.info(chalk.red.bold('🚨 COMPILACIÓN COMPLETADA CON ERRORES'));
1079
- logger.info(chalk.red(' Por favor revisa y corrige los problemas anteriores.'));
1080
- }
1081
- else if (totalWarnings > 0) {
1082
- logger.info(chalk.yellow.bold('⚠️ COMPILACIÓN COMPLETADA CON ADVERTENCIAS'));
1083
- logger.info(chalk.yellow(' Considera revisar las advertencias anteriores.'));
1084
- }
1085
- else {
1086
- logger.info(chalk.green.bold('✅ COMPILACIÓN EXITOSA'));
1087
- logger.info(chalk.green(' ¡Todos los archivos se compilaron sin problemas!'));
1088
- }
1089
- logger.info('');
1090
- logger.info(chalk.bold.cyan(statLine));
1091
- }
1092
- else {
1093
- // Caso exitoso sin errores
1094
- const successLine = '═'.repeat(50);
1095
- logger.info('');
1096
- logger.info(chalk.bold.green(successLine));
1097
- logger.info(chalk.bold.green(' ✨ ÉXITO'));
1098
- logger.info(chalk.bold.green(successLine));
1099
- logger.info('');
1100
- logger.info(chalk.green.bold('🎉 COMPILACIÓN COMPLETADA EXITOSAMENTE'));
1101
- logger.info(chalk.green(' ¡No se encontraron errores ni advertencias!'));
1102
- logger.info('');
1103
- logger.info(chalk.bold.green(successLine));
1104
- }
1105
- logger.info('');
1106
- }
1107
- /**
1108
- * Muestra errores del linter con formato visual moderno y profesional
1109
- */
1110
- async function displayLinterErrors(errors) {
1111
- const chalk = await loadChalk();
1112
- // Agrupar errores por archivo
1113
- const errorsByFile = new Map();
1114
- errors.forEach(error => {
1115
- if (!errorsByFile.has(error.file)) {
1116
- errorsByFile.set(error.file, []);
1117
- }
1118
- errorsByFile.get(error.file).push(error);
1119
- });
1120
- const totalErrors = errors.filter(e => e.severity === 'error').length;
1121
- const totalWarnings = errors.filter(e => e.severity === 'warning').length;
1122
- const totalFiles = errorsByFile.size;
1123
- // Header estilo moderno con gradiente visual
1124
- logger.info(chalk.bold.rgb(255, 120, 120)('╭─────────────────────────────────────────────────────────────╮'));
1125
- logger.info(chalk.bold.rgb(255, 120, 120)('│ ') +
1126
- chalk.bold.white('🔍 LINTER REPORT') +
1127
- chalk.bold.rgb(255, 120, 120)(' │'));
1128
- logger.info(chalk.bold.rgb(255, 120, 120)('╰─────────────────────────────────────────────────────────────╯'));
1129
- // Resumen con iconos profesionales
1130
- const errorIcon = totalErrors > 0 ? chalk.red('●') : chalk.green('○');
1131
- const warningIcon = totalWarnings > 0 ? chalk.yellow('●') : chalk.green('○');
1132
- logger.info('');
1133
- logger.info(chalk.bold('📊 Summary:'));
1134
- logger.info(` ${errorIcon} ${chalk.bold(totalErrors)} ${chalk.red('errors')}`);
1135
- logger.info(` ${warningIcon} ${chalk.bold(totalWarnings)} ${chalk.yellow('warnings')}`);
1136
- logger.info(` 📁 ${chalk.bold(totalFiles)} ${chalk.cyan('files')}`);
1137
- logger.info('');
1138
- if (totalErrors === 0 && totalWarnings === 0) {
1139
- logger.info(chalk.green.bold('✨ All checks passed! No issues found.'));
1140
- return;
1141
- }
1142
- // Mostrar errores por archivo con formato elegante
1143
- let fileIndex = 1;
1144
- for (const [filePath, fileErrors] of errorsByFile) {
1145
- await displayFileErrorsGroup(filePath, fileErrors, fileIndex, totalFiles);
1146
- fileIndex++;
1147
- if (fileIndex <= totalFiles) {
1148
- logger.info(chalk.gray('─'.repeat(80))); // Separador entre archivos
1149
- }
1150
- }
1151
- // Footer con estadísticas
1152
- logger.info('');
1153
- logger.info(chalk.bold.rgb(255, 120, 120)('╭─────────────────────────────────────────────────────────────╮'));
1154
- logger.info(chalk.bold.rgb(255, 120, 120)('│ ') +
1155
- chalk.bold.white(`Found ${totalErrors + totalWarnings} issues in ${totalFiles} files`) +
1156
- ' '.repeat(Math.max(0, 52 -
1157
- `Found ${totalErrors + totalWarnings} issues in ${totalFiles} files`
1158
- .length)) +
1159
- chalk.bold.rgb(255, 120, 120)(' │'));
1160
- logger.info(chalk.bold.rgb(255, 120, 120)('╰─────────────────────────────────────────────────────────────╯'));
1161
- }
1162
- /**
1163
- * Muestra un grupo de errores para un archivo específico con formato moderno
1164
- */
1165
- async function displayFileErrorsGroup(filePath, fileErrors, _fileIndex, _totalFiles) {
1166
- const chalk = await loadChalk();
1167
- // Header del archivo con iconos de estado
1168
- const errorCount = fileErrors.filter(e => e.severity === 'error').length;
1169
- const warningCount = fileErrors.filter(e => e.severity === 'warning').length;
1170
- const statusIcon = errorCount > 0 ? chalk.red('✕') : chalk.yellow('⚠');
1171
- const fileIcon = filePath.endsWith('.vue')
1172
- ? '🎨'
1173
- : filePath.endsWith('.ts')
1174
- ? '📘'
1175
- : filePath.endsWith('.js')
1176
- ? '📜'
1177
- : '📄';
1178
- logger.info('');
1179
- logger.info(chalk.bold(`${statusIcon} ${fileIcon} ${chalk.cyan(path.relative(process.cwd(), filePath))}`));
1180
- logger.info(chalk.gray(` ${errorCount} errors, ${warningCount} warnings`));
1181
- logger.info('');
1182
- // Mostrar cada error con formato elegante
1183
- for (let i = 0; i < fileErrors.length; i++) {
1184
- const error = fileErrors[i];
1185
- await displayModernLinterError(error, filePath, i + 1, fileErrors.length);
1186
- }
1187
- }
1188
- /**
1189
- * Muestra un error individual con formato visual moderno tipo ESLint/Prettier
1190
- */
1191
- async function displayModernLinterError(error, filePath, errorIndex, totalErrorsInFile) {
1192
- const chalk = await loadChalk();
1193
- const fs = await import('node:fs/promises');
1194
- // Determinar tipo y color del error
1195
- const isError = error.severity === 'error';
1196
- const typeColor = isError ? chalk.red : chalk.yellow;
1197
- const typeIcon = isError ? '✕' : '⚠';
1198
- const line = error.line || 1;
1199
- const column = error.column || 1;
1200
- const ruleId = error.ruleId || error.from || 'unknown';
1201
- // Línea principal del error con formato moderno
1202
- const errorHeader = ` ${typeColor(typeIcon)} ${chalk.bold(error.message)}`;
1203
- const ruleInfo = `${chalk.gray(ruleId)}`;
1204
- const locationInfo = `${chalk.blue(`${line}:${column}`)}`;
1205
- logger.info(errorHeader);
1206
- logger.info(` ${chalk.gray('at')} ${locationInfo} ${chalk.gray('·')} ${ruleInfo}`);
1207
- // Mostrar código con contexto
1208
- try {
1209
- const absolutePath = path.resolve(filePath);
1210
- const fileContent = await fs.readFile(absolutePath, 'utf-8');
1211
- const lines = fileContent.split('\n');
1212
- const lineNum = parseInt(line.toString()) - 1;
1213
- if (lineNum >= 0 && lineNum < lines.length) {
1214
- logger.info('');
1215
- // Mostrar líneas de contexto con numeración elegante
1216
- const startLine = Math.max(0, lineNum - 1);
1217
- const endLine = Math.min(lines.length - 1, lineNum + 1);
1218
- const maxLineNumWidth = (endLine + 1).toString().length;
1219
- for (let i = startLine; i <= endLine; i++) {
1220
- const currentLineNum = i + 1;
1221
- const currentLine = lines[i] || '';
1222
- const lineNumStr = currentLineNum
1223
- .toString()
1224
- .padStart(maxLineNumWidth, ' ');
1225
- const isErrorLine = i === lineNum;
1226
- if (isErrorLine) {
1227
- // Línea con el error - destacada
1228
- logger.info(` ${chalk.red('>')} ${chalk.gray(lineNumStr)} ${chalk.gray('│')} ${currentLine}`);
1229
- // Indicador de posición del error
1230
- const pointer = ' '.repeat(Math.max(0, column - 1)) + typeColor('^');
1231
- logger.info(` ${chalk.gray(' ')} ${chalk.gray(' '.repeat(maxLineNumWidth))} ${chalk.gray('│')} ${pointer}`);
1232
- }
1233
- else {
1234
- // Líneas de contexto
1235
- logger.info(` ${chalk.gray(' ')} ${chalk.gray(lineNumStr)} ${chalk.gray('│')} ${chalk.gray(currentLine)}`);
1236
- }
1237
- }
1238
- }
1239
- }
1240
- catch {
1241
- // Si no se puede leer el archivo, mostrar formato simplificado
1242
- logger.info(` ${chalk.gray('│')} ${chalk.gray('(Unable to read file content)')}`);
1243
- }
1244
- // Mostrar ayuda si está disponible
1245
- if (error.help) {
1246
- logger.info('');
1247
- const helpText = error.help.replace(/^Regla \w+: /, '').trim();
1248
- logger.info(` ${chalk.blue('💡')} ${chalk.blue('Help:')} ${chalk.gray(helpText)}`);
1249
- }
1250
- // Separador entre errores (solo si no es el último)
1251
- if (errorIndex < totalErrorsInFile) {
1252
- logger.info('');
1253
- }
1254
- }
1255
- /**
1256
- * Muestra un solo error del linter con formato visual mejorado
1257
- * @deprecated Use displayModernLinterError instead
1258
- */
1259
- async function _displaySingleLinterError(error, filePath) {
1260
- const chalk = await loadChalk();
1261
- const fs = await import('node:fs/promises');
1262
- const icon = error.severity === 'error' ? '×' : '⚠';
1263
- const ruleInfo = error.help || '';
1264
- const line = error.line || 'N/A';
1265
- const column = error.column || 10; // Columna por defecto si no está disponible
1266
- // Línea principal del error
1267
- const mainErrorLine = `${chalk.red(icon)} ${chalk.cyan(`${error.from}(${ruleInfo.replace(/^Regla \w+: /, '')})`)}: ${error.message}`;
1268
- logger.info(mainErrorLine);
1269
- // Intentar leer el contenido del archivo para mostrar contexto
1270
- try {
1271
- const absolutePath = path.resolve(filePath);
1272
- const fileContent = await fs.readFile(absolutePath, 'utf-8');
1273
- const lines = fileContent.split('\n');
1274
- const lineNum = parseInt(line.toString()) - 1; // Convertir a índice 0-based
1275
- if (lineNum >= 0 && lineNum < lines.length) {
1276
- // Mostrar ubicación
1277
- logger.info(chalk.blue(` ╭─[${filePath}:${line}:${column}]`));
1278
- // Mostrar líneas de contexto
1279
- const startLine = Math.max(0, lineNum - 1);
1280
- const endLine = Math.min(lines.length - 1, lineNum + 1);
1281
- for (let i = startLine; i <= endLine; i++) {
1282
- const currentLineNum = i + 1;
1283
- const currentLine = lines[i] || '';
1284
- const prefix = currentLineNum.toString().padStart(2, ' ');
1285
- if (i === lineNum) {
1286
- // Línea con el error
1287
- logger.info(chalk.blue(` ${prefix} │ `) + currentLine);
1288
- // Mostrar el indicador de error
1289
- const indent = ' '.repeat(prefix.length + 3); // Espacios para alinear
1290
- const pointer = ' '.repeat(Math.max(0, (column || 1) - 1)) +
1291
- chalk.red('───────┬──────');
1292
- logger.info(chalk.blue(indent + '·') + pointer);
1293
- // Mensaje de ubicación específica
1294
- const messageIndent = ' '.repeat(Math.max(0, (column || 1) + 6));
1295
- logger.info(chalk.blue(indent + '·') +
1296
- messageIndent +
1297
- chalk.red('╰── ') +
1298
- chalk.gray(getErrorLocationMessage(error)));
1299
- }
1300
- else {
1301
- // Líneas de contexto
1302
- logger.info(chalk.blue(` ${prefix} │ `) + chalk.gray(currentLine));
1303
- }
1304
- }
1305
- logger.info(chalk.blue(' ╰────'));
1306
- }
1307
- }
1308
- catch {
1309
- // Si no se puede leer el archivo, mostrar formato simplificado
1310
- logger.info(chalk.blue(` ╭─[${filePath}:${line}:${column}]`));
1311
- logger.info(chalk.blue(' │ ') +
1312
- chalk.gray('(No se pudo leer el contenido del archivo)'));
1313
- logger.info(chalk.blue(' ╰────'));
1314
- }
1315
- // Mostrar ayuda si está disponible
1316
- if (error.help) {
1317
- const helpMessage = error.help.replace(/^Regla \w+: /, '');
1318
- logger.info(chalk.blue(' help: ') + chalk.yellow(helpMessage));
1319
- }
1320
- logger.info(''); // Espacio entre errores
1321
- }
1322
- /**
1323
- * Genera un mensaje descriptivo para la ubicación específica del error
1324
- */
1325
- function getErrorLocationMessage(error) {
1326
- if (error.message.includes('declared but never used')) {
1327
- const match = error.message.match(/'([^']+)'/);
1328
- if (match) {
1329
- return `'${match[1]}' is declared here`;
1330
- }
1331
- }
1332
- if (error.message.includes('Unexpected var')) {
1333
- return 'var declaration found here';
1334
- }
1335
- if (error.message.includes('never reassigned')) {
1336
- const match = error.message.match(/'([^']+)'/);
1337
- if (match) {
1338
- return `'${match[1]}' is assigned here`;
1339
- }
1340
- }
1341
- return 'error location';
1342
- }
1343
- /**
1344
- * Obtiene el color apropiado para cada etapa de compilación
1345
- */
1346
- async function getStageColor(stage) {
1347
- const chalk = await loadChalk();
1348
- switch (stage) {
1349
- case 'vue':
1350
- return chalk.green;
1351
- case 'typescript':
1352
- return chalk.blue;
1353
- case 'standardization':
1354
- return chalk.yellow;
1355
- case 'minification':
1356
- return chalk.red;
1357
- case 'tailwind':
1358
- return chalk.magenta;
1359
- case 'file-read':
1360
- return chalk.gray;
1361
- default:
1362
- return chalk.white;
1363
- }
1364
- }
1365
- export function normalizeRuta(ruta) {
1366
- if (path.isAbsolute(ruta)) {
1367
- return path.normalize(ruta).replace(/\\/g, '/');
1368
- }
1369
- const file = path
1370
- .normalize(!ruta.startsWith('.') ? './' + ruta : ruta)
1371
- .replace(/\\/g, '/');
1372
- const sourceForDist = file.startsWith('./') ? file : `./${file}`;
1373
- return sourceForDist;
1374
- }
1375
- export function getOutputPath(ruta) {
1376
- const pathSource = env.PATH_SOURCE ?? '';
1377
- const pathDist = env.PATH_DIST ?? '';
1378
- if (!pathSource || !pathDist) {
1379
- return ruta.replace(/\.(vue|ts)$/, '.js');
1380
- }
1381
- const normalizedRuta = path.normalize(ruta).replace(/\\/g, '/');
1382
- const normalizedSource = path.normalize(pathSource).replace(/\\/g, '/');
1383
- const normalizedDist = path.normalize(pathDist).replace(/\\/g, '/');
1384
- let outputPath;
1385
- if (normalizedRuta.includes(normalizedSource)) {
1386
- const relativePath = normalizedRuta
1387
- .substring(normalizedRuta.indexOf(normalizedSource) +
1388
- normalizedSource.length)
1389
- .replace(/^[/\\]/, '');
1390
- outputPath = path
1391
- .join(normalizedDist, relativePath)
1392
- .replace(/\\/g, '/');
1393
- }
1394
- else {
1395
- const fileName = path.basename(normalizedRuta);
1396
- outputPath = path.join(normalizedDist, fileName).replace(/\\/g, '/');
1397
- }
1398
- if (outputPath.includes('vue') || outputPath.includes('ts')) {
1399
- return outputPath.replace(/\.(vue|ts)$/, '.js');
1400
- }
1401
- else {
1402
- return outputPath;
1403
- }
1404
- }
1405
- // Optimización para modo watch: debouncing y cache de archivos
1406
- class WatchModeOptimizer {
1407
- static instance;
1408
- fileSystemCache = new Map();
1409
- debounceTimers = new Map();
1410
- DEBOUNCE_DELAY = 100; // 100ms debounce
1411
- static getInstance() {
1412
- if (!WatchModeOptimizer.instance) {
1413
- WatchModeOptimizer.instance = new WatchModeOptimizer();
1414
- }
1415
- return WatchModeOptimizer.instance;
1416
- }
1417
- async compileForWatch(filePath, compileFn) {
1418
- return new Promise(resolve => {
1419
- const existingTimer = this.debounceTimers.get(filePath);
1420
- if (existingTimer) {
1421
- clearTimeout(existingTimer);
1422
- }
1423
- const timer = setTimeout(async () => {
1424
- this.debounceTimers.delete(filePath);
1425
- try {
1426
- const stats = await stat(filePath);
1427
- const cached = this.fileSystemCache.get(filePath);
1428
- if (cached && cached.mtime >= stats.mtimeMs) {
1429
- resolve({ success: true, cached: true });
1430
- return;
1431
- } // Configurar worker pool para modo watch
1432
- const { TypeScriptWorkerPool } = (await import('./typescript-worker-pool.js'));
1433
- const workerPool = TypeScriptWorkerPool.getInstance();
1434
- workerPool.setMode('watch');
1435
- const result = await compileFn(filePath);
1436
- this.fileSystemCache.set(filePath, {
1437
- mtime: stats.mtimeMs,
1438
- });
1439
- resolve(result);
1440
- }
1441
- catch (error) {
1442
- resolve({ success: false, error });
1443
- }
1444
- }, this.DEBOUNCE_DELAY);
1445
- this.debounceTimers.set(filePath, timer);
1446
- });
1447
- }
1448
- cleanup() {
1449
- this.debounceTimers.forEach(timer => clearTimeout(timer));
1450
- this.debounceTimers.clear();
1451
- this.fileSystemCache.clear();
1452
- }
1453
- }
1454
- async function compileJS(inPath, outPath, mode = 'individual') {
1455
- const timings = {};
1456
- // Si la ruta ya es absoluta, no la resolvamos de nuevo
1457
- inPath = path.isAbsolute(inPath)
1458
- ? normalizeRuta(inPath)
1459
- : normalizeRuta(path.resolve(inPath)); // 🚀 Usar OptimizedModuleManager para carga optimizada
1460
- const moduleManager = OptimizedModuleManager.getInstance();
1461
- // Timing de lectura
1462
- let start = Date.now();
1463
- const extension = path.extname(inPath); // Asegurar que el parser esté cargado
1464
- await moduleManager.ensureModuleLoaded('parser');
1465
- const getCodeFile = await loadParser();
1466
- const result = await getCodeFile(inPath);
1467
- let code = result.code;
1468
- const error = result.error;
1469
- timings.fileRead = Date.now() - start;
1470
- if (error) {
1471
- await handleCompilationError(error instanceof Error ? error : new Error(String(error)), inPath, 'file-read', mode, env.VERBOSE === 'true');
1472
- throw new Error(error instanceof Error ? error.message : String(error));
1473
- }
1474
- if (!code ||
1475
- code.trim().length === 0 ||
1476
- code === 'undefined' ||
1477
- code === 'null') {
1478
- await handleCompilationError(new Error('El archivo está vacío o no se pudo leer.'), inPath, 'file-read', mode, env.VERBOSE === 'true');
1479
- throw new Error('El archivo está vacío o no se pudo leer.');
1480
- } // Logs detallados en modo verbose
1481
- const shouldShowDetailedLogs = env.VERBOSE === 'true'; // Compilación de Vue
1482
- let vueResult;
1483
- if (extension === '.vue') {
1484
- start = Date.now();
1485
- if (shouldShowDetailedLogs) {
1486
- logger.info(chalk.green(`💚 Precompilando VUE: ${path.basename(inPath)}`));
1487
- }
1488
- // Asegurar que el módulo Vue esté cargado
1489
- await moduleManager.ensureModuleLoaded('vue');
1490
- const preCompileVue = await loadVue();
1491
- if (typeof preCompileVue !== 'function') {
1492
- throw new Error(`loadVue devolvió ${typeof preCompileVue} en lugar de una función para archivo: ${inPath}`);
1493
- }
1494
- vueResult = await preCompileVue(code, inPath, env.isPROD === 'true');
1495
- timings.vueCompile = Date.now() - start;
1496
- if (vueResult === undefined || vueResult === null) {
1497
- throw new Error(`preCompileVue devolvió ${vueResult} para archivo: ${inPath}`);
1498
- }
1499
- if (vueResult.error) {
1500
- await handleCompilationError(vueResult.error instanceof Error
1501
- ? vueResult.error
1502
- : new Error(String(vueResult.error)), inPath, 'vue', mode, env.VERBOSE === 'true');
1503
- throw new Error(vueResult.error instanceof Error
1504
- ? vueResult.error.message
1505
- : String(vueResult.error));
1506
- }
1507
- registerCompilationSuccess(inPath, 'vue');
1508
- code = vueResult.data;
1509
- }
1510
- if (!code || code.trim().length === 0) {
1511
- await handleCompilationError(new Error('El código Vue compilado está vacío.'), inPath, 'vue', mode, env.VERBOSE === 'true');
1512
- throw new Error('El código Vue compilado está vacío.');
1513
- }
1514
- // Compilación de TypeScript
1515
- let tsResult;
1516
- if (extension === '.ts' || vueResult?.lang === 'ts') {
1517
- start = Date.now();
1518
- if (shouldShowDetailedLogs) {
1519
- logger.info(chalk.blue(`🔄️ Precompilando TS: ${path.basename(inPath)}`));
1520
- }
1521
- // Asegurar que el módulo TypeScript esté cargado
1522
- await moduleManager.ensureModuleLoaded('typescript');
1523
- const preCompileTS = await loadTypeScript();
1524
- if (typeof preCompileTS !== 'function') {
1525
- throw new Error(`loadTypeScript devolvió ${typeof preCompileTS} en lugar de una función para archivo: ${inPath}`);
1526
- }
1527
- tsResult = await preCompileTS(code, inPath);
1528
- timings.tsCompile = Date.now() - start;
1529
- if (tsResult === undefined || tsResult === null) {
1530
- throw new Error(`preCompileTS devolvió ${tsResult} para archivo: ${inPath}`);
1531
- }
1532
- if (tsResult.error) {
1533
- if (mode === 'all') {
1534
- // En modo --all, registrar el error pero continuar la compilación
1535
- registerCompilationError(inPath, 'typescript', tsResult.error instanceof Error
1536
- ? tsResult.error.message
1537
- : String(tsResult.error), 'error');
1538
- }
1539
- else {
1540
- await handleCompilationError(tsResult.error, inPath, 'typescript', mode, env.VERBOSE === 'true');
1541
- throw new Error(tsResult.error instanceof Error
1542
- ? tsResult.error.message
1543
- : String(tsResult.error));
1544
- }
1545
- }
1546
- else {
1547
- registerCompilationSuccess(inPath, 'typescript');
1548
- code = tsResult.data;
1549
- }
1550
- }
1551
- if (!code || code.trim().length === 0) {
1552
- await handleCompilationError(new Error('El código TypeScript compilado está vacío.'), inPath, 'typescript', mode, env.VERBOSE === 'true');
1553
- throw new Error('El código TypeScript compilado está vacío.');
1554
- } // Estandarización
1555
- if (shouldShowDetailedLogs) {
1556
- logger.info(chalk.yellow(`💛 Estandarizando: ${path.basename(inPath)}`));
1557
- }
1558
- start = Date.now();
1559
- // Asegurar que el módulo de transformaciones esté cargado
1560
- await moduleManager.ensureModuleLoaded('transforms');
1561
- const estandarizaCode = await loadTransforms();
1562
- const resultSTD = await estandarizaCode(code, inPath);
1563
- timings.standardization = Date.now() - start;
1564
- if (resultSTD === undefined || resultSTD === null) {
1565
- throw new Error(`estandarizaCode devolvió ${resultSTD} para archivo: ${inPath}`);
1566
- }
1567
- if (resultSTD.error) {
1568
- await handleCompilationError(new Error(resultSTD.error), inPath, 'standardization', mode, env.VERBOSE === 'true');
1569
- throw new Error(resultSTD.error);
1570
- }
1571
- registerCompilationSuccess(inPath, 'standardization');
1572
- code = resultSTD.code;
1573
- if (!code || code.trim().length === 0) {
1574
- await handleCompilationError(new Error('El código estandarizado está vacío.'), inPath, 'standardization', mode, env.VERBOSE === 'true');
1575
- throw new Error('El código estandarizado está vacío.');
1576
- }
1577
- // Minificación (solo en producción)
1578
- if (env.isPROD === 'true') {
1579
- start = Date.now();
1580
- if (shouldShowDetailedLogs) {
1581
- logger.info(chalk.red(`🤖 Minificando: ${path.basename(inPath)}`));
1582
- }
1583
- // Asegurar que el módulo de minificación esté cargado
1584
- await moduleManager.ensureModuleLoaded('minify');
1585
- const minifyJS = await loadMinify();
1586
- const resultMinify = await minifyJS(code, inPath, true);
1587
- timings.minification = Date.now() - start;
1588
- if (resultMinify === undefined || resultMinify === null) {
1589
- throw new Error(`minifyJS devolvió ${resultMinify} para archivo: ${inPath}`);
1590
- }
1591
- if (resultMinify.error) {
1592
- await handleCompilationError(resultMinify.error instanceof Error
1593
- ? resultMinify.error
1594
- : new Error(String(resultMinify.error)), inPath, 'minification', mode, env.VERBOSE === 'true');
1595
- throw new Error(resultMinify.error instanceof Error
1596
- ? resultMinify.error.message
1597
- : String(resultMinify.error));
1598
- }
1599
- registerCompilationSuccess(inPath, 'minification');
1600
- code = resultMinify.code;
1601
- } // Escribir archivo final
1602
- const destinationDir = path.dirname(outPath);
1603
- await mkdir(destinationDir, { recursive: true });
1604
- await writeFile(outPath, code, 'utf-8');
1605
- // Logs de timing detallados en modo verbose
1606
- if (shouldShowDetailedLogs) {
1607
- const totalTime = Object.values(timings).reduce((sum, time) => sum + time, 0);
1608
- logger.info(chalk.cyan(`⏱️ Timing para ${path.basename(inPath)}:`));
1609
- if (timings.fileRead)
1610
- logger.info(chalk.cyan(` 📖 Lectura: ${timings.fileRead}ms`));
1611
- if (timings.vueCompile)
1612
- logger.info(chalk.cyan(` 💚 Vue: ${timings.vueCompile}ms`));
1613
- if (timings.tsCompile)
1614
- logger.info(chalk.cyan(` 🔄️ TypeScript: ${timings.tsCompile}ms`));
1615
- if (timings.standardization)
1616
- logger.info(chalk.cyan(` 💛 Estandarización: ${timings.standardization}ms`));
1617
- if (timings.minification)
1618
- logger.info(chalk.cyan(` 🤖 Minificación: ${timings.minification}ms`));
1619
- logger.info(chalk.cyan(` 🏁 Total: ${totalTime}ms`));
1620
- }
1621
- return {
1622
- error: null,
1623
- action: 'extension',
1624
- };
1625
- }
1626
- export async function initCompile(ruta, compileTailwind = true, mode = 'individual') {
1627
- try {
1628
- // 🚀 Sistema de Carga Inteligente de Módulos
1629
- const moduleManager = OptimizedModuleManager.getInstance();
1630
- const fileExtension = path.extname(ruta);
1631
- const fileExtensions = new Set([fileExtension]);
1632
- // Inicializar módulos según el contexto
1633
- await moduleManager.preloadForContext(mode === 'all' ? 'batch' : mode, fileExtensions);
1634
- // Generar TailwindCSS si está habilitado
1635
- if (compileTailwind && Boolean(env.TAILWIND)) {
1636
- await moduleManager.ensureModuleLoaded('tailwind');
1637
- const generateTailwindCSS = await loadTailwind();
1638
- const resultTW = await generateTailwindCSS();
1639
- if (typeof resultTW !== 'boolean') {
1640
- if (resultTW?.success) {
1641
- logger.info(`🎨 ${resultTW.message}`);
1642
- }
1643
- else {
1644
- const errorMsg = `${resultTW.message}${resultTW.details ? '\n' + resultTW.details : ''}`;
1645
- await handleCompilationError(new Error(errorMsg), 'tailwind.config.js', 'tailwind', mode, env.VERBOSE === 'true');
1646
- // No hacer throw aquí, permitir que la compilación continúe
1647
- }
1648
- }
1649
- }
1650
- const startTime = Date.now();
1651
- const file = normalizeRuta(ruta);
1652
- const outFile = getOutputPath(file);
1653
- // 🚀 Verificar cache antes de compilar (especialmente importante en modo watch)
1654
- if (mode === 'watch' || mode === 'individual') {
1655
- if (await shouldSkipFile(file)) {
1656
- if (env.VERBOSE === 'true') {
1657
- logger.info(`⏭️ Archivo omitido (cache): ${path.basename(file)}`);
1658
- }
1659
- return {
1660
- success: true,
1661
- cached: true,
1662
- output: smartCache.getOutputPath(file) || outFile,
1663
- action: 'cached',
1664
- };
1665
- }
1666
- }
1667
- if (mode === 'individual' && env.VERBOSE === 'true') {
1668
- logger.info(`🔜 Fuente: ${file}`);
1669
- }
1670
- const result = await compileJS(file, outFile, mode);
1671
- if (result.error) {
1672
- throw new Error(result.error);
1673
- }
1674
- // 🚀 Actualizar cache después de compilación exitosa (especialmente en modo watch)
1675
- if (mode === 'watch' || mode === 'individual') {
1676
- await smartCache.set(file, outFile);
1677
- }
1678
- const endTime = Date.now();
1679
- const elapsedTime = showTimingForHumans(endTime - startTime);
1680
- if (mode === 'individual') {
1681
- if (env.VERBOSE === 'true') {
1682
- logger.info(`🔚 Destino: ${outFile}`);
1683
- logger.info(`⏱️ Tiempo: ${elapsedTime}`);
1684
- }
1685
- const chalk = await loadChalk();
1686
- logger.info(chalk.green(`✅ Compilación exitosa: ${path.basename(file)}`));
1687
- }
1688
- return {
1689
- success: true,
1690
- output: outFile,
1691
- action: result.action,
1692
- };
1693
- }
1694
- catch (error) {
1695
- const errorMessage = error instanceof Error ? error.message : String(error);
1696
- if (env.VERBOSE === 'true') {
1697
- logger.error(`❌ Error en compilación de ${path.basename(ruta)}: ${errorMessage}`);
1698
- }
1699
- return {
1700
- success: false,
1701
- output: '',
1702
- error: errorMessage,
1703
- };
1704
- }
1705
- }
1706
- // Variable para el último progreso mostrado (evitar spam)
1707
- let lastProgressUpdate = 0;
1708
- // Sistema de gestión de progreso persistente (como Jest)
1709
- class ProgressManager {
1710
- static instance;
1711
- progressActive = false;
1712
- lastProgressLine = '';
1713
- logBuffer = [];
1714
- originalConsoleLog;
1715
- originalConsoleError;
1716
- originalConsoleWarn;
1717
- hasProgressLine = false;
1718
- constructor() {
1719
- // Guardar referencias originales
1720
- this.originalConsoleLog = console.log;
1721
- this.originalConsoleError = console.error;
1722
- this.originalConsoleWarn = console.warn;
1723
- }
1724
- static getInstance() {
1725
- if (!ProgressManager.instance) {
1726
- ProgressManager.instance = new ProgressManager();
1727
- }
1728
- return ProgressManager.instance;
1729
- }
1730
- interceptConsole() {
1731
- // Interceptar console.log y similares
1732
- console.log = (...args) => {
1733
- this.addLog(args.map(arg => String(arg)).join(' '));
1734
- };
1735
- console.error = (...args) => {
1736
- this.addLog(args.map(arg => String(arg)).join(' '));
1737
- };
1738
- console.warn = (...args) => {
1739
- this.addLog(args.map(arg => String(arg)).join(' '));
1740
- };
1741
- }
1742
- restoreConsole() {
1743
- console.log = this.originalConsoleLog;
1744
- console.error = this.originalConsoleError;
1745
- console.warn = this.originalConsoleWarn;
1746
- }
1747
- startProgress() {
1748
- this.progressActive = true;
1749
- this.logBuffer = [];
1750
- this.hasProgressLine = false;
1751
- this.interceptConsole();
1752
- // 🎨 Header moderno de inicio de compilación
1753
- const headerLine = '━'.repeat(48);
1754
- process.stdout.write('\n\x1b[96m' + headerLine + '\x1b[0m\n');
1755
- process.stdout.write('\x1b[96m│ \x1b[97m\x1b[1m🚀 Iniciando Compilación\x1b[0m\x1b[96m' +
1756
- ' '.repeat(22) +
1757
- '│\x1b[0m\n');
1758
- process.stdout.write('\x1b[96m' + headerLine + '\x1b[0m\n');
1759
- }
1760
- updateProgress(progressText) {
1761
- if (!this.progressActive)
1762
- return;
1763
- // Si hay logs pendientes, mostrarlos primero
1764
- if (this.logBuffer.length > 0) {
1765
- // Si ya hay una línea de progreso, limpiarla primero
1766
- if (this.hasProgressLine) {
1767
- process.stdout.write('\r\x1b[K');
1768
- }
1769
- // Escribir todos los logs pendientes
1770
- for (const log of this.logBuffer) {
1771
- process.stdout.write((this.hasProgressLine ? '\n' : '') + log + '\n');
1772
- this.hasProgressLine = false;
1773
- }
1774
- this.logBuffer = [];
1775
- } // Escribir separador elegante antes del progreso
1776
- if (this.hasProgressLine) {
1777
- process.stdout.write('\r\x1b[K');
1778
- }
1779
- else {
1780
- process.stdout.write('\n\x1b[96m' + '▔'.repeat(50) + '\x1b[0m\n');
1781
- }
1782
- // 🎨 Barra de progreso con colores dinámicos
1783
- const stage = this.getStageFromText(progressText);
1784
- const { bgColor, textColor, icon } = this.getProgressColors(stage);
1785
- const progressBar = '█'.repeat(3);
1786
- const enhancedProgress = `\x1b[${bgColor}m\x1b[${textColor}m ${progressBar} ${icon} ${progressText} ${progressBar} \x1b[0m`;
1787
- process.stdout.write(enhancedProgress);
1788
- this.hasProgressLine = true;
1789
- this.lastProgressLine = progressText;
1790
- }
1791
- addLog(message) {
1792
- if (this.progressActive) {
1793
- this.logBuffer.push(message);
1794
- }
1795
- else {
1796
- this.originalConsoleLog(message);
1797
- }
1798
- }
1799
- addImmediateLog(message) {
1800
- if (this.progressActive) {
1801
- if (this.hasProgressLine) {
1802
- process.stdout.write('\r\x1b[K');
1803
- }
1804
- // Añadir un punto de separación visual para logs inmediatos
1805
- process.stdout.write('\x1b[90m│\x1b[0m ' + message + '\n');
1806
- this.hasProgressLine = false;
1807
- }
1808
- else {
1809
- this.originalConsoleLog(message);
1810
- }
1811
- }
1812
- endProgress() {
1813
- if (this.progressActive) {
1814
- if (this.hasProgressLine) {
1815
- process.stdout.write('\n');
1816
- }
1817
- // Mostrar barra de progreso final completa antes del separador
1818
- process.stdout.write('\n\x1b[33m' + '-'.repeat(50) + '\x1b[0m\n');
1819
- const finalProgressBar = '█'.repeat(3);
1820
- const finalProgress = `\x1b[42m\x1b[30m ${finalProgressBar} ✅ PROCESO COMPLETADO 100% ${finalProgressBar} \x1b[0m`;
1821
- process.stdout.write(finalProgress + '\n');
1822
- // 🎨 Footer moderno de finalización
1823
- const footerLine = '━'.repeat(48);
1824
- process.stdout.write('\x1b[92m' + footerLine + '\x1b[0m\n');
1825
- process.stdout.write('\x1b[92m│ \x1b[97m\x1b[1m✅ ¡Compilación Completada!\x1b[0m\x1b[92m' +
1826
- ' '.repeat(23) +
1827
- '│\x1b[0m\n');
1828
- process.stdout.write('\x1b[92m' + footerLine + '\x1b[0m\n\n');
1829
- // Escribir logs finales pendientes
1830
- if (this.logBuffer.length > 0) {
1831
- for (const log of this.logBuffer) {
1832
- process.stdout.write(log + '\n');
1833
- }
1834
- }
1835
- }
1836
- this.restoreConsole();
1837
- this.progressActive = false;
1838
- this.lastProgressLine = '';
1839
- this.logBuffer = [];
1840
- this.hasProgressLine = false;
1841
- }
1842
- isActive() {
1843
- return this.progressActive;
1844
- }
1845
- /**
1846
- * 🎨 Determina la etapa del progreso basándose en el texto
1847
- */
1848
- getStageFromText(text) {
1849
- if (text.includes('Iniciando') || text.includes('Starting'))
1850
- return 'start';
1851
- if (text.includes('Tailwind') || text.includes('CSS'))
1852
- return 'tailwind';
1853
- if (text.includes('Recopilando') ||
1854
- text.includes('archivos') ||
1855
- text.includes('files'))
1856
- return 'files';
1857
- if (text.includes('Compilando') || text.includes('workers'))
1858
- return 'compile';
1859
- if (text.includes('cache') || text.includes('Guardando'))
1860
- return 'cache';
1861
- if (text.includes('linter') || text.includes('Linter'))
1862
- return 'linter';
1863
- if (text.includes('completado') || text.includes('Complete'))
1864
- return 'complete';
1865
- return 'default';
1866
- }
1867
- /**
1868
- * 🌈 Obtiene colores dinámicos para cada etapa
1869
- */
1870
- getProgressColors(stage) {
1871
- const colorSchemes = {
1872
- start: { bgColor: '45', textColor: '97', icon: '🚀' }, // Cyan brillante
1873
- tailwind: { bgColor: '105', textColor: '97', icon: '🎨' }, // Magenta
1874
- files: { bgColor: '43', textColor: '30', icon: '📁' }, // Amarillo
1875
- compile: { bgColor: '42', textColor: '30', icon: '⚙️' }, // Verde
1876
- cache: { bgColor: '44', textColor: '97', icon: '💾' }, // Azul
1877
- linter: { bgColor: '101', textColor: '97', icon: '🔍' }, // Rojo claro
1878
- complete: { bgColor: '102', textColor: '30', icon: '✅' }, // Verde claro
1879
- default: { bgColor: '100', textColor: '30', icon: '⏳' }, // Gris claro
1880
- };
1881
- const defaultColors = { bgColor: '100', textColor: '30', icon: '⏳' };
1882
- return colorSchemes[stage] || defaultColors;
1883
- }
1884
- }
1885
- // Función para ejecutar el linter antes de la compilación
1886
- export async function runLinter(showResult = false) {
1887
- const linterENV = env.linter;
1888
- const linterPromises = [];
1889
- const linterErrors = [];
1890
- let proceedWithCompilation = true;
1891
- if (env.ENABLE_LINTER !== 'true') {
1892
- return true;
1893
- }
1894
- if (typeof linterENV === 'string' && linterENV.trim() !== '') {
1895
- logger.info('🔍 Ejecutando linting...');
1896
- try {
1897
- const parsedLinterEnv = JSON.parse(linterENV);
1898
- if (Array.isArray(parsedLinterEnv)) {
1899
- // Cargar dependencias de linting de forma lazy
1900
- const { ESLint, OxLint } = await loadLinter();
1901
- for (const item of parsedLinterEnv) {
1902
- if (item.name.toLowerCase() === 'eslint') {
1903
- logger.info(`🔧 Ejecutando ESLint con config: ${item.configFile || 'por defecto'}`);
1904
- const eslintPromise = ESLint(item)
1905
- .then((eslintResult) => {
1906
- if (eslintResult && eslintResult.json) {
1907
- // Procesar resultados de ESLint
1908
- if (Array.isArray(eslintResult.json)) {
1909
- eslintResult.json.forEach((result) => {
1910
- const filePath = result.filePath ||
1911
- result.file ||
1912
- 'archivo no especificado';
1913
- linterErrors.push({
1914
- from: 'eslint',
1915
- line: result.line || 'N/A',
1916
- column: result.column || 1,
1917
- file: filePath,
1918
- message: result.message,
1919
- severity: result.severity === 2
1920
- ? 'error'
1921
- : 'warning',
1922
- help: result.ruleId
1923
- ? `Regla ESLint: ${result.ruleId}`
1924
- : undefined,
1925
- });
1926
- });
1927
- }
1928
- else if (eslintResult.json.results &&
1929
- Array.isArray(eslintResult.json.results)) {
1930
- eslintResult.json.results.forEach((fileResult) => {
1931
- if (fileResult.messages &&
1932
- Array.isArray(fileResult.messages)) {
1933
- fileResult.messages.forEach((msg) => {
1934
- const filePath = fileResult.filePath ||
1935
- fileResult.file ||
1936
- 'archivo no especificado';
1937
- linterErrors.push({
1938
- from: 'eslint',
1939
- line: msg.line ||
1940
- 'N/A',
1941
- column: msg.column ||
1942
- 1,
1943
- file: filePath,
1944
- message: msg.message,
1945
- severity: msg.severity ===
1946
- 2
1947
- ? 'error'
1948
- : 'warning',
1949
- help: msg.ruleId
1950
- ? `Regla ESLint: ${msg.ruleId}`
1951
- : undefined,
1952
- });
1953
- });
1954
- }
1955
- });
1956
- }
1957
- }
1958
- })
1959
- .catch((err) => {
1960
- logger.error(`❌ Error durante la ejecución de ESLint: ${err.message}`);
1961
- linterErrors.push({
1962
- file: item.configFile || 'ESLint Config',
1963
- message: `Fallo al ejecutar ESLint: ${err.message}`,
1964
- severity: 'error',
1965
- });
1966
- });
1967
- linterPromises.push(eslintPromise);
1968
- }
1969
- else if (item.name.toLowerCase() === 'oxlint') {
1970
- logger.info(`🔧 Ejecutando OxLint con config: ${item.configFile || 'por defecto'}`);
1971
- const oxlintPromise = OxLint(item)
1972
- .then((oxlintResult) => {
1973
- if (oxlintResult &&
1974
- oxlintResult['json'] &&
1975
- Array.isArray(oxlintResult['json']['diagnostics'])) {
1976
- oxlintResult['json']['diagnostics'].forEach((result) => {
1977
- const filePath = result.filename ||
1978
- result.file ||
1979
- 'archivo no especificado';
1980
- const lineNumber = result.labels &&
1981
- result.labels[0] &&
1982
- result.labels[0].span
1983
- ? result.labels[0].span
1984
- .line ||
1985
- result.labels[0].span
1986
- .start?.line
1987
- : 'N/A';
1988
- const columnNumber = result.labels &&
1989
- result.labels[0] &&
1990
- result.labels[0].span
1991
- ? result.labels[0].span
1992
- .column ||
1993
- result.labels[0].span
1994
- .start?.column
1995
- : 1;
1996
- linterErrors.push({
1997
- from: 'oxlint',
1998
- line: lineNumber,
1999
- column: columnNumber,
2000
- file: filePath,
2001
- message: result.message,
2002
- severity: typeof result.severity ===
2003
- 'string'
2004
- ? result.severity.toLowerCase()
2005
- : 'error',
2006
- help: result.help ||
2007
- (result.code
2008
- ? `Regla Oxlint: ${result.code}`
2009
- : undefined),
2010
- });
2011
- });
2012
- }
2013
- })
2014
- .catch((err) => {
2015
- logger.error(`❌ Error durante la ejecución de OxLint: ${err.message}`);
2016
- linterErrors.push({
2017
- file: item.configFile || 'Oxlint Config',
2018
- message: `Fallo al ejecutar Oxlint: ${err.message}`,
2019
- severity: 'error',
2020
- });
2021
- });
2022
- linterPromises.push(oxlintPromise);
2023
- }
2024
- }
2025
- }
2026
- else {
2027
- logger.warn('⚠️ La configuración de linter no es un array válido.');
2028
- }
2029
- await Promise.all(linterPromises);
2030
- if (showResult) {
2031
- // Modo --linter: Solo mostrar resultados sin preguntar
2032
- if (linterErrors.length > 0) {
2033
- await displayLinterErrors(linterErrors);
2034
- }
2035
- else {
2036
- const chalk = await loadChalk();
2037
- logger.info(chalk.green('✅ No se encontraron errores ni advertencias de linting.'));
2038
- }
2039
- }
2040
- else {
2041
- // Modo compilación: Mostrar errores si los hay y preguntar al usuario
2042
- if (linterErrors.length > 0) {
2043
- await displayLinterErrors(linterErrors);
2044
- logger.warn('🚨 Se encontraron errores o advertencias durante el linting.');
2045
- if (env.yes === 'false') {
2046
- const result = await promptUser('¿Deseas continuar con la compilación a pesar de los errores de linting? (s/N): ');
2047
- if (result.toLowerCase() !== 's') {
2048
- logger.info('🛑 Compilación cancelada por el usuario.');
2049
- proceedWithCompilation = false;
2050
- }
2051
- }
2052
- }
2053
- }
2054
- }
2055
- catch (parseError) {
2056
- logger.warn(`Error parseando configuración de linter: ${parseError instanceof Error ? parseError.message : 'Error desconocido'}, omitiendo...`);
2057
- }
2058
- }
2059
- return proceedWithCompilation;
2060
- }
2061
- // Función para crear una barra de progreso visual
2062
- function createProgressBar(current, total, width = 30) {
2063
- const percentage = Math.round((current / total) * 100);
2064
- const filled = Math.round((percentage / 100) * width);
2065
- const empty = width - filled;
2066
- return `[${'█'.repeat(filled)}${' '.repeat(empty)}] ${percentage}% (${current}/${total})`;
2067
- }
2068
- // Función helper para verificar si un archivo debe ser omitido por cache
2069
- async function shouldSkipFile(filePath) {
2070
- return await smartCache.isValid(filePath);
2071
- }
2072
- // Función para compilar archivos con límite de concurrencia
2073
- async function compileWithConcurrencyLimit(files, maxConcurrency = 8) {
2074
- const results = [];
2075
- const executing = [];
2076
- const total = files.length;
2077
- let completed = 0;
2078
- let skipped = 0;
2079
- let failed = 0;
2080
- // Usar el gestor de progreso existente (ya iniciado en initCompileAll)
2081
- const progressManager = ProgressManager.getInstance();
2082
- // Variable para controlar el progreso inicial
2083
- let hasShownInitialProgress = false;
2084
- // Contador para limpieza periódica de memoria
2085
- let compilationCounter = 0;
2086
- const CLEANUP_INTERVAL = 20; // Limpiar cada 20 compilaciones
2087
- // Función para mostrar progreso
2088
- function showProgress() {
2089
- const currentTotal = completed + skipped + failed;
2090
- const progressBar = createProgressBar(currentTotal, total);
2091
- const progressPercent = Math.round((currentTotal / total) * 100);
2092
- // Mostrar progreso inicial cuando se inicie O cuando haya progreso real
2093
- if ((currentTotal === 0 && !hasShownInitialProgress) ||
2094
- (progressPercent > lastProgressUpdate + 1 && currentTotal > 0) ||
2095
- currentTotal === total) {
2096
- const progressText = `🚀 ${progressBar} [✅ ${completed} | ⏭️ ${skipped} | ❌ ${failed}]`;
2097
- progressManager.updateProgress(progressText);
2098
- if (currentTotal === 0) {
2099
- hasShownInitialProgress = true;
2100
- }
2101
- lastProgressUpdate = progressPercent;
2102
- // NO terminar el progreso aquí - se termina en initCompileAll
2103
- }
2104
- }
2105
- // Mostrar progreso inicial
2106
- showProgress();
2107
- for (const file of files) {
2108
- const promise = (async () => {
2109
- try {
2110
- // Log verbose: Iniciando compilación del archivo
2111
- if (env.VERBOSE === 'true') {
2112
- logger.info(`🔄 Compilando: ${path.basename(file)}`);
2113
- }
2114
- // Verificar cache antes de compilar
2115
- if (await shouldSkipFile(file)) {
2116
- skipped++;
2117
- if (env.VERBOSE === 'true') {
2118
- logger.info(`⏭️ Archivo omitido (cache): ${path.basename(file)}`);
2119
- }
2120
- showProgress();
2121
- return {
2122
- success: true,
2123
- cached: true,
2124
- output: smartCache.getOutputPath(file),
2125
- };
2126
- }
2127
- const result = await initCompile(file, false, 'batch');
2128
- // Actualizar cache si la compilación fue exitosa
2129
- if (result.success && result.output) {
2130
- await smartCache.set(file, result.output);
2131
- if (env.VERBOSE === 'true') {
2132
- logger.info(`✅ Completado: ${path.basename(file)} → ${path.basename(result.output)}`);
2133
- }
2134
- }
2135
- else if (env.VERBOSE === 'true') {
2136
- logger.info(`❌ Error en: ${path.basename(file)}`);
2137
- }
2138
- completed++;
2139
- compilationCounter++; // Limpieza periódica de memoria
2140
- if (compilationCounter % CLEANUP_INTERVAL === 0) {
2141
- // Forzar garbage collection si está disponible
2142
- try {
2143
- if (typeof globalThis.gc === 'function') {
2144
- globalThis.gc();
2145
- }
2146
- }
2147
- catch {
2148
- // gc no disponible, continuar normalmente
2149
- }
2150
- // Limpiar cache si la memoria es alta
2151
- const memUsage = process.memoryUsage();
2152
- const heapUsedMB = memUsage.heapUsed / (1024 * 1024);
2153
- if (heapUsedMB > 300) {
2154
- // Si el heap supera 300MB
2155
- const cacheEntries = smartCache.getStats().entries;
2156
- if (cacheEntries > 50) {
2157
- console.log(`[Memory] Heap alto (${heapUsedMB.toFixed(1)}MB), limpiando cache...`);
2158
- // Limpiar entradas más antiguas del cache
2159
- const removedEntries = smartCache.cleanOldEntries(20);
2160
- if (removedEntries > 0) {
2161
- console.log(`[Memory] Se removieron ${removedEntries} entradas del cache`);
2162
- }
2163
- }
2164
- }
2165
- }
2166
- showProgress();
2167
- return result;
2168
- }
2169
- catch (error) {
2170
- failed++;
2171
- if (env.VERBOSE === 'true') {
2172
- const errorMsg = error instanceof Error ? error.message : String(error);
2173
- logger.error(`💥 Falló: ${path.basename(file)} - ${errorMsg}`);
2174
- }
2175
- showProgress();
2176
- return {
2177
- success: false,
2178
- error: error instanceof Error ? error.message : String(error),
2179
- };
2180
- }
2181
- })();
2182
- results.push(promise);
2183
- executing.push(promise);
2184
- if (executing.length >= maxConcurrency) {
2185
- await Promise.race(executing);
2186
- executing.splice(executing.findIndex(p => p === promise), 1);
2187
- }
2188
- }
2189
- await Promise.all(results);
2190
- // El progreso ya se termina automáticamente en showProgress() cuando se completa
2191
- }
2192
- export async function initCompileAll() {
2193
- try {
2194
- // Inicializar el gestor de progreso desde el inicio
2195
- const progressManager = ProgressManager.getInstance();
2196
- progressManager.startProgress();
2197
- // Fase 1: Preparación inicial
2198
- progressManager.updateProgress('🚀 Iniciando compilación...');
2199
- // Limpiar estado de compilación anterior
2200
- clearCompilationState();
2201
- // Cargar cache al inicio
2202
- progressManager.updateProgress('📦 Cargando cache...');
2203
- await loadCache();
2204
- lastProgressUpdate = 0; // Fase 2: Linting
2205
- progressManager.updateProgress('🔍 Ejecutando linter...');
2206
- const shouldContinue = await runLinter(false); // false = mostrar errores y preguntar si hay errores
2207
- if (!shouldContinue) {
2208
- // await displayCompilationSummary(env.VERBOSE === 'true');
2209
- progressManager.endProgress();
2210
- return;
2211
- }
2212
- const startTime = Date.now();
2213
- const rawPathSource = env.PATH_SOURCE ?? '';
2214
- const pathDist = env.PATH_DIST ?? '';
2215
- const normalizedGlobPathSource = rawPathSource.replace(/\\/g, '/');
2216
- const patterns = [
2217
- `${normalizedGlobPathSource}/**/*.js`,
2218
- `${normalizedGlobPathSource}/**/*.vue`,
2219
- `${normalizedGlobPathSource}/**/*.ts`,
2220
- `${normalizedGlobPathSource}/**/*.mjs`,
2221
- `${normalizedGlobPathSource}/**/*.cjs`,
2222
- ];
2223
- logger.info(`📝 Compilando todos los archivos...`);
2224
- logger.info(`🔜 Fuente: ${rawPathSource}`);
2225
- logger.info(`🔚 Destino: ${pathDist}\n`);
2226
- // Fase 3: TailwindCSS
2227
- progressManager.updateProgress('🎨 Generando TailwindCSS...');
2228
- const generateTailwindCSS = await loadTailwind();
2229
- const resultTW = await generateTailwindCSS();
2230
- if (typeof resultTW !== 'boolean') {
2231
- if (resultTW?.success) {
2232
- logger.info(`🎨 ${resultTW.message}\n`);
2233
- }
2234
- else {
2235
- await handleCompilationError(new Error(`${resultTW.message}${resultTW.details ? '\n' + resultTW.details : ''}`), 'tailwind.config.js', 'tailwind', 'all', env.VERBOSE === 'true');
2236
- }
2237
- }
2238
- // Fase 4: Recopilando archivos
2239
- progressManager.updateProgress('📁 Recopilando archivos...');
2240
- const filesToCompile = [];
2241
- for await (const file of glob(patterns)) {
2242
- if (file.endsWith('.d.ts')) {
2243
- continue;
2244
- }
2245
- // Usar la ruta tal como viene de glob, sin modificar
2246
- filesToCompile.push(file);
2247
- } // Determinar concurrencia óptima considerando memoria disponible
2248
- const cpuCount = os.cpus().length;
2249
- const fileCount = filesToCompile.length;
2250
- const memUsage = process.memoryUsage();
2251
- const availableMemoryMB = (memUsage.heapTotal - memUsage.heapUsed) / (1024 * 1024);
2252
- let maxConcurrency;
2253
- // Ajustar concurrencia basado en memoria disponible y archivos
2254
- if (availableMemoryMB < 100) {
2255
- // Poca memoria disponible
2256
- maxConcurrency = Math.min(2, cpuCount);
2257
- }
2258
- else if (fileCount < 10) {
2259
- maxConcurrency = Math.min(fileCount, Math.min(cpuCount, 4));
2260
- }
2261
- else if (fileCount < 50) {
2262
- maxConcurrency = Math.min(cpuCount, 6); // Reducido
2263
- }
2264
- else {
2265
- maxConcurrency = Math.min(cpuCount, 8); // Reducido
2266
- }
2267
- // Fase 5: Configurando workers
2268
- progressManager.updateProgress('⚙️ Configurando workers...');
2269
- logger.info(`🚀 Compilando ${fileCount} archivos con concurrencia optimizada (${maxConcurrency} hilos)...`); // Configurar worker pool para modo batch
2270
- try {
2271
- const { TypeScriptWorkerPool } = (await import('./typescript-worker-pool.js'));
2272
- const workerPool = TypeScriptWorkerPool.getInstance();
2273
- workerPool.setMode('batch');
2274
- }
2275
- catch {
2276
- // Error silencioso en configuración del pool
2277
- } // Fase 6: Compilación (el progreso continúa en compileWithConcurrencyLimit)
2278
- progressManager.updateProgress(`🚀 Iniciando compilación de ${fileCount} archivos...`);
2279
- await compileWithConcurrencyLimit(filesToCompile, maxConcurrency); // Guardar cache al final
2280
- progressManager.updateProgress('💾 Guardando cache...');
2281
- await saveCache();
2282
- const endTime = Date.now();
2283
- const elapsedTime = showTimingForHumans(endTime - startTime); // Finalizar progreso
2284
- progressManager.endProgress();
2285
- // Mostrar resumen de compilación con tiempo total
2286
- await displayCompilationSummary(env.VERBOSE === 'true', elapsedTime);
2287
- }
2288
- catch (error) {
2289
- // Asegurar que el progreso termine en caso de error
2290
- const progressManager = ProgressManager.getInstance();
2291
- if (progressManager.isActive()) {
2292
- progressManager.endProgress();
2293
- }
2294
- const errorMessage = error instanceof Error ? error.message : String(error);
2295
- logger.error(`🚩 Error al compilar todos los archivos: ${errorMessage}`);
2296
- // Registrar el error en el sistema unificado
2297
- await handleCompilationError(error instanceof Error ? error : new Error(String(error)), 'compilación general', 'all', 'all', env.VERBOSE === 'true'); // Mostrar resumen incluso si hay errores generales
2298
- await displayCompilationSummary(env.VERBOSE === 'true');
2299
- }
2300
- }
2301
- /**
2302
- * 🎨 Obtiene icono apropiado para cada etapa
2303
- */
2304
- function getStageIcon(stage) {
2305
- const icons = {
2306
- vue: '🎨',
2307
- typescript: '📘',
2308
- standardization: '💛',
2309
- minification: '🗜️',
2310
- tailwind: '🎨',
2311
- 'file-read': '📖',
2312
- default: '⚙️',
2313
- };
2314
- return icons[stage] ?? '⚙️';
2315
- }
2316
- /**
2317
- * Crea una barra de progreso visual con porcentaje
2318
- */
2319
- function createProgressBarWithPercentage(percentage, width) {
2320
- const filled = Math.round((percentage / 100) * width);
2321
- const empty = width - filled;
2322
- // Usar código directo para evitar problemas de importación
2323
- const greenBar = '\x1b[32m' + '█'.repeat(filled) + '\x1b[0m';
2324
- const grayBar = '\x1b[90m' + '░'.repeat(empty) + '\x1b[0m';
2325
- return `${greenBar}${grayBar} ${percentage}%`;
2326
- }
2327
- // Función wrapper para compatibilidad con tests
2328
- export async function compileFile(filePath) {
2329
- return await initCompile(filePath, true, 'individual');
2330
- }
2331
- export { WatchModeOptimizer };
2332
- //# sourceMappingURL=compile.js.map
1
+ import{createHash as e}from"node:crypto";import{glob as t,mkdir as n,readFile as r,stat as i,unlink as a,writeFile as o}from"node:fs/promises";import s from"node:os";import c from"node:path";import l,{argv as u,cwd as d,env as f}from"node:process";import{logger as p,setProgressManagerGetter as m}from"../servicios/logger.js";import{promptUser as h}from"../utils/promptUser.js";import{showTimingForHumans as g}from"../utils/utils.js";m(()=>Q.getInstance());let _,v,y,b,x,S,C,w,T,E,D;class O{static instance;isInitialized=!1;loadedModules=new Set;modulePool=new Map;loadingPromises=new Map;usageStats=new Map;preloadQueue=new Set;backgroundLoader=null;HOT_MODULES=[`chalk`,`parser`];currentContext=null;constructor(){this.startBackgroundPreloading()}static getInstance(){return O.instance||=new O,O.instance}startBackgroundPreloading(){this.backgroundLoader=this.preloadCriticalModules()}async preloadCriticalModules(){try{let e=this.HOT_MODULES.map(e=>this.ensureModuleLoaded(e).catch(()=>{}));await Promise.allSettled(e)}catch{}}async preloadForContext(e,t=new Set){this.currentContext=e,this.backgroundLoader&&await this.backgroundLoader;let n=[];e===`batch`||e===`watch`?n.push(`transforms`,`vue`,`typescript`,`module-resolution-optimizer`):(t.has(`.vue`)&&n.push(`vue`),(t.has(`.ts`)||t.has(`.vue`))&&n.push(`typescript`),this.loadedModules.has(`transforms`)||n.push(`transforms`));let r=n.map(e=>this.ensureModuleLoaded(e).catch(()=>{console.warn(`Warning: No se pudo precargar módulo ${e}`)}));await Promise.allSettled(r)}async ensureModuleLoaded(e){if(this.modulePool.has(e))return this.updateUsageStats(e),this.modulePool.get(e);if(this.loadingPromises.has(e))return this.loadingPromises.get(e);let t=this.loadModuleInternal(e);this.loadingPromises.set(e,t);try{let n=await t;return this.modulePool.set(e,n),this.loadedModules.add(e),this.updateUsageStats(e),n}finally{this.loadingPromises.delete(e)}}updateUsageStats(e){let t=this.usageStats.get(e)||0;this.usageStats.set(e,t+1)}async loadModuleInternal(e){switch(e){case`chalk`:return this.loadChalk();case`parser`:return this.loadParser();case`transforms`:return this.loadTransforms();case`vue`:return this.loadVue();case`typescript`:return this.loadTypeScript();case`minify`:return this.loadMinify();case`tailwind`:return this.loadTailwind();case`linter`:return this.loadLinter();case`transform-optimizer`:return this.loadTransformOptimizer();case`module-resolution-optimizer`:return this.loadModuleResolutionOptimizer();default:throw Error(`Módulo desconocido: ${e}`)}}async loadChalk(){return _||=(await import(`chalk`)).default,_}async loadParser(){if(!x){let e=await import(`./parser.js`);x=e.getCodeFile}return x}async loadTransforms(){if(!C){let e=await import(`./transforms.js`);C=e.estandarizaCode}return C}async loadVue(){if(!T){let e=await import(`./vuejs.js`);T=e.preCompileVue}return T}async loadTypeScript(){if(!w){let e=await import(`./typescript-manager.js`);w=e.preCompileTS}return w}async loadMinify(){if(!b){let e=await import(`./minify.js`);b=e.minifyJS}return b}async loadTailwind(){if(!S){let e=await import(`./tailwindcss.js`);S=e.generateTailwindCSS}return S}async loadLinter(){if(!v||!y){let e=await import(`./linter.js`);v=e.ESLint,y=e.OxLint}return{ESLint:v,OxLint:y}}async loadTransformOptimizer(){if(!E){let e=await import(`./transform-optimizer.js`);E=e.TransformOptimizer.getInstance()}return E}async loadModuleResolutionOptimizer(){if(!D){let e=await import(`./module-resolution-optimizer.js`);D=e.ModuleResolutionOptimizer.getInstance()}return D}getPerformanceStats(){let e=Array.from(this.usageStats.entries()).sort((e,t)=>t[1]-e[1]).slice(0,5).map(([e])=>e);return{loadedModules:Array.from(this.loadedModules),usageStats:Object.fromEntries(this.usageStats),poolSize:this.modulePool.size,loadingInProgress:Array.from(this.loadingPromises.keys()),mostUsedModules:e}}cleanupUnusedModules(){let e=1;for(let[e,t]of this.usageStats)t<1&&!this.HOT_MODULES.includes(e)&&(this.modulePool.delete(e),this.loadedModules.delete(e),this.usageStats.delete(e))}reset(){this.isInitialized=!1,this.loadedModules.clear(),this.modulePool.clear(),this.loadingPromises.clear(),this.usageStats.clear(),this.preloadQueue.clear(),this.currentContext=null,this.backgroundLoader=null,this.startBackgroundPreloading()}}async function k(){return _||=(await import(`chalk`)).default,_}async function oe(){if(!v||!y){let e=await import(`./linter.js`);v=e.ESLint,y=e.OxLint}return{ESLint:v,OxLint:y}}async function se(){if(!b){let e=await import(`./minify.js`);b=e.minifyJS}return b}async function A(){if(!x){let e=await import(`./parser.js`);x=e.getCodeFile}return x}async function j(){if(!S){let e=await import(`./tailwindcss.js`);S=e.generateTailwindCSS}return S}async function M(){if(!C){let e=await import(`./transforms.js`);C=e.estandarizaCode}return C}async function ce(){if(!w){let e=await import(`./typescript-manager.js`);w=e.preCompileTS}return w}async function le(){if(!T){let e=await import(`./vuejs.js`);T=e.preCompileVue}return T}const N=[],P=[],F=[`NODE_ENV`,`isPROD`,`TAILWIND`,`ENABLE_LINTER`,`VERBOSE`,`typeCheck`,`PATH_ALIAS`,`tailwindcss`,`linter`,`tsconfigFile`];class I{cache=new Map;maxEntries=200;maxMemory=50*1024*1024;currentMemoryUsage=0;fileWatchers=new Map;dependencyGraph=new Map;reverseDependencyGraph=new Map;packageJsonPath=c.join(d(),`package.json`);nodeModulesPath=c.join(d(),`node_modules`);isWatchingDependencies=!1;async generateContentHash(t){try{let n=await r(t,`utf8`);return e(`sha256`).update(n).digest(`hex`)}catch{let n=`${t}-${Date.now()}`;return e(`sha256`).update(n).digest(`hex`)}}generateConfigHash(){try{let t={isPROD:f.isPROD||`false`,TAILWIND:f.TAILWIND||`false`,ENABLE_LINTER:f.ENABLE_LINTER||`false`,PATH_ALIAS:f.PATH_ALIAS||`{}`,tailwindcss:f.tailwindcss||`false`,linter:f.linter||`false`,tsconfigFile:f.tsconfigFile||`./tsconfig.json`},n=JSON.stringify(t,Object.keys(t).sort());return e(`sha256`).update(n).digest(`hex`).substring(0,12)}catch{return`no-config`}}generateEnvHash(){try{let t=F.map(e=>`${e}=${f[e]||``}`).join(`|`);return e(`sha256`).update(t).digest(`hex`).substring(0,12)}catch{return`no-env`}}async generateDependencyHash(){try{let t=e(`sha256`),n=c.join(d(),`package.json`),a=await r(n,`utf8`),o=JSON.parse(a),s={...o.dependencies,...o.devDependencies},l=JSON.stringify(s,Object.keys(s).sort());t.update(`package:${l}`);try{let e=c.join(d(),`package-lock.json`),n=await r(e,`utf8`),i=JSON.parse(n),a={};if(i.packages){for(let[e,t]of Object.entries(i.packages))if(e&&e!==``&&typeof t==`object`&&t){let n=e.replace(`node_modules/`,``);t.version&&(a[n]=t.version)}}t.update(`lock:${JSON.stringify(a,Object.keys(a).sort())}`)}catch{}try{let e=c.join(d(),`node_modules`),n=await i(e);t.update(`nmtime:${n.mtimeMs}`);let r=Object.keys(s).slice(0,10);for(let n of r)try{let r=c.join(e,n),a=await i(r);t.update(`${n}:${a.mtimeMs}`)}catch{t.update(`${n}:missing`)}}catch{t.update(`nmtime:none`)}return t.digest(`hex`).substring(0,16)}catch(t){return e(`sha256`).update(`error:${t instanceof Error?t.message:`unknown`}`).digest(`hex`).substring(0,16)}}async generateCacheKey(e){let t=await this.generateContentHash(e),n=this.generateConfigHash(),r=this.generateEnvHash(),i=await this.generateDependencyHash();return`${e}|${t.substring(0,12)}|${n}|${r}|${i}`}async isValid(e){let t=this.cache.get(e);if(!t)return!1;try{await i(t.outputPath);let n=await this.generateContentHash(e);if(t.contentHash!==n)return this.cache.delete(e),!1;let r=this.generateConfigHash();if(t.configHash!==r)return this.cache.delete(e),!1;let a=this.generateEnvHash();if(t.envHash!==a)return this.cache.delete(e),!1;let o=await this.generateDependencyHash();if(t.dependencyHash!==o)return this.cache.delete(e),!1;let s=await i(e);return s.mtimeMs>t.mtime?(this.cache.delete(e),!1):(t.lastUsed=Date.now(),!0)}catch{return this.cache.delete(e),!1}}async set(e,t){try{let n=await i(e),r=await this.generateContentHash(e),a=this.generateConfigHash(),o=this.generateEnvHash(),s=await this.generateDependencyHash(),c={contentHash:r,configHash:a,envHash:o,dependencyHash:s,mtime:n.mtimeMs,outputPath:t,lastUsed:Date.now(),size:n.size};this.evictIfNeeded(c.size),this.cache.set(e,c),this.currentMemoryUsage+=c.size}catch(t){console.warn(`Warning: No se pudo cachear ${e}:`,t)}}evictIfNeeded(e){for(;this.cache.size>=this.maxEntries*.8;)this.evictLRU();for(;this.currentMemoryUsage+e>this.maxMemory*.8&&this.cache.size>0;)this.evictLRU();let t=l.memoryUsage(),n=t.heapUsed/(1024*1024);if(n>200&&this.cache.size>50){let e=Math.min(this.cache.size-50,10);for(let t=0;t<e;t++)this.evictLRU()}}evictLRU(){let e=``,t=1/0;for(let[n,r]of this.cache)r.lastUsed<t&&(t=r.lastUsed,e=n);if(e){let t=this.cache.get(e);t&&(this.currentMemoryUsage-=t.size,this.cache.delete(e))}}cleanOldEntries(e=20){let t=0;for(let n=0;n<e&&this.cache.size>0;n++){let e=this.cache.size;if(this.evictLRU(),this.cache.size<e)t++;else break}return t}async load(e){try{if(f.cleanCache===`true`){this.cache.clear(),this.currentMemoryUsage=0;try{await a(e)}catch{}return}let t=await r(e,`utf-8`),n=JSON.parse(t);for(let[e,t]of Object.entries(n)){let n=t;n.contentHash&&n.outputPath&&n.mtime&&(this.cache.set(e,n),this.currentMemoryUsage+=n.size||0)}}catch{this.cache.clear(),this.currentMemoryUsage=0}}async save(e,t){try{await n(t,{recursive:!0});let r=Object.fromEntries(this.cache);await o(e,JSON.stringify(r,null,2))}catch(e){console.warn(`Warning: No se pudo guardar el cache:`,e)}}clear(){this.cache.clear(),this.currentMemoryUsage=0}getOutputPath(e){let t=this.cache.get(e);return t?.outputPath||``}getStats(){return{entries:this.cache.size,memoryUsage:this.currentMemoryUsage,hitRate:0}}async startDependencyWatching(){if(!this.isWatchingDependencies)try{let e=await import(`chokidar`);if(await this.fileExists(this.packageJsonPath)){let t=e.watch(this.packageJsonPath,{persistent:!1,ignoreInitial:!0});t.on(`change`,()=>{p.info(`📦 package.json modificado - invalidando cache de dependencias`),this.invalidateByDependencyChange()}),this.fileWatchers.set(`package.json`,t)}if(await this.fileExists(this.nodeModulesPath)){let t=e.watch(this.nodeModulesPath,{persistent:!1,ignoreInitial:!0,depth:1,ignored:/(^|[/\\])\../});t.on(`addDir`,e=>{p.info(`📦 Nueva dependencia instalada: ${e.split(/[/\\]/).pop()}`),this.invalidateByDependencyChange()}),t.on(`unlinkDir`,e=>{p.info(`📦 Dependencia eliminada: ${e.split(/[/\\]/).pop()}`),this.invalidateByDependencyChange()}),this.fileWatchers.set(`node_modules`,t)}this.isWatchingDependencies=!0,p.info(`🔍 Vigilancia de dependencias iniciada`)}catch(e){p.warn(`⚠️ No se pudo iniciar vigilancia de dependencias:`,e)}}async stopDependencyWatching(){for(let[e,t]of this.fileWatchers)try{await t.close(),p.info(`🛑 Vigilancia detenida: ${e}`)}catch(t){p.warn(`⚠️ Error cerrando watcher ${e}:`,t)}this.fileWatchers.clear(),this.isWatchingDependencies=!1}registerDependencies(e,t){let n=this.dependencyGraph.get(e);if(n)for(let t of n){let n=this.reverseDependencyGraph.get(t);n&&(n.delete(e),n.size===0&&this.reverseDependencyGraph.delete(t))}let r=new Set(t);this.dependencyGraph.set(e,r);for(let t of r)this.reverseDependencyGraph.has(t)||this.reverseDependencyGraph.set(t,new Set),this.reverseDependencyGraph.get(t).add(e)}invalidateByDependencyChange(){let e=0;for(let[t]of this.cache)this.cache.delete(t),e++;this.dependencyGraph.clear(),this.reverseDependencyGraph.clear(),this.currentMemoryUsage=0,p.info(`🗑️ Cache invalidado: ${e} archivos (cambio en dependencias)`)}invalidateCascade(e){let t=[],n=new Set([e]),r=[e];for(;r.length>0;){let e=r.shift(),t=this.reverseDependencyGraph.get(e);if(t)for(let e of t)n.has(e)||(n.add(e),r.push(e))}for(let e of n)if(this.cache.has(e)){let n=this.cache.get(e);this.currentMemoryUsage-=n.size,this.cache.delete(e),t.push(e)}return t.length>0&&p.info(`🔄 Invalidación cascada: ${t.length} archivos afectados por ${e}`),t}async fileExists(e){try{return await i(e),!0}catch{return!1}}getAdvancedStats(){return{entries:this.cache.size,memoryUsage:this.currentMemoryUsage,hitRate:0,dependencyNodes:this.dependencyGraph.size,watchingDependencies:this.isWatchingDependencies,activeWatchers:this.fileWatchers.size}}}const L=new I,R=c.join(c.resolve(f.PATH_PROY||d(),`compiler`),`.cache`),z=c.join(R,`versacompile-cache.json`);async function B(){await L.load(z),(f.WATCH_MODE===`true`||u.includes(`--watch`)||u.includes(`-w`))&&await L.startDependencyWatching()}async function ue(){await L.save(z,R)}function V(e,t,n,r=`error`,i,a){N.push({file:e,stage:t,message:n,severity:r,details:i,help:a,timestamp:Date.now()})}function H(e,t,n,r=[]){let i=P.find(t=>t.stage===e);i?(i.errors+=t,i.success+=n,i.files.push(...r)):P.push({stage:e,errors:t,success:n,files:[...r]})}async function U(e,t,n,r,i=!1){let a=e instanceof Error?e.message:e,o=e instanceof Error?e.stack:void 0;if(V(t,n,a,`error`,o),H(n,1,0,[t]),r===`individual`||r===`watch`){let e=await k(),r=c.basename(t),s=await Y(n);if(i){if(p.error(e.red(`❌ Error en etapa ${s(n)} - ${r}:`)),p.error(e.red(a)),o&&(n===`typescript`||n===`vue`)){let t=o.split(`
2
+ `).slice(0,5);t.forEach(t=>{t.trim()&&p.error(e.gray(` ${t.trim()}`))})}}else{let t=a.split(`
3
+ `)[0];p.error(e.red(`❌ Error en ${s(n)}: ${r}`)),p.error(e.red(` ${t}`)),p.info(e.yellow(`💡 Usa --verbose para ver detalles completos`))}}}function W(e,t){H(t,0,1,[e])}function G(){N.length=0,P.length=0}async function K(e=!1,t){let n=await k();if(N.length===0&&P.length===0){p.info(n.green(`✅ No hay errores de compilación para mostrar.`)),t&&p.info(n.bold(`\n⏱️ TIEMPO TOTAL DE COMPILACIÓN: ${t}`));return}let r=`━`.repeat(40);if(p.info(``),p.info(n.bold.cyan(`📊 Resumen de Compilación`)),p.info(n.gray(r)),t&&(p.info(n.bold(`⏱️ Tiempo Total: ${n.green(t)}`)),p.info(``)),P.length>0){p.info(n.bold.blue(`🔧 Estadísticas por Etapa:`));for(let e of P){let t=e.success+e.errors,r=t>0?Math.round(e.success/t*100):0,i=_e(e.stage),a=e.errors===0?n.green:n.red,o=ve(r,20);p.info(` ${i} ${n.bold(e.stage)}`),p.info(` ${a(`●`)} ${e.success}/${t} archivos ${a(`(${r}%)`)}`),p.info(` ${o}`),e.errors>0&&p.info(` ${n.red(`⚠`)} ${e.errors} ${e.errors===1?`error`:`errores`}`),p.info(``)}}if(N.length>0){p.info(n.red(`\n❌ Se encontraron ${N.length} errores:`));let t=new Map;N.forEach(e=>{t.has(e.file)||t.set(e.file,[]),t.get(e.file).push(e)});let r=1;for(let[i,a]of t){let t=c.basename(i),o=a.filter(e=>e.severity===`error`).length,s=a.filter(e=>e.severity===`warning`).length;p.info(n.cyan(`\n📄 ${r}. ${t}`)),p.info(n.gray(` Ruta: ${i}`)),p.info(n.yellow(` ${o} errores, ${s} advertencias`));for(let t of a){let r=t.severity===`error`?`❌`:`⚠️`,i=await Y(t.stage);if(p.info(` ${r} [${i(t.stage)}] ${t.message}`),e&&t.details){let e=t.details.split(`
4
+ `).slice(0,5);e.forEach(e=>{e.trim()&&p.info(n.gray(` ${e.trim()}`))})}t.help&&p.info(n.blue(` 💡 ${t.help}`))}r++}let i=N.filter(e=>e.severity===`error`).length,a=N.filter(e=>e.severity===`warning`).length,o=t.size,s=`═`.repeat(50);p.info(``),p.info(n.bold.cyan(s)),p.info(n.bold.cyan(` 📊 RESUMEN FINAL`)),p.info(n.bold.cyan(s)),p.info(``),p.info(n.bold(`🎯 Resultados:`)),p.info(` 📁 Archivos afectados: ${n.cyan.bold(o)}`),p.info(` ${i>0?n.red(`●`):n.green(`○`)} Errores: ${i>0?n.red.bold(i):n.green.bold(`0`)}`),p.info(` ${a>0?n.yellow(`●`):n.green(`○`)} Advertencias: ${a>0?n.yellow.bold(a):n.green.bold(`0`)}`),p.info(``),i>0?(p.info(n.red.bold(`🚨 COMPILACIÓN COMPLETADA CON ERRORES`)),p.info(n.red(` Por favor revisa y corrige los problemas anteriores.`))):a>0?(p.info(n.yellow.bold(`⚠️ COMPILACIÓN COMPLETADA CON ADVERTENCIAS`)),p.info(n.yellow(` Considera revisar las advertencias anteriores.`))):(p.info(n.green.bold(`✅ COMPILACIÓN EXITOSA`)),p.info(n.green(` ¡Todos los archivos se compilaron sin problemas!`))),p.info(``),p.info(n.bold.cyan(s))}else{let e=`═`.repeat(50);p.info(``),p.info(n.bold.green(e)),p.info(n.bold.green(` ✨ ÉXITO`)),p.info(n.bold.green(e)),p.info(``),p.info(n.green.bold(`🎉 COMPILACIÓN COMPLETADA EXITOSAMENTE`)),p.info(n.green(` ¡No se encontraron errores ni advertencias!`)),p.info(``),p.info(n.bold.green(e))}p.info(``)}async function q(e){let t=await k(),n=new Map;e.forEach(e=>{n.has(e.file)||n.set(e.file,[]),n.get(e.file).push(e)});let r=e.filter(e=>e.severity===`error`).length,i=e.filter(e=>e.severity===`warning`).length,a=n.size;p.info(t.bold.rgb(255,120,120)(`╭─────────────────────────────────────────────────────────────╮`)),p.info(t.bold.rgb(255,120,120)(`│ `)+t.bold.white(`🔍 LINTER REPORT`)+t.bold.rgb(255,120,120)(` │`)),p.info(t.bold.rgb(255,120,120)(`╰─────────────────────────────────────────────────────────────╯`));let o=r>0?t.red(`●`):t.green(`○`),s=i>0?t.yellow(`●`):t.green(`○`);if(p.info(``),p.info(t.bold(`📊 Summary:`)),p.info(` ${o} ${t.bold(r)} ${t.red(`errors`)}`),p.info(` ${s} ${t.bold(i)} ${t.yellow(`warnings`)}`),p.info(` 📁 ${t.bold(a)} ${t.cyan(`files`)}`),p.info(``),r===0&&i===0){p.info(t.green.bold(`✨ All checks passed! No issues found.`));return}let c=1;for(let[e,r]of n)await J(e,r,c,a),c++,c<=a&&p.info(t.gray(`─`.repeat(80)));p.info(``),p.info(t.bold.rgb(255,120,120)(`╭─────────────────────────────────────────────────────────────╮`)),p.info(t.bold.rgb(255,120,120)(`│ `)+t.bold.white(`Found ${r+i} issues in ${a} files`)+` `.repeat(Math.max(0,52-`Found ${r+i} issues in ${a} files`.length))+t.bold.rgb(255,120,120)(` │`)),p.info(t.bold.rgb(255,120,120)(`╰─────────────────────────────────────────────────────────────╯`))}async function J(e,t,n,r){let i=await k(),a=t.filter(e=>e.severity===`error`).length,o=t.filter(e=>e.severity===`warning`).length,s=a>0?i.red(`✕`):i.yellow(`⚠`),u=e.endsWith(`.vue`)?`🎨`:e.endsWith(`.ts`)?`📘`:e.endsWith(`.js`)?`📜`:`📄`;p.info(``),p.info(i.bold(`${s} ${u} ${i.cyan(c.relative(l.cwd(),e))}`)),p.info(i.gray(` ${a} errors, ${o} warnings`)),p.info(``);for(let n=0;n<t.length;n++){let r=t[n];await de(r,e,n+1,t.length)}}async function de(e,t,n,r){let i=await k(),a=await import(`node:fs/promises`),o=e.severity===`error`,s=o?i.red:i.yellow,l=o?`✕`:`⚠`,u=e.line||1,d=e.column||1,f=e.ruleId||e.from||`unknown`,m=` ${s(l)} ${i.bold(e.message)}`,h=`${i.gray(f)}`,g=`${i.blue(`${u}:${d}`)}`;p.info(m),p.info(` ${i.gray(`at`)} ${g} ${i.gray(`·`)} ${h}`);try{let e=c.resolve(t),n=await a.readFile(e,`utf-8`),r=n.split(`
5
+ `),o=parseInt(u.toString())-1;if(o>=0&&o<r.length){p.info(``);let e=Math.max(0,o-1),t=Math.min(r.length-1,o+1),n=(t+1).toString().length;for(let a=e;a<=t;a++){let e=a+1,t=r[a]||``,c=e.toString().padStart(n,` `),l=a===o;if(l){p.info(` ${i.red(`>`)} ${i.gray(c)} ${i.gray(`│`)} ${t}`);let e=` `.repeat(Math.max(0,d-1))+s(`^`);p.info(` ${i.gray(` `)} ${i.gray(` `.repeat(n))} ${i.gray(`│`)} ${e}`)}else p.info(` ${i.gray(` `)} ${i.gray(c)} ${i.gray(`│`)} ${i.gray(t)}`)}}}catch{p.info(` ${i.gray(`│`)} ${i.gray(`(Unable to read file content)`)}`)}if(e.help){p.info(``);let t=e.help.replace(/^Regla \w+: /,``).trim();p.info(` ${i.blue(`💡`)} ${i.blue(`Help:`)} ${i.gray(t)}`)}n<r&&p.info(``)}async function fe(e,t){let n=await k(),r=await import(`node:fs/promises`),i=e.severity===`error`?`×`:`⚠`,a=e.help||``,o=e.line||`N/A`,s=e.column||10,l=`${n.red(i)} ${n.cyan(`${e.from}(${a.replace(/^Regla \w+: /,``)})`)}: ${e.message}`;p.info(l);try{let i=c.resolve(t),a=await r.readFile(i,`utf-8`),l=a.split(`
6
+ `),u=parseInt(o.toString())-1;if(u>=0&&u<l.length){p.info(n.blue(` ╭─[${t}:${o}:${s}]`));let r=Math.max(0,u-1),i=Math.min(l.length-1,u+1);for(let t=r;t<=i;t++){let r=t+1,i=l[t]||``,a=r.toString().padStart(2,` `);if(t===u){p.info(n.blue(` ${a} │ `)+i);let t=` `.repeat(a.length+3),r=` `.repeat(Math.max(0,(s||1)-1))+n.red(`───────┬──────`);p.info(n.blue(t+`·`)+r);let o=` `.repeat(Math.max(0,(s||1)+6));p.info(n.blue(t+`·`)+o+n.red(`╰── `)+n.gray(pe(e)))}else p.info(n.blue(` ${a} │ `)+n.gray(i))}p.info(n.blue(` ╰────`))}}catch{p.info(n.blue(` ╭─[${t}:${o}:${s}]`)),p.info(n.blue(` │ `)+n.gray(`(No se pudo leer el contenido del archivo)`)),p.info(n.blue(` ╰────`))}if(e.help){let t=e.help.replace(/^Regla \w+: /,``);p.info(n.blue(` help: `)+n.yellow(t))}p.info(``)}function pe(e){if(e.message.includes(`declared but never used`)){let t=e.message.match(/'([^']+)'/);if(t)return`'${t[1]}' is declared here`}if(e.message.includes(`Unexpected var`))return`var declaration found here`;if(e.message.includes(`never reassigned`)){let t=e.message.match(/'([^']+)'/);if(t)return`'${t[1]}' is assigned here`}return`error location`}async function Y(e){let t=await k();switch(e){case`vue`:return t.green;case`typescript`:return t.blue;case`standardization`:return t.yellow;case`minification`:return t.red;case`tailwind`:return t.magenta;case`file-read`:return t.gray;default:return t.white}}export function normalizeRuta(e){if(c.isAbsolute(e))return c.normalize(e).replace(/\\/g,`/`);let t=c.normalize(e.startsWith(`.`)?e:`./`+e).replace(/\\/g,`/`),n=t.startsWith(`./`)?t:`./${t}`;return n}export function getOutputPath(e){let t=f.PATH_SOURCE??``,n=f.PATH_DIST??``;if(!t||!n)return e.replace(/\.(vue|ts)$/,`.js`);let r=c.normalize(e).replace(/\\/g,`/`),i=c.normalize(t).replace(/\\/g,`/`),a=c.normalize(n).replace(/\\/g,`/`),o;if(r.includes(i)){let e=r.substring(r.indexOf(i)+i.length).replace(/^[/\\]/,``);o=c.join(a,e).replace(/\\/g,`/`)}else{let e=c.basename(r);o=c.join(a,e).replace(/\\/g,`/`)}return o.includes(`vue`)||o.includes(`ts`)?o.replace(/\.(vue|ts)$/,`.js`):o}class X{static instance;fileSystemCache=new Map;debounceTimers=new Map;DEBOUNCE_DELAY=100;static getInstance(){return X.instance||=new X,X.instance}async compileForWatch(e,t){return new Promise(n=>{let r=this.debounceTimers.get(e);r&&clearTimeout(r);let a=setTimeout(async()=>{this.debounceTimers.delete(e);try{let r=await i(e),a=this.fileSystemCache.get(e);if(a&&a.mtime>=r.mtimeMs){n({success:!0,cached:!0});return}let{TypeScriptWorkerPool:o}=await import(`./typescript-worker-pool.js`),s=o.getInstance();s.setMode(`watch`);let c=await t(e);this.fileSystemCache.set(e,{mtime:r.mtimeMs}),n(c)}catch(e){n({success:!1,error:e})}},this.DEBOUNCE_DELAY);this.debounceTimers.set(e,a)})}cleanup(){this.debounceTimers.forEach(e=>clearTimeout(e)),this.debounceTimers.clear(),this.fileSystemCache.clear()}}async function me(e,t,r=`individual`){let i={};e=c.isAbsolute(e)?normalizeRuta(e):normalizeRuta(c.resolve(e));let a=O.getInstance(),s=Date.now(),l=c.extname(e);await a.ensureModuleLoaded(`parser`);let u=await A(),d=await u(e),m=d.code,h=d.error;if(i.fileRead=Date.now()-s,h)throw await U(h instanceof Error?h:Error(String(h)),e,`file-read`,r,f.VERBOSE===`true`),Error(h instanceof Error?h.message:String(h));if(!m||m.trim().length===0||m===`undefined`||m===`null`)throw await U(Error(`El archivo está vacío o no se pudo leer.`),e,`file-read`,r,f.VERBOSE===`true`),Error(`El archivo está vacío o no se pudo leer.`);let g=f.VERBOSE===`true`,v;if(l===`.vue`){s=Date.now(),g&&p.info(_.green(`💚 Precompilando VUE: ${c.basename(e)}`)),await a.ensureModuleLoaded(`vue`);let t=await le();if(typeof t!=`function`)throw Error(`loadVue devolvió ${typeof t} en lugar de una función para archivo: ${e}`);if(v=await t(m,e,f.isPROD===`true`),i.vueCompile=Date.now()-s,v==null)throw Error(`preCompileVue devolvió ${v} para archivo: ${e}`);if(v.error)throw await U(v.error instanceof Error?v.error:Error(String(v.error)),e,`vue`,r,f.VERBOSE===`true`),Error(v.error instanceof Error?v.error.message:String(v.error));W(e,`vue`),m=v.data}if(!m||m.trim().length===0)throw await U(Error(`El código Vue compilado está vacío.`),e,`vue`,r,f.VERBOSE===`true`),Error(`El código Vue compilado está vacío.`);let y;if(l===`.ts`||v?.lang===`ts`){s=Date.now(),g&&p.info(_.blue(`🔄️ Precompilando TS: ${c.basename(e)}`)),await a.ensureModuleLoaded(`typescript`);let t=await ce();if(typeof t!=`function`)throw Error(`loadTypeScript devolvió ${typeof t} en lugar de una función para archivo: ${e}`);if(y=await t(m,e),i.tsCompile=Date.now()-s,y==null)throw Error(`preCompileTS devolvió ${y} para archivo: ${e}`);if(y.error)if(r===`all`)V(e,`typescript`,y.error instanceof Error?y.error.message:String(y.error),`error`);else throw await U(y.error,e,`typescript`,r,f.VERBOSE===`true`),Error(y.error instanceof Error?y.error.message:String(y.error));else W(e,`typescript`),m=y.data}if(!m||m.trim().length===0)throw await U(Error(`El código TypeScript compilado está vacío.`),e,`typescript`,r,f.VERBOSE===`true`),Error(`El código TypeScript compilado está vacío.`);g&&p.info(_.yellow(`💛 Estandarizando: ${c.basename(e)}`)),s=Date.now(),await a.ensureModuleLoaded(`transforms`);let b=await M(),x=await b(m,e);if(i.standardization=Date.now()-s,x==null)throw Error(`estandarizaCode devolvió ${x} para archivo: ${e}`);if(x.error)throw await U(Error(x.error),e,`standardization`,r,f.VERBOSE===`true`),Error(x.error);if(W(e,`standardization`),m=x.code,!m||m.trim().length===0)throw await U(Error(`El código estandarizado está vacío.`),e,`standardization`,r,f.VERBOSE===`true`),Error(`El código estandarizado está vacío.`);if(f.isPROD===`true`){s=Date.now(),g&&p.info(_.red(`🤖 Minificando: ${c.basename(e)}`)),await a.ensureModuleLoaded(`minify`);let t=await se(),n=await t(m,e,!0);if(i.minification=Date.now()-s,n==null)throw Error(`minifyJS devolvió ${n} para archivo: ${e}`);if(n.error)throw await U(n.error instanceof Error?n.error:Error(String(n.error)),e,`minification`,r,f.VERBOSE===`true`),Error(n.error instanceof Error?n.error.message:String(n.error));W(e,`minification`),m=n.code}let S=c.dirname(t);if(await n(S,{recursive:!0}),await o(t,m,`utf-8`),g){let t=Object.values(i).reduce((e,t)=>e+t,0);p.info(_.cyan(`⏱️ Timing para ${c.basename(e)}:`)),i.fileRead&&p.info(_.cyan(` 📖 Lectura: ${i.fileRead}ms`)),i.vueCompile&&p.info(_.cyan(` 💚 Vue: ${i.vueCompile}ms`)),i.tsCompile&&p.info(_.cyan(` 🔄️ TypeScript: ${i.tsCompile}ms`)),i.standardization&&p.info(_.cyan(` 💛 Estandarización: ${i.standardization}ms`)),i.minification&&p.info(_.cyan(` 🤖 Minificación: ${i.minification}ms`)),p.info(_.cyan(` 🏁 Total: ${t}ms`))}return{error:null,action:`extension`}}export async function initCompile(e,t=!0,n=`individual`){try{let r=O.getInstance(),i=c.extname(e),a=new Set([i]);if(await r.preloadForContext(n===`all`?`batch`:n,a),t&&f.TAILWIND){await r.ensureModuleLoaded(`tailwind`);let e=await j(),t=await e();if(typeof t!=`boolean`)if(t?.success)p.info(`🎨 ${t.message}`);else{let e=`${t.message}${t.details?`
7
+ `+t.details:``}`;await U(Error(e),`tailwind.config.js`,`tailwind`,n,f.VERBOSE===`true`)}}let o=Date.now(),s=normalizeRuta(e),l=getOutputPath(s);if((n===`watch`||n===`individual`)&&await $(s))return f.VERBOSE===`true`&&p.info(`⏭️ Archivo omitido (cache): ${c.basename(s)}`),{success:!0,cached:!0,output:L.getOutputPath(s)||l,action:`cached`};n===`individual`&&f.VERBOSE===`true`&&p.info(`🔜 Fuente: ${s}`);let u=await me(s,l,n);if(u.error)throw Error(u.error);(n===`watch`||n===`individual`)&&await L.set(s,l);let d=Date.now(),m=g(d-o);if(n===`individual`){f.VERBOSE===`true`&&(p.info(`🔚 Destino: ${l}`),p.info(`⏱️ Tiempo: ${m}`));let e=await k();p.info(e.green(`✅ Compilación exitosa: ${c.basename(s)}`))}return{success:!0,output:l,action:u.action}}catch(t){let n=t instanceof Error?t.message:String(t);return f.VERBOSE===`true`&&p.error(`❌ Error en compilación de ${c.basename(e)}: ${n}`),{success:!1,output:``,error:n}}}let Z=0;class Q{static instance;progressActive=!1;lastProgressLine=``;logBuffer=[];originalConsoleLog;originalConsoleError;originalConsoleWarn;hasProgressLine=!1;constructor(){this.originalConsoleLog=console.log,this.originalConsoleError=console.error,this.originalConsoleWarn=console.warn}static getInstance(){return Q.instance||=new Q,Q.instance}interceptConsole(){console.log=(...e)=>{this.addLog(e.map(e=>String(e)).join(` `))},console.error=(...e)=>{this.addLog(e.map(e=>String(e)).join(` `))},console.warn=(...e)=>{this.addLog(e.map(e=>String(e)).join(` `))}}restoreConsole(){console.log=this.originalConsoleLog,console.error=this.originalConsoleError,console.warn=this.originalConsoleWarn}startProgress(){this.progressActive=!0,this.logBuffer=[],this.hasProgressLine=!1,this.interceptConsole();let e=`━`.repeat(48);l.stdout.write(`
8
+ \x1B[96m`+e+`\x1B[0m
9
+ `),l.stdout.write(`\x1B[96m│ \x1B[97m\x1B[1m🚀 Iniciando Compilación\x1B[0m\x1B[96m`+` `.repeat(22)+`│\x1B[0m
10
+ `),l.stdout.write(`\x1B[96m`+e+`\x1B[0m
11
+ `)}updateProgress(e){if(!this.progressActive)return;if(this.logBuffer.length>0){this.hasProgressLine&&l.stdout.write(`\r\x1B[K`);for(let e of this.logBuffer)l.stdout.write((this.hasProgressLine?`
12
+ `:``)+e+`
13
+ `),this.hasProgressLine=!1;this.logBuffer=[]}this.hasProgressLine?l.stdout.write(`\r\x1B[K`):l.stdout.write(`
14
+ \x1B[96m`+`▔`.repeat(50)+`\x1B[0m
15
+ `);let t=this.getStageFromText(e),{bgColor:n,textColor:r,icon:i}=this.getProgressColors(t),a=`█`.repeat(3),o=`\x1b[${n}m\x1b[${r}m ${a} ${i} ${e} ${a} \x1b[0m`;l.stdout.write(o),this.hasProgressLine=!0,this.lastProgressLine=e}addLog(e){this.progressActive?this.logBuffer.push(e):this.originalConsoleLog(e)}addImmediateLog(e){this.progressActive?(this.hasProgressLine&&l.stdout.write(`\r\x1B[K`),l.stdout.write(`\x1B[90m│\x1B[0m `+e+`
16
+ `),this.hasProgressLine=!1):this.originalConsoleLog(e)}endProgress(){if(this.progressActive){this.hasProgressLine&&l.stdout.write(`
17
+ `),l.stdout.write(`
18
+ \x1B[33m`+`-`.repeat(50)+`\x1B[0m
19
+ `);let e=`█`.repeat(3),t=`\x1b[42m\x1b[30m ${e} ✅ PROCESO COMPLETADO 100% ${e} \x1b[0m`;l.stdout.write(t+`
20
+ `);let n=`━`.repeat(48);if(l.stdout.write(`\x1B[92m`+n+`\x1B[0m
21
+ `),l.stdout.write(`\x1B[92m│ \x1B[97m\x1B[1m✅ ¡Compilación Completada!\x1B[0m\x1B[92m`+` `.repeat(23)+`│\x1B[0m
22
+ `),l.stdout.write(`\x1B[92m`+n+`\x1B[0m
23
+
24
+ `),this.logBuffer.length>0)for(let e of this.logBuffer)l.stdout.write(e+`
25
+ `)}this.restoreConsole(),this.progressActive=!1,this.lastProgressLine=``,this.logBuffer=[],this.hasProgressLine=!1}isActive(){return this.progressActive}getStageFromText(e){return e.includes(`Iniciando`)||e.includes(`Starting`)?`start`:e.includes(`Tailwind`)||e.includes(`CSS`)?`tailwind`:e.includes(`Recopilando`)||e.includes(`archivos`)||e.includes(`files`)?`files`:e.includes(`Compilando`)||e.includes(`workers`)?`compile`:e.includes(`cache`)||e.includes(`Guardando`)?`cache`:e.includes(`linter`)||e.includes(`Linter`)?`linter`:e.includes(`completado`)||e.includes(`Complete`)?`complete`:`default`}getProgressColors(e){let t={start:{bgColor:`45`,textColor:`97`,icon:`🚀`},tailwind:{bgColor:`105`,textColor:`97`,icon:`🎨`},files:{bgColor:`43`,textColor:`30`,icon:`📁`},compile:{bgColor:`42`,textColor:`30`,icon:`⚙️`},cache:{bgColor:`44`,textColor:`97`,icon:`💾`},linter:{bgColor:`101`,textColor:`97`,icon:`🔍`},complete:{bgColor:`102`,textColor:`30`,icon:`✅`},default:{bgColor:`100`,textColor:`30`,icon:`⏳`}},n={bgColor:`100`,textColor:`30`,icon:`⏳`};return t[e]||n}}export async function runLinter(e=!1){let t=f.linter,n=[],r=[],i=!0;if(f.ENABLE_LINTER!==`true`)return!0;if(typeof t==`string`&&t.trim()!==``){p.info(`🔍 Ejecutando linting...`);try{let a=JSON.parse(t);if(Array.isArray(a)){let{ESLint:e,OxLint:t}=await oe();for(let i of a)if(i.name.toLowerCase()===`eslint`){p.info(`🔧 Ejecutando ESLint con config: ${i.configFile||`por defecto`}`);let t=e(i).then(e=>{e&&e.json&&(Array.isArray(e.json)?e.json.forEach(e=>{let t=e.filePath||e.file||`archivo no especificado`;r.push({from:`eslint`,line:e.line||`N/A`,column:e.column||1,file:t,message:e.message,severity:e.severity===2?`error`:`warning`,help:e.ruleId?`Regla ESLint: ${e.ruleId}`:void 0})}):e.json.results&&Array.isArray(e.json.results)&&e.json.results.forEach(e=>{e.messages&&Array.isArray(e.messages)&&e.messages.forEach(t=>{let n=e.filePath||e.file||`archivo no especificado`;r.push({from:`eslint`,line:t.line||`N/A`,column:t.column||1,file:n,message:t.message,severity:t.severity===2?`error`:`warning`,help:t.ruleId?`Regla ESLint: ${t.ruleId}`:void 0})})}))}).catch(e=>{p.error(`❌ Error durante la ejecución de ESLint: ${e.message}`),r.push({file:i.configFile||`ESLint Config`,message:`Fallo al ejecutar ESLint: ${e.message}`,severity:`error`})});n.push(t)}else if(i.name.toLowerCase()===`oxlint`){p.info(`🔧 Ejecutando OxLint con config: ${i.configFile||`por defecto`}`);let e=t(i).then(e=>{e&&e.json&&Array.isArray(e.json.diagnostics)&&e.json.diagnostics.forEach(e=>{let t=e.filename||e.file||`archivo no especificado`,n=e.labels&&e.labels[0]&&e.labels[0].span?e.labels[0].span.line||e.labels[0].span.start?.line:`N/A`,i=e.labels&&e.labels[0]&&e.labels[0].span?e.labels[0].span.column||e.labels[0].span.start?.column:1;r.push({from:`oxlint`,line:n,column:i,file:t,message:e.message,severity:typeof e.severity==`string`?e.severity.toLowerCase():`error`,help:e.help||(e.code?`Regla Oxlint: ${e.code}`:void 0)})})}).catch(e=>{p.error(`❌ Error durante la ejecución de OxLint: ${e.message}`),r.push({file:i.configFile||`Oxlint Config`,message:`Fallo al ejecutar Oxlint: ${e.message}`,severity:`error`})});n.push(e)}}else p.warn(`⚠️ La configuración de linter no es un array válido.`);if(await Promise.all(n),e)if(r.length>0)await q(r);else{let e=await k();p.info(e.green(`✅ No se encontraron errores ni advertencias de linting.`))}else if(r.length>0&&(await q(r),p.warn(`🚨 Se encontraron errores o advertencias durante el linting.`),f.yes===`false`)){let e=await h(`¿Deseas continuar con la compilación a pesar de los errores de linting? (s/N): `);e.toLowerCase()!==`s`&&(p.info(`🛑 Compilación cancelada por el usuario.`),i=!1)}}catch(e){p.warn(`Error parseando configuración de linter: ${e instanceof Error?e.message:`Error desconocido`}, omitiendo...`)}}return i}function he(e,t,n=30){let r=Math.round(e/t*100),i=Math.round(r/100*n),a=n-i;return`[${`█`.repeat(i)}${` `.repeat(a)}] ${r}% (${e}/${t})`}async function $(e){return await L.isValid(e)}async function ge(e,t=8){let n=[],r=[],i=e.length,a=0,o=0,s=0,u=Q.getInstance(),d=!1,m=0,h=20;function g(){let e=a+o+s,t=he(e,i),n=Math.round(e/i*100);if(e===0&&!d||n>Z+1&&e>0||e===i){let r=`🚀 ${t} [✅ ${a} | ⏭️ ${o} | ❌ ${s}]`;u.updateProgress(r),e===0&&(d=!0),Z=n}}g();for(let i of e){let e=(async()=>{try{if(f.VERBOSE===`true`&&p.info(`🔄 Compilando: ${c.basename(i)}`),await $(i))return o++,f.VERBOSE===`true`&&p.info(`⏭️ Archivo omitido (cache): ${c.basename(i)}`),g(),{success:!0,cached:!0,output:L.getOutputPath(i)};let e=await initCompile(i,!1,`batch`);if(e.success&&e.output?(await L.set(i,e.output),f.VERBOSE===`true`&&p.info(`✅ Completado: ${c.basename(i)} → ${c.basename(e.output)}`)):f.VERBOSE===`true`&&p.info(`❌ Error en: ${c.basename(i)}`),a++,m++,m%20==0){try{typeof globalThis.gc==`function`&&globalThis.gc()}catch{}let e=l.memoryUsage(),t=e.heapUsed/(1024*1024);if(t>300){let e=L.getStats().entries;if(e>50){console.log(`[Memory] Heap alto (${t.toFixed(1)}MB), limpiando cache...`);let e=L.cleanOldEntries(20);e>0&&console.log(`[Memory] Se removieron ${e} entradas del cache`)}}}return g(),e}catch(e){if(s++,f.VERBOSE===`true`){let t=e instanceof Error?e.message:String(e);p.error(`💥 Falló: ${c.basename(i)} - ${t}`)}return g(),{success:!1,error:e instanceof Error?e.message:String(e)}}})();n.push(e),r.push(e),r.length>=t&&(await Promise.race(r),r.splice(r.findIndex(t=>t===e),1))}await Promise.all(n)}export async function initCompileAll(){try{let e=Q.getInstance();e.startProgress(),e.updateProgress(`🚀 Iniciando compilación...`),G(),e.updateProgress(`📦 Cargando cache...`),await B(),Z=0,e.updateProgress(`🔍 Ejecutando linter...`);let n=await runLinter(!1);if(!n){e.endProgress();return}let r=Date.now(),i=f.PATH_SOURCE??``,a=f.PATH_DIST??``,o=i.replace(/\\/g,`/`),c=[`${o}/**/*.js`,`${o}/**/*.vue`,`${o}/**/*.ts`,`${o}/**/*.mjs`,`${o}/**/*.cjs`];p.info(`📝 Compilando todos los archivos...`),p.info(`🔜 Fuente: ${i}`),p.info(`🔚 Destino: ${a}\n`),e.updateProgress(`🎨 Generando TailwindCSS...`);let u=await j(),d=await u();typeof d!=`boolean`&&(d?.success?p.info(`🎨 ${d.message}\n`):await U(Error(`${d.message}${d.details?`
26
+ `+d.details:``}`),`tailwind.config.js`,`tailwind`,`all`,f.VERBOSE===`true`)),e.updateProgress(`📁 Recopilando archivos...`);let m=[];for await(let e of t(c)){if(e.endsWith(`.d.ts`))continue;m.push(e)}let h=s.cpus().length,_=m.length,v=l.memoryUsage(),y=(v.heapTotal-v.heapUsed)/(1024*1024),b;b=y<100?Math.min(2,h):_<10?Math.min(_,Math.min(h,4)):_<50?Math.min(h,6):Math.min(h,8),e.updateProgress(`⚙️ Configurando workers...`),p.info(`🚀 Compilando ${_} archivos con concurrencia optimizada (${b} hilos)...`);try{let{TypeScriptWorkerPool:e}=await import(`./typescript-worker-pool.js`),t=e.getInstance();t.setMode(`batch`)}catch{}e.updateProgress(`🚀 Iniciando compilación de ${_} archivos...`),await ge(m,b),e.updateProgress(`💾 Guardando cache...`),await ue();let x=Date.now(),S=g(x-r);e.endProgress(),await K(f.VERBOSE===`true`,S)}catch(e){let t=Q.getInstance();t.isActive()&&t.endProgress();let n=e instanceof Error?e.message:String(e);p.error(`🚩 Error al compilar todos los archivos: ${n}`),await U(e instanceof Error?e:Error(String(e)),`compilación general`,`all`,`all`,f.VERBOSE===`true`),await K(f.VERBOSE===`true`)}}function _e(e){let t={vue:`🎨`,typescript:`📘`,standardization:`💛`,minification:`🗜️`,tailwind:`🎨`,"file-read":`📖`,default:`⚙️`};return t[e]??`⚙️`}function ve(e,t){let n=Math.round(e/100*t),r=t-n,i=`\x1B[32m`+`█`.repeat(n)+`\x1B[0m`,a=`\x1B[90m`+`░`.repeat(r)+`\x1B[0m`;return`${i}${a} ${e}%`}export async function compileFile(e){return await initCompile(e,!0,`individual`)}export{X as WatchModeOptimizer};