versacompiler 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +70 -54
  2. package/dist/compiler/compile-worker-pool.js +12 -0
  3. package/dist/compiler/compile.js +102 -17
  4. package/dist/compiler/error-reporter.js +12 -0
  5. package/dist/compiler/integrity-validator.js +12 -0
  6. package/dist/compiler/linter.js +12 -0
  7. package/dist/compiler/minify.js +12 -0
  8. package/dist/compiler/minifyTemplate.js +12 -0
  9. package/dist/compiler/module-resolution-optimizer.js +13 -1
  10. package/dist/compiler/parser.js +12 -0
  11. package/dist/compiler/performance-monitor.js +12 -0
  12. package/dist/compiler/pipeline/build-pipeline.js +12 -0
  13. package/dist/compiler/pipeline/core-plugins.js +12 -0
  14. package/dist/compiler/pipeline/module-graph.js +12 -0
  15. package/dist/compiler/pipeline/plugin-driver.js +12 -0
  16. package/dist/compiler/pipeline/types.js +12 -0
  17. package/dist/compiler/tailwindcss.js +12 -0
  18. package/dist/compiler/transform-optimizer.js +12 -0
  19. package/dist/compiler/transformTStoJS.js +38 -5
  20. package/dist/compiler/transforms.js +12 -0
  21. package/dist/compiler/typescript-compiler.js +12 -0
  22. package/dist/compiler/typescript-error-parser.js +12 -0
  23. package/dist/compiler/typescript-manager.js +12 -0
  24. package/dist/compiler/typescript-sync-validator.js +12 -0
  25. package/dist/compiler/typescript-worker-pool.js +12 -0
  26. package/dist/compiler/typescript-worker.js +12 -0
  27. package/dist/compiler/vuejs.js +41 -15
  28. package/dist/config.js +12 -0
  29. package/dist/hrm/VueHRM.js +132 -7
  30. package/dist/hrm/errorScreen.js +12 -0
  31. package/dist/hrm/getInstanciaVue.js +12 -0
  32. package/dist/hrm/initHRM.js +117 -9
  33. package/dist/hrm/versaHMR.js +317 -0
  34. package/dist/main.js +9 -2
  35. package/dist/servicios/browserSync.js +119 -4
  36. package/dist/servicios/file-watcher.js +104 -15
  37. package/dist/servicios/logger.js +12 -0
  38. package/dist/servicios/readConfig.js +13 -1
  39. package/dist/servicios/versacompile.config.types.js +12 -0
  40. package/dist/utils/excluded-modules.js +12 -0
  41. package/dist/utils/module-resolver.js +12 -0
  42. package/dist/utils/promptUser.js +12 -0
  43. package/dist/utils/proxyValidator.js +12 -0
  44. package/dist/utils/resolve-bin.js +12 -0
  45. package/dist/utils/utils.js +12 -0
  46. package/dist/utils/vue-types-setup.js +14 -2
  47. package/dist/wrappers/eslint-node.js +12 -0
  48. package/dist/wrappers/oxlint-node.js +12 -0
  49. package/dist/wrappers/tailwind-node.js +12 -0
  50. package/package.json +4 -3
