versacompiler 2.1.0 → 2.2.0
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 +1 -1
- package/dist/compiler/compile.js +2520 -25
- package/dist/compiler/error-reporter.js +467 -38
- package/dist/compiler/linter.js +72 -1
- package/dist/compiler/minify.js +272 -1
- package/dist/compiler/minifyTemplate.js +230 -1
- package/dist/compiler/module-resolution-optimizer.js +844 -1
- package/dist/compiler/parser.js +336 -1
- package/dist/compiler/performance-monitor.js +204 -56
- package/dist/compiler/tailwindcss.js +39 -1
- package/dist/compiler/transform-optimizer.js +392 -1
- package/dist/compiler/transformTStoJS.js +16 -1
- package/dist/compiler/transforms.js +554 -1
- package/dist/compiler/typescript-compiler.js +172 -2
- package/dist/compiler/typescript-error-parser.js +281 -10
- package/dist/compiler/typescript-manager.js +304 -2
- package/dist/compiler/typescript-sync-validator.js +295 -31
- package/dist/compiler/typescript-worker-pool.js +936 -1
- package/dist/compiler/typescript-worker-thread.cjs +466 -22
- package/dist/compiler/typescript-worker.js +339 -1
- package/dist/compiler/vuejs.js +396 -37
- package/dist/hrm/VueHRM.js +359 -1
- package/dist/hrm/errorScreen.js +83 -1
- package/dist/hrm/getInstanciaVue.js +313 -1
- package/dist/hrm/initHRM.js +586 -1
- package/dist/main.js +353 -7
- package/dist/servicios/browserSync.js +589 -2
- package/dist/servicios/file-watcher.js +425 -4
- package/dist/servicios/logger.js +63 -3
- package/dist/servicios/readConfig.js +399 -53
- package/dist/utils/excluded-modules.js +37 -1
- package/dist/utils/module-resolver.js +466 -1
- package/dist/utils/promptUser.js +48 -2
- package/dist/utils/proxyValidator.js +68 -1
- package/dist/utils/resolve-bin.js +58 -1
- package/dist/utils/utils.js +21 -1
- package/dist/utils/vue-types-setup.js +435 -241
- package/dist/wrappers/eslint-node.js +1 -1
- package/dist/wrappers/oxlint-node.js +122 -1
- package/dist/wrappers/tailwind-node.js +94 -1
- package/package.json +106 -103
|
@@ -1 +1,844 @@
|
|
|
1
|
-
import{createHash as e}from"node:crypto";import{existsSync as i,readFileSync as a,readdirSync as o,statSync as s}from"node:fs";import{dirname as c,join as l,relative as u}from"node:path";import{cwd as d,env as f}from"node:process";import{logger as p}from"../servicios/logger.js";import{EXCLUDED_MODULES as m}from"../utils/excluded-modules.js";export class ModuleResolutionOptimizer{static instance;moduleIndex=new Map;resolutionCache=new Map;cacheOrder=[];aliasIndex=[];nodeModulesCache=new Map;metrics={totalResolutions:0,cacheHits:0,cacheMisses:0,averageResolveTime:0,indexLookups:0,filesystemAccess:0,aliasMatches:0};maxCacheSize=500;cacheMaxAge=300*1e3;indexRefreshInterval=600*1e3;excludedModules=m;lastIndexUpdate=0;constructor(){this.initializeIndexes(),this.setupPeriodicRefresh()}static getInstance(){return ModuleResolutionOptimizer.instance||(ModuleResolutionOptimizer.instance=new ModuleResolutionOptimizer),ModuleResolutionOptimizer.instance}initializeIndexes(){let e=performance.now();try{this.buildModuleIndex(),this.buildAliasIndex(),this.lastIndexUpdate=Date.now();let i=performance.now()-e;f.VERBOSE===`true`&&(p.info(`🚀 Índices de resolución construidos en ${i.toFixed(2)}ms`),p.info(`📦 ${this.moduleIndex.size} módulos indexados`),p.info(`🔗 ${this.aliasIndex.length} alias indexados`))}catch(e){p.error(`Error inicializando índices de resolución:`,e)}}buildModuleIndex(){let e=l(d(),`node_modules`);if(i(e))try{let i=this.discoverModules(e);for(let e of i)this.moduleIndex.set(e.name,{fullPath:e.fullPath,entryPoint:e.entryPoint,packageJson:e.packageJson,isESM:e.isESM,hasExports:e.hasExports,optimizedEntry:e.optimizedEntry,lastModified:e.lastModified});f.VERBOSE===`true`&&p.info(`📚 Índice de módulos construido: ${this.moduleIndex.size} entradas`)}catch(e){p.error(`Error construyendo índice de módulos:`,e)}}discoverModules(e){let i=[];try{let a=o(e);this.metrics.filesystemAccess++;for(let s of a){let a=l(e,s);try{if(s.startsWith(`/dist/examples`)){let e=o(a);this.metrics.filesystemAccess++;for(let o of e){let e=l(a,o),c=this.analyzeModule(`${s}/${o}`,e);c&&i.push(c)}}else{let e=this.analyzeModule(s,a);e&&i.push(e)}}catch{continue}}}catch(e){p.error(`Error descubriendo módulos:`,e)}return i}analyzeModule(e,o){try{let c=l(o,`package.json`);if(!i(c))return null;let u=s(c);this.metrics.filesystemAccess++;let d=JSON.parse(a(c,`utf-8`));this.metrics.filesystemAccess++;let f=d.type===`module`,p=!!d.exports,m=this.determineOptimalEntryPoint(d),h;return m&&(h=this.findOptimalESMVersion(o,m)),{name:e,fullPath:o,entryPoint:m||`index.js`,packageJson:d,isESM:f,hasExports:p,optimizedEntry:h,lastModified:u.mtime.getTime()}}catch{return null}}determineOptimalEntryPoint(e){let i=null;if(e.module)i=e.module;else if(e.exports){if(typeof e.exports==`string`)i=e.exports;else if(e.exports[`.`]){let a=e.exports[`.`];typeof a==`string`?i=a:typeof a==`object`&&(i=a.import||a.browser||a.default)}}else i=e.browser&&typeof e.browser==`string`?e.browser:e.main||null;return i&&(i=this.validateAndOptimizeEntryPoint(i,e)),i}validateAndOptimizeEntryPoint(e,i){let a=f.isProd===`true`,o=e.toLowerCase();if(!a&&(o.includes(`.min.`)||o.includes(`.prod.`))){let a=this.findDevelopmentAlternatives(e,i);if(a)return a}if(o.includes(`runtime`)&&!o.includes(`browser`)){let a=this.findBrowserAlternative(e,i);if(a)return a}return e}findDevelopmentAlternatives(e,i){let a=e.replace(`.min.`,`.`).replace(`.prod.`,`.`);if(i.exports&&typeof i.exports==`object`){let e=i.exports[`.`];if(e&&typeof e==`object`){let i=[e.development,e.import,e.browser,e.default].filter(Boolean);for(let e of i)if(typeof e==`string`&&!e.includes(`.min.`)&&!e.includes(`.prod.`))return e}}if(i.browser&&typeof i.browser==`object`){for(let e of Object.values(i.browser))if(typeof e==`string`&&!e.includes(`.min.`)&&!e.includes(`.prod.`)&&(e.includes(`browser`)||e.includes(`esm`)))return e}return a===e?null:a}findBrowserAlternative(e,i){if(i.exports&&typeof i.exports==`object`){let e=i.exports[`.`];if(e&&typeof e==`object`){let i=Object.keys(e).filter(e=>e.includes(`browser`)&&(e.includes(`esm`)||e.includes(`module`)));if(i.length>0){let a=i[0];if(a&&typeof e[a]==`string`)return e[a]}if(e.browser&&typeof e.browser==`string`)return e.browser}}let a=e.replace(/\.[^/.]+$/,``),o=[a.replace(`runtime`,`esm-browser`),a.replace(`runtime`,`browser`),a.replace(`runtime.esm-bundler`,`esm-browser`),e.replace(`runtime`,`esm-browser`),e.replace(`runtime`,`browser`)];return e.includes(`vue.runtime.esm-bundler`)&&o.unshift(`dist/vue.esm-browser.js`,`dist/vue.browser.esm.js`),o.find(i=>i!==e)||null}findOptimalESMVersion(e,a){let s=c(a),u=(a.split(`/`).pop()||``).replace(/\.[^/.]+$/,``),d=l(e,s);if(i(d))try{let e=o(d);this.metrics.filesystemAccess++;let i=[`${u}.esm-browser.js`,`${u}.esm.js`,`${u}.module.js`,`${u}.browser.js`];for(let a of i)if(e.includes(a))return l(s,a)}catch{}}buildAliasIndex(){if(f.PATH_ALIAS)try{let e=JSON.parse(f.PATH_ALIAS);this.aliasIndex=[];for(let[i,a]of Object.entries(e)){let e=i.replace(`/*`,``),o=e.length;this.aliasIndex.push({pattern:e,target:Array.isArray(a)?a:[a],regex:RegExp(`^${e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}(?=/|$)`),priority:o})}this.aliasIndex.sort((e,i)=>i.priority-e.priority),f.VERBOSE===`true`&&p.info(`🔗 Índice de alias construido: ${this.aliasIndex.length} patrones`)}catch(e){p.error(`Error construyendo índice de alias:`,e)}}async resolveModule(e,i){let a=performance.now();if(this.metrics.totalResolutions++,this.excludedModules.has(e))return{path:null,cached:!1,resolveTime:performance.now()-a};let o=this.createCacheKey(e,i),s=this.getFromCache(o);if(s!==void 0)return this.metrics.cacheHits++,{path:s,cached:!0,resolveTime:performance.now()-a,fromCache:!0};this.metrics.cacheMisses++;let c=null;try{c=e.includes(`/`)?await this.resolveSubPath(e):this.resolveFromIndex(e),c||(c=this.fallbackResolve(e)),c&&(c=this.getNodeModulesRelativePath(c))}catch(i){f.VERBOSE===`true`&&p.warn(`Error resolviendo ${e}:`,i)}this.setCache(o,c);let l=performance.now()-a;return this.updateMetrics(l),{path:c,cached:!1,resolveTime:l}}resolveFromIndex(e){this.metrics.indexLookups++;let i=this.moduleIndex.get(e);if(!i)return null;let a=i.optimizedEntry||i.entryPoint;return l(i.fullPath,a)}async resolveSubPath(e){let[a,...o]=e.split(`/`),s=o.join(`/`);if(!a)return null;this.metrics.indexLookups++;let c=this.moduleIndex.get(a);if(!c)return null;if(c.hasExports&&c.packageJson.exports){let e=`./${s}`,i=c.packageJson.exports[e];if(i){if(typeof i==`string`)return l(c.fullPath,i);if(typeof i==`object`){let e=i.import||i.default;if(typeof e==`string`)return l(c.fullPath,e)}}}let u=l(c.fullPath,s);if(i(u))return this.metrics.filesystemAccess++,u;for(let e of[`.mjs`,`.js`,`.cjs`]){let a=u+e;if(i(a))return this.metrics.filesystemAccess++,a}return null}fallbackResolve(e){let o=l(d(),`node_modules`,e),s=l(o,`package.json`);if(!i(s))return this.metrics.filesystemAccess++,null;try{let e=JSON.parse(a(s,`utf-8`));this.metrics.filesystemAccess++;let c=l(o,this.determineOptimalEntryPoint(e)||`index.js`);if(i(c))return this.metrics.filesystemAccess++,c}catch{}return null}findMatchingAlias(e){this.metrics.aliasMatches++;for(let i of this.aliasIndex)if(i.regex.test(e))return i;return null}resolveAlias(e){let i=this.findMatchingAlias(e);if(!i||!f.PATH_DIST)return null;let a=e.replace(i.pattern,``),o=i.target[0];if(!o)return null;let s,c=f.PATH_DIST.replace(`./`,``);if(a===``&&!o.includes(`*`))if(o.startsWith(`/`))s=l(`/`,c,o.substring(1));else{let e=o.replace(`./`,``);s=e.startsWith(`src/`)?l(`/`,c,e.replace(`src/`,``)):l(`/`,c,e)}else if(o.startsWith(`/`)){let e=o.substring(1).replace(`/*`,``);s=(e===`src`||e.startsWith(`src/`),l(`/`,c,a))}else{let e=o.replace(`./`,``).replace(`/*`,``);s=e===c?l(`/`,c,a):e.startsWith(c+`/`)?l(`/`,e,a):e.startsWith(`src/`)?l(`/`,c,e.replace(`src/`,``),a):[`examples`,`src`,`app`,`lib`].includes(e)?l(`/`,c,a):l(`/`,c,e,a)}return s.replace(/\\/g,`/`)}getFromCache(e){let i=this.resolutionCache.get(e);if(i){if(Date.now()-i.timestamp>this.cacheMaxAge){this.resolutionCache.delete(e),this.cacheOrder=this.cacheOrder.filter(i=>i!==e);return}return i.hits++,this.cacheOrder=this.cacheOrder.filter(i=>i!==e),this.cacheOrder.push(e),i.result}}setCache(e,i){if(this.resolutionCache.size>=this.maxCacheSize){let e=this.cacheOrder.shift();e&&this.resolutionCache.delete(e)}this.resolutionCache.set(e,{result:i,timestamp:Date.now(),hits:0}),this.cacheOrder.push(e)}createCacheKey(i,a){let o=e(`md5`);return o.update(i),a&&o.update(a),o.digest(`hex`)}getNodeModulesRelativePath(e){let i=e.indexOf(`node_modules`);if(i!==-1)return`/`+e.substring(i).replace(/\\/g,`/`);let a=u(d(),e).replace(/\\/g,`/`);return a.startsWith(`/`)?a:`/`+a}updateMetrics(e){this.metrics.averageResolveTime=(this.metrics.averageResolveTime*(this.metrics.totalResolutions-1)+e)/this.metrics.totalResolutions}setupPeriodicRefresh(){setInterval(()=>{Date.now()-this.lastIndexUpdate>this.indexRefreshInterval&&(f.VERBOSE===`true`&&p.info(`🔄 Actualizando índices de resolución de módulos`),this.refreshIndexes())},this.indexRefreshInterval)}refreshIndexes(){try{let e=this.moduleIndex.size;this.buildModuleIndex(),this.buildAliasIndex(),this.lastIndexUpdate=Date.now(),f.VERBOSE===`true`&&p.info(`📚 Índices actualizados: ${e} → ${this.moduleIndex.size} módulos`)}catch(e){p.error(`Error actualizando índices:`,e)}}clearExpiredCache(){let e=Date.now(),i=[];for(let[a,o]of this.resolutionCache.entries())e-o.timestamp>this.cacheMaxAge&&i.push(a);for(let e of i)this.resolutionCache.delete(e),this.cacheOrder=this.cacheOrder.filter(i=>i!==e);f.VERBOSE===`true`&&i.length>0&&p.info(`🧹 Limpiado caché expirado: ${i.length} entradas`)}getMetrics(){return{...this.metrics,cacheSize:this.resolutionCache.size,moduleIndexSize:this.moduleIndex.size,aliasIndexSize:this.aliasIndex.length,cacheHitRate:this.metrics.totalResolutions>0?this.metrics.cacheHits/this.metrics.totalResolutions*100:0}}resetMetrics(){this.metrics={totalResolutions:0,cacheHits:0,cacheMisses:0,averageResolveTime:0,indexLookups:0,filesystemAccess:0,aliasMatches:0}}forceRefresh(){this.initializeIndexes(),this.resolutionCache.clear(),this.cacheOrder=[],f.VERBOSE===`true`&&p.info(`🔄 Índices de resolución reconstruidos forzosamente`)}cleanup(){this.moduleIndex.clear(),this.resolutionCache.clear(),this.cacheOrder=[],this.aliasIndex=[],this.nodeModulesCache.clear(),f.VERBOSE===`true`&&p.info(`🧹 Sistema de resolución de módulos limpiado`)}}export async function getOptimizedModulePath(e,i){return(await ModuleResolutionOptimizer.getInstance().resolveModule(e,i)).path}export function getOptimizedAliasPath(e){return ModuleResolutionOptimizer.getInstance().resolveAlias(e)}export function getModuleResolutionMetrics(){return ModuleResolutionOptimizer.getInstance().getMetrics()}
|
|
1
|
+
/**
|
|
2
|
+
* Module Resolution Optimizer
|
|
3
|
+
*
|
|
4
|
+
* Optimiza la resolución de módulos mediante:
|
|
5
|
+
* - Sistema de indexación O(1) para búsquedas de módulos
|
|
6
|
+
* - Caché LRU para resoluciones repetidas
|
|
7
|
+
* - Indexación de alias para búsquedas rápidas
|
|
8
|
+
* - Batch processing para múltiples resoluciones
|
|
9
|
+
* - Monitoreo de performance y métricas
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
13
|
+
import { dirname, join, relative } from 'node:path';
|
|
14
|
+
import { cwd, env } from 'node:process';
|
|
15
|
+
import { logger } from '../servicios/logger.js';
|
|
16
|
+
import { EXCLUDED_MODULES } from '../utils/excluded-modules.js';
|
|
17
|
+
/**
|
|
18
|
+
* Sistema de optimización de resolución de módulos
|
|
19
|
+
* Implementa indexación, caché y búsquedas O(1)
|
|
20
|
+
*/
|
|
21
|
+
export class ModuleResolutionOptimizer {
|
|
22
|
+
static instance;
|
|
23
|
+
// Índice principal de módulos para búsquedas O(1)
|
|
24
|
+
moduleIndex = new Map();
|
|
25
|
+
// Caché LRU para resoluciones repetidas
|
|
26
|
+
resolutionCache = new Map();
|
|
27
|
+
cacheOrder = [];
|
|
28
|
+
// Índice de alias optimizado
|
|
29
|
+
aliasIndex = [];
|
|
30
|
+
// Caché de rutas de node_modules descubiertas
|
|
31
|
+
nodeModulesCache = new Map();
|
|
32
|
+
// Métricas de rendimiento
|
|
33
|
+
metrics = {
|
|
34
|
+
totalResolutions: 0,
|
|
35
|
+
cacheHits: 0,
|
|
36
|
+
cacheMisses: 0,
|
|
37
|
+
averageResolveTime: 0,
|
|
38
|
+
indexLookups: 0,
|
|
39
|
+
filesystemAccess: 0,
|
|
40
|
+
aliasMatches: 0,
|
|
41
|
+
};
|
|
42
|
+
// Configuración
|
|
43
|
+
maxCacheSize = 500;
|
|
44
|
+
cacheMaxAge = 5 * 60 * 1000; // 5 minutos
|
|
45
|
+
indexRefreshInterval = 10 * 60 * 1000; // 10 minutos // Lista de módulos excluidos - usar la lista centralizada
|
|
46
|
+
excludedModules = EXCLUDED_MODULES;
|
|
47
|
+
lastIndexUpdate = 0;
|
|
48
|
+
constructor() {
|
|
49
|
+
this.initializeIndexes();
|
|
50
|
+
this.setupPeriodicRefresh();
|
|
51
|
+
}
|
|
52
|
+
static getInstance() {
|
|
53
|
+
if (!ModuleResolutionOptimizer.instance) {
|
|
54
|
+
ModuleResolutionOptimizer.instance =
|
|
55
|
+
new ModuleResolutionOptimizer();
|
|
56
|
+
}
|
|
57
|
+
return ModuleResolutionOptimizer.instance;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resetea la instancia del singleton (útil para tests)
|
|
61
|
+
*/
|
|
62
|
+
static resetInstance() {
|
|
63
|
+
ModuleResolutionOptimizer.instance = null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Inicializa los índices de módulos y alias
|
|
67
|
+
*/
|
|
68
|
+
initializeIndexes() {
|
|
69
|
+
const startTime = performance.now();
|
|
70
|
+
try {
|
|
71
|
+
this.buildModuleIndex();
|
|
72
|
+
this.buildAliasIndex();
|
|
73
|
+
this.lastIndexUpdate = Date.now();
|
|
74
|
+
const indexTime = performance.now() - startTime;
|
|
75
|
+
if (env.VERBOSE === 'true') {
|
|
76
|
+
logger.info(`🚀 Índices de resolución construidos en ${indexTime.toFixed(2)}ms`);
|
|
77
|
+
logger.info(`📦 ${this.moduleIndex.size} módulos indexados`);
|
|
78
|
+
logger.info(`🔗 ${this.aliasIndex.length} alias indexados`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logger.error('Error inicializando índices de resolución:', error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Construye el índice principal de módulos para búsquedas O(1)
|
|
87
|
+
*/
|
|
88
|
+
buildModuleIndex() {
|
|
89
|
+
const nodeModulesPath = join(cwd(), 'node_modules');
|
|
90
|
+
if (!existsSync(nodeModulesPath)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const modules = this.discoverModules(nodeModulesPath);
|
|
95
|
+
for (const moduleData of modules) {
|
|
96
|
+
this.moduleIndex.set(moduleData.name, {
|
|
97
|
+
fullPath: moduleData.fullPath,
|
|
98
|
+
entryPoint: moduleData.entryPoint,
|
|
99
|
+
packageJson: moduleData.packageJson,
|
|
100
|
+
isESM: moduleData.isESM,
|
|
101
|
+
hasExports: moduleData.hasExports,
|
|
102
|
+
optimizedEntry: moduleData.optimizedEntry,
|
|
103
|
+
lastModified: moduleData.lastModified,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (env.VERBOSE === 'true') {
|
|
107
|
+
logger.info(`📚 Índice de módulos construido: ${this.moduleIndex.size} entradas`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
logger.error('Error construyendo índice de módulos:', error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Descubre módulos disponibles en node_modules con información optimizada
|
|
116
|
+
*/
|
|
117
|
+
discoverModules(nodeModulesPath) {
|
|
118
|
+
const modules = [];
|
|
119
|
+
try {
|
|
120
|
+
const entries = readdirSync(nodeModulesPath);
|
|
121
|
+
this.metrics.filesystemAccess++;
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
const modulePath = join(nodeModulesPath, entry);
|
|
124
|
+
try {
|
|
125
|
+
if (entry.startsWith('/dist/examples')) {
|
|
126
|
+
// Scoped packages
|
|
127
|
+
const scopedModules = readdirSync(modulePath);
|
|
128
|
+
this.metrics.filesystemAccess++;
|
|
129
|
+
for (const scopedModule of scopedModules) {
|
|
130
|
+
const scopedPath = join(modulePath, scopedModule);
|
|
131
|
+
const moduleData = this.analyzeModule(`${entry}/${scopedModule}`, scopedPath);
|
|
132
|
+
if (moduleData) {
|
|
133
|
+
modules.push(moduleData);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Regular packages
|
|
139
|
+
const moduleData = this.analyzeModule(entry, modulePath);
|
|
140
|
+
if (moduleData) {
|
|
141
|
+
modules.push(moduleData);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Ignorar módulos que no se puedan analizar
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
logger.error('Error descubriendo módulos:', error);
|
|
153
|
+
}
|
|
154
|
+
return modules;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Analiza un módulo individual y extrae información relevante
|
|
158
|
+
*/
|
|
159
|
+
analyzeModule(name, modulePath) {
|
|
160
|
+
try {
|
|
161
|
+
const packageJsonPath = join(modulePath, 'package.json');
|
|
162
|
+
if (!existsSync(packageJsonPath)) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const stats = statSync(packageJsonPath);
|
|
166
|
+
this.metrics.filesystemAccess++;
|
|
167
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
168
|
+
this.metrics.filesystemAccess++;
|
|
169
|
+
const isESM = packageJson.type === 'module';
|
|
170
|
+
const hasExports = !!packageJson.exports; // Determinar entry point optimizado
|
|
171
|
+
const entryPoint = this.determineOptimalEntryPoint(packageJson);
|
|
172
|
+
let optimizedEntry;
|
|
173
|
+
// Buscar versión ESM/browser optimizada
|
|
174
|
+
if (entryPoint) {
|
|
175
|
+
optimizedEntry = this.findOptimalESMVersion(modulePath, entryPoint);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
name,
|
|
179
|
+
fullPath: modulePath,
|
|
180
|
+
entryPoint: entryPoint || 'index.js',
|
|
181
|
+
packageJson,
|
|
182
|
+
isESM,
|
|
183
|
+
hasExports,
|
|
184
|
+
optimizedEntry,
|
|
185
|
+
lastModified: stats.mtime.getTime(),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
} /**
|
|
192
|
+
* Determina el entry point óptimo basado en package.json
|
|
193
|
+
*/
|
|
194
|
+
determineOptimalEntryPoint(packageJson) {
|
|
195
|
+
// Prioridad: module > exports > browser > main
|
|
196
|
+
let entryPoint = null;
|
|
197
|
+
if (packageJson.module) {
|
|
198
|
+
entryPoint = packageJson.module;
|
|
199
|
+
}
|
|
200
|
+
else if (packageJson.exports) {
|
|
201
|
+
if (typeof packageJson.exports === 'string') {
|
|
202
|
+
entryPoint = packageJson.exports;
|
|
203
|
+
}
|
|
204
|
+
else if (packageJson.exports['.']) {
|
|
205
|
+
const dotExport = packageJson.exports['.'];
|
|
206
|
+
if (typeof dotExport === 'string') {
|
|
207
|
+
entryPoint = dotExport;
|
|
208
|
+
}
|
|
209
|
+
else if (typeof dotExport === 'object') {
|
|
210
|
+
entryPoint =
|
|
211
|
+
dotExport.import ||
|
|
212
|
+
dotExport.browser ||
|
|
213
|
+
dotExport.default;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else if (packageJson.browser &&
|
|
218
|
+
typeof packageJson.browser === 'string') {
|
|
219
|
+
entryPoint = packageJson.browser;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
entryPoint = packageJson.main || null;
|
|
223
|
+
}
|
|
224
|
+
// ✨ NUEVA VALIDACIÓN POST-RESOLUCIÓN
|
|
225
|
+
// Verificar si el archivo resuelto cumple con criterios de desarrollo
|
|
226
|
+
if (entryPoint) {
|
|
227
|
+
entryPoint = this.validateAndOptimizeEntryPoint(entryPoint, packageJson);
|
|
228
|
+
}
|
|
229
|
+
return entryPoint;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* ✨ NUEVA FUNCIÓN: Valida y optimiza el entry point basado en criterios de desarrollo
|
|
233
|
+
*/
|
|
234
|
+
validateAndOptimizeEntryPoint(entryPoint, packageJson) {
|
|
235
|
+
const isProd = env.isProd === 'true';
|
|
236
|
+
const fileName = entryPoint.toLowerCase();
|
|
237
|
+
// Si estamos en desarrollo, evitar archivos .min o .prod
|
|
238
|
+
if (!isProd &&
|
|
239
|
+
(fileName.includes('.min.') || fileName.includes('.prod.'))) {
|
|
240
|
+
// Buscar alternativas mejores en el package.json
|
|
241
|
+
const alternatives = this.findDevelopmentAlternatives(entryPoint, packageJson);
|
|
242
|
+
if (alternatives) {
|
|
243
|
+
return alternatives;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Priorizar versiones browser y esm para mejor compatibilidad
|
|
247
|
+
if (fileName.includes('runtime') && !fileName.includes('browser')) {
|
|
248
|
+
const browserAlternative = this.findBrowserAlternative(entryPoint, packageJson);
|
|
249
|
+
if (browserAlternative) {
|
|
250
|
+
return browserAlternative;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return entryPoint;
|
|
254
|
+
} /**
|
|
255
|
+
* ✨ NUEVA FUNCIÓN: Busca alternativas de desarrollo (no minificadas)
|
|
256
|
+
*/
|
|
257
|
+
findDevelopmentAlternatives(entryPoint, packageJson) {
|
|
258
|
+
// Crear versión de desarrollo basada en el entry point actual
|
|
259
|
+
const devVersion = entryPoint
|
|
260
|
+
.replace('.min.', '.')
|
|
261
|
+
.replace('.prod.', '.');
|
|
262
|
+
// Si hay exports, buscar en diferentes condiciones
|
|
263
|
+
if (packageJson.exports && typeof packageJson.exports === 'object') {
|
|
264
|
+
const dotExport = packageJson.exports['.'];
|
|
265
|
+
if (dotExport && typeof dotExport === 'object') {
|
|
266
|
+
// Buscar versiones development, import, browser
|
|
267
|
+
const candidates = [
|
|
268
|
+
dotExport.development,
|
|
269
|
+
dotExport.import,
|
|
270
|
+
dotExport.browser,
|
|
271
|
+
dotExport.default,
|
|
272
|
+
].filter(Boolean);
|
|
273
|
+
for (const candidate of candidates) {
|
|
274
|
+
if (typeof candidate === 'string' &&
|
|
275
|
+
!candidate.includes('.min.') &&
|
|
276
|
+
!candidate.includes('.prod.')) {
|
|
277
|
+
return candidate;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} // Si browser field es un objeto, buscar alternativas
|
|
282
|
+
if (packageJson.browser && typeof packageJson.browser === 'object') {
|
|
283
|
+
for (const value of Object.values(packageJson.browser)) {
|
|
284
|
+
if (typeof value === 'string' &&
|
|
285
|
+
!value.includes('.min.') &&
|
|
286
|
+
!value.includes('.prod.') &&
|
|
287
|
+
(value.includes('browser') || value.includes('esm'))) {
|
|
288
|
+
return value;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return devVersion !== entryPoint ? devVersion : null;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* ✨ NUEVA FUNCIÓN: Busca alternativas browser para versiones runtime
|
|
296
|
+
*/
|
|
297
|
+
findBrowserAlternative(entryPoint, packageJson) {
|
|
298
|
+
// Primero intentar con exports
|
|
299
|
+
if (packageJson.exports && typeof packageJson.exports === 'object') {
|
|
300
|
+
const dotExport = packageJson.exports['.'];
|
|
301
|
+
if (dotExport && typeof dotExport === 'object') {
|
|
302
|
+
// Buscar specific browser+esm combinations
|
|
303
|
+
const browserKeys = Object.keys(dotExport).filter(key => key.includes('browser') &&
|
|
304
|
+
(key.includes('esm') || key.includes('module')));
|
|
305
|
+
if (browserKeys.length > 0) {
|
|
306
|
+
const firstBrowserKey = browserKeys[0];
|
|
307
|
+
if (firstBrowserKey &&
|
|
308
|
+
typeof dotExport[firstBrowserKey] === 'string') {
|
|
309
|
+
return dotExport[firstBrowserKey];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Fallback a browser general
|
|
313
|
+
if (dotExport.browser &&
|
|
314
|
+
typeof dotExport.browser === 'string') {
|
|
315
|
+
return dotExport.browser;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Buscar en directorio dist versiones browser
|
|
320
|
+
const baseName = entryPoint.replace(/\.[^/.]+$/, '');
|
|
321
|
+
const browserCandidates = [
|
|
322
|
+
baseName.replace('runtime', 'esm-browser'),
|
|
323
|
+
baseName.replace('runtime', 'browser'),
|
|
324
|
+
baseName.replace('runtime.esm-bundler', 'esm-browser'),
|
|
325
|
+
entryPoint.replace('runtime', 'esm-browser'),
|
|
326
|
+
entryPoint.replace('runtime', 'browser'),
|
|
327
|
+
];
|
|
328
|
+
// Para Vue específicamente
|
|
329
|
+
if (entryPoint.includes('vue.runtime.esm-bundler')) {
|
|
330
|
+
browserCandidates.unshift('dist/vue.esm-browser.js', 'dist/vue.browser.esm.js');
|
|
331
|
+
}
|
|
332
|
+
return (browserCandidates.find(candidate => candidate !== entryPoint) ||
|
|
333
|
+
null);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Busca versión ESM/browser optimizada (simplificada del module-resolver)
|
|
337
|
+
*/
|
|
338
|
+
findOptimalESMVersion(moduleDir, entryPoint) {
|
|
339
|
+
const dir = dirname(entryPoint);
|
|
340
|
+
const baseName = entryPoint.split('/').pop() || '';
|
|
341
|
+
const nameWithoutExt = baseName.replace(/\.[^/.]+$/, '');
|
|
342
|
+
const searchDir = join(moduleDir, dir);
|
|
343
|
+
if (!existsSync(searchDir)) {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
const files = readdirSync(searchDir);
|
|
348
|
+
this.metrics.filesystemAccess++;
|
|
349
|
+
// Patrones de prioridad para versiones optimizadas
|
|
350
|
+
const patterns = [
|
|
351
|
+
`${nameWithoutExt}.esm-browser.js`,
|
|
352
|
+
`${nameWithoutExt}.esm.js`,
|
|
353
|
+
`${nameWithoutExt}.module.js`,
|
|
354
|
+
`${nameWithoutExt}.browser.js`,
|
|
355
|
+
];
|
|
356
|
+
for (const pattern of patterns) {
|
|
357
|
+
if (files.includes(pattern)) {
|
|
358
|
+
return join(dir, pattern);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
// Ignorar errores de filesystem
|
|
364
|
+
}
|
|
365
|
+
return undefined;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Construye el índice de alias optimizado para búsquedas rápidas
|
|
369
|
+
*/
|
|
370
|
+
buildAliasIndex() {
|
|
371
|
+
if (!env.PATH_ALIAS) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
const pathAlias = JSON.parse(env.PATH_ALIAS);
|
|
376
|
+
this.aliasIndex = [];
|
|
377
|
+
// Convertir alias a índice con prioridad
|
|
378
|
+
for (const [alias, target] of Object.entries(pathAlias)) {
|
|
379
|
+
const pattern = alias.replace('/*', '');
|
|
380
|
+
const priority = pattern.length; // Patrones más largos tienen prioridad
|
|
381
|
+
// El regex debe coincidir con el patrón al inicio, seguido de cualquier cosa o fin de cadena
|
|
382
|
+
// Por ejemplo, para "@/" debe coincidir con "@/cualquier-cosa" o solo "@/"
|
|
383
|
+
this.aliasIndex.push({
|
|
384
|
+
pattern,
|
|
385
|
+
target: Array.isArray(target) ? target : [target],
|
|
386
|
+
regex: new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
|
|
387
|
+
priority,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// Ordenar por prioridad (patrones más largos primero)
|
|
391
|
+
this.aliasIndex.sort((a, b) => b.priority - a.priority);
|
|
392
|
+
if (env.VERBOSE === 'true') {
|
|
393
|
+
logger.info(`🔗 Índice de alias construido: ${this.aliasIndex.length} patrones`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
logger.error('Error construyendo índice de alias:', error);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Resuelve un módulo utilizando el sistema optimizado
|
|
402
|
+
*/
|
|
403
|
+
async resolveModule(moduleName, fromFile) {
|
|
404
|
+
const startTime = performance.now();
|
|
405
|
+
this.metrics.totalResolutions++;
|
|
406
|
+
// Verificar si está excluido
|
|
407
|
+
if (this.excludedModules.has(moduleName)) {
|
|
408
|
+
return {
|
|
409
|
+
path: null,
|
|
410
|
+
cached: false,
|
|
411
|
+
resolveTime: performance.now() - startTime,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
// Crear clave de caché
|
|
415
|
+
const cacheKey = this.createCacheKey(moduleName, fromFile);
|
|
416
|
+
// Verificar caché
|
|
417
|
+
const cached = this.getFromCache(cacheKey);
|
|
418
|
+
if (cached !== undefined) {
|
|
419
|
+
this.metrics.cacheHits++;
|
|
420
|
+
return {
|
|
421
|
+
path: cached,
|
|
422
|
+
cached: true,
|
|
423
|
+
resolveTime: performance.now() - startTime,
|
|
424
|
+
fromCache: true,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
this.metrics.cacheMisses++;
|
|
428
|
+
// Resolver módulo
|
|
429
|
+
let resolvedPath = null;
|
|
430
|
+
try {
|
|
431
|
+
// 1. Verificar si es subpath de módulo (ej: 'vue/dist/vue.esm-bundler')
|
|
432
|
+
if (moduleName.includes('/')) {
|
|
433
|
+
resolvedPath = await this.resolveSubPath(moduleName);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
// 2. Búsqueda O(1) en el índice
|
|
437
|
+
resolvedPath = this.resolveFromIndex(moduleName);
|
|
438
|
+
}
|
|
439
|
+
// 3. Si no se encuentra en índice, intentar resolución tradicional
|
|
440
|
+
if (!resolvedPath) {
|
|
441
|
+
resolvedPath = this.fallbackResolve(moduleName);
|
|
442
|
+
}
|
|
443
|
+
// Convertir a ruta relativa desde node_modules
|
|
444
|
+
if (resolvedPath) {
|
|
445
|
+
resolvedPath = this.getNodeModulesRelativePath(resolvedPath);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
if (env.VERBOSE === 'true') {
|
|
450
|
+
logger.warn(`Error resolviendo ${moduleName}:`, error);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Guardar en caché
|
|
454
|
+
this.setCache(cacheKey, resolvedPath);
|
|
455
|
+
const resolveTime = performance.now() - startTime;
|
|
456
|
+
this.updateMetrics(resolveTime);
|
|
457
|
+
return {
|
|
458
|
+
path: resolvedPath,
|
|
459
|
+
cached: false,
|
|
460
|
+
resolveTime,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Busca módulo en el índice (O(1))
|
|
465
|
+
*/
|
|
466
|
+
resolveFromIndex(moduleName) {
|
|
467
|
+
this.metrics.indexLookups++;
|
|
468
|
+
const moduleInfo = this.moduleIndex.get(moduleName);
|
|
469
|
+
if (!moduleInfo) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
// Usar versión optimizada si está disponible
|
|
473
|
+
const entryPoint = moduleInfo.optimizedEntry || moduleInfo.entryPoint;
|
|
474
|
+
return join(moduleInfo.fullPath, entryPoint);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Resuelve subpaths de módulos (ej: 'vue/dist/vue.esm-bundler')
|
|
478
|
+
*/
|
|
479
|
+
async resolveSubPath(moduleName) {
|
|
480
|
+
const [packageName, ...subPathParts] = moduleName.split('/');
|
|
481
|
+
const subPath = subPathParts.join('/');
|
|
482
|
+
if (!packageName) {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
this.metrics.indexLookups++;
|
|
486
|
+
const moduleInfo = this.moduleIndex.get(packageName);
|
|
487
|
+
if (!moduleInfo) {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
// Verificar exports field para subpaths
|
|
491
|
+
if (moduleInfo.hasExports && moduleInfo.packageJson.exports) {
|
|
492
|
+
const exportKey = `./${subPath}`;
|
|
493
|
+
const exportPath = moduleInfo.packageJson.exports[exportKey];
|
|
494
|
+
if (exportPath) {
|
|
495
|
+
if (typeof exportPath === 'string') {
|
|
496
|
+
return join(moduleInfo.fullPath, exportPath);
|
|
497
|
+
}
|
|
498
|
+
else if (typeof exportPath === 'object') {
|
|
499
|
+
const importPath = exportPath.import || exportPath.default;
|
|
500
|
+
if (typeof importPath === 'string') {
|
|
501
|
+
return join(moduleInfo.fullPath, importPath);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// Fallback: resolver directamente el subpath
|
|
507
|
+
const directPath = join(moduleInfo.fullPath, subPath);
|
|
508
|
+
if (existsSync(directPath)) {
|
|
509
|
+
this.metrics.filesystemAccess++;
|
|
510
|
+
return directPath;
|
|
511
|
+
}
|
|
512
|
+
// Intentar con extensiones comunes
|
|
513
|
+
const extensions = ['.mjs', '.js', '.cjs'];
|
|
514
|
+
for (const ext of extensions) {
|
|
515
|
+
const pathWithExt = directPath + ext;
|
|
516
|
+
if (existsSync(pathWithExt)) {
|
|
517
|
+
this.metrics.filesystemAccess++;
|
|
518
|
+
return pathWithExt;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Resolución de fallback cuando no se encuentra en índice
|
|
525
|
+
*/
|
|
526
|
+
fallbackResolve(moduleName) {
|
|
527
|
+
const nodeModulesPath = join(cwd(), 'node_modules', moduleName);
|
|
528
|
+
const packagePath = join(nodeModulesPath, 'package.json');
|
|
529
|
+
if (!existsSync(packagePath)) {
|
|
530
|
+
this.metrics.filesystemAccess++;
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
|
|
535
|
+
this.metrics.filesystemAccess++;
|
|
536
|
+
const entryPoint = this.determineOptimalEntryPoint(packageJson) || 'index.js';
|
|
537
|
+
const finalPath = join(nodeModulesPath, entryPoint);
|
|
538
|
+
if (existsSync(finalPath)) {
|
|
539
|
+
this.metrics.filesystemAccess++;
|
|
540
|
+
return finalPath;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
// Ignorar errores
|
|
545
|
+
}
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Encuentra alias que coincida con el path dado
|
|
550
|
+
*/
|
|
551
|
+
findMatchingAlias(path) {
|
|
552
|
+
this.metrics.aliasMatches++;
|
|
553
|
+
for (const alias of this.aliasIndex) {
|
|
554
|
+
if (alias.regex.test(path)) {
|
|
555
|
+
return alias;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
} /**
|
|
560
|
+
* Resuelve un alias a su ruta correspondiente
|
|
561
|
+
*/
|
|
562
|
+
resolveAlias(path) {
|
|
563
|
+
const alias = this.findMatchingAlias(path);
|
|
564
|
+
if (!alias || !env.PATH_DIST) {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
// El relativePath es lo que queda después del pattern
|
|
568
|
+
// Por ejemplo: '@/components/Button.vue' con pattern '@/components' → '/Button.vue'
|
|
569
|
+
const relativePath = path.replace(alias.pattern, '');
|
|
570
|
+
const targetPath = alias.target[0];
|
|
571
|
+
if (!targetPath) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
// Construir ruta final
|
|
575
|
+
let finalPath;
|
|
576
|
+
const pathDist = env.PATH_DIST.replace('./', '');
|
|
577
|
+
// Manejar caso especial: alias exacto sin wildcard (como #config -> config/index.js)
|
|
578
|
+
if (relativePath === '' && !targetPath.includes('*')) {
|
|
579
|
+
// Es un alias exacto, usar el target tal como está
|
|
580
|
+
if (targetPath.startsWith('/')) {
|
|
581
|
+
finalPath = join('/', pathDist, targetPath.substring(1));
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
const cleanTarget = targetPath.replace('./', '');
|
|
585
|
+
if (cleanTarget.startsWith('src/')) {
|
|
586
|
+
const targetWithoutSrc = cleanTarget.replace('src/', '');
|
|
587
|
+
finalPath = join('/', pathDist, targetWithoutSrc);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
finalPath = join('/', pathDist, cleanTarget);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
else if (targetPath.startsWith('/')) {
|
|
595
|
+
// Si el target empieza con /, es una ruta absoluta desde la raíz del proyecto
|
|
596
|
+
// Extraer la parte del target después de /src
|
|
597
|
+
const targetWithoutSlash = targetPath
|
|
598
|
+
.substring(1)
|
|
599
|
+
.replace('/*', '');
|
|
600
|
+
// El target puede ser:
|
|
601
|
+
// - "/src/*" → queremos mapear a "/dist/*"
|
|
602
|
+
// - "/src/components/*" → queremos mapear a "/dist/components/*"
|
|
603
|
+
if (targetWithoutSlash === 'src') {
|
|
604
|
+
// Para "/src/*", mapear directamente a "/pathDist/relativePath"
|
|
605
|
+
finalPath = join('/', pathDist, relativePath);
|
|
606
|
+
}
|
|
607
|
+
else if (targetWithoutSlash.startsWith('src/')) {
|
|
608
|
+
// Para "/src/components/*", extraer "components" y usarlo
|
|
609
|
+
// targetWithoutSlash = 'src/components'
|
|
610
|
+
// Queremos: 'components'
|
|
611
|
+
const targetSubpath = targetWithoutSlash.replace(/^src\/?/, '');
|
|
612
|
+
// relativePath ya incluye la barra inicial
|
|
613
|
+
finalPath = join('/', pathDist, targetSubpath, relativePath);
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
// Para otros casos como "/examples/*"
|
|
617
|
+
finalPath = join('/', pathDist, targetWithoutSlash, relativePath);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
// Si es una ruta relativa, construir basándose en el target
|
|
622
|
+
const cleanTarget = targetPath.replace('./', '').replace('/*', '');
|
|
623
|
+
// Si el target ya incluye el directorio de distribución, no duplicar
|
|
624
|
+
if (cleanTarget === pathDist) {
|
|
625
|
+
finalPath = join('/', pathDist, relativePath);
|
|
626
|
+
}
|
|
627
|
+
else if (cleanTarget.startsWith(pathDist + '/')) {
|
|
628
|
+
// Si el target ya contiene PATH_DIST como prefijo
|
|
629
|
+
finalPath = join('/', cleanTarget, relativePath);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
// Caso normal: mapear manteniendo la estructura relativa al target
|
|
633
|
+
if (cleanTarget.startsWith('src/')) {
|
|
634
|
+
// Para "src/components/*" -> "/pathDist/components/*"
|
|
635
|
+
const targetWithoutSrc = cleanTarget.replace('src/', '');
|
|
636
|
+
finalPath = join('/', pathDist, targetWithoutSrc, relativePath);
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
// Para casos como "examples/*" -> "/pathDist/*"
|
|
640
|
+
// No incluir el directorio raíz en la ruta final
|
|
641
|
+
const isRootDirectory = [
|
|
642
|
+
'examples',
|
|
643
|
+
'src',
|
|
644
|
+
'app',
|
|
645
|
+
'lib',
|
|
646
|
+
].includes(cleanTarget);
|
|
647
|
+
if (isRootDirectory) {
|
|
648
|
+
finalPath = join('/', pathDist, relativePath);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
// Para subdirectorios específicos, mantener la estructura
|
|
652
|
+
finalPath = join('/', pathDist, cleanTarget, relativePath);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return finalPath.replace(/\\/g, '/');
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Gestión de caché LRU
|
|
661
|
+
*/
|
|
662
|
+
getFromCache(key) {
|
|
663
|
+
const entry = this.resolutionCache.get(key);
|
|
664
|
+
if (!entry) {
|
|
665
|
+
return undefined;
|
|
666
|
+
}
|
|
667
|
+
// Verificar expiración
|
|
668
|
+
if (Date.now() - entry.timestamp > this.cacheMaxAge) {
|
|
669
|
+
this.resolutionCache.delete(key);
|
|
670
|
+
this.cacheOrder = this.cacheOrder.filter(k => k !== key);
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
// Actualizar orden LRU
|
|
674
|
+
entry.hits++;
|
|
675
|
+
this.cacheOrder = this.cacheOrder.filter(k => k !== key);
|
|
676
|
+
this.cacheOrder.push(key);
|
|
677
|
+
return entry.result;
|
|
678
|
+
}
|
|
679
|
+
setCache(key, result) {
|
|
680
|
+
// Implementar límite de caché LRU
|
|
681
|
+
if (this.resolutionCache.size >= this.maxCacheSize) {
|
|
682
|
+
const oldestKey = this.cacheOrder.shift();
|
|
683
|
+
if (oldestKey) {
|
|
684
|
+
this.resolutionCache.delete(oldestKey);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
this.resolutionCache.set(key, {
|
|
688
|
+
result,
|
|
689
|
+
timestamp: Date.now(),
|
|
690
|
+
hits: 0,
|
|
691
|
+
});
|
|
692
|
+
this.cacheOrder.push(key);
|
|
693
|
+
}
|
|
694
|
+
createCacheKey(moduleName, fromFile) {
|
|
695
|
+
const hash = createHash('md5');
|
|
696
|
+
hash.update(moduleName);
|
|
697
|
+
if (fromFile) {
|
|
698
|
+
hash.update(fromFile);
|
|
699
|
+
}
|
|
700
|
+
return hash.digest('hex');
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Convierte ruta absoluta a ruta relativa desde node_modules
|
|
704
|
+
*/
|
|
705
|
+
getNodeModulesRelativePath(fullPath) {
|
|
706
|
+
const idx = fullPath.indexOf('node_modules');
|
|
707
|
+
if (idx !== -1) {
|
|
708
|
+
return '/' + fullPath.substring(idx).replace(/\\/g, '/');
|
|
709
|
+
}
|
|
710
|
+
// Para rutas que no están en node_modules
|
|
711
|
+
const rel = relative(cwd(), fullPath).replace(/\\/g, '/');
|
|
712
|
+
return rel.startsWith('/') ? rel : '/' + rel;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Actualiza métricas de rendimiento
|
|
716
|
+
*/
|
|
717
|
+
updateMetrics(resolveTime) {
|
|
718
|
+
this.metrics.averageResolveTime =
|
|
719
|
+
(this.metrics.averageResolveTime *
|
|
720
|
+
(this.metrics.totalResolutions - 1) +
|
|
721
|
+
resolveTime) /
|
|
722
|
+
this.metrics.totalResolutions;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Configura actualización periódica de índices
|
|
726
|
+
*/
|
|
727
|
+
setupPeriodicRefresh() {
|
|
728
|
+
setInterval(() => {
|
|
729
|
+
if (Date.now() - this.lastIndexUpdate > this.indexRefreshInterval) {
|
|
730
|
+
if (env.VERBOSE === 'true') {
|
|
731
|
+
logger.info('🔄 Actualizando índices de resolución de módulos');
|
|
732
|
+
}
|
|
733
|
+
this.refreshIndexes();
|
|
734
|
+
}
|
|
735
|
+
}, this.indexRefreshInterval);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Actualiza los índices manteniendo el caché válido
|
|
739
|
+
*/
|
|
740
|
+
refreshIndexes() {
|
|
741
|
+
try {
|
|
742
|
+
const oldSize = this.moduleIndex.size;
|
|
743
|
+
this.buildModuleIndex();
|
|
744
|
+
this.buildAliasIndex();
|
|
745
|
+
this.lastIndexUpdate = Date.now();
|
|
746
|
+
if (env.VERBOSE === 'true') {
|
|
747
|
+
logger.info(`📚 Índices actualizados: ${oldSize} → ${this.moduleIndex.size} módulos`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
logger.error('Error actualizando índices:', error);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Limpia caché expirado
|
|
756
|
+
*/
|
|
757
|
+
clearExpiredCache() {
|
|
758
|
+
const now = Date.now();
|
|
759
|
+
const keysToDelete = [];
|
|
760
|
+
for (const [key, entry] of this.resolutionCache.entries()) {
|
|
761
|
+
if (now - entry.timestamp > this.cacheMaxAge) {
|
|
762
|
+
keysToDelete.push(key);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
for (const key of keysToDelete) {
|
|
766
|
+
this.resolutionCache.delete(key);
|
|
767
|
+
this.cacheOrder = this.cacheOrder.filter(k => k !== key);
|
|
768
|
+
}
|
|
769
|
+
if (env.VERBOSE === 'true' && keysToDelete.length > 0) {
|
|
770
|
+
logger.info(`🧹 Limpiado caché expirado: ${keysToDelete.length} entradas`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Obtiene métricas de rendimiento
|
|
775
|
+
*/
|
|
776
|
+
getMetrics() {
|
|
777
|
+
return {
|
|
778
|
+
...this.metrics,
|
|
779
|
+
cacheSize: this.resolutionCache.size,
|
|
780
|
+
moduleIndexSize: this.moduleIndex.size,
|
|
781
|
+
aliasIndexSize: this.aliasIndex.length,
|
|
782
|
+
cacheHitRate: this.metrics.totalResolutions > 0
|
|
783
|
+
? (this.metrics.cacheHits / this.metrics.totalResolutions) *
|
|
784
|
+
100
|
|
785
|
+
: 0,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Resetea métricas de rendimiento
|
|
790
|
+
*/
|
|
791
|
+
resetMetrics() {
|
|
792
|
+
this.metrics = {
|
|
793
|
+
totalResolutions: 0,
|
|
794
|
+
cacheHits: 0,
|
|
795
|
+
cacheMisses: 0,
|
|
796
|
+
averageResolveTime: 0,
|
|
797
|
+
indexLookups: 0,
|
|
798
|
+
filesystemAccess: 0,
|
|
799
|
+
aliasMatches: 0,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Forzar reconstrucción de índices
|
|
804
|
+
*/
|
|
805
|
+
forceRefresh() {
|
|
806
|
+
this.initializeIndexes();
|
|
807
|
+
this.resolutionCache.clear();
|
|
808
|
+
this.cacheOrder = [];
|
|
809
|
+
if (env.VERBOSE === 'true') {
|
|
810
|
+
logger.info('🔄 Índices de resolución reconstruidos forzosamente');
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Limpia todos los cachés y índices
|
|
815
|
+
*/
|
|
816
|
+
cleanup() {
|
|
817
|
+
this.moduleIndex.clear();
|
|
818
|
+
this.resolutionCache.clear();
|
|
819
|
+
this.cacheOrder = [];
|
|
820
|
+
this.aliasIndex = [];
|
|
821
|
+
this.nodeModulesCache.clear();
|
|
822
|
+
if (env.VERBOSE === 'true') {
|
|
823
|
+
logger.info('🧹 Sistema de resolución de módulos limpiado');
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
// Funciones de compatibilidad con el sistema existente
|
|
828
|
+
export async function getOptimizedModulePath(moduleName, fromFile) {
|
|
829
|
+
const optimizer = ModuleResolutionOptimizer.getInstance();
|
|
830
|
+
const result = await optimizer.resolveModule(moduleName, fromFile);
|
|
831
|
+
return result.path;
|
|
832
|
+
}
|
|
833
|
+
export function getOptimizedAliasPath(path) {
|
|
834
|
+
const optimizer = ModuleResolutionOptimizer.getInstance();
|
|
835
|
+
return optimizer.resolveAlias(path);
|
|
836
|
+
}
|
|
837
|
+
export function getModuleResolutionMetrics() {
|
|
838
|
+
const optimizer = ModuleResolutionOptimizer.getInstance();
|
|
839
|
+
return optimizer.getMetrics();
|
|
840
|
+
}
|
|
841
|
+
export function resetModuleResolutionOptimizer() {
|
|
842
|
+
ModuleResolutionOptimizer.resetInstance();
|
|
843
|
+
}
|
|
844
|
+
//# sourceMappingURL=module-resolution-optimizer.js.map
|