versacompiler 2.4.1 → 2.6.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.
Files changed (52) hide show
  1. package/README.md +722 -722
  2. package/dist/compiler/compile-worker-pool.js +108 -0
  3. package/dist/compiler/compile-worker-thread.cjs +72 -0
  4. package/dist/compiler/compile.js +177 -18
  5. package/dist/compiler/error-reporter.js +12 -0
  6. package/dist/compiler/integrity-validator.js +13 -1
  7. package/dist/compiler/linter.js +12 -0
  8. package/dist/compiler/minify.js +12 -0
  9. package/dist/compiler/minifyTemplate.js +12 -0
  10. package/dist/compiler/module-resolution-optimizer.js +35 -20
  11. package/dist/compiler/parser.js +12 -0
  12. package/dist/compiler/performance-monitor.js +73 -61
  13. package/dist/compiler/pipeline/build-pipeline.js +139 -0
  14. package/dist/compiler/pipeline/core-plugins.js +230 -0
  15. package/dist/compiler/pipeline/module-graph.js +75 -0
  16. package/dist/compiler/pipeline/plugin-driver.js +99 -0
  17. package/dist/compiler/pipeline/types.js +14 -0
  18. package/dist/compiler/tailwindcss.js +12 -0
  19. package/dist/compiler/transform-optimizer.js +12 -0
  20. package/dist/compiler/transformTStoJS.js +38 -5
  21. package/dist/compiler/transforms.js +234 -16
  22. package/dist/compiler/typescript-compiler.js +12 -0
  23. package/dist/compiler/typescript-error-parser.js +12 -0
  24. package/dist/compiler/typescript-manager.js +15 -1
  25. package/dist/compiler/typescript-sync-validator.js +45 -31
  26. package/dist/compiler/typescript-worker-pool.js +12 -0
  27. package/dist/compiler/typescript-worker-thread.cjs +482 -475
  28. package/dist/compiler/typescript-worker.js +12 -0
  29. package/dist/compiler/vuejs.js +73 -47
  30. package/dist/config.js +14 -0
  31. package/dist/hrm/VueHRM.js +484 -359
  32. package/dist/hrm/errorScreen.js +95 -83
  33. package/dist/hrm/getInstanciaVue.js +325 -313
  34. package/dist/hrm/initHRM.js +736 -586
  35. package/dist/hrm/versaHMR.js +317 -0
  36. package/dist/main.js +23 -3
  37. package/dist/servicios/browserSync.js +127 -6
  38. package/dist/servicios/file-watcher.js +139 -8
  39. package/dist/servicios/logger.js +12 -0
  40. package/dist/servicios/readConfig.js +141 -54
  41. package/dist/servicios/versacompile.config.types.js +14 -0
  42. package/dist/utils/excluded-modules.js +12 -0
  43. package/dist/utils/module-resolver.js +86 -40
  44. package/dist/utils/promptUser.js +12 -0
  45. package/dist/utils/proxyValidator.js +12 -0
  46. package/dist/utils/resolve-bin.js +12 -0
  47. package/dist/utils/utils.js +12 -0
  48. package/dist/utils/vue-types-setup.js +260 -248
  49. package/dist/wrappers/eslint-node.js +15 -1
  50. package/dist/wrappers/oxlint-node.js +15 -1
  51. package/dist/wrappers/tailwind-node.js +12 -0
  52. package/package.json +74 -54