@@ -1,3 +1,15 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
1
13
  /**
2
14
  * @fileoverview Inicialización del sistema Hot Module Replacement (HMR) para VersaCompiler
3
15
  * Este archivo maneja la conexión con BrowserSync y configura los listeners para HMR de Vue
@@ -11,6 +23,9 @@
11
23
 
12
24
  import { hideErrorOverlay, showErrorOverlay } from './errorScreen.js';
13
25
  import { obtenerInstanciaVue } from './getInstanciaVue.js';
26
+
27
+ // oxlint-disable-next-line import/no-unassigned-import -- side-effect: inicializa window.__versaHMR
28
+ import './versaHMR.js';
14
29
  import { reloadComponent } from './VueHRM.js';
15
30
 
16
31
  /**
@@ -343,6 +358,27 @@ async function initSocket(retries = 0) {
343
358
  socket.on('reloadFull', () => window.location.reload()); // Obtener la instancia de Vue con toda la lógica integrada
344
359
  let vueInstance = await obtenerInstanciaVue();
345
360
 
361
+ // Exponer función de recarga Vue por path para que los shims de módulos
362
+ // puedan disparar una actualización de instancia Vue cuando una dependencia
363
+ // (sampleFile.js, etc.) se actualiza vía HMR propagation.
364
+ if (window.__versaHMR) {
365
+ window.__versaHMR._reloadVueByPath = async path => {
366
+ try {
367
+ vueInstance = window.__VUE_APP__ || vueInstance;
368
+ // normalizedPath sin slash inicial (reloadComponent usa origin + '/' + path)
369
+ const normalizedPath = path.replace(/^\//, '');
370
+ const nameFile =
371
+ path.split('/').pop()?.replace('.js', '') ?? '';
372
+ await reloadComponent(vueInstance, {
373
+ normalizedPath,
374
+ nameFile,
375
+ });
376
+ } catch (err) {
377
+ console.error('❌ _reloadVueByPath failed:', err);
378
+ }
379
+ };
380
+ }
381
+
346
382
  // Configurar listener para HMR de componentes Vue
347
383
  socket.on('HRMVue', async (/** @type {ComponentInfo} */ data) => {
348
384
  try {
@@ -372,12 +408,31 @@ async function initSocket(retries = 0) {
372
408
  console.log('🔄 HRMHelper recibido:', data);
373
409
  console.log('📋 Archivo modificado:', data.filePath);
374
410
 
411
+ // moduleId: identificador canónico del módulo en el registry
412
+ // El servidor lo envía como el path del output (ej: /public/utils/math.js)
413
+ const moduleId = data.moduleId || data.filePath;
414
+
375
415
  if (data?.strategy) {
376
416
  switch (data.strategy) {
377
417
  case 'self-accept': {
418
+ // El módulo acepta su propio reemplazo (import.meta.hot.accept)
378
419
  try {
379
420
  const timestamp = Date.now();
380
- await import(`${data.filePath}?t=${timestamp}`);
421
+ // Usar moduleId (path absoluto con /) en lugar de data.filePath (relativo)
422
+ // data.filePath relativo resuelve mal desde /__versa/initHRM.js
423
+ const newModule = await import(
424
+ `${moduleId}?t=${timestamp}`
425
+ );
426
+ // También notificar al registry por si hay consumers adicionales
427
+ const registry = window.__versaHMR;
428
+ if (registry && registry.hasObservers(moduleId)) {
429
+ const exportedValue =
430
+ newModule.default !== undefined
431
+ ? newModule.default
432
+ : newModule;
433
+ registry.notifyUpdate(moduleId, exportedValue);
434
+ }
435
+ console.log(`✅ Self-accept HMR: ${moduleId}`);
381
436
  return;
382
437
  } catch (error) {
383
438
  reportErrorToServer(
@@ -391,9 +446,48 @@ async function initSocket(retries = 0) {
391
446
  break;
392
447
  }
393
448
  case 'propagate': {
449
+ // Re-importar el módulo con cache-bust y notificar al registry
394
450
  try {
395
451
  const timestamp = Date.now();
396
- await import(`${data.filePath}?t=${timestamp}`);
452
+ // Usar moduleId (path absoluto con /) en lugar de data.filePath (relativo)
453
+ // data.filePath relativo resuelve mal desde /__versa/initHRM.js
454
+ const newModule = await import(
455
+ `${moduleId}?t=${timestamp}`
456
+ );
457
+
458
+ // Extraer el valor exportado (default o namespace)
459
+ const exportedValue =
460
+ newModule.default !== undefined
461
+ ? newModule.default
462
+ : newModule;
463
+
464
+ // Notificar al registry de VersaHMR si hay observers registrados
465
+ const registry = window.__versaHMR;
466
+ if (registry && registry.hasObservers(moduleId)) {
467
+ const notified = registry.notifyUpdate(
468
+ moduleId,
469
+ exportedValue,
470
+ );
471
+ if (notified) {
472
+ console.log(
473
+ `✅ HMR sin recarga: ${moduleId} actualizado via registry`,
474
+ );
475
+ return;
476
+ }
477
+ // Si los callbacks fallaron, hacer full-reload como safety net
478
+ console.warn(
479
+ `⚠️ Callbacks del registry fallaron para ${moduleId}, haciendo full-reload`,
480
+ );
481
+ window.location.reload();
482
+ return;
483
+ }
484
+
485
+ // Sin observers en registry → la re-importación ya actualizó
486
+ // el módulo en el scope de ES modules del browser.
487
+ // Los consumers que hicieron import dinámico obtendrán la nueva versión.
488
+ console.log(
489
+ `✅ HMR propagado: ${moduleId} (sin observers en registry, re-import completado)`,
490
+ );
397
491
  return;
398
492
  } catch (error) {
399
493
  reportErrorToServer(
@@ -403,8 +497,10 @@ async function initSocket(retries = 0) {
403
497
  : new Error(String(error)),
404
498
  data,
405
499
  );
500
+ // Fallback a full-reload en caso de error
501
+ window.location.reload();
502
+ return;
406
503
  }
407
- break;
408
504
  }
409
505
  case 'full-reload':
410
506
  default: {
@@ -453,18 +549,30 @@ async function initSocket(retries = 0) {
453
549
  break;
454
550
 
455
551
  case 'propagate':
456
- // Propagar la actualización a los importadores
552
+ // Propagar la actualización: re-importar y notificar al registry
457
553
  console.log(
458
554
  '🔄 Propagando actualización a importadores',
459
555
  );
460
556
  try {
461
- // Invalidar el módulo en el cache del navegador
462
- // y dejar que los importadores se actualicen
463
557
  const timestamp = Date.now();
464
- await import(`${data.filePath}?t=${timestamp}`);
465
- console.log(
466
- '✅ Actualización propagada exitosamente',
558
+ const newModule = await import(
559
+ `${data.filePath}?t=${timestamp}`
467
560
  );
561
+ const exportedValue =
562
+ newModule.default !== undefined
563
+ ? newModule.default
564
+ : newModule;
565
+ const registry = window.__versaHMR;
566
+ if (registry && registry.hasObservers(moduleId)) {
567
+ registry.notifyUpdate(moduleId, exportedValue);
568
+ console.log(
569
+ '✅ Actualización propagada via registry',
570
+ );
571
+ } else {
572
+ console.log(
573
+ '✅ Re-import completado (sin observers en registry)',
574
+ );
575
+ }
468
576
  return;
469
577
  } catch (error) {
470
578
  console.error(
@@ -0,0 +1,317 @@
1
+ /* VersaCompiler HMR shim [dev] */
2
+ if (typeof window !== 'undefined' && window.__versaHMR) {
3
+ (() => {
4
+ const _id = new URL(import.meta.url).pathname;
5
+ import.meta.hot = {
6
+ accept(cb) { window.__versaHMR.accept(_id, typeof cb === 'function' ? cb : () => {}); },
7
+ invalidate() { window.__versaHMR._invalidate?.(_id); },
8
+ dispose(cb) { window.__versaHMR._onDispose?.(_id, cb); },
9
+ get data() { return window.__versaHMR._getHotData?.(_id) ?? {}; },
10
+ };
11
+ })();
12
+ }
13
+ /**
14
+ * @fileoverview VersaHMR — Registry de módulos para Hot Module Replacement
15
+ *
16
+ * Permite que librerías y utilidades JS/TS reciban actualizaciones sin full-reload.
17
+ *
18
+ * Uso básico (en cualquier módulo que consuma una librería):
19
+ *
20
+ * window.__versaHMR.accept('/public/utils/math.js', (newModule) => {
21
+ * // Recibir la nueva versión y actualizar referencias locales
22
+ * mathLib = newModule;
23
+ * });
24
+ *
25
+ * Uso automático (para módulos que solo exportan funciones/constantes):
26
+ * El sistema detecta automáticamente si es seguro hacer HMR y llama a los callbacks.
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} ModuleEntry
31
+ * @property {any} module - La instancia actual del módulo
32
+ * @property {Set<Function>} callbacks - Callbacks registrados para actualizaciones
33
+ * @property {number} version - Versión (incrementa en cada update)
34
+ */
35
+
36
+ class VersaModuleRegistry {
37
+ constructor() {
38
+ /** @type {Map<string, ModuleEntry>} */
39
+ this._registry = new Map();
40
+
41
+ /** @type {Map<string, Set<string>>} Árbol inverso: módulo → quién lo importa */
42
+ this._importers = new Map();
43
+
44
+ /** @type {Set<string>} Módulos que han fallado al actualizarse */
45
+ this._failedUpdates = new Set();
46
+
47
+ /** @type {Map<string, Set<Function>>} Callbacks de cleanup por módulo */
48
+ this._disposeCallbacks = new Map();
49
+
50
+ /** @type {Map<string, Object>} Datos persistentes entre ciclos HMR */
51
+ this._hotData = new Map();
52
+ }
53
+
54
+ /**
55
+ * Normaliza un moduleId para uso como clave en el registry.
56
+ * Elimina query params y asegura formato consistente.
57
+ * @param {string} moduleId
58
+ * @returns {string}
59
+ */
60
+ _normalizeId(moduleId) {
61
+ try {
62
+ // Si es una URL relativa, la convertimos a pathname limpio
63
+ const url = new URL(moduleId, window.location.origin);
64
+ return url.pathname;
65
+ } catch {
66
+ return moduleId.split('?')[0];
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Registra un callback para recibir actualizaciones de un módulo.
72
+ * El callback se llama con (newModule, { moduleId, version }) cuando el módulo cambia.
73
+ *
74
+ * @param {string} moduleId - Path/URL del módulo a observar (ej: '/public/utils/math.js')
75
+ * @param {Function} updateCallback - Función llamada cuando el módulo cambia
76
+ * @returns {Function} Función para cancelar el registro (unsubscribe)
77
+ */
78
+ accept(moduleId, updateCallback) {
79
+ const id = this._normalizeId(moduleId);
80
+
81
+ if (!this._registry.has(id)) {
82
+ this._registry.set(id, {
83
+ module: null,
84
+ callbacks: new Set(),
85
+ version: 0,
86
+ });
87
+ }
88
+
89
+ const entry = this._registry.get(id);
90
+ entry.callbacks.add(updateCallback);
91
+
92
+ console.log(`[VersaHMR] Registrado observer para: ${id}`);
93
+
94
+ // Retornar función de cleanup
95
+ return () => {
96
+ const e = this._registry.get(id);
97
+ if (e) {
98
+ e.callbacks.delete(updateCallback);
99
+ if (e.callbacks.size === 0) {
100
+ this._registry.delete(id);
101
+ console.log(`[VersaHMR] Registry limpiado para: ${id}`);
102
+ }
103
+ }
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Notifica a todos los observers registrados que un módulo fue actualizado.
109
+ * Llamado internamente por el handler de HRMHelper cuando recibe un nuevo módulo.
110
+ *
111
+ * @param {string} moduleId - Path del módulo actualizado
112
+ * @param {any} newModule - La nueva instancia del módulo exportado
113
+ * @returns {boolean} true si había al menos un observer y todos ejecutaron sin error
114
+ */
115
+ notifyUpdate(moduleId, newModule) {
116
+ const id = this._normalizeId(moduleId);
117
+ const entry = this._registry.get(id);
118
+
119
+ if (!entry || entry.callbacks.size === 0) {
120
+ return false;
121
+ }
122
+
123
+ // Ejecutar dispose callbacks antes de actualizar
124
+ this._runDispose(id);
125
+
126
+ entry.version++;
127
+ entry.module = newModule;
128
+ const meta = { moduleId: id, version: entry.version };
129
+
130
+ let allSucceeded = true;
131
+
132
+ for (const callback of entry.callbacks) {
133
+ try {
134
+ callback(newModule, meta);
135
+ } catch (err) {
136
+ console.error(
137
+ `[VersaHMR] Error en callback de update para ${id}:`,
138
+ err,
139
+ );
140
+ allSucceeded = false;
141
+ this._failedUpdates.add(id);
142
+ }
143
+ }
144
+
145
+ if (allSucceeded) {
146
+ this._failedUpdates.delete(id);
147
+ console.log(
148
+ `[VersaHMR] ✅ Módulo actualizado (v${entry.version}): ${id} — ${entry.callbacks.size} observer(s) notificado(s)`,
149
+ );
150
+ }
151
+
152
+ return allSucceeded;
153
+ }
154
+
155
+ /**
156
+ * Registra la relación de importación entre módulos.
157
+ * Esto permite propagación en cadena cuando cambia un módulo.
158
+ *
159
+ * @param {string} importer - Path del módulo que importa
160
+ * @param {string} imported - Path del módulo importado
161
+ */
162
+ registerImporter(importer, imported) {
163
+ const importedId = this._normalizeId(imported);
164
+ const importerId = this._normalizeId(importer);
165
+
166
+ if (!this._importers.has(importedId)) {
167
+ this._importers.set(importedId, new Set());
168
+ }
169
+ this._importers.get(importedId).add(importerId);
170
+ }
171
+
172
+ /**
173
+ * Obtiene el módulo actual registrado (si fue cargado via notifyUpdate).
174
+ * @param {string} moduleId
175
+ * @returns {any | null}
176
+ */
177
+ getModule(moduleId) {
178
+ const id = this._normalizeId(moduleId);
179
+ return this._registry.get(id)?.module ?? null;
180
+ }
181
+
182
+ /**
183
+ * Registra un callback de dispose que se ejecuta antes de que el módulo
184
+ * sea reemplazado. Permite cleanup de timers, event listeners, etc.
185
+ * Expuesto como import.meta.hot.dispose(cb) en el shim de HMR.
186
+ *
187
+ * @param {string} moduleId
188
+ * @param {Function} cb - Llamado con (data) donde data = _getHotData(moduleId)
189
+ */
190
+ _onDispose(moduleId, cb) {
191
+ const id = this._normalizeId(moduleId);
192
+ if (!this._disposeCallbacks.has(id)) {
193
+ this._disposeCallbacks.set(id, new Set());
194
+ }
195
+ this._disposeCallbacks.get(id).add(cb);
196
+ }
197
+
198
+ /**
199
+ * Retorna el objeto de datos persistentes de un módulo.
200
+ * El objeto sobrevive entre ciclos HMR para preservar estado local.
201
+ * Expuesto como import.meta.hot.data en el shim de HMR.
202
+ *
203
+ * @param {string} moduleId
204
+ * @returns {Object}
205
+ */
206
+ _getHotData(moduleId) {
207
+ const id = this._normalizeId(moduleId);
208
+ if (!this._hotData.has(id)) {
209
+ this._hotData.set(id, {});
210
+ }
211
+ return this._hotData.get(id);
212
+ }
213
+
214
+ /**
215
+ * Ejecuta los callbacks de dispose antes de un update HMR.
216
+ * Llamado internamente desde notifyUpdate antes de notificar observers.
217
+ *
218
+ * @param {string} moduleId
219
+ */
220
+ _runDispose(moduleId) {
221
+ const id = this._normalizeId(moduleId);
222
+ const disposers = this._disposeCallbacks.get(id);
223
+ if (!disposers || disposers.size === 0) return;
224
+
225
+ const data = this._getHotData(id);
226
+ for (const cb of disposers) {
227
+ try {
228
+ cb(data);
229
+ } catch (err) {
230
+ console.error(
231
+ `[VersaHMR] Error en dispose callback para ${id}:`,
232
+ err,
233
+ );
234
+ }
235
+ }
236
+ this._disposeCallbacks.delete(id);
237
+ }
238
+
239
+ /**
240
+ * Invalida un módulo: ejecuta dispose callbacks y fuerza recarga de página.
241
+ * Expuesto como import.meta.hot.invalidate() en el shim de HMR.
242
+ *
243
+ * @param {string} moduleId
244
+ */
245
+ _invalidate(moduleId) {
246
+ const id = this._normalizeId(moduleId);
247
+
248
+ // Ejecutar dispose callbacks antes de invalidar
249
+ this._runDispose(id);
250
+
251
+ // Limpiar estado del módulo
252
+ this._hotData.delete(id);
253
+ this._registry.delete(id);
254
+
255
+ console.log(
256
+ `[VersaHMR] Módulo invalidado: ${id} — forzando recarga completa`,
257
+ );
258
+ window.location.reload();
259
+ }
260
+
261
+ /**
262
+ * Indica si un módulo tiene observers registrados (puede hacer HMR).
263
+ * @param {string} moduleId
264
+ * @returns {boolean}
265
+ */
266
+ hasObservers(moduleId) {
267
+ const id = this._normalizeId(moduleId);
268
+ const entry = this._registry.get(id);
269
+ return !!(entry && entry.callbacks.size > 0);
270
+ }
271
+
272
+ /**
273
+ * Indica si un módulo tuvo fallos en el último update.
274
+ * @param {string} moduleId
275
+ * @returns {boolean}
276
+ */
277
+ hasFailed(moduleId) {
278
+ return this._failedUpdates.has(this._normalizeId(moduleId));
279
+ }
280
+
281
+ /**
282
+ * Limpia todos los registros (útil para tests o hot-reload del propio sistema).
283
+ */
284
+ clear() {
285
+ this._registry.clear();
286
+ this._importers.clear();
287
+ this._failedUpdates.clear();
288
+ this._disposeCallbacks.clear();
289
+ this._hotData.clear();
290
+ }
291
+
292
+ /**
293
+ * Estadísticas del registry (para debugging).
294
+ * @returns {{ modules: number, totalObservers: number, failedModules: number }}
295
+ */
296
+ getStats() {
297
+ let totalObservers = 0;
298
+ for (const entry of this._registry.values()) {
299
+ totalObservers += entry.callbacks.size;
300
+ }
301
+ return {
302
+ modules: this._registry.size,
303
+ totalObservers,
304
+ failedModules: this._failedUpdates.size,
305
+ };
306
+ }
307
+ }
308
+
309
+ // Singleton global expuesto en window.__versaHMR
310
+ // Se preserva entre recargas parciales para no perder observers
311
+ if (!window.__versaHMR) {
312
+ window.__versaHMR = new VersaModuleRegistry();
313
+ console.log('[VersaHMR] Registry inicializado');
314
+ }
315
+
316
+ export const versaHMR = window.__versaHMR;
317
+ export default versaHMR;
package/dist/main.js CHANGED
@@ -259,6 +259,13 @@ async function main() {
259
259
  try {
260
260
  // Verificar si el archivo existe
261
261
  await fs.access(file);
262
+ }
263
+ catch {
264
+ logger.error(chalk.red(`❌ El archivo '${file}' no existe.`));
265
+ hasErrors = true;
266
+ continue;
267
+ }
268
+ try {
262
269
  logger.info(chalk.blue(`🔄 Compilando: ${file}`));
263
270
  const result = await compileFile(file);
264
271
  if (result.success) {
@@ -269,8 +276,8 @@ async function main() {
269
276
  hasErrors = true;
270
277
  }
271
278
  }
272
- catch {
273
- logger.error(chalk.red(`❌ El archivo '${file}' no existe.`));
279
+ catch (err) {
280
+ logger.error(chalk.red(`❌ Error al compilar '${file}': ${err instanceof Error ? err.message : String(err)}`));
274
281
  hasErrors = true;
275
282
  }
276
283
  }