versacompiler 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +345 -69
- package/dist/compiler/compile.js +427 -185
- package/dist/compiler/minify.js +199 -10
- package/dist/compiler/module-resolution-optimizer.js +844 -0
- package/dist/compiler/parser.js +179 -6
- package/dist/compiler/performance-monitor.js +192 -0
- package/dist/compiler/transform-optimizer.js +287 -0
- package/dist/compiler/transforms.js +121 -87
- package/dist/compiler/{typescript.js → typescript-compiler.js} +27 -30
- package/dist/compiler/typescript-error-parser.js +6 -7
- package/dist/compiler/typescript-manager.js +378 -0
- package/dist/compiler/typescript-sync-validator.js +13 -15
- package/dist/compiler/typescript-worker-pool.js +479 -0
- package/dist/compiler/typescript-worker.js +51 -21
- package/dist/compiler/vuejs.js +131 -37
- package/dist/main.js +5 -6
- package/dist/servicios/browserSync.js +313 -21
- package/dist/servicios/file-watcher.js +316 -0
- package/dist/servicios/logger.js +1 -0
- package/dist/servicios/readConfig.js +1 -0
- package/dist/utils/module-resolver.js +8 -19
- package/dist/utils/promptUser.js +1 -1
- package/dist/utils/resolve-bin.js +28 -9
- package/package.json +7 -7
- package/dist/servicios/chokidar.js +0 -178
package/dist/compiler/compile.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { glob, mkdir, readFile, stat, unlink, writeFile, } from 'node:fs/promises';
|
|
2
3
|
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
|
-
import { env } from 'node:process';
|
|
5
|
+
import { cwd, env, stdout } from 'node:process';
|
|
5
6
|
// Lazy loading optimizations - Only import lightweight modules synchronously
|
|
6
7
|
import { logger } from '../servicios/logger.js';
|
|
7
8
|
import { promptUser } from '../utils/promptUser.js';
|
|
@@ -16,157 +17,267 @@ let generateTailwindCSS;
|
|
|
16
17
|
let estandarizaCode;
|
|
17
18
|
let preCompileTS;
|
|
18
19
|
let preCompileVue;
|
|
19
|
-
// 🚀
|
|
20
|
-
|
|
20
|
+
// 🚀 Importar optimizador de transformaciones
|
|
21
|
+
let TransformOptimizer;
|
|
22
|
+
// 🚀 Importar optimizador de resolución de módulos
|
|
23
|
+
let ModuleResolutionOptimizer;
|
|
24
|
+
// 🚀 Sistema de Carga Inteligente de Módulos - VERSIÓN OPTIMIZADA V2
|
|
25
|
+
class OptimizedModuleManager {
|
|
21
26
|
static instance;
|
|
22
27
|
isInitialized = false;
|
|
23
|
-
initializationPromise = null;
|
|
24
28
|
loadedModules = new Set();
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
// ✨ NUEVAS OPTIMIZACIONES
|
|
30
|
+
modulePool = new Map(); // Pool de instancias reutilizables
|
|
31
|
+
loadingPromises = new Map(); // Prevenir cargas duplicadas
|
|
32
|
+
usageStats = new Map(); // Estadísticas de uso
|
|
33
|
+
preloadQueue = new Set(); // Cola de precarga
|
|
34
|
+
backgroundLoader = null; // Cargador en background
|
|
35
|
+
// Módulos críticos que siempre se precargan
|
|
36
|
+
HOT_MODULES = ['chalk', 'parser'];
|
|
37
|
+
// Contexto actual para optimizar cargas
|
|
38
|
+
currentContext = null;
|
|
39
|
+
constructor() {
|
|
40
|
+
// Iniciar precarga en background inmediatamente
|
|
41
|
+
this.startBackgroundPreloading();
|
|
42
|
+
}
|
|
30
43
|
static getInstance() {
|
|
31
|
-
if (!
|
|
32
|
-
|
|
44
|
+
if (!OptimizedModuleManager.instance) {
|
|
45
|
+
OptimizedModuleManager.instance = new OptimizedModuleManager();
|
|
33
46
|
}
|
|
34
|
-
return
|
|
47
|
+
return OptimizedModuleManager.instance;
|
|
35
48
|
}
|
|
36
49
|
/**
|
|
37
|
-
* NUEVO: Precarga
|
|
50
|
+
* ✨ NUEVO: Precarga en background para módulos críticos
|
|
38
51
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
case 'chalk':
|
|
45
|
-
return this._loadModule('chalk', loadChalk);
|
|
46
|
-
case 'parser':
|
|
47
|
-
return this._loadModule('parser', loadParser);
|
|
48
|
-
case 'transforms':
|
|
49
|
-
return this._loadModule('transforms', loadTransforms);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
await Promise.all(preloadPromises);
|
|
54
|
-
// console.log('[ModuleManager] Precarga completada para modo watch');
|
|
55
|
-
} /**
|
|
56
|
-
* MEJORADO: Inicializa los módulos necesarios según el contexto de compilación
|
|
57
|
-
* @param context Contexto de compilación: 'individual', 'batch', 'watch'
|
|
58
|
-
* @param fileExtensions Extensiones de archivos a compilar para optimizar la carga
|
|
52
|
+
startBackgroundPreloading() {
|
|
53
|
+
this.backgroundLoader = this.preloadCriticalModules();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* ✨ NUEVO: Precarga módulos críticos en background
|
|
59
57
|
*/
|
|
60
|
-
async
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
58
|
+
async preloadCriticalModules() {
|
|
59
|
+
try {
|
|
60
|
+
// Precargar módulos críticos de forma asíncrona
|
|
61
|
+
const preloadPromises = this.HOT_MODULES.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
|
|
62
|
+
// Silenciar errores de precarga, se intentará cargar después
|
|
63
|
+
}));
|
|
64
|
+
await Promise.allSettled(preloadPromises);
|
|
68
65
|
}
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
catch {
|
|
67
|
+
// Fallos en precarga no deben afectar la funcionalidad principal
|
|
71
68
|
}
|
|
72
|
-
if (this.isInitialized && context !== 'individual') {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
this.initializationPromise = this._performInitialization(context, fileExtensions);
|
|
76
|
-
await this.initializationPromise;
|
|
77
|
-
this.initializationPromise = null;
|
|
78
69
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
if (!this.loadedModules.has('transforms')) {
|
|
89
|
-
modulesToLoad.push(this._loadModule('transforms', loadTransforms));
|
|
70
|
+
/**
|
|
71
|
+
* ✨ MEJORADO: Precarga contextual basada en tipos de archivo
|
|
72
|
+
*/
|
|
73
|
+
async preloadForContext(context, fileTypes = new Set()) {
|
|
74
|
+
this.currentContext = context;
|
|
75
|
+
// Esperar que termine la precarga crítica si está en progreso
|
|
76
|
+
if (this.backgroundLoader) {
|
|
77
|
+
await this.backgroundLoader;
|
|
90
78
|
}
|
|
91
|
-
|
|
79
|
+
const toPreload = []; // Precarga basada en contexto
|
|
92
80
|
if (context === 'batch' || context === 'watch') {
|
|
93
|
-
// En
|
|
94
|
-
|
|
95
|
-
modulesToLoad.push(this._loadModule('vue', loadVue));
|
|
96
|
-
}
|
|
97
|
-
if (!this.loadedModules.has('typescript')) {
|
|
98
|
-
modulesToLoad.push(this._loadModule('typescript', loadTypeScript));
|
|
99
|
-
}
|
|
100
|
-
if (!this.loadedModules.has('minify')) {
|
|
101
|
-
modulesToLoad.push(this._loadModule('minify', loadMinify));
|
|
102
|
-
}
|
|
81
|
+
// En batch/watch, precargar todos los módulos comunes
|
|
82
|
+
toPreload.push('transforms', 'vue', 'typescript', 'module-resolution-optimizer');
|
|
103
83
|
}
|
|
104
84
|
else {
|
|
105
|
-
// En
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
if (env.isPROD === 'true' && !this.loadedModules.has('minify')) {
|
|
114
|
-
modulesToLoad.push(this._loadModule('minify', loadMinify));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
// Cargar módulos en paralelo
|
|
118
|
-
await Promise.all(modulesToLoad);
|
|
119
|
-
this.isInitialized = true;
|
|
120
|
-
}
|
|
121
|
-
async _loadModule(name, loadFunction) {
|
|
122
|
-
if (!this.loadedModules.has(name)) {
|
|
123
|
-
await loadFunction();
|
|
124
|
-
this.loadedModules.add(name);
|
|
85
|
+
// En individual, cargar solo según tipos de archivo detectados
|
|
86
|
+
if (fileTypes.has('.vue'))
|
|
87
|
+
toPreload.push('vue');
|
|
88
|
+
if (fileTypes.has('.ts') || fileTypes.has('.vue'))
|
|
89
|
+
toPreload.push('typescript');
|
|
90
|
+
if (!this.loadedModules.has('transforms'))
|
|
91
|
+
toPreload.push('transforms');
|
|
125
92
|
}
|
|
93
|
+
// Precargar en paralelo
|
|
94
|
+
const preloadPromises = toPreload.map(moduleName => this.ensureModuleLoaded(moduleName).catch(() => {
|
|
95
|
+
// Log warning pero no fallar
|
|
96
|
+
console.warn(`Warning: No se pudo precargar módulo ${moduleName}`);
|
|
97
|
+
}));
|
|
98
|
+
await Promise.allSettled(preloadPromises);
|
|
126
99
|
}
|
|
127
100
|
/**
|
|
128
|
-
*
|
|
101
|
+
* ✨ MEJORADO: Carga inteligente con pooling y deduplicación
|
|
129
102
|
*/
|
|
130
103
|
async ensureModuleLoaded(moduleName) {
|
|
131
|
-
|
|
132
|
-
|
|
104
|
+
// 1. Verificar pool de módulos primero
|
|
105
|
+
if (this.modulePool.has(moduleName)) {
|
|
106
|
+
this.updateUsageStats(moduleName);
|
|
107
|
+
return this.modulePool.get(moduleName);
|
|
133
108
|
}
|
|
109
|
+
// 2. Verificar si ya está cargando (deduplicación)
|
|
110
|
+
if (this.loadingPromises.has(moduleName)) {
|
|
111
|
+
return this.loadingPromises.get(moduleName);
|
|
112
|
+
}
|
|
113
|
+
// 3. Iniciar carga
|
|
114
|
+
const loadPromise = this.loadModuleInternal(moduleName);
|
|
115
|
+
this.loadingPromises.set(moduleName, loadPromise);
|
|
116
|
+
try {
|
|
117
|
+
const moduleInstance = await loadPromise;
|
|
118
|
+
// 4. Almacenar en pool y estadísticas
|
|
119
|
+
this.modulePool.set(moduleName, moduleInstance);
|
|
120
|
+
this.loadedModules.add(moduleName);
|
|
121
|
+
this.updateUsageStats(moduleName);
|
|
122
|
+
return moduleInstance;
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
// 5. Limpiar promesa de carga
|
|
126
|
+
this.loadingPromises.delete(moduleName);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* ✨ NUEVO: Actualiza estadísticas de uso para optimizaciones futuras
|
|
131
|
+
*/
|
|
132
|
+
updateUsageStats(moduleName) {
|
|
133
|
+
const currentCount = this.usageStats.get(moduleName) || 0;
|
|
134
|
+
this.usageStats.set(moduleName, currentCount + 1);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* ✨ MEJORADO: Carga interna de módulos con mejor manejo de errores
|
|
138
|
+
*/ async loadModuleInternal(moduleName) {
|
|
134
139
|
switch (moduleName) {
|
|
140
|
+
case 'chalk':
|
|
141
|
+
return this.loadChalk();
|
|
142
|
+
case 'parser':
|
|
143
|
+
return this.loadParser();
|
|
144
|
+
case 'transforms':
|
|
145
|
+
return this.loadTransforms();
|
|
135
146
|
case 'vue':
|
|
136
|
-
|
|
137
|
-
break;
|
|
147
|
+
return this.loadVue();
|
|
138
148
|
case 'typescript':
|
|
139
|
-
|
|
140
|
-
break;
|
|
149
|
+
return this.loadTypeScript();
|
|
141
150
|
case 'minify':
|
|
142
|
-
|
|
143
|
-
break;
|
|
151
|
+
return this.loadMinify();
|
|
144
152
|
case 'tailwind':
|
|
145
|
-
|
|
146
|
-
break;
|
|
153
|
+
return this.loadTailwind();
|
|
147
154
|
case 'linter':
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
return this.loadLinter();
|
|
156
|
+
case 'transform-optimizer':
|
|
157
|
+
return this.loadTransformOptimizer();
|
|
158
|
+
case 'module-resolution-optimizer':
|
|
159
|
+
return this.loadModuleResolutionOptimizer();
|
|
150
160
|
default:
|
|
151
161
|
throw new Error(`Módulo desconocido: ${moduleName}`);
|
|
152
162
|
}
|
|
153
163
|
}
|
|
164
|
+
// ✨ Métodos de carga específicos optimizados
|
|
165
|
+
async loadChalk() {
|
|
166
|
+
if (!chalk) {
|
|
167
|
+
chalk = (await import('chalk')).default;
|
|
168
|
+
}
|
|
169
|
+
return chalk;
|
|
170
|
+
}
|
|
171
|
+
async loadParser() {
|
|
172
|
+
if (!getCodeFile) {
|
|
173
|
+
const parserModule = await import('./parser.js');
|
|
174
|
+
getCodeFile = parserModule.getCodeFile;
|
|
175
|
+
}
|
|
176
|
+
return getCodeFile;
|
|
177
|
+
}
|
|
178
|
+
async loadTransforms() {
|
|
179
|
+
if (!estandarizaCode) {
|
|
180
|
+
const transformsModule = await import('./transforms.js');
|
|
181
|
+
estandarizaCode = transformsModule.estandarizaCode;
|
|
182
|
+
}
|
|
183
|
+
return estandarizaCode;
|
|
184
|
+
}
|
|
185
|
+
async loadVue() {
|
|
186
|
+
if (!preCompileVue) {
|
|
187
|
+
const vueModule = await import('./vuejs.js');
|
|
188
|
+
preCompileVue = vueModule.preCompileVue;
|
|
189
|
+
}
|
|
190
|
+
return preCompileVue;
|
|
191
|
+
}
|
|
192
|
+
async loadTypeScript() {
|
|
193
|
+
if (!preCompileTS) {
|
|
194
|
+
const typescriptModule = await import('./typescript-manager.js');
|
|
195
|
+
preCompileTS = typescriptModule.preCompileTS;
|
|
196
|
+
}
|
|
197
|
+
return preCompileTS;
|
|
198
|
+
}
|
|
199
|
+
async loadMinify() {
|
|
200
|
+
if (!minifyJS) {
|
|
201
|
+
const minifyModule = await import('./minify.js');
|
|
202
|
+
minifyJS = minifyModule.minifyJS;
|
|
203
|
+
}
|
|
204
|
+
return minifyJS;
|
|
205
|
+
}
|
|
206
|
+
async loadTailwind() {
|
|
207
|
+
if (!generateTailwindCSS) {
|
|
208
|
+
const tailwindModule = await import('./tailwindcss.js');
|
|
209
|
+
generateTailwindCSS = tailwindModule.generateTailwindCSS;
|
|
210
|
+
}
|
|
211
|
+
return generateTailwindCSS;
|
|
212
|
+
}
|
|
213
|
+
async loadLinter() {
|
|
214
|
+
if (!ESLint || !OxLint) {
|
|
215
|
+
const linterModule = await import('./linter.js');
|
|
216
|
+
ESLint = linterModule.ESLint;
|
|
217
|
+
OxLint = linterModule.OxLint;
|
|
218
|
+
}
|
|
219
|
+
return { ESLint, OxLint };
|
|
220
|
+
}
|
|
221
|
+
async loadTransformOptimizer() {
|
|
222
|
+
if (!TransformOptimizer) {
|
|
223
|
+
const transformModule = await import('./transform-optimizer.js');
|
|
224
|
+
TransformOptimizer =
|
|
225
|
+
transformModule.TransformOptimizer.getInstance();
|
|
226
|
+
}
|
|
227
|
+
return TransformOptimizer;
|
|
228
|
+
}
|
|
229
|
+
async loadModuleResolutionOptimizer() {
|
|
230
|
+
if (!ModuleResolutionOptimizer) {
|
|
231
|
+
const resolutionModule = await import('./module-resolution-optimizer.js');
|
|
232
|
+
ModuleResolutionOptimizer =
|
|
233
|
+
resolutionModule.ModuleResolutionOptimizer.getInstance();
|
|
234
|
+
}
|
|
235
|
+
return ModuleResolutionOptimizer;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* ✨ NUEVO: Obtiene estadísticas de performance del manager
|
|
239
|
+
*/
|
|
240
|
+
getPerformanceStats() {
|
|
241
|
+
const sortedByUsage = Array.from(this.usageStats.entries())
|
|
242
|
+
.sort((a, b) => b[1] - a[1])
|
|
243
|
+
.slice(0, 5)
|
|
244
|
+
.map(([name]) => name);
|
|
245
|
+
return {
|
|
246
|
+
loadedModules: Array.from(this.loadedModules),
|
|
247
|
+
usageStats: Object.fromEntries(this.usageStats),
|
|
248
|
+
poolSize: this.modulePool.size,
|
|
249
|
+
loadingInProgress: Array.from(this.loadingPromises.keys()),
|
|
250
|
+
mostUsedModules: sortedByUsage,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* ✨ NUEVO: Limpia módulos no utilizados para liberar memoria
|
|
255
|
+
*/
|
|
256
|
+
cleanupUnusedModules() {
|
|
257
|
+
const threshold = 1; // Mínimo de usos para mantener en pool
|
|
258
|
+
for (const [moduleName, usageCount] of this.usageStats) {
|
|
259
|
+
if (usageCount < threshold &&
|
|
260
|
+
!this.HOT_MODULES.includes(moduleName)) {
|
|
261
|
+
this.modulePool.delete(moduleName);
|
|
262
|
+
this.loadedModules.delete(moduleName);
|
|
263
|
+
this.usageStats.delete(moduleName);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
154
267
|
/**
|
|
155
268
|
* Resetea el estado del manager (útil para tests)
|
|
156
269
|
*/
|
|
157
270
|
reset() {
|
|
158
271
|
this.isInitialized = false;
|
|
159
|
-
this.initializationPromise = null;
|
|
160
272
|
this.loadedModules.clear();
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
};
|
|
273
|
+
this.modulePool.clear();
|
|
274
|
+
this.loadingPromises.clear();
|
|
275
|
+
this.usageStats.clear();
|
|
276
|
+
this.preloadQueue.clear();
|
|
277
|
+
this.currentContext = null;
|
|
278
|
+
this.backgroundLoader = null;
|
|
279
|
+
// Reiniciar precarga crítica
|
|
280
|
+
this.startBackgroundPreloading();
|
|
170
281
|
}
|
|
171
282
|
}
|
|
172
283
|
// Lazy loading helper functions
|
|
@@ -214,7 +325,7 @@ async function loadTransforms() {
|
|
|
214
325
|
}
|
|
215
326
|
async function loadTypeScript() {
|
|
216
327
|
if (!preCompileTS) {
|
|
217
|
-
const typescriptModule = await import('./typescript.js');
|
|
328
|
+
const typescriptModule = await import('./typescript-manager.js');
|
|
218
329
|
preCompileTS = typescriptModule.preCompileTS;
|
|
219
330
|
}
|
|
220
331
|
return preCompileTS;
|
|
@@ -229,40 +340,194 @@ async function loadVue() {
|
|
|
229
340
|
// Almacenamiento global de errores y resultados
|
|
230
341
|
const compilationErrors = [];
|
|
231
342
|
const compilationResults = [];
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
343
|
+
class SmartCompilationCache {
|
|
344
|
+
cache = new Map();
|
|
345
|
+
maxEntries = 500; // Máximo archivos en cache
|
|
346
|
+
maxMemory = 100 * 1024 * 1024; // 100MB límite
|
|
347
|
+
currentMemoryUsage = 0;
|
|
348
|
+
/**
|
|
349
|
+
* Genera hash SHA-256 del contenido del archivo
|
|
350
|
+
*/ async generateContentHash(filePath) {
|
|
351
|
+
try {
|
|
352
|
+
const content = await readFile(filePath, 'utf8');
|
|
353
|
+
return createHash('sha256').update(content).digest('hex');
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
// Si no se puede leer el archivo, generar hash único basado en la ruta y timestamp
|
|
357
|
+
const fallback = `${filePath}-${Date.now()}`;
|
|
358
|
+
return createHash('sha256').update(fallback).digest('hex');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Verifica si una entrada de cache es válida
|
|
363
|
+
*/
|
|
364
|
+
async isValid(filePath) {
|
|
365
|
+
const entry = this.cache.get(filePath);
|
|
366
|
+
if (!entry)
|
|
367
|
+
return false;
|
|
368
|
+
try {
|
|
369
|
+
// Verificar si el archivo de salida existe
|
|
370
|
+
await stat(entry.outputPath);
|
|
371
|
+
// Verificar si el contenido ha cambiado
|
|
372
|
+
const currentHash = await this.generateContentHash(filePath);
|
|
373
|
+
if (entry.contentHash !== currentHash) {
|
|
374
|
+
this.cache.delete(filePath);
|
|
375
|
+
return false;
|
|
241
376
|
}
|
|
242
|
-
|
|
243
|
-
|
|
377
|
+
// Verificar tiempo de modificación como backup
|
|
378
|
+
const stats = await stat(filePath);
|
|
379
|
+
if (stats.mtimeMs > entry.mtime) {
|
|
380
|
+
this.cache.delete(filePath);
|
|
381
|
+
return false;
|
|
244
382
|
}
|
|
383
|
+
// Actualizar tiempo de uso para LRU
|
|
384
|
+
entry.lastUsed = Date.now();
|
|
385
|
+
return true;
|
|
245
386
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
387
|
+
catch {
|
|
388
|
+
// Si hay error verificando, eliminar del cache
|
|
389
|
+
this.cache.delete(filePath);
|
|
390
|
+
return false;
|
|
250
391
|
}
|
|
251
392
|
}
|
|
252
|
-
|
|
253
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Añade una entrada al cache
|
|
395
|
+
*/
|
|
396
|
+
async set(filePath, outputPath) {
|
|
397
|
+
try {
|
|
398
|
+
const stats = await stat(filePath);
|
|
399
|
+
const contentHash = await this.generateContentHash(filePath);
|
|
400
|
+
const entry = {
|
|
401
|
+
contentHash,
|
|
402
|
+
mtime: stats.mtimeMs,
|
|
403
|
+
outputPath,
|
|
404
|
+
lastUsed: Date.now(),
|
|
405
|
+
size: stats.size,
|
|
406
|
+
};
|
|
407
|
+
// Aplicar límites de memoria y entradas antes de agregar
|
|
408
|
+
this.evictIfNeeded(entry.size);
|
|
409
|
+
this.cache.set(filePath, entry);
|
|
410
|
+
this.currentMemoryUsage += entry.size;
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
// Si hay error, no cachear
|
|
414
|
+
console.warn(`Warning: No se pudo cachear ${filePath}:`, error);
|
|
415
|
+
}
|
|
254
416
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Aplica política LRU para liberar espacio
|
|
419
|
+
*/
|
|
420
|
+
evictIfNeeded(newEntrySize) {
|
|
421
|
+
// Verificar límite de entradas
|
|
422
|
+
while (this.cache.size >= this.maxEntries) {
|
|
423
|
+
this.evictLRU();
|
|
424
|
+
}
|
|
425
|
+
// Verificar límite de memoria
|
|
426
|
+
while (this.currentMemoryUsage + newEntrySize > this.maxMemory &&
|
|
427
|
+
this.cache.size > 0) {
|
|
428
|
+
this.evictLRU();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Elimina la entrada menos recientemente usada
|
|
433
|
+
*/
|
|
434
|
+
evictLRU() {
|
|
435
|
+
let oldestKey = '';
|
|
436
|
+
let oldestTime = Infinity;
|
|
437
|
+
for (const [key, entry] of this.cache) {
|
|
438
|
+
if (entry.lastUsed < oldestTime) {
|
|
439
|
+
oldestTime = entry.lastUsed;
|
|
440
|
+
oldestKey = key;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (oldestKey) {
|
|
444
|
+
const entry = this.cache.get(oldestKey);
|
|
445
|
+
if (entry) {
|
|
446
|
+
this.currentMemoryUsage -= entry.size;
|
|
447
|
+
this.cache.delete(oldestKey);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Carga el cache desde disco
|
|
453
|
+
*/
|
|
454
|
+
async load(cacheFile) {
|
|
455
|
+
try {
|
|
456
|
+
if (env.cleanCache === 'true') {
|
|
457
|
+
this.cache.clear();
|
|
458
|
+
this.currentMemoryUsage = 0;
|
|
459
|
+
try {
|
|
460
|
+
await unlink(cacheFile);
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
// Ignorar errores al eliminar el archivo
|
|
464
|
+
}
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const cacheData = await readFile(cacheFile, 'utf-8');
|
|
468
|
+
const parsed = JSON.parse(cacheData);
|
|
469
|
+
// Validar y cargar entradas del cache
|
|
470
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
471
|
+
const entry = value;
|
|
472
|
+
if (entry.contentHash && entry.outputPath && entry.mtime) {
|
|
473
|
+
this.cache.set(key, entry);
|
|
474
|
+
this.currentMemoryUsage += entry.size || 0;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
// Cache file doesn't exist or is invalid, start fresh
|
|
480
|
+
this.cache.clear();
|
|
481
|
+
this.currentMemoryUsage = 0;
|
|
482
|
+
}
|
|
261
483
|
}
|
|
262
|
-
|
|
263
|
-
|
|
484
|
+
/**
|
|
485
|
+
* Guarda el cache a disco
|
|
486
|
+
*/
|
|
487
|
+
async save(cacheFile, cacheDir) {
|
|
488
|
+
try {
|
|
489
|
+
await mkdir(cacheDir, { recursive: true });
|
|
490
|
+
const cacheData = Object.fromEntries(this.cache);
|
|
491
|
+
await writeFile(cacheFile, JSON.stringify(cacheData, null, 2));
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
console.warn('Warning: No se pudo guardar el cache:', error);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Limpia completamente el cache
|
|
499
|
+
*/
|
|
500
|
+
clear() {
|
|
501
|
+
this.cache.clear();
|
|
502
|
+
this.currentMemoryUsage = 0;
|
|
503
|
+
} /**
|
|
504
|
+
* Obtiene la ruta de salida para un archivo cacheado
|
|
505
|
+
*/
|
|
506
|
+
getOutputPath(filePath) {
|
|
507
|
+
const entry = this.cache.get(filePath);
|
|
508
|
+
return entry?.outputPath || '';
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Obtiene estadísticas del cache
|
|
512
|
+
*/
|
|
513
|
+
getStats() {
|
|
514
|
+
return {
|
|
515
|
+
entries: this.cache.size,
|
|
516
|
+
memoryUsage: this.currentMemoryUsage,
|
|
517
|
+
hitRate: 0, // Se calculará externamente
|
|
518
|
+
};
|
|
264
519
|
}
|
|
265
520
|
}
|
|
521
|
+
// Instancia global del cache inteligente
|
|
522
|
+
const smartCache = new SmartCompilationCache();
|
|
523
|
+
const CACHE_DIR = path.join(path.resolve(env.PATH_PROY || cwd(), 'compiler'), '.cache');
|
|
524
|
+
const CACHE_FILE = path.join(CACHE_DIR, 'versacompile-cache.json');
|
|
525
|
+
async function loadCache() {
|
|
526
|
+
await smartCache.load(CACHE_FILE);
|
|
527
|
+
}
|
|
528
|
+
async function saveCache() {
|
|
529
|
+
await smartCache.save(CACHE_FILE, CACHE_DIR);
|
|
530
|
+
}
|
|
266
531
|
// 🎯 Funciones del Sistema Unificado de Manejo de Errores
|
|
267
532
|
/**
|
|
268
533
|
* Registra un error de compilación en el sistema unificado
|
|
@@ -551,10 +816,10 @@ class WatchModeOptimizer {
|
|
|
551
816
|
if (cached && cached.mtime >= stats.mtimeMs) {
|
|
552
817
|
resolve({ success: true, cached: true });
|
|
553
818
|
return;
|
|
554
|
-
} // Configurar worker para modo watch
|
|
555
|
-
const {
|
|
556
|
-
const
|
|
557
|
-
|
|
819
|
+
} // Configurar worker pool para modo watch
|
|
820
|
+
const { TypeScriptWorkerPool } = await import('./typescript-worker-pool.js');
|
|
821
|
+
const workerPool = TypeScriptWorkerPool.getInstance();
|
|
822
|
+
workerPool.setMode('watch');
|
|
558
823
|
const result = await compileFn(filePath);
|
|
559
824
|
this.fileSystemCache.set(filePath, {
|
|
560
825
|
mtime: stats.mtimeMs,
|
|
@@ -579,9 +844,8 @@ async function compileJS(inPath, outPath, mode = 'individual') {
|
|
|
579
844
|
// Si la ruta ya es absoluta, no la resolvamos de nuevo
|
|
580
845
|
inPath = path.isAbsolute(inPath)
|
|
581
846
|
? normalizeRuta(inPath)
|
|
582
|
-
: normalizeRuta(path.resolve(inPath));
|
|
583
|
-
|
|
584
|
-
const moduleManager = ModuleManager.getInstance();
|
|
847
|
+
: normalizeRuta(path.resolve(inPath)); // 🚀 Usar OptimizedModuleManager para carga optimizada
|
|
848
|
+
const moduleManager = OptimizedModuleManager.getInstance();
|
|
585
849
|
// Timing de lectura
|
|
586
850
|
let start = Date.now();
|
|
587
851
|
const extension = path.extname(inPath);
|
|
@@ -729,9 +993,6 @@ async function compileJS(inPath, outPath, mode = 'individual') {
|
|
|
729
993
|
const destinationDir = path.dirname(outPath);
|
|
730
994
|
await mkdir(destinationDir, { recursive: true });
|
|
731
995
|
await writeFile(outPath, code, 'utf-8');
|
|
732
|
-
if (env.VERBOSE === 'true') {
|
|
733
|
-
logger.info(`\n📊 Timings para ${path.basename(inPath)}:`, JSON.stringify(timings));
|
|
734
|
-
}
|
|
735
996
|
return {
|
|
736
997
|
error: null,
|
|
737
998
|
action: 'extension',
|
|
@@ -740,11 +1001,11 @@ async function compileJS(inPath, outPath, mode = 'individual') {
|
|
|
740
1001
|
export async function initCompile(ruta, compileTailwind = true, mode = 'individual') {
|
|
741
1002
|
try {
|
|
742
1003
|
// 🚀 Sistema de Carga Inteligente de Módulos
|
|
743
|
-
const moduleManager =
|
|
1004
|
+
const moduleManager = OptimizedModuleManager.getInstance();
|
|
744
1005
|
const fileExtension = path.extname(ruta);
|
|
745
1006
|
const fileExtensions = new Set([fileExtension]);
|
|
746
1007
|
// Inicializar módulos según el contexto
|
|
747
|
-
await moduleManager.
|
|
1008
|
+
await moduleManager.preloadForContext(mode === 'all' ? 'batch' : mode, fileExtensions);
|
|
748
1009
|
// Generar TailwindCSS si está habilitado
|
|
749
1010
|
if (compileTailwind && Boolean(env.TAILWIND)) {
|
|
750
1011
|
await moduleManager.ensureModuleLoaded('tailwind');
|
|
@@ -950,28 +1211,7 @@ function createProgressBar(current, total, width = 30) {
|
|
|
950
1211
|
}
|
|
951
1212
|
// Función helper para verificar si un archivo debe ser omitido por cache
|
|
952
1213
|
async function shouldSkipFile(filePath) {
|
|
953
|
-
|
|
954
|
-
const stats = await stat(filePath);
|
|
955
|
-
const cacheEntry = compilationCache.get(filePath);
|
|
956
|
-
if (!cacheEntry) {
|
|
957
|
-
return false; // No hay entrada en cache, debe compilarse
|
|
958
|
-
}
|
|
959
|
-
// Verificar si el archivo no ha cambiado desde la última compilación
|
|
960
|
-
if (stats.mtimeMs <= cacheEntry.mtime) {
|
|
961
|
-
// Verificar si el archivo de salida existe
|
|
962
|
-
try {
|
|
963
|
-
await stat(cacheEntry.outputPath);
|
|
964
|
-
return true; // Archivo existe y no ha cambiado, se puede omitir
|
|
965
|
-
}
|
|
966
|
-
catch {
|
|
967
|
-
return false; // Archivo de salida no existe, debe recompilarse
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
return false; // Archivo ha cambiado, debe recompilarse
|
|
971
|
-
}
|
|
972
|
-
catch {
|
|
973
|
-
return false; // Error al verificar, compilar por seguridad
|
|
974
|
-
}
|
|
1214
|
+
return await smartCache.isValid(filePath);
|
|
975
1215
|
}
|
|
976
1216
|
// Función para compilar archivos con límite de concurrencia
|
|
977
1217
|
async function compileWithConcurrencyLimit(files, maxConcurrency = 8) {
|
|
@@ -987,7 +1227,7 @@ async function compileWithConcurrencyLimit(files, maxConcurrency = 8) {
|
|
|
987
1227
|
const progressPercent = Math.round((currentTotal / total) * 100);
|
|
988
1228
|
if (progressPercent > lastProgressUpdate + 1 ||
|
|
989
1229
|
currentTotal === total) {
|
|
990
|
-
|
|
1230
|
+
stdout.write(`\r🚀 ${progressBar} [✅ ${completed} | ⏭️ ${skipped} | ❌ ${failed}]`);
|
|
991
1231
|
lastProgressUpdate = progressPercent;
|
|
992
1232
|
}
|
|
993
1233
|
}
|
|
@@ -1001,18 +1241,12 @@ async function compileWithConcurrencyLimit(files, maxConcurrency = 8) {
|
|
|
1001
1241
|
return {
|
|
1002
1242
|
success: true,
|
|
1003
1243
|
cached: true,
|
|
1004
|
-
output:
|
|
1244
|
+
output: smartCache.getOutputPath(file),
|
|
1005
1245
|
};
|
|
1006
1246
|
}
|
|
1007
|
-
const result = await initCompile(file, false, 'batch');
|
|
1008
|
-
// Actualizar cache si la compilación fue exitosa
|
|
1247
|
+
const result = await initCompile(file, false, 'batch'); // Actualizar cache si la compilación fue exitosa
|
|
1009
1248
|
if (result.success && result.output) {
|
|
1010
|
-
|
|
1011
|
-
compilationCache.set(file, {
|
|
1012
|
-
hash: '', // Se podría implementar hash del contenido si es necesario
|
|
1013
|
-
mtime: stats.mtimeMs,
|
|
1014
|
-
outputPath: result.output,
|
|
1015
|
-
});
|
|
1249
|
+
await smartCache.set(file, result.output);
|
|
1016
1250
|
}
|
|
1017
1251
|
completed++;
|
|
1018
1252
|
showProgress();
|
|
@@ -1094,7 +1328,15 @@ export async function initCompileAll() {
|
|
|
1094
1328
|
else {
|
|
1095
1329
|
maxConcurrency = Math.min(cpuCount * 2, 16);
|
|
1096
1330
|
}
|
|
1097
|
-
logger.info(`🚀 Compilando ${fileCount} archivos con concurrencia optimizada (${maxConcurrency} hilos)...`);
|
|
1331
|
+
logger.info(`🚀 Compilando ${fileCount} archivos con concurrencia optimizada (${maxConcurrency} hilos)...`); // Configurar worker pool para modo batch
|
|
1332
|
+
try {
|
|
1333
|
+
const { TypeScriptWorkerPool } = await import('./typescript-worker-pool.js');
|
|
1334
|
+
const workerPool = TypeScriptWorkerPool.getInstance();
|
|
1335
|
+
workerPool.setMode('batch');
|
|
1336
|
+
}
|
|
1337
|
+
catch {
|
|
1338
|
+
// Error silencioso en configuración del pool
|
|
1339
|
+
}
|
|
1098
1340
|
await compileWithConcurrencyLimit(filesToCompile, maxConcurrency);
|
|
1099
1341
|
// Guardar cache al final
|
|
1100
1342
|
await saveCache();
|