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/parser.js
CHANGED
|
@@ -1,6 +1,173 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import fs, { readFile } from 'node:fs/promises';
|
|
2
3
|
import oxc from 'oxc-parser';
|
|
3
|
-
|
|
4
|
+
class ParserASTCache {
|
|
5
|
+
static instance;
|
|
6
|
+
cache = new Map();
|
|
7
|
+
MAX_CACHE_SIZE = 150; // Máximo ASTs en cache
|
|
8
|
+
MAX_CACHE_MEMORY = 30 * 1024 * 1024; // 30MB límite
|
|
9
|
+
CACHE_TTL = 10 * 60 * 1000; // 10 minutos
|
|
10
|
+
currentMemoryUsage = 0;
|
|
11
|
+
// Métricas
|
|
12
|
+
cacheHits = 0;
|
|
13
|
+
cacheMisses = 0;
|
|
14
|
+
totalParses = 0;
|
|
15
|
+
static getInstance() {
|
|
16
|
+
if (!ParserASTCache.instance) {
|
|
17
|
+
ParserASTCache.instance = new ParserASTCache();
|
|
18
|
+
}
|
|
19
|
+
return ParserASTCache.instance;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Genera un hash del contenido del código
|
|
23
|
+
*/
|
|
24
|
+
generateContentHash(code, astType) {
|
|
25
|
+
return createHash('sha256').update(`${code}:${astType}`).digest('hex');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Estima el tamaño en memoria de un AST
|
|
29
|
+
*/
|
|
30
|
+
estimateASTSize(ast) {
|
|
31
|
+
try {
|
|
32
|
+
return JSON.stringify(ast).length * 2; // UTF-16 characters
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return 10000; // Estimación por defecto
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Obtiene AST desde cache o lo parsea
|
|
40
|
+
*/
|
|
41
|
+
async getOrParseAST(filename, code, astType = 'js') {
|
|
42
|
+
this.totalParses++;
|
|
43
|
+
const contentHash = this.generateContentHash(code, astType);
|
|
44
|
+
const cacheKey = `${filename}:${contentHash}`;
|
|
45
|
+
// Verificar cache
|
|
46
|
+
const cached = this.cache.get(cacheKey);
|
|
47
|
+
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
|
48
|
+
// Actualizar timestamp de uso (LRU)
|
|
49
|
+
cached.timestamp = Date.now();
|
|
50
|
+
this.cacheHits++;
|
|
51
|
+
return {
|
|
52
|
+
ast: cached.ast,
|
|
53
|
+
cached: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Cache miss - parsear nuevo AST
|
|
57
|
+
this.cacheMisses++;
|
|
58
|
+
const ast = oxc.parseSync(filename, code, {
|
|
59
|
+
sourceType: 'module',
|
|
60
|
+
showSemanticErrors: true,
|
|
61
|
+
astType,
|
|
62
|
+
});
|
|
63
|
+
// Cachear resultado si es válido
|
|
64
|
+
if (ast && !ast.errors?.length) {
|
|
65
|
+
this.addToCache(cacheKey, ast, astType);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
ast,
|
|
69
|
+
cached: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Añade AST al cache con gestión de memoria
|
|
74
|
+
*/
|
|
75
|
+
addToCache(cacheKey, ast, astType) {
|
|
76
|
+
try {
|
|
77
|
+
const size = this.estimateASTSize(ast);
|
|
78
|
+
// Aplicar políticas de eviction si es necesario
|
|
79
|
+
this.evictIfNeeded(size);
|
|
80
|
+
const entry = {
|
|
81
|
+
contentHash: cacheKey.split(':')[1] || '',
|
|
82
|
+
ast,
|
|
83
|
+
astType,
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
size,
|
|
86
|
+
};
|
|
87
|
+
this.cache.set(cacheKey, entry);
|
|
88
|
+
this.currentMemoryUsage += size;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.warn('[ParserASTCache] Error cacheando AST:', error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Aplica políticas de eviction LRU si es necesario
|
|
96
|
+
*/
|
|
97
|
+
evictIfNeeded(newEntrySize) {
|
|
98
|
+
// Verificar límite de entradas
|
|
99
|
+
while (this.cache.size >= this.MAX_CACHE_SIZE) {
|
|
100
|
+
this.evictLRU();
|
|
101
|
+
}
|
|
102
|
+
// Verificar límite de memoria
|
|
103
|
+
while (this.currentMemoryUsage + newEntrySize > this.MAX_CACHE_MEMORY &&
|
|
104
|
+
this.cache.size > 0) {
|
|
105
|
+
this.evictLRU();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Elimina la entrada menos recientemente usada
|
|
110
|
+
*/
|
|
111
|
+
evictLRU() {
|
|
112
|
+
let oldestKey = '';
|
|
113
|
+
let oldestTime = Infinity;
|
|
114
|
+
for (const [key, entry] of this.cache) {
|
|
115
|
+
if (entry.timestamp < oldestTime) {
|
|
116
|
+
oldestTime = entry.timestamp;
|
|
117
|
+
oldestKey = key;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (oldestKey) {
|
|
121
|
+
const entry = this.cache.get(oldestKey);
|
|
122
|
+
if (entry) {
|
|
123
|
+
this.currentMemoryUsage -= entry.size;
|
|
124
|
+
this.cache.delete(oldestKey);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Limpia entradas expiradas
|
|
130
|
+
*/
|
|
131
|
+
cleanExpired() {
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
134
|
+
if (now - entry.timestamp > this.CACHE_TTL) {
|
|
135
|
+
this.currentMemoryUsage -= entry.size;
|
|
136
|
+
this.cache.delete(key);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Obtiene estadísticas del cache
|
|
142
|
+
*/
|
|
143
|
+
getStats() {
|
|
144
|
+
const hitRate = this.totalParses > 0
|
|
145
|
+
? Math.round((this.cacheHits / this.totalParses) * 100)
|
|
146
|
+
: 0;
|
|
147
|
+
return {
|
|
148
|
+
cacheHits: this.cacheHits,
|
|
149
|
+
cacheMisses: this.cacheMisses,
|
|
150
|
+
hitRate,
|
|
151
|
+
totalParses: this.totalParses,
|
|
152
|
+
cacheSize: this.cache.size,
|
|
153
|
+
maxCacheSize: this.MAX_CACHE_SIZE,
|
|
154
|
+
memoryUsage: this.currentMemoryUsage,
|
|
155
|
+
maxMemoryUsage: this.MAX_CACHE_MEMORY,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Limpia todo el cache
|
|
160
|
+
*/
|
|
161
|
+
clear() {
|
|
162
|
+
this.cache.clear();
|
|
163
|
+
this.currentMemoryUsage = 0;
|
|
164
|
+
this.cacheHits = 0;
|
|
165
|
+
this.cacheMisses = 0;
|
|
166
|
+
this.totalParses = 0;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Instancia global del cache AST
|
|
170
|
+
const astCache = ParserASTCache.getInstance();
|
|
4
171
|
/**
|
|
5
172
|
* Parses the given JavaScript code using Acorn and returns the Abstract Syntax Tree (AST).
|
|
6
173
|
*
|
|
@@ -9,11 +176,7 @@ import oxc from 'oxc-parser';
|
|
|
9
176
|
* @throws {Error} If there is an error during parsing, it logs the error details and stack trace.
|
|
10
177
|
*/
|
|
11
178
|
export const parser = async (filename, code, astType = 'js') => {
|
|
12
|
-
const ast =
|
|
13
|
-
sourceType: 'module',
|
|
14
|
-
showSemanticErrors: true,
|
|
15
|
-
astType,
|
|
16
|
-
});
|
|
179
|
+
const { ast } = await astCache.getOrParseAST(filename, code, astType);
|
|
17
180
|
return ast;
|
|
18
181
|
};
|
|
19
182
|
export const getCodeFile = async (filename) => {
|
|
@@ -27,4 +190,14 @@ export const getCodeFile = async (filename) => {
|
|
|
27
190
|
return { code: null, error };
|
|
28
191
|
}
|
|
29
192
|
};
|
|
193
|
+
// ✨ NUEVAS FUNCIONES: Exportar funcionalidades del cache AST para uso externo
|
|
194
|
+
export const getParserCacheStats = () => {
|
|
195
|
+
return astCache.getStats();
|
|
196
|
+
};
|
|
197
|
+
export const clearParserCache = () => {
|
|
198
|
+
astCache.clear();
|
|
199
|
+
};
|
|
200
|
+
export const cleanExpiredParserCache = () => {
|
|
201
|
+
astCache.cleanExpired();
|
|
202
|
+
};
|
|
30
203
|
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance Monitor - Sistema centralizado de monitoreo de optimizaciones
|
|
3
|
+
* Reúne todas las métricas de cache y performance del VersaCompiler
|
|
4
|
+
*/
|
|
5
|
+
import { clearBrowserSyncCache, getBrowserSyncCacheStats, } from '../servicios/browserSync.js';
|
|
6
|
+
import { cleanExpiredMinificationCache, clearMinificationCache, getMinificationCacheStats, } from './minify.js';
|
|
7
|
+
import { getModuleResolutionMetrics } from './module-resolution-optimizer.js';
|
|
8
|
+
import { cleanExpiredParserCache, clearParserCache, getParserCacheStats, } from './parser.js';
|
|
9
|
+
import { TransformOptimizer } from './transform-optimizer.js';
|
|
10
|
+
import { cleanExpiredVueHMRCache, clearVueHMRCache, getVueHMRCacheStats, } from './vuejs.js';
|
|
11
|
+
export class PerformanceMonitor {
|
|
12
|
+
static instance;
|
|
13
|
+
static getInstance() {
|
|
14
|
+
if (!PerformanceMonitor.instance) {
|
|
15
|
+
PerformanceMonitor.instance = new PerformanceMonitor();
|
|
16
|
+
}
|
|
17
|
+
return PerformanceMonitor.instance;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Obtiene todas las estadísticas de performance de manera unificada
|
|
21
|
+
*/
|
|
22
|
+
getAllStats() {
|
|
23
|
+
const vueHMRCache = getVueHMRCacheStats();
|
|
24
|
+
const parserCache = getParserCacheStats();
|
|
25
|
+
const browserSyncCache = getBrowserSyncCacheStats();
|
|
26
|
+
const minificationCache = getMinificationCacheStats();
|
|
27
|
+
const transformOptimizer = TransformOptimizer.getInstance().getStats();
|
|
28
|
+
const moduleResolution = getModuleResolutionMetrics();
|
|
29
|
+
// Calcular resumen general
|
|
30
|
+
const totalCacheHits = (parserCache.cacheHits || 0) +
|
|
31
|
+
(browserSyncCache.cacheHits || 0) +
|
|
32
|
+
(minificationCache.cacheHits || 0) +
|
|
33
|
+
(transformOptimizer.cacheHits || 0) +
|
|
34
|
+
(moduleResolution.cacheHits || 0);
|
|
35
|
+
const totalCacheMisses = (parserCache.cacheMisses || 0) +
|
|
36
|
+
(browserSyncCache.cacheMisses || 0) +
|
|
37
|
+
(minificationCache.cacheMisses || 0) +
|
|
38
|
+
(transformOptimizer.cacheMisses || 0) +
|
|
39
|
+
(moduleResolution.cacheMisses || 0);
|
|
40
|
+
const totalRequests = totalCacheHits + totalCacheMisses;
|
|
41
|
+
const overallHitRate = totalRequests > 0
|
|
42
|
+
? Math.round((totalCacheHits / totalRequests) * 100)
|
|
43
|
+
: 0;
|
|
44
|
+
const totalMemoryUsage = (parserCache.memoryUsage || 0) +
|
|
45
|
+
(browserSyncCache.memoryUsage || 0) +
|
|
46
|
+
(minificationCache.memoryUsage || 0) +
|
|
47
|
+
(transformOptimizer.memoryUsage || 0);
|
|
48
|
+
const totalCacheEntries = (vueHMRCache.size || 0) +
|
|
49
|
+
(parserCache.cacheSize || 0) +
|
|
50
|
+
(browserSyncCache.cacheSize || 0) +
|
|
51
|
+
(minificationCache.cacheSize || 0) +
|
|
52
|
+
(transformOptimizer.cacheSize || 0) +
|
|
53
|
+
(moduleResolution.cacheSize || 0);
|
|
54
|
+
return {
|
|
55
|
+
vueHMRCache,
|
|
56
|
+
parserCache,
|
|
57
|
+
browserSyncCache,
|
|
58
|
+
minificationCache,
|
|
59
|
+
transformOptimizer,
|
|
60
|
+
moduleResolution,
|
|
61
|
+
summary: {
|
|
62
|
+
totalCacheHits,
|
|
63
|
+
totalCacheMisses,
|
|
64
|
+
overallHitRate,
|
|
65
|
+
totalMemoryUsage,
|
|
66
|
+
totalCacheEntries,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Genera un reporte detallado de performance
|
|
72
|
+
*/
|
|
73
|
+
generateReport() {
|
|
74
|
+
const stats = this.getAllStats();
|
|
75
|
+
const formatBytes = (bytes) => {
|
|
76
|
+
if (bytes === 0)
|
|
77
|
+
return '0 B';
|
|
78
|
+
const k = 1024;
|
|
79
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
80
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
81
|
+
return (parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]);
|
|
82
|
+
};
|
|
83
|
+
const report = `
|
|
84
|
+
🚀 VERSACOMPILER PERFORMANCE REPORT
|
|
85
|
+
=====================================
|
|
86
|
+
|
|
87
|
+
📊 RESUMEN GENERAL
|
|
88
|
+
Hit Rate Total: ${stats.summary.overallHitRate}%
|
|
89
|
+
Cache Hits: ${stats.summary.totalCacheHits}
|
|
90
|
+
Cache Misses: ${stats.summary.totalCacheMisses}
|
|
91
|
+
Memoria Total: ${formatBytes(stats.summary.totalMemoryUsage)}
|
|
92
|
+
Entradas Cache: ${stats.summary.totalCacheEntries}
|
|
93
|
+
|
|
94
|
+
🎯 VUE HMR CACHE
|
|
95
|
+
Size: ${stats.vueHMRCache.size}/${stats.vueHMRCache.maxSize}
|
|
96
|
+
TTL: ${Math.round(stats.vueHMRCache.ttl / 1000 / 60)}min
|
|
97
|
+
|
|
98
|
+
📝 PARSER AST CACHE
|
|
99
|
+
Hit Rate: ${stats.parserCache.hitRate}%
|
|
100
|
+
Cache Hits: ${stats.parserCache.cacheHits}
|
|
101
|
+
Cache Misses: ${stats.parserCache.cacheMisses}
|
|
102
|
+
Size: ${stats.parserCache.cacheSize}/${stats.parserCache.maxCacheSize}
|
|
103
|
+
Memoria: ${formatBytes(stats.parserCache.memoryUsage)}/${formatBytes(stats.parserCache.maxMemoryUsage)}
|
|
104
|
+
|
|
105
|
+
🌐 BROWSERSYNC FILE CACHE
|
|
106
|
+
Hit Rate: ${stats.browserSyncCache.hitRate}%
|
|
107
|
+
Cache Hits: ${stats.browserSyncCache.cacheHits}
|
|
108
|
+
Cache Misses: ${stats.browserSyncCache.cacheMisses}
|
|
109
|
+
Size: ${stats.browserSyncCache.cacheSize}/${stats.browserSyncCache.maxCacheSize}
|
|
110
|
+
Memoria: ${formatBytes(stats.browserSyncCache.memoryUsage)}/${formatBytes(stats.browserSyncCache.maxMemoryUsage)}
|
|
111
|
+
|
|
112
|
+
🗜️ MINIFICATION CACHE
|
|
113
|
+
Hit Rate: ${stats.minificationCache.hitRate}%
|
|
114
|
+
Cache Hits: ${stats.minificationCache.cacheHits}
|
|
115
|
+
Cache Misses: ${stats.minificationCache.cacheMisses}
|
|
116
|
+
Size: ${stats.minificationCache.cacheSize}/${stats.minificationCache.maxCacheSize}
|
|
117
|
+
Memoria: ${formatBytes(stats.minificationCache.memoryUsage)}/${formatBytes(stats.minificationCache.maxMemoryUsage)}
|
|
118
|
+
Compresión Promedio: ${stats.minificationCache.avgCompressionRatio}%
|
|
119
|
+
|
|
120
|
+
🔄 TRANSFORM OPTIMIZER
|
|
121
|
+
Hit Rate: ${stats.transformOptimizer.hitRate}%
|
|
122
|
+
Cache Hits: ${stats.transformOptimizer.cacheHits}
|
|
123
|
+
Cache Misses: ${stats.transformOptimizer.cacheMisses}
|
|
124
|
+
Transformaciones: ${stats.transformOptimizer.totalTransforms}
|
|
125
|
+
Size: ${stats.transformOptimizer.cacheSize}
|
|
126
|
+
Memoria: ${formatBytes(stats.transformOptimizer.memoryUsage)}
|
|
127
|
+
|
|
128
|
+
📦 MODULE RESOLUTION
|
|
129
|
+
Hit Rate: ${stats.moduleResolution.cacheHitRate?.toFixed(1)}%
|
|
130
|
+
Cache Hits: ${stats.moduleResolution.cacheHits}
|
|
131
|
+
Cache Misses: ${stats.moduleResolution.cacheMisses}
|
|
132
|
+
Resoluciones: ${stats.moduleResolution.totalResolutions}
|
|
133
|
+
Índice Módulos: ${stats.moduleResolution.moduleIndexSize}
|
|
134
|
+
Índice Alias: ${stats.moduleResolution.aliasIndexSize}
|
|
135
|
+
Tiempo Promedio: ${stats.moduleResolution.averageResolveTime?.toFixed(2)}ms
|
|
136
|
+
|
|
137
|
+
=====================================
|
|
138
|
+
`;
|
|
139
|
+
return report;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Limpia todos los caches
|
|
143
|
+
*/
|
|
144
|
+
clearAllCaches() {
|
|
145
|
+
clearVueHMRCache();
|
|
146
|
+
clearParserCache();
|
|
147
|
+
clearBrowserSyncCache();
|
|
148
|
+
clearMinificationCache();
|
|
149
|
+
TransformOptimizer.getInstance().clear();
|
|
150
|
+
console.log('🧹 Todos los caches han sido limpiados');
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Limpia entradas expiradas de todos los caches
|
|
154
|
+
*/
|
|
155
|
+
cleanExpiredCaches() {
|
|
156
|
+
cleanExpiredVueHMRCache();
|
|
157
|
+
cleanExpiredParserCache();
|
|
158
|
+
cleanExpiredMinificationCache();
|
|
159
|
+
console.log('🧹 Entradas expiradas limpiadas de todos los caches');
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Configura limpieza automática periódica
|
|
163
|
+
*/
|
|
164
|
+
setupAutomaticCleanup(intervalMinutes = 30) {
|
|
165
|
+
setInterval(() => {
|
|
166
|
+
this.cleanExpiredCaches();
|
|
167
|
+
console.log(`🔄 Limpieza automática ejecutada cada ${intervalMinutes} minutos`);
|
|
168
|
+
}, intervalMinutes * 60 * 1000);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Obtiene métricas simplificadas para logging
|
|
172
|
+
*/
|
|
173
|
+
getSimpleMetrics() {
|
|
174
|
+
const stats = this.getAllStats();
|
|
175
|
+
return {
|
|
176
|
+
hitRate: stats.summary.overallHitRate,
|
|
177
|
+
totalHits: stats.summary.totalCacheHits,
|
|
178
|
+
totalMisses: stats.summary.totalCacheMisses,
|
|
179
|
+
memoryUsage: stats.summary.totalMemoryUsage,
|
|
180
|
+
cacheEntries: stats.summary.totalCacheEntries,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Exportar instancia singleton
|
|
185
|
+
export const performanceMonitor = PerformanceMonitor.getInstance();
|
|
186
|
+
// Funciones de conveniencia
|
|
187
|
+
export const getAllPerformanceStats = () => performanceMonitor.getAllStats();
|
|
188
|
+
export const generatePerformanceReport = () => performanceMonitor.generateReport();
|
|
189
|
+
export const clearAllCaches = () => performanceMonitor.clearAllCaches();
|
|
190
|
+
export const cleanExpiredCaches = () => performanceMonitor.cleanExpiredCaches();
|
|
191
|
+
export const getSimpleMetrics = () => performanceMonitor.getSimpleMetrics();
|
|
192
|
+
//# sourceMappingURL=performance-monitor.js.map
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform Optimizer - Sistema de optimización de transformaciones AST
|
|
3
|
+
* Implementa procesamiento paralelo y caching inteligente para transformaciones
|
|
4
|
+
*/
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
/**
|
|
8
|
+
* Sistema de optimización de transformaciones con paralelización y caching
|
|
9
|
+
*/
|
|
10
|
+
export class TransformOptimizer {
|
|
11
|
+
static instance;
|
|
12
|
+
transformCache = new Map();
|
|
13
|
+
workers = [];
|
|
14
|
+
workerQueue = [];
|
|
15
|
+
pendingTasks = new Map();
|
|
16
|
+
// Configuración de performance
|
|
17
|
+
MAX_CACHE_SIZE = 200; // Máximo transformaciones en cache
|
|
18
|
+
MAX_CACHE_MEMORY = 50 * 1024 * 1024; // 50MB límite
|
|
19
|
+
WORKER_POOL_SIZE = Math.min(os.cpus().length, 4);
|
|
20
|
+
TASK_TIMEOUT = 10000; // 10 segundos timeout
|
|
21
|
+
// Métricas
|
|
22
|
+
cacheHits = 0;
|
|
23
|
+
cacheMisses = 0;
|
|
24
|
+
totalTransforms = 0;
|
|
25
|
+
currentMemoryUsage = 0;
|
|
26
|
+
constructor() {
|
|
27
|
+
this.initializeWorkers();
|
|
28
|
+
}
|
|
29
|
+
static getInstance() {
|
|
30
|
+
if (!TransformOptimizer.instance) {
|
|
31
|
+
TransformOptimizer.instance = new TransformOptimizer();
|
|
32
|
+
}
|
|
33
|
+
return TransformOptimizer.instance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Inicializa el pool de workers para transformaciones paralelas
|
|
37
|
+
*/
|
|
38
|
+
async initializeWorkers() {
|
|
39
|
+
// Por ahora, implementaremos sin workers para evitar complejidad adicional
|
|
40
|
+
// En el futuro se puede añadir worker pool específico para transformaciones
|
|
41
|
+
console.log('[TransformOptimizer] Inicializado sin workers (procesamiento síncrono optimizado)');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Aplica transformaciones con caching y optimización
|
|
45
|
+
*/
|
|
46
|
+
async transform(code, transforms, options = {}) {
|
|
47
|
+
this.totalTransforms++;
|
|
48
|
+
// 1. Generar hash para cache lookup
|
|
49
|
+
const cacheKey = this.generateCacheKey(code, transforms, options);
|
|
50
|
+
// 2. Verificar cache
|
|
51
|
+
const cached = await this.getFromCache(cacheKey);
|
|
52
|
+
if (cached) {
|
|
53
|
+
this.cacheHits++;
|
|
54
|
+
return cached;
|
|
55
|
+
}
|
|
56
|
+
this.cacheMisses++;
|
|
57
|
+
// 3. Aplicar transformaciones
|
|
58
|
+
const result = await this.applyTransforms(code, transforms, options);
|
|
59
|
+
// 4. Cachear resultado
|
|
60
|
+
await this.addToCache(cacheKey, code, transforms, options, result);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Genera clave de cache basada en contenido y transformaciones
|
|
65
|
+
*/
|
|
66
|
+
generateCacheKey(code, transforms, options) {
|
|
67
|
+
const content = `${code}||${transforms.join(',')}||${JSON.stringify(options)}`;
|
|
68
|
+
return createHash('sha256').update(content).digest('hex');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Obtiene resultado del cache si es válido
|
|
72
|
+
*/
|
|
73
|
+
async getFromCache(cacheKey) {
|
|
74
|
+
const entry = this.transformCache.get(cacheKey);
|
|
75
|
+
if (!entry)
|
|
76
|
+
return null;
|
|
77
|
+
// Actualizar tiempo de uso para LRU
|
|
78
|
+
entry.lastUsed = Date.now();
|
|
79
|
+
return entry.result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Añade resultado al cache con gestión de memoria
|
|
83
|
+
*/
|
|
84
|
+
async addToCache(cacheKey, code, transforms, options, result) {
|
|
85
|
+
try {
|
|
86
|
+
const size = this.estimateSize(code, result);
|
|
87
|
+
// Aplicar políticas de eviction si es necesario
|
|
88
|
+
this.evictIfNeeded(size);
|
|
89
|
+
const entry = {
|
|
90
|
+
inputHash: createHash('sha256').update(code).digest('hex'),
|
|
91
|
+
transformHash: createHash('sha256')
|
|
92
|
+
.update(transforms.join(','))
|
|
93
|
+
.digest('hex'),
|
|
94
|
+
result,
|
|
95
|
+
lastUsed: Date.now(),
|
|
96
|
+
size,
|
|
97
|
+
};
|
|
98
|
+
this.transformCache.set(cacheKey, entry);
|
|
99
|
+
this.currentMemoryUsage += size;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.warn('[TransformOptimizer] Error cacheando transformación:', error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Aplica las transformaciones reales al código
|
|
107
|
+
*/
|
|
108
|
+
async applyTransforms(code, transforms, options) {
|
|
109
|
+
try {
|
|
110
|
+
let currentCode = code;
|
|
111
|
+
let currentMap;
|
|
112
|
+
const dependencies = [];
|
|
113
|
+
// Aplicar transformaciones secuencialmente (por ahora)
|
|
114
|
+
// En el futuro se puede paralelizar transformaciones independientes
|
|
115
|
+
for (const transform of transforms) {
|
|
116
|
+
const transformResult = await this.applySingleTransform(currentCode, transform, options, currentMap);
|
|
117
|
+
currentCode = transformResult.code;
|
|
118
|
+
if (transformResult.map) {
|
|
119
|
+
currentMap = transformResult.map;
|
|
120
|
+
}
|
|
121
|
+
if (transformResult.dependencies) {
|
|
122
|
+
dependencies.push(...transformResult.dependencies);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
code: currentCode,
|
|
127
|
+
map: currentMap,
|
|
128
|
+
dependencies: [...new Set(dependencies)], // Deduplicar dependencias
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
throw new Error(`Error aplicando transformaciones: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Aplica una transformación individual
|
|
137
|
+
*/
|
|
138
|
+
async applySingleTransform(code, transform, options, sourceMap) {
|
|
139
|
+
// Importar dinámicamente el módulo de transformación necesario
|
|
140
|
+
switch (transform) {
|
|
141
|
+
case 'typescript':
|
|
142
|
+
return this.applyTypeScriptTransform(code, options, sourceMap);
|
|
143
|
+
case 'vue':
|
|
144
|
+
return this.applyVueTransform(code, options, sourceMap);
|
|
145
|
+
case 'minify':
|
|
146
|
+
return this.applyMinifyTransform(code, options, sourceMap);
|
|
147
|
+
case 'babel':
|
|
148
|
+
return this.applyBabelTransform(code, options, sourceMap);
|
|
149
|
+
default:
|
|
150
|
+
throw new Error(`Transformación desconocida: ${transform}`);
|
|
151
|
+
}
|
|
152
|
+
} /**
|
|
153
|
+
* Aplica transformación TypeScript
|
|
154
|
+
*/
|
|
155
|
+
async applyTypeScriptTransform(code, options, sourceMap) {
|
|
156
|
+
// Importación dinámica para evitar carga innecesaria
|
|
157
|
+
const { preCompileTS } = await import('./typescript-manager.js');
|
|
158
|
+
const result = await preCompileTS(code, 'temp.ts');
|
|
159
|
+
if (result.error) {
|
|
160
|
+
throw result.error;
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
code: result.data || code,
|
|
164
|
+
map: sourceMap, // Mantener source map existente por ahora
|
|
165
|
+
dependencies: [], // TypeScript puede extraer dependencias en el futuro
|
|
166
|
+
};
|
|
167
|
+
} /**
|
|
168
|
+
* Aplica transformación Vue
|
|
169
|
+
*/
|
|
170
|
+
async applyVueTransform(code, options, sourceMap) {
|
|
171
|
+
const { preCompileVue } = await import('./vuejs.js');
|
|
172
|
+
const result = await preCompileVue(code, 'temp.vue', false);
|
|
173
|
+
if (result.error) {
|
|
174
|
+
throw result.error;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
code: result.data || code,
|
|
178
|
+
map: sourceMap,
|
|
179
|
+
dependencies: [],
|
|
180
|
+
};
|
|
181
|
+
} /**
|
|
182
|
+
* Aplica transformación de minificación
|
|
183
|
+
*/
|
|
184
|
+
async applyMinifyTransform(code, options, sourceMap) {
|
|
185
|
+
const { minifyJS } = await import('./minify.js');
|
|
186
|
+
const result = await minifyJS(code, 'temp.js', true);
|
|
187
|
+
if (result.error) {
|
|
188
|
+
throw result.error;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
code: result.code || code,
|
|
192
|
+
map: sourceMap, // minifyJS no devuelve map, mantener el existente
|
|
193
|
+
dependencies: [],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Aplica transformación Babel (futuro)
|
|
198
|
+
*/
|
|
199
|
+
async applyBabelTransform(code, options, sourceMap) {
|
|
200
|
+
// Placeholder para transformaciones Babel futuras
|
|
201
|
+
return {
|
|
202
|
+
code,
|
|
203
|
+
map: sourceMap,
|
|
204
|
+
dependencies: [],
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Estima el tamaño en memoria de una entrada de cache
|
|
209
|
+
*/
|
|
210
|
+
estimateSize(code, result) {
|
|
211
|
+
return (code.length * 2 + // UTF-16 characters
|
|
212
|
+
result.code.length * 2 +
|
|
213
|
+
(result.map?.length || 0) * 2 +
|
|
214
|
+
(result.dependencies?.join('').length || 0) * 2 +
|
|
215
|
+
200 // Overhead de objetos
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Aplica políticas de eviction LRU si es necesario
|
|
220
|
+
*/
|
|
221
|
+
evictIfNeeded(newEntrySize) {
|
|
222
|
+
// Verificar límite de entradas
|
|
223
|
+
while (this.transformCache.size >= this.MAX_CACHE_SIZE) {
|
|
224
|
+
this.evictLRU();
|
|
225
|
+
}
|
|
226
|
+
// Verificar límite de memoria
|
|
227
|
+
while (this.currentMemoryUsage + newEntrySize > this.MAX_CACHE_MEMORY &&
|
|
228
|
+
this.transformCache.size > 0) {
|
|
229
|
+
this.evictLRU();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Elimina la entrada menos recientemente usada
|
|
234
|
+
*/
|
|
235
|
+
evictLRU() {
|
|
236
|
+
let oldestKey = '';
|
|
237
|
+
let oldestTime = Infinity;
|
|
238
|
+
for (const [key, entry] of this.transformCache) {
|
|
239
|
+
if (entry.lastUsed < oldestTime) {
|
|
240
|
+
oldestTime = entry.lastUsed;
|
|
241
|
+
oldestKey = key;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (oldestKey) {
|
|
245
|
+
const entry = this.transformCache.get(oldestKey);
|
|
246
|
+
if (entry) {
|
|
247
|
+
this.currentMemoryUsage -= entry.size;
|
|
248
|
+
this.transformCache.delete(oldestKey);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Obtiene estadísticas del optimizador
|
|
254
|
+
*/
|
|
255
|
+
getStats() {
|
|
256
|
+
const hitRate = this.totalTransforms > 0
|
|
257
|
+
? Math.round((this.cacheHits / this.totalTransforms) * 100)
|
|
258
|
+
: 0;
|
|
259
|
+
return {
|
|
260
|
+
cacheHits: this.cacheHits,
|
|
261
|
+
cacheMisses: this.cacheMisses,
|
|
262
|
+
hitRate,
|
|
263
|
+
totalTransforms: this.totalTransforms,
|
|
264
|
+
cacheSize: this.transformCache.size,
|
|
265
|
+
memoryUsage: this.currentMemoryUsage,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Limpia el cache y reinicia estadísticas
|
|
270
|
+
*/
|
|
271
|
+
clear() {
|
|
272
|
+
this.transformCache.clear();
|
|
273
|
+
this.currentMemoryUsage = 0;
|
|
274
|
+
this.cacheHits = 0;
|
|
275
|
+
this.cacheMisses = 0;
|
|
276
|
+
this.totalTransforms = 0;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Cierra el optimizador y limpia recursos
|
|
280
|
+
*/
|
|
281
|
+
async terminate() {
|
|
282
|
+
// Limpiar workers si se implementan en el futuro
|
|
283
|
+
this.clear();
|
|
284
|
+
console.log('[TransformOptimizer] Cerrado exitosamente');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=transform-optimizer.js.map
|