@@ -1,359 +1,484 @@
1
- /**
2
- * @typedef {Object} TreeNode
3
- * @property {string} name - Nombre del componente
4
- * @property {Object} instancia - Instancia del componente Vue
5
- * @property {TreeNode[]} children - Nodos hijos
6
- * @property {TreeNode|null} parent - Nodo padre
7
- * @property {boolean} isRoot - Si es el nodo raíz
8
- * @property {string} [from] - Origen del nodo
9
- */
10
-
11
- import { obtenerInstanciaVue } from './getInstanciaVue.js';
12
-
13
- /**
14
- * @typedef {Object} VNode
15
- * @property {Object} [type] - Tipo del VNode
16
- * @property {Object} [component] - Componente asociado
17
- * @property {VNode[]} [children] - VNodes hijos
18
- * @property {VNode[]} [dynamicChildren] - VNodes dinámicos
19
- * @property {Object} [suspense] - Objeto suspense
20
- */
21
-
22
- /**
23
- * @typedef {Object} ComponentInstance
24
- * @property {Object} type - Tipo del componente
25
- * @property {string} [type.name] - Nombre del tipo
26
- * @property {string} [type.__name] - Nombre alternativo del tipo
27
- * @property {Object} [components] - Componentes registrados
28
- * @property {VNode} subTree - Subárbol del componente
29
- * @property {Object} [proxy] - Proxy del componente
30
- * @property {Function} [proxy.$forceUpdate] - Función de actualización forzada
31
- * @property {Function} [update] - Función de actualización
32
- * @property {Object} [ctx] - Contexto del componente
33
- * @property {Object} [ctx._] - Contexto interno del componente
34
- * @property {Object} [ctx._.setupState] - Estado del setup del componente
35
- * @property {number} [ctx._.setupState.versaComponentKey] - Clave del componente para HMR
36
- */
37
-
38
- /**
39
- * @typedef {Object} ComponentInfo
40
- * @property {string} normalizedPath - Ruta normalizada del componente
41
- * @property {string} nameFile - Nombre del archivo del componente
42
- */
43
-
44
- /**
45
- * @typedef {Object} VueApp
46
- * @property {ComponentInstance} _instance - Instancia principal de la aplicación
47
- */
48
-
49
- /**
50
- * Busca nodos en el árbol por nombre de instancia
51
- * @param {TreeNode} tree - Árbol de componentes
52
- * @param {string} instance - Nombre de la instancia a buscar
53
- * @returns {TreeNode[]} Array de nodos encontrados
54
- */
55
- function findNodeByInstance(tree, instance) {
56
- const matches = [];
57
- /**
58
- * @param {TreeNode} node - Nodo a buscar recursivamente
59
- */
60
- function searchRecursively(node) {
61
- if (node.name === instance) {
62
- matches.push(node);
63
- }
64
- for (const child of node.children) {
65
- searchRecursively(child);
66
- }
67
- }
68
-
69
- searchRecursively(tree);
70
- return matches;
71
- }
72
- /**
73
- * Obtiene el camino desde un nodo hasta la raíz
74
- * @param {TreeNode} node - Nodo inicial
75
- * @returns {TreeNode[]} Camino desde el nodo hasta la raíz
76
- */
77
- function getPathToRoot(node) {
78
- const path = [];
79
- while (node) {
80
- path.push(node);
81
- node = node.parent;
82
- }
83
- return path; // Ordenado desde hijo hasta raíz
84
- }
85
-
86
- /**
87
- * Encuentra componentes recursivamente dentro de un VNode
88
- * @param {VNode} vnode - VNode a explorar
89
- * @param {TreeNode} parentTreeNode - Nodo padre en el árbol
90
- */
91
- function recursivelyFindComponentsInVNode(vnode, parentTreeNode) {
92
- if (!vnode || typeof vnode !== 'object') {
93
- return;
94
- }
95
- if (vnode?.type.name === 'Suspense') {
96
- const childComponentInstance = vnode?.suspense.activeBranch;
97
- const childTreeNode = {
98
- name: vnode?.type.name,
99
- instancia: childComponentInstance,
100
- children: [],
101
- parent: parentTreeNode,
102
- isRoot: false,
103
- };
104
- parentTreeNode.children.push(childTreeNode);
105
- recursivelyFindComponentsInVNode(childComponentInstance, childTreeNode);
106
- } else if (vnode.component) {
107
- const childComponentInstance = vnode.component;
108
-
109
- let componentName = 'Anonymous';
110
- if (childComponentInstance.type) {
111
- if (childComponentInstance.type.name) {
112
- componentName = childComponentInstance.type.name;
113
- } else if (childComponentInstance.type.__name) {
114
- componentName = childComponentInstance.type.__name;
115
- } else if (typeof childComponentInstance.type === 'function') {
116
- const funcName = childComponentInstance.type.name;
117
- if (funcName && funcName !== 'Anonymous function') {
118
- componentName = funcName;
119
- }
120
- // Heurísticas para componentes comunes de Vue
121
- const typeStr = childComponentInstance.type.toString();
122
- if (typeStr.includes('BaseTransition')) {
123
- componentName = 'Transition';
124
- } else if (typeStr.includes('KeepAlive')) {
125
- componentName = 'KeepAlive';
126
- } else if (typeStr.includes('Suspense')) {
127
- componentName = 'Suspense';
128
- }
129
- }
130
- }
131
-
132
- const childTreeNode = {
133
- name: componentName,
134
- instancia: childComponentInstance,
135
- children: [],
136
- parent: parentTreeNode,
137
- isRoot: false,
138
- };
139
- parentTreeNode.children.push(childTreeNode);
140
- traverseComponentInstance(childComponentInstance, childTreeNode);
141
- } else {
142
- const childrenToExplore = vnode.children || vnode.dynamicChildren;
143
- if (Array.isArray(childrenToExplore)) {
144
- childrenToExplore.forEach(childVNode => {
145
- recursivelyFindComponentsInVNode(childVNode, parentTreeNode);
146
- });
147
- }
148
- }
149
- }
150
-
151
- /**
152
- * Recorre una instancia de componente y construye el árbol
153
- * @param {ComponentInstance} componentInstance - Instancia del componente
154
- * @param {TreeNode} currentTreeNode - Nodo actual del árbol
155
- */
156
- function traverseComponentInstance(componentInstance, currentTreeNode) {
157
- const subTreeVNode = componentInstance.subTree;
158
-
159
- if (!subTreeVNode) {
160
- return;
161
- }
162
-
163
- recursivelyFindComponentsInVNode(subTreeVNode, currentTreeNode);
164
- }
165
-
166
- /**
167
- * Construye el árbol de componentes desde una instancia raíz
168
- * @param {ComponentInstance} componentRootInstance - Instancia raíz del componente
169
- * @returns {TreeNode|null} Árbol de componentes o null si falla
170
- */
171
- export const buildComponentTree = componentRootInstance => {
172
- if (!componentRootInstance || !componentRootInstance.type) {
173
- console.warn(
174
- 'No se pudo construir el árbol de componentes: instancia inválida',
175
- );
176
- return null;
177
- }
178
- const tree = {
179
- name:
180
- componentRootInstance.type?.name ||
181
- componentRootInstance.type?.__name ||
182
- 'Anonymous',
183
- instancia: componentRootInstance,
184
- children: [],
185
- parent: null,
186
- isRoot: true,
187
- from: 'root',
188
- };
189
- traverseComponentInstance(componentRootInstance, tree);
190
-
191
- return tree;
192
- };
193
-
194
- /**
195
- * Intenta forzar la actualización de una instancia de componente
196
- * @param {ComponentInstance} instance - Instancia del componente a actualizar
197
- * @returns {boolean} True si la actualización fue exitosa, false en caso contrario
198
- */
199
- function tryForceUpdate(instance) {
200
- if (!instance) {
201
- return false;
202
- }
203
- if (instance.proxy && typeof instance.proxy.$forceUpdate === 'function') {
204
- instance.proxy.$forceUpdate();
205
- if (typeof instance.update === 'function') {
206
- instance.update();
207
- }
208
- // buscar una variable en el componente que se llame versaComponentKey y sumarle 1
209
- if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
210
- instance.ctx._.setupState.versaComponentKey++;
211
- }
212
- return true;
213
- }
214
- if (typeof instance.update === 'function') {
215
- if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
216
- instance.ctx._.setupState.versaComponentKey++;
217
- }
218
- instance.update();
219
- return true;
220
- }
221
- return false;
222
- }
223
-
224
- /**
225
- * Intenta actualizar un componente en el camino del árbol
226
- * @param {TreeNode[]} path - Camino de nodos desde el componente hasta la raíz
227
- * @param {Object} newComponent - Nuevo componente a usar
228
- * @param {string} componentName - Nombre del componente
229
- * @param {VueApp} App - Aplicación Vue
230
- * @returns {boolean} True si la actualización fue exitosa
231
- */
232
- function tryUpdateComponentPath(path, newComponent, componentName, App) {
233
- if (!path || !newComponent || !componentName || !App) {
234
- console.error('❌ Parámetros inválidos para tryUpdateComponentPath');
235
- return false;
236
- }
237
-
238
- // Recorrer el path desde el padre hacia la raíz (saltando el primer elemento que es el propio componente)
239
- for (let i = 1; i < path.length; i++) {
240
- const parent = path[i];
241
-
242
- if (parent.isRoot || parent.name === 'KeepAlive') {
243
- window.location.reload();
244
- return true;
245
- }
246
-
247
- if (!parent || !parent.instancia) {
248
- console.error('❌ Nodo padre no válido en el camino:', parent);
249
- continue; // Continúa con el siguiente padre en lugar de fallar
250
- }
251
-
252
- // Actualizar la instancia del componente
253
- const componentsDefinition =
254
- parent.instancia?.type?.components || parent.instancia?.components;
255
-
256
- if (componentsDefinition && componentsDefinition[componentName]) {
257
- componentsDefinition[componentName] = newComponent;
258
-
259
- // Forzar actualización de la instancia padre
260
- return (
261
- tryForceUpdate(parent.instancia) ||
262
- tryForceUpdate(parent.instancia.proxy)
263
- );
264
- }
265
- }
266
-
267
- return false;
268
- }
269
-
270
- /**
271
- * Recarga un componente Vue con Hot Module Replacement
272
- * @param {VueApp} App - Aplicación Vue principal
273
- * @param {ComponentInfo} Component - Información del componente a recargar
274
- * @returns {Promise<boolean>} Promise que resuelve a true si la recarga fue exitosa
275
- */
276
- export async function reloadComponent(App, Component) {
277
- try {
278
- const { normalizedPath: relativePath, nameFile: componentName } =
279
- Component;
280
- if (!App || !App._instance) {
281
- const vueInstance = await obtenerInstanciaVue();
282
- if (!vueInstance) {
283
- console.error('❌ No se pudo obtener la instancia de Vue');
284
- return false;
285
- }
286
- App = vueInstance;
287
- }
288
-
289
- if (!relativePath) {
290
- console.error('❌ No se proporcionó relativePath');
291
- return false;
292
- }
293
-
294
- const baseUrl = window.location.href;
295
- const newBaseUrl = new URL(baseUrl);
296
- const urlOrigin = `${newBaseUrl.origin}/${relativePath}`;
297
- const timestamp = Date.now();
298
- const moduleUrl = `${urlOrigin}?t=${timestamp}`;
299
-
300
- const module = await import(moduleUrl);
301
-
302
- if (!module.default) {
303
- console.error('❌ El módulo importado no tiene export default');
304
- return false;
305
- }
306
-
307
- const componentTree = buildComponentTree(App._instance);
308
- if (!componentTree) {
309
- console.error('❌ No se pudo construir el árbol de componentes');
310
- return false;
311
- }
312
-
313
- const targetNodes = findNodeByInstance(componentTree, componentName);
314
- if (!targetNodes) {
315
- console.warn(
316
- '⚠️ No se encontró el nodo objetivo para:',
317
- componentName,
318
- );
319
-
320
- return false;
321
- }
322
-
323
- console.log(
324
- `🔍 Se encontraron ${targetNodes.length} instancias del componente ${componentName}`,
325
- );
326
-
327
- let successfulUpdates = 0; // Procesar TODAS las instancias encontradas
328
- for (let i = 0; i < targetNodes.length; i++) {
329
- const node = targetNodes[i];
330
- if (node) {
331
- const path = getPathToRoot(node);
332
- const updateResult = await tryUpdateComponentPath(
333
- path,
334
- module.default,
335
- componentName,
336
- App,
337
- );
338
-
339
- if (updateResult) {
340
- successfulUpdates++;
341
- } else {
342
- console.error(
343
- `❌ No se pudo actualizar la instancia ${i + 1}`,
344
- );
345
- }
346
- }
347
- }
348
-
349
- const hasSuccessfulUpdate = successfulUpdates > 0;
350
- console.log(
351
- `\n📊 Resultado final: ${successfulUpdates}/${targetNodes.length} instancias actualizadas`,
352
- );
353
-
354
- return hasSuccessfulUpdate;
355
- } catch (error) {
356
- console.error('❌ Error en reloadComponent:', error);
357
- return false;
358
- }
359
- }
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
+ * @typedef {Object} TreeNode
15
+ * @property {string} name - Nombre del componente
16
+ * @property {Object} instancia - Instancia del componente Vue
17
+ * @property {TreeNode[]} children - Nodos hijos
18
+ * @property {TreeNode|null} parent - Nodo padre
19
+ * @property {boolean} isRoot - Si es el nodo raíz
20
+ * @property {string} [from] - Origen del nodo
21
+ */
22
+
23
+ import { obtenerInstanciaVue } from './getInstanciaVue.js';
24
+
25
+ /**
26
+ * @typedef {Object} VNode
27
+ * @property {Object} [type] - Tipo del VNode
28
+ * @property {Object} [component] - Componente asociado
29
+ * @property {VNode[]} [children] - VNodes hijos
30
+ * @property {VNode[]} [dynamicChildren] - VNodes dinámicos
31
+ * @property {Object} [suspense] - Objeto suspense
32
+ */
33
+
34
+ /**
35
+ * @typedef {Object} ComponentInstance
36
+ * @property {Object} type - Tipo del componente
37
+ * @property {string} [type.name] - Nombre del tipo
38
+ * @property {string} [type.__name] - Nombre alternativo del tipo
39
+ * @property {Object} [components] - Componentes registrados
40
+ * @property {VNode} subTree - Subárbol del componente
41
+ * @property {Object} [proxy] - Proxy del componente
42
+ * @property {Function} [proxy.$forceUpdate] - Función de actualización forzada
43
+ * @property {Function} [update] - Función de actualización
44
+ * @property {Object} [ctx] - Contexto del componente
45
+ * @property {Object} [ctx._] - Contexto interno del componente
46
+ * @property {Object} [ctx._.setupState] - Estado del setup del componente
47
+ * @property {number} [ctx._.setupState.versaComponentKey] - Clave del componente para HMR
48
+ */
49
+
50
+ /**
51
+ * @typedef {Object} ComponentInfo
52
+ * @property {string} normalizedPath - Ruta normalizada del componente
53
+ * @property {string} nameFile - Nombre del archivo del componente
54
+ */
55
+
56
+ /**
57
+ * @typedef {Object} VueApp
58
+ * @property {ComponentInstance} _instance - Instancia principal de la aplicación
59
+ */
60
+
61
+ /**
62
+ * Busca nodos en el árbol por nombre de instancia
63
+ * @param {TreeNode} tree - Árbol de componentes
64
+ * @param {string} instance - Nombre de la instancia a buscar
65
+ * @returns {TreeNode[]} Array de nodos encontrados
66
+ */
67
+ function findNodeByInstance(tree, instance) {
68
+ const matches = [];
69
+ /**
70
+ * @param {TreeNode} node - Nodo a buscar recursivamente
71
+ */
72
+ function searchRecursively(node) {
73
+ if (node.name === instance) {
74
+ matches.push(node);
75
+ }
76
+ for (const child of node.children) {
77
+ searchRecursively(child);
78
+ }
79
+ }
80
+
81
+ searchRecursively(tree);
82
+ return matches;
83
+ }
84
+ /**
85
+ * Obtiene el camino desde un nodo hasta la raíz
86
+ * @param {TreeNode} node - Nodo inicial
87
+ * @returns {TreeNode[]} Camino desde el nodo hasta la raíz
88
+ */
89
+ function getPathToRoot(node) {
90
+ const path = [];
91
+ while (node) {
92
+ path.push(node);
93
+ node = node.parent;
94
+ }
95
+ return path; // Ordenado desde hijo hasta raíz
96
+ }
97
+
98
+ /**
99
+ * Encuentra componentes recursivamente dentro de un VNode
100
+ * @param {VNode} vnode - VNode a explorar
101
+ * @param {TreeNode} parentTreeNode - Nodo padre en el árbol
102
+ */
103
+ function recursivelyFindComponentsInVNode(vnode, parentTreeNode) {
104
+ if (!vnode || typeof vnode !== 'object') {
105
+ return;
106
+ }
107
+ if (vnode?.type.name === 'Suspense') {
108
+ const childComponentInstance = vnode?.suspense.activeBranch;
109
+ const childTreeNode = {
110
+ name: vnode?.type.name,
111
+ instancia: childComponentInstance,
112
+ children: [],
113
+ parent: parentTreeNode,
114
+ isRoot: false,
115
+ };
116
+ parentTreeNode.children.push(childTreeNode);
117
+ recursivelyFindComponentsInVNode(childComponentInstance, childTreeNode);
118
+ } else if (vnode.component) {
119
+ const childComponentInstance = vnode.component;
120
+
121
+ let componentName = 'Anonymous';
122
+ if (childComponentInstance.type) {
123
+ if (childComponentInstance.type.name) {
124
+ componentName = childComponentInstance.type.name;
125
+ } else if (childComponentInstance.type.__name) {
126
+ componentName = childComponentInstance.type.__name;
127
+ } else if (typeof childComponentInstance.type === 'function') {
128
+ const funcName = childComponentInstance.type.name;
129
+ if (funcName && funcName !== 'Anonymous function') {
130
+ componentName = funcName;
131
+ }
132
+ // Heurísticas para componentes comunes de Vue
133
+ const typeStr = childComponentInstance.type.toString();
134
+ if (typeStr.includes('BaseTransition')) {
135
+ componentName = 'Transition';
136
+ } else if (typeStr.includes('KeepAlive')) {
137
+ componentName = 'KeepAlive';
138
+ } else if (typeStr.includes('Suspense')) {
139
+ componentName = 'Suspense';
140
+ }
141
+ }
142
+ }
143
+
144
+ const childTreeNode = {
145
+ name: componentName,
146
+ instancia: childComponentInstance,
147
+ children: [],
148
+ parent: parentTreeNode,
149
+ isRoot: false,
150
+ };
151
+ parentTreeNode.children.push(childTreeNode);
152
+ traverseComponentInstance(childComponentInstance, childTreeNode);
153
+ } else {
154
+ const childrenToExplore = vnode.children || vnode.dynamicChildren;
155
+ if (Array.isArray(childrenToExplore)) {
156
+ childrenToExplore.forEach(childVNode => {
157
+ recursivelyFindComponentsInVNode(childVNode, parentTreeNode);
158
+ });
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Recorre una instancia de componente y construye el árbol
165
+ * @param {ComponentInstance} componentInstance - Instancia del componente
166
+ * @param {TreeNode} currentTreeNode - Nodo actual del árbol
167
+ */
168
+ function traverseComponentInstance(componentInstance, currentTreeNode) {
169
+ const subTreeVNode = componentInstance.subTree;
170
+
171
+ if (!subTreeVNode) {
172
+ return;
173
+ }
174
+
175
+ recursivelyFindComponentsInVNode(subTreeVNode, currentTreeNode);
176
+ }
177
+
178
+ /**
179
+ * Construye el árbol de componentes desde una instancia raíz
180
+ * @param {ComponentInstance} componentRootInstance - Instancia raíz del componente
181
+ * @returns {TreeNode|null} Árbol de componentes o null si falla
182
+ */
183
+ export const buildComponentTree = componentRootInstance => {
184
+ if (!componentRootInstance || !componentRootInstance.type) {
185
+ console.warn(
186
+ 'No se pudo construir el árbol de componentes: instancia inválida',
187
+ );
188
+ return null;
189
+ }
190
+ const tree = {
191
+ name:
192
+ componentRootInstance.type?.name ||
193
+ componentRootInstance.type?.__name ||
194
+ 'Anonymous',
195
+ instancia: componentRootInstance,
196
+ children: [],
197
+ parent: null,
198
+ isRoot: true,
199
+ from: 'root',
200
+ };
201
+ traverseComponentInstance(componentRootInstance, tree);
202
+
203
+ return tree;
204
+ };
205
+
206
+ /**
207
+ * Intenta forzar la actualización de una instancia de componente
208
+ * @param {ComponentInstance} instance - Instancia del componente a actualizar
209
+ * @returns {boolean} True si la actualización fue exitosa, false en caso contrario
210
+ */
211
+ function tryForceUpdate(instance) {
212
+ if (!instance) {
213
+ return false;
214
+ }
215
+ if (instance.proxy && typeof instance.proxy.$forceUpdate === 'function') {
216
+ instance.proxy.$forceUpdate();
217
+ if (typeof instance.update === 'function') {
218
+ instance.update();
219
+ }
220
+ // buscar una variable en el componente que se llame versaComponentKey y sumarle 1
221
+ if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
222
+ instance.ctx._.setupState.versaComponentKey++;
223
+ }
224
+ return true;
225
+ }
226
+ if (typeof instance.update === 'function') {
227
+ if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
228
+ instance.ctx._.setupState.versaComponentKey++;
229
+ }
230
+ instance.update();
231
+ return true;
232
+ }
233
+ return false;
234
+ }
235
+
236
+ /**
237
+ * Limpia los caches internos de Vue para una definición de componente.
238
+ * Necesario para que Vue detecte el cambio de props/emits/options.
239
+ * @param {Object} appContext - Contexto de la app Vue (instance.appContext)
240
+ * @param {Object} componentDef - Definición del componente
241
+ */
242
+ function clearVueCaches(appContext, componentDef) {
243
+ if (!appContext || !componentDef) return;
244
+ try {
245
+ appContext.propsCache?.delete(componentDef);
246
+ appContext.emitsCache?.delete(componentDef);
247
+ appContext.optionsCache?.delete(componentDef);
248
+ } catch {
249
+ // Los caches pueden no existir en todas las versiones de Vue
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Actualiza una instancia de componente Vue en-place con la nueva definición.
255
+ * Muta el objeto `instance.type` directamente para que TODAS las referencias
256
+ * a la definición (incluidas las capturadas en closures de render functions
257
+ * de componentes padre que hacen import estático) vean la nueva versión.
258
+ *
259
+ * @param {Object} instance - Instancia Vue del componente a actualizar
260
+ * @param {Object} newComponentDef - Nueva definición del componente
261
+ * @returns {boolean} true si la actualización fue exitosa
262
+ */
263
+ function updateInstanceInPlace(instance, newComponentDef) {
264
+ if (!instance || !newComponentDef) return false;
265
+
266
+ const oldDef = instance.type;
267
+ if (!oldDef || typeof oldDef !== 'object') return false;
268
+
269
+ // 1. Mutar la definición existente en-place.
270
+ // Object.assign copia propiedades enumerables; copiamos render/setup
271
+ // explícitamente porque pueden no ser enumerables en algunos builds.
272
+ Object.assign(oldDef, newComponentDef);
273
+ if (newComponentDef.render) oldDef.render = newComponentDef.render;
274
+ if (newComponentDef.setup) oldDef.setup = newComponentDef.setup;
275
+ if (newComponentDef.ssrRender) oldDef.ssrRender = newComponentDef.ssrRender;
276
+
277
+ // 2. Actualizar instance.render directamente.
278
+ // Vue almacena la referencia a la render function en instance.render durante
279
+ // el mount (handleSetupResult), y es ESA la que llama en cada patch.
280
+ // Cambiar solo instance.type.render NO es suficiente — hay que actualizar
281
+ // también instance.render para que el próximo update use la nueva template.
282
+ if (newComponentDef.render && typeof instance.render !== 'undefined') {
283
+ instance.render = newComponentDef.render;
284
+ }
285
+
286
+ // 3. Limpiar caches internos de Vue para que re-evalúe props/emits/options.
287
+ clearVueCaches(instance.appContext, oldDef);
288
+
289
+ // 4. Forzar actualización de ESTA instancia directamente (no solo del padre).
290
+ // Incrementar versaComponentKey para triggear el :key del template.
291
+ if (instance.ctx?._.setupState?.versaComponentKey !== undefined) {
292
+ instance.ctx._.setupState.versaComponentKey++;
293
+ }
294
+ if (typeof instance.update === 'function') {
295
+ instance.update();
296
+ return true;
297
+ }
298
+ if (instance.proxy && typeof instance.proxy.$forceUpdate === 'function') {
299
+ instance.proxy.$forceUpdate();
300
+ return true;
301
+ }
302
+
303
+ return false;
304
+ }
305
+
306
+ /**
307
+ * Intenta actualizar un componente en el camino del árbol.
308
+ * Ahora usa mutación in-place de la definición + limpieza de caches Vue,
309
+ * en lugar de reemplazar la referencia en el mapa de components del padre.
310
+ *
311
+ * @param {TreeNode[]} path - Camino de nodos desde el componente hasta la raíz
312
+ * @param {Object} newComponent - Nuevo componente a usar
313
+ * @param {string} componentName - Nombre del componente
314
+ * @param {VueApp} App - Aplicación Vue
315
+ * @returns {boolean} True si la actualización fue exitosa
316
+ */
317
+ function tryUpdateComponentPath(path, newComponent, componentName, App) {
318
+ if (!path || !newComponent || !componentName || !App) {
319
+ console.error('❌ Parámetros inválidos para tryUpdateComponentPath');
320
+ return false;
321
+ }
322
+
323
+ // path[0] es el nodo del propio componente a actualizar.
324
+ // Intentar actualización directa en la instancia del componente.
325
+ const targetNode = path[0];
326
+ if (targetNode?.instancia) {
327
+ const updated = updateInstanceInPlace(
328
+ targetNode.instancia,
329
+ newComponent,
330
+ );
331
+ if (updated) {
332
+ // También forzar actualización del padre para que el vdom se reconcilie.
333
+ const parentNode = path[1];
334
+ if (parentNode?.instancia && !parentNode.isRoot) {
335
+ tryForceUpdate(parentNode.instancia);
336
+ }
337
+ return true;
338
+ }
339
+ }
340
+
341
+ // Fallback: recorrer hacia el padre si el nodo propio no es accesible.
342
+ for (let i = 1; i < path.length; i++) {
343
+ const parent = path[i];
344
+
345
+ if (parent.isRoot || parent.name === 'KeepAlive') {
346
+ window.location.reload();
347
+ return true;
348
+ }
349
+
350
+ if (!parent?.instancia) {
351
+ console.error('❌ Nodo padre no válido en el camino:', parent);
352
+ continue;
353
+ }
354
+
355
+ const componentsDefinition =
356
+ parent.instancia?.type?.components || parent.instancia?.components;
357
+
358
+ if (componentsDefinition && componentsDefinition[componentName]) {
359
+ // Mutar la definición existente en el mapa del padre también,
360
+ // para que nuevas instancias del componente creadas después se usen
361
+ // con la definición actualizada.
362
+ const existingDef = componentsDefinition[componentName];
363
+ if (existingDef && typeof existingDef === 'object') {
364
+ Object.assign(existingDef, newComponent);
365
+ if (newComponent.render)
366
+ existingDef.render = newComponent.render;
367
+ if (newComponent.setup) existingDef.setup = newComponent.setup;
368
+ clearVueCaches(parent.instancia.appContext, existingDef);
369
+ } else {
370
+ componentsDefinition[componentName] = newComponent;
371
+ }
372
+
373
+ return (
374
+ tryForceUpdate(parent.instancia) ||
375
+ tryForceUpdate(parent.instancia.proxy)
376
+ );
377
+ }
378
+ }
379
+
380
+ return false;
381
+ }
382
+
383
+ /**
384
+ * Recarga un componente Vue con Hot Module Replacement
385
+ * @param {VueApp} App - Aplicación Vue principal
386
+ * @param {ComponentInfo} Component - Información del componente a recargar
387
+ * @returns {Promise<boolean>} Promise que resuelve a true si la recarga fue exitosa
388
+ */
389
+ export async function reloadComponent(App, Component) {
390
+ try {
391
+ const { normalizedPath: relativePath, nameFile: componentName } =
392
+ Component;
393
+ if (!App || !App._instance) {
394
+ const vueInstance = await obtenerInstanciaVue();
395
+ if (!vueInstance) {
396
+ console.error('❌ No se pudo obtener la instancia de Vue');
397
+ return false;
398
+ }
399
+ App = vueInstance;
400
+ }
401
+
402
+ if (!relativePath) {
403
+ console.error('❌ No se proporcionó relativePath');
404
+ return false;
405
+ }
406
+
407
+ const baseUrl = window.location.href;
408
+ const newBaseUrl = new URL(baseUrl);
409
+ const urlOrigin = `${newBaseUrl.origin}/${relativePath}`;
410
+ const timestamp = Date.now();
411
+ const moduleUrl = `${urlOrigin}?t=${timestamp}`;
412
+
413
+ // Eliminar style tags del ciclo HMR anterior para este componente
414
+ // para evitar acumulación de estilos duplicados en el documento.
415
+ const componentName_clean = componentName.replace(
416
+ /[^a-zA-Z0-9_-]/g,
417
+ '',
418
+ );
419
+ document
420
+ .querySelectorAll(
421
+ `[data-versa-hmr-component="${componentName_clean}"]`,
422
+ )
423
+ .forEach(el => el.remove());
424
+
425
+ const module = await import(moduleUrl);
426
+
427
+ if (!module.default) {
428
+ console.error('❌ El módulo importado no tiene export default');
429
+ return false;
430
+ }
431
+
432
+ const componentTree = buildComponentTree(App._instance);
433
+ if (!componentTree) {
434
+ console.error('❌ No se pudo construir el árbol de componentes');
435
+ return false;
436
+ }
437
+
438
+ const targetNodes = findNodeByInstance(componentTree, componentName);
439
+ if (!targetNodes) {
440
+ console.warn(
441
+ '⚠️ No se encontró el nodo objetivo para:',
442
+ componentName,
443
+ );
444
+
445
+ return false;
446
+ }
447
+
448
+ console.log(
449
+ `🔍 Se encontraron ${targetNodes.length} instancias del componente ${componentName}`,
450
+ );
451
+
452
+ let successfulUpdates = 0; // Procesar TODAS las instancias encontradas
453
+ for (let i = 0; i < targetNodes.length; i++) {
454
+ const node = targetNodes[i];
455
+ if (node) {
456
+ const path = getPathToRoot(node);
457
+ const updateResult = await tryUpdateComponentPath(
458
+ path,
459
+ module.default,
460
+ componentName,
461
+ App,
462
+ );
463
+
464
+ if (updateResult) {
465
+ successfulUpdates++;
466
+ } else {
467
+ console.error(
468
+ `❌ No se pudo actualizar la instancia ${i + 1}`,
469
+ );
470
+ }
471
+ }
472
+ }
473
+
474
+ const hasSuccessfulUpdate = successfulUpdates > 0;
475
+ console.log(
476
+ `\n📊 Resultado final: ${successfulUpdates}/${targetNodes.length} instancias actualizadas`,
477
+ );
478
+
479
+ return hasSuccessfulUpdate;
480
+ } catch (error) {
481
+ console.error('❌ Error en reloadComponent:', error);
482
+ return false;
483
+ }
484
+ }