versacompiler 2.3.3 → 2.3.5

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.
@@ -0,0 +1,527 @@
1
+ import { parseSync } from 'oxc-parser';
2
+ import { logger } from '../servicios/logger.js';
3
+ /**
4
+ * Sistema de validación de integridad para código compilado/transformado
5
+ *
6
+ * Detecta automáticamente:
7
+ * - Código vacío después de minificación
8
+ * - Exports eliminados por error
9
+ * - Sintaxis inválida introducida por transformaciones
10
+ * - Estructura de código corrupta
11
+ *
12
+ * Performance: <5ms por archivo (típicamente 1-3ms)
13
+ */
14
+ export class IntegrityValidator {
15
+ static instance;
16
+ cache = new Map();
17
+ MAX_CACHE_SIZE = 100;
18
+ // Estadísticas
19
+ stats = {
20
+ totalValidations: 0,
21
+ successfulValidations: 0,
22
+ failedValidations: 0,
23
+ cacheHits: 0,
24
+ cacheMisses: 0,
25
+ totalDuration: 0,
26
+ averageDuration: 0,
27
+ };
28
+ constructor() { }
29
+ static getInstance() {
30
+ if (!IntegrityValidator.instance) {
31
+ IntegrityValidator.instance = new IntegrityValidator();
32
+ }
33
+ return IntegrityValidator.instance;
34
+ }
35
+ /**
36
+ * Valida la integridad del código procesado
37
+ *
38
+ * @param original - Código original antes del procesamiento
39
+ * @param processed - Código después del procesamiento
40
+ * @param context - Contexto de la validación (ej: "minify:file.js")
41
+ * @param options - Opciones de validación
42
+ * @returns Resultado detallado de la validación
43
+ */
44
+ validate(original, processed, context, options = {}) {
45
+ const startTime = performance.now();
46
+ this.stats.totalValidations++;
47
+ // Revisar cache
48
+ const cacheKey = this.getCacheKey(context, processed);
49
+ const cached = this.cache.get(cacheKey);
50
+ if (cached) {
51
+ this.stats.cacheHits++;
52
+ if (options.verbose) {
53
+ logger.info(`[IntegrityValidator] Cache hit for ${context}`);
54
+ }
55
+ return cached;
56
+ }
57
+ this.stats.cacheMisses++;
58
+ const errors = [];
59
+ // Check 1: Size (más rápido, ~0.1ms)
60
+ const sizeOk = this.checkSize(processed);
61
+ if (!sizeOk) {
62
+ errors.push('Código procesado está vacío o demasiado pequeño');
63
+ // Early return - no tiene sentido continuar
64
+ const result = this.createResult(false, {
65
+ size: false,
66
+ structure: false,
67
+ exports: false,
68
+ syntax: options?.skipSyntaxCheck === true, // Respetar skipSyntaxCheck incluso en early return
69
+ }, errors, original, processed, startTime);
70
+ this.handleValidationResult(result, context, options);
71
+ return result;
72
+ }
73
+ // Check 2: Structure (~1ms) - TEMPORALMENTE DESHABILITADO
74
+ // TODO: Mejorar detección de character classes en regex literals
75
+ const structureOk = true; // this.checkStructure(processed);
76
+ // if (!structureOk) {
77
+ // errors.push(
78
+ // 'Estructura de código inválida (paréntesis/llaves/corchetes desbalanceados)',
79
+ // );
80
+ // }
81
+ // Check 3: Exports (~1ms)
82
+ const exportsOk = this.checkExports(original, processed);
83
+ if (!exportsOk) {
84
+ errors.push('Exports fueron eliminados o modificados incorrectamente');
85
+ }
86
+ // Check 4: Syntax (~3ms) - solo si otros checks pasaron y no está skippeado
87
+ let syntaxOk = true;
88
+ if (options?.skipSyntaxCheck) {
89
+ // Si se salta el check de sintaxis, asumir que es válido
90
+ syntaxOk = true;
91
+ }
92
+ else if (structureOk && exportsOk) {
93
+ // Solo validar sintaxis si estructura y exports pasaron
94
+ syntaxOk = this.checkSyntax(processed);
95
+ if (!syntaxOk) {
96
+ errors.push('Código procesado contiene errores de sintaxis');
97
+ }
98
+ }
99
+ else {
100
+ // Si otros checks fallaron, no ejecutar syntax check (optimización)
101
+ // pero mantener syntaxOk = true para no agregar más errores
102
+ syntaxOk = true;
103
+ }
104
+ const valid = errors.length === 0;
105
+ const result = this.createResult(valid, {
106
+ size: sizeOk,
107
+ structure: structureOk,
108
+ exports: exportsOk,
109
+ syntax: syntaxOk,
110
+ }, errors, original, processed, startTime);
111
+ // Guardar en caché
112
+ this.saveToCache(cacheKey, result);
113
+ // Actualizar estadísticas
114
+ this.handleValidationResult(result, context, options);
115
+ return result;
116
+ }
117
+ /**
118
+ * Check 1: Verificar que el código no esté vacío
119
+ */
120
+ checkSize(code) {
121
+ // Código debe tener al menos 10 caracteres y no ser solo whitespace
122
+ const trimmed = code.trim();
123
+ return trimmed.length >= 10;
124
+ }
125
+ /**
126
+ * Check 2: Verificar estructura básica del código
127
+ */
128
+ checkStructure(code) {
129
+ // Verificar paréntesis, llaves y corchetes balanceados
130
+ const counters = {
131
+ '(': 0,
132
+ '[': 0,
133
+ '{': 0,
134
+ };
135
+ let inString = false;
136
+ let inTemplate = false;
137
+ let inTemplateInterpolation = false; // Dentro de ${ } en template literal
138
+ let templateBraceDepth = 0; // Para trackear nested braces en interpolación
139
+ let inComment = false;
140
+ let inMultilineComment = false;
141
+ let inRegex = false; // Dentro de regex literal /pattern/flags
142
+ let stringChar = '';
143
+ let escapeNext = false;
144
+ let prevNonWhitespaceChar = ''; // Para detectar contexto de regex
145
+ for (let i = 0; i < code.length;) {
146
+ const char = code[i];
147
+ const nextChar = i < code.length - 1 ? code[i + 1] : '';
148
+ // Manejar escape (en strings, templates y regex)
149
+ if (escapeNext) {
150
+ escapeNext = false;
151
+ i++;
152
+ continue;
153
+ }
154
+ if (char === '\\' && (inString || inTemplate || inRegex)) {
155
+ escapeNext = true;
156
+ i++;
157
+ continue;
158
+ }
159
+ // Detectar regex literals (antes de comentarios, porque ambos usan /)
160
+ if (!inString &&
161
+ !inTemplate &&
162
+ !inComment &&
163
+ !inMultilineComment &&
164
+ !inRegex &&
165
+ char === '/' &&
166
+ nextChar !== '/' &&
167
+ nextChar !== '*') {
168
+ // Contexto donde se espera regex (no división)
169
+ const regexContext = /[=([,;:!&|?+\-{]$/;
170
+ if (regexContext.test(prevNonWhitespaceChar)) {
171
+ inRegex = true;
172
+ i++;
173
+ continue;
174
+ }
175
+ }
176
+ // Detectar fin de regex literal
177
+ if (inRegex && char === '/') {
178
+ inRegex = false;
179
+ // Skip flags como g, i, m, s, u, y
180
+ let j = i + 1;
181
+ while (j < code.length) {
182
+ const flag = code[j];
183
+ if (flag && /[gimsuvy]/.test(flag)) {
184
+ j++;
185
+ }
186
+ else {
187
+ break;
188
+ }
189
+ }
190
+ i = j;
191
+ continue;
192
+ }
193
+ // Skip contenido dentro de regex
194
+ if (inRegex) {
195
+ i++;
196
+ continue;
197
+ }
198
+ // Detectar inicio de comentario de línea
199
+ if (char === '/' &&
200
+ nextChar === '/' &&
201
+ !inString &&
202
+ !inTemplate &&
203
+ !inMultilineComment) {
204
+ inComment = true;
205
+ i += 2; // Skip // completamente
206
+ continue;
207
+ }
208
+ // Detectar fin de comentario de línea
209
+ if (inComment && (char === '\n' || char === '\r')) {
210
+ inComment = false;
211
+ i++;
212
+ continue;
213
+ }
214
+ // Detectar inicio de comentario multilínea
215
+ if (char === '/' &&
216
+ nextChar === '*' &&
217
+ !inString &&
218
+ !inTemplate &&
219
+ !inComment) {
220
+ inMultilineComment = true;
221
+ i += 2; // Skip /* completamente
222
+ continue;
223
+ }
224
+ // Detectar fin de comentario multilínea
225
+ if (inMultilineComment && char === '*' && nextChar === '/') {
226
+ inMultilineComment = false;
227
+ i += 2; // Skip */ completamente
228
+ continue;
229
+ }
230
+ // Skip caracteres dentro de comentarios
231
+ if (inComment || inMultilineComment) {
232
+ i++;
233
+ continue;
234
+ }
235
+ // Detectar strings (incluyendo dentro de interpolaciones de template)
236
+ if (char === '"' || char === "'") {
237
+ // Las comillas funcionan normalmente FUERA de templates O DENTRO de interpolaciones
238
+ if (!inTemplate || inTemplateInterpolation) {
239
+ if (!inString) {
240
+ inString = true;
241
+ stringChar = char;
242
+ }
243
+ else if (char === stringChar) {
244
+ inString = false;
245
+ stringChar = '';
246
+ }
247
+ }
248
+ i++;
249
+ continue;
250
+ }
251
+ // Detectar template literals (solo fuera de regex)
252
+ if (!inString && !inRegex && char === '`') {
253
+ if (inTemplate && !inTemplateInterpolation) {
254
+ // Salir de template
255
+ inTemplate = false;
256
+ }
257
+ else if (!inTemplate) {
258
+ // Entrar a template
259
+ inTemplate = true;
260
+ inTemplateInterpolation = false;
261
+ templateBraceDepth = 0;
262
+ }
263
+ i++;
264
+ continue;
265
+ }
266
+ // Detectar inicio de interpolación en template literal: ${
267
+ if (inTemplate &&
268
+ !inTemplateInterpolation &&
269
+ char === '$' &&
270
+ nextChar === '{') {
271
+ inTemplateInterpolation = true;
272
+ templateBraceDepth = 0;
273
+ i += 2; // Skip ${ completamente
274
+ continue;
275
+ }
276
+ // Dentro de interpolación de template, contar brackets
277
+ if (inTemplateInterpolation) {
278
+ if (char === '{') {
279
+ templateBraceDepth++;
280
+ counters['{']++;
281
+ }
282
+ else if (char === '}') {
283
+ if (templateBraceDepth === 0) {
284
+ // Este } cierra la interpolación
285
+ inTemplateInterpolation = false;
286
+ }
287
+ else {
288
+ templateBraceDepth--;
289
+ counters['{']--;
290
+ }
291
+ }
292
+ else if (char === '(') {
293
+ counters['(']++;
294
+ }
295
+ else if (char === ')') {
296
+ counters['(']--;
297
+ }
298
+ else if (char === '[') {
299
+ counters['[']++;
300
+ }
301
+ else if (char === ']') {
302
+ counters['[']--;
303
+ }
304
+ // Early return si algún contador se vuelve negativo
305
+ if (counters['('] < 0 ||
306
+ counters['['] < 0 ||
307
+ counters['{'] < 0) {
308
+ return false;
309
+ }
310
+ i++;
311
+ continue;
312
+ }
313
+ // Skip contenido dentro de strings o templates (pero no interpolaciones)
314
+ if (inString || inTemplate) {
315
+ i++;
316
+ continue;
317
+ }
318
+ // Solo contar brackets fuera de strings/templates/comentarios
319
+ if (char === '(')
320
+ counters['(']++;
321
+ else if (char === ')')
322
+ counters['(']--;
323
+ else if (char === '[')
324
+ counters['[']++;
325
+ else if (char === ']')
326
+ counters['[']--;
327
+ else if (char === '{')
328
+ counters['{']++;
329
+ else if (char === '}')
330
+ counters['{']--;
331
+ // Early return si algún contador se vuelve negativo
332
+ if (counters['('] < 0 || counters['['] < 0 || counters['{'] < 0) {
333
+ return false;
334
+ }
335
+ // Track prev non-whitespace char para contexto de regex
336
+ if (char &&
337
+ char !== ' ' &&
338
+ char !== '\t' &&
339
+ char !== '\n' &&
340
+ char !== '\r') {
341
+ prevNonWhitespaceChar = char;
342
+ }
343
+ i++;
344
+ }
345
+ // Verificar que todos estén balanceados
346
+ return (counters['('] === 0 && counters['['] === 0 && counters['{'] === 0);
347
+ }
348
+ /**
349
+ * Check 3: Verificar que los exports se mantengan
350
+ */
351
+ checkExports(original, processed) {
352
+ const originalExports = this.extractExports(original);
353
+ const processedExports = this.extractExports(processed);
354
+ // Si no hay exports en el original, no hay nada que validar
355
+ if (originalExports.length === 0) {
356
+ return true;
357
+ }
358
+ // Verificar que todos los exports originales estén presentes
359
+ for (const exp of originalExports) {
360
+ if (!processedExports.includes(exp)) {
361
+ return false;
362
+ }
363
+ }
364
+ return true;
365
+ }
366
+ /**
367
+ * Extraer exports de código JavaScript/TypeScript
368
+ */
369
+ extractExports(code) {
370
+ const exports = [];
371
+ // export default
372
+ if (/export\s+default\s/.test(code)) {
373
+ exports.push('default');
374
+ }
375
+ // export { a, b, c }
376
+ const namedExportsMatches = code.matchAll(/export\s*\{\s*([^}]+)\s*\}/g);
377
+ for (const match of namedExportsMatches) {
378
+ if (match[1]) {
379
+ const names = match[1]
380
+ .split(',')
381
+ .map(n => {
382
+ const parts = n.trim().split(/\s+as\s+/);
383
+ return parts[0]?.trim() || '';
384
+ })
385
+ .filter(n => n);
386
+ exports.push(...names);
387
+ }
388
+ }
389
+ // export const/let/var/function/class
390
+ const directExportsMatches = code.matchAll(/export\s+(?:const|let|var|function|class|async\s+function)\s+(\w+)/g);
391
+ for (const match of directExportsMatches) {
392
+ if (match[1]) {
393
+ exports.push(match[1]);
394
+ }
395
+ }
396
+ // export * from
397
+ if (/export\s+\*\s+from/.test(code)) {
398
+ exports.push('*');
399
+ }
400
+ return [...new Set(exports)]; // Deduplicar
401
+ }
402
+ /**
403
+ * Check 4: Validación de sintaxis con oxc-parser
404
+ */
405
+ checkSyntax(code) {
406
+ try {
407
+ const parseResult = parseSync('integrity-check.js', code, {
408
+ sourceType: 'module',
409
+ });
410
+ return parseResult.errors.length === 0;
411
+ }
412
+ catch {
413
+ // Si parseSync lanza error, la sintaxis es inválida
414
+ return false;
415
+ }
416
+ }
417
+ /**
418
+ * Crear objeto de resultado
419
+ */
420
+ createResult(valid, checks, errors, original, processed, startTime) {
421
+ const duration = performance.now() - startTime;
422
+ return {
423
+ valid,
424
+ checks,
425
+ errors,
426
+ metrics: {
427
+ duration,
428
+ originalSize: original.length,
429
+ processedSize: processed.length,
430
+ exportCount: this.extractExports(processed).length,
431
+ },
432
+ };
433
+ }
434
+ /**
435
+ * Manejar resultado de validación (estadísticas, logging, errores)
436
+ */
437
+ handleValidationResult(result, context, options) {
438
+ // Actualizar estadísticas
439
+ if (result.valid) {
440
+ this.stats.successfulValidations++;
441
+ }
442
+ else {
443
+ this.stats.failedValidations++;
444
+ }
445
+ this.stats.totalDuration += result.metrics.duration;
446
+ this.stats.averageDuration =
447
+ this.stats.totalDuration / this.stats.totalValidations;
448
+ // Logging
449
+ if (options.verbose) {
450
+ if (result.valid) {
451
+ logger.info(`[IntegrityValidator] ✓ ${context} - ` +
452
+ `${result.metrics.duration.toFixed(2)}ms - ` +
453
+ `${result.metrics.originalSize} → ${result.metrics.processedSize} bytes`);
454
+ }
455
+ else {
456
+ logger.error(`[IntegrityValidator] ✗ ${context} - ` +
457
+ `Failed: ${result.errors.join(', ')}`);
458
+ }
459
+ }
460
+ // Lanzar error si está configurado
461
+ if (!result.valid && options.throwOnError) {
462
+ throw new Error(`Integrity validation failed for ${context}: ${result.errors.join(', ')}`);
463
+ }
464
+ }
465
+ /**
466
+ * Generar clave de caché
467
+ */
468
+ getCacheKey(context, code) {
469
+ // Hash simple pero rápido
470
+ const hash = this.hashCode(code);
471
+ return `${context}:${hash}`;
472
+ }
473
+ /**
474
+ * Hash simple para cache
475
+ */
476
+ hashCode(str) {
477
+ let hash = 0;
478
+ for (let i = 0; i < str.length; i++) {
479
+ const char = str.charCodeAt(i);
480
+ hash = (hash << 5) - hash + char;
481
+ hash = hash & hash; // Convert to 32-bit integer
482
+ }
483
+ return hash.toString(36);
484
+ }
485
+ /**
486
+ * Guardar en caché con LRU eviction
487
+ */
488
+ saveToCache(key, result) {
489
+ // LRU eviction
490
+ if (this.cache.size >= this.MAX_CACHE_SIZE) {
491
+ const firstKey = this.cache.keys().next().value;
492
+ if (firstKey) {
493
+ this.cache.delete(firstKey);
494
+ }
495
+ }
496
+ this.cache.set(key, result);
497
+ }
498
+ /**
499
+ * Obtener estadísticas de validación
500
+ */
501
+ getStats() {
502
+ return { ...this.stats };
503
+ }
504
+ /**
505
+ * Limpiar caché
506
+ */
507
+ clearCache() {
508
+ this.cache.clear();
509
+ }
510
+ /**
511
+ * Resetear estadísticas
512
+ */
513
+ resetStats() {
514
+ this.stats = {
515
+ totalValidations: 0,
516
+ successfulValidations: 0,
517
+ failedValidations: 0,
518
+ cacheHits: 0,
519
+ cacheMisses: 0,
520
+ totalDuration: 0,
521
+ averageDuration: 0,
522
+ };
523
+ }
524
+ }
525
+ // Export singleton instance
526
+ export const integrityValidator = IntegrityValidator.getInstance();
527
+ //# sourceMappingURL=integrity-validator.js.map
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { minifySync } from 'oxc-minify';
3
3
  import { logger } from '../servicios/logger.js';
4
+ import { integrityValidator } from './integrity-validator.js';
4
5
  import { minifyTemplate } from './minifyTemplate.js';
5
6
  class MinificationCache {
6
7
  static instance;
@@ -51,6 +52,23 @@ class MinificationCache {
51
52
  const originalSize = data.length;
52
53
  try {
53
54
  const result = minifySync(filename, data, options);
55
+ // VALIDACIÓN DE INTEGRIDAD - Solo si flag está activo
56
+ if (process.env.CHECK_INTEGRITY === 'true') {
57
+ const validation = integrityValidator.validate(data, result.code, `minify:${filename}`, {
58
+ skipSyntaxCheck: false,
59
+ verbose: process.env.VERBOSE === 'true',
60
+ throwOnError: true, // Detener build si falla
61
+ });
62
+ if (!validation.valid) {
63
+ // El validator ya lanzó el error si throwOnError=true
64
+ // Pero por si acaso, retornamos el código original
65
+ logger.error(`❌ Validación de integridad fallida para ${filename}`, validation.errors.join(', '));
66
+ throw new Error(`Integrity check failed for ${filename}: ${validation.errors.join(', ')}`);
67
+ }
68
+ if (process.env.VERBOSE === 'true') {
69
+ logger.info(`✅ Validación de integridad OK para ${filename} (${validation.metrics.duration.toFixed(2)}ms)`);
70
+ }
71
+ }
54
72
  // Si el código de entrada no estaba vacío pero el resultado sí,
55
73
  // retornar código original sin minificar con advertencia
56
74
  if (data.trim() && !result.code.trim()) {
@@ -233,7 +251,7 @@ export const minifyJS = async (data, filename, isProd = true) => {
233
251
  normal: true,
234
252
  jsdoc: true,
235
253
  annotation: true,
236
- legal: true
254
+ legal: true,
237
255
  },
238
256
  sourcemap: !isProd,
239
257
  };
@@ -1,5 +1,6 @@
1
1
  import { minifyHTMLLiterals } from 'minify-html-literals';
2
2
  import { logger } from '../servicios/logger.js';
3
+ import { integrityValidator } from './integrity-validator.js';
3
4
  const defaultMinifyOptions = {
4
5
  // Opciones esenciales para componentes Vue
5
6
  caseSensitive: true, // Preserva mayúsculas/minúsculas en nombres de componentes
@@ -219,6 +220,21 @@ const minifyTemplate = (data, fileName) => {
219
220
  // Esto convierte __VERSA_TEMP__` de vuelta a ` para que el código
220
221
  // final no contenga los marcadores temporales
221
222
  const finalCode = removeTemporaryTags(minifiedCode);
223
+ // VALIDACIÓN DE INTEGRIDAD - Solo si flag está activo
224
+ if (process.env.CHECK_INTEGRITY === 'true') {
225
+ const validation = integrityValidator.validate(data, finalCode, `minifyTemplate:${fileName}`, {
226
+ skipSyntaxCheck: true, // No validar sintaxis (puede no ser JS puro)
227
+ verbose: process.env.VERBOSE === 'true',
228
+ throwOnError: true, // Detener build si falla
229
+ });
230
+ if (!validation.valid) {
231
+ logger.error(`❌ Validación de integridad fallida para template ${fileName}`, validation.errors.join(', '));
232
+ throw new Error(`Template integrity check failed for ${fileName}: ${validation.errors.join(', ')}`);
233
+ }
234
+ if (process.env.VERBOSE === 'true') {
235
+ logger.info(`✅ Validación de template OK para ${fileName} (${validation.metrics.duration.toFixed(2)}ms)`);
236
+ }
237
+ }
222
238
  return { code: finalCode, error: null };
223
239
  }
224
240
  catch (error) {
@@ -3,9 +3,24 @@ import { env } from 'node:process';
3
3
  import { logger } from '../servicios/logger.js';
4
4
  import { EXCLUDED_MODULES } from '../utils/excluded-modules.js';
5
5
  import { getModuleSubPath } from '../utils/module-resolver.js';
6
+ import { integrityValidator } from './integrity-validator.js';
6
7
  import { analyzeAndFormatMultipleErrors } from './error-reporter.js';
7
8
  import { getOptimizedAliasPath, getOptimizedModulePath, } from './module-resolution-optimizer.js';
8
9
  import { parser } from './parser.js';
10
+ // ✨ OPTIMIZACIÓN CRÍTICA: Cache de PATH_ALIAS parseado
11
+ let cachedPathAlias = null;
12
+ let lastPathAliasString = null;
13
+ function getParsedPathAlias() {
14
+ if (!env.PATH_ALIAS)
15
+ return null;
16
+ // Solo parsear si el string cambió
17
+ if (cachedPathAlias && lastPathAliasString === env.PATH_ALIAS) {
18
+ return cachedPathAlias;
19
+ }
20
+ cachedPathAlias = JSON.parse(env.PATH_ALIAS);
21
+ lastPathAliasString = env.PATH_ALIAS;
22
+ return cachedPathAlias;
23
+ }
9
24
  // Módulos built-in de Node.js que no deben ser resueltos
10
25
  const NODE_BUILTIN_MODULES = new Set([
11
26
  'fs',
@@ -94,7 +109,7 @@ export async function replaceAliasImportStatic(file, code) {
94
109
  if (!env.PATH_ALIAS || !env.PATH_DIST) {
95
110
  return code;
96
111
  }
97
- const pathAlias = JSON.parse(env.PATH_ALIAS);
112
+ const pathAlias = getParsedPathAlias();
98
113
  let resultCode = code;
99
114
  // Usar regex para transformar imports estáticos
100
115
  const importRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*(?:\{[^}]*\}|\*\s+as\s+\w+|\w+))*\s+from\s+)?['"`]([^'"`]+)['"`]/g;
@@ -206,7 +221,7 @@ export async function replaceAliasImportDynamic(code, _imports, file) {
206
221
  if (!env.PATH_ALIAS || !env.PATH_DIST) {
207
222
  return code;
208
223
  }
209
- const pathAlias = JSON.parse(env.PATH_ALIAS);
224
+ const pathAlias = getParsedPathAlias();
210
225
  const pathDist = env.PATH_DIST;
211
226
  let resultCode = code;
212
227
  // Regex para imports dinámicos normales con string (solo comillas simples y dobles)
@@ -391,7 +406,7 @@ async function replaceAliasInStrings(code) {
391
406
  if (!env.PATH_ALIAS || !env.PATH_DIST) {
392
407
  return code;
393
408
  }
394
- const pathAlias = JSON.parse(env.PATH_ALIAS);
409
+ const pathAlias = getParsedPathAlias();
395
410
  const pathDist = env.PATH_DIST;
396
411
  let resultCode = code; // Regex para encontrar strings que contengan posibles alias
397
412
  // Busca strings entre comillas simples, dobles o backticks que contengan alias
@@ -518,6 +533,7 @@ const removeCodeTagImport = async (data) => {
518
533
  return data;
519
534
  };
520
535
  export async function estandarizaCode(code, file) {
536
+ const originalCode = code; // Guardar código original para validación
521
537
  try {
522
538
  const ast = await parser(file, code);
523
539
  if (ast && ast.errors && ast.errors.length > 0) {
@@ -542,6 +558,21 @@ export async function estandarizaCode(code, file) {
542
558
  if (env.isPROD === 'true') {
543
559
  code = await removePreserverComent(code);
544
560
  }
561
+ // VALIDACIÓN DE INTEGRIDAD - Solo si flag está activo
562
+ if (env.CHECK_INTEGRITY === 'true') {
563
+ const validation = integrityValidator.validate(originalCode, code, `transforms:${path.basename(file)}`, {
564
+ skipSyntaxCheck: false, // SÍ validar sintaxis en transformaciones
565
+ verbose: env.VERBOSE === 'true',
566
+ throwOnError: true,
567
+ });
568
+ if (!validation.valid) {
569
+ logger.error(`❌ Validación de integridad fallida en transformaciones para ${path.basename(file)}`, validation.errors.join(', '));
570
+ throw new Error(`Transform integrity check failed for ${path.basename(file)}: ${validation.errors.join(', ')}`);
571
+ }
572
+ if (env.VERBOSE === 'true') {
573
+ logger.info(`✅ Validación de transformaciones OK para ${path.basename(file)} (${validation.metrics.duration.toFixed(2)}ms)`);
574
+ }
575
+ }
545
576
  return { code, error: null };
546
577
  }
547
578
  catch (error) {