versacompiler 2.0.4 → 2.0.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.
@@ -6,6 +6,42 @@ import * as fs from 'node:fs';
6
6
  import * as path from 'node:path';
7
7
  import * as process from 'node:process';
8
8
  import * as typescript from 'typescript';
9
+ /**
10
+ * Genera declaraciones básicas de tipos para Vue como fallback
11
+ */
12
+ const generateBasicVueTypes = () => {
13
+ return `// Declaraciones básicas de tipos Vue para validación
14
+ declare global {
15
+ function ref<T>(value: T): { value: T };
16
+ function reactive<T extends object>(target: T): T;
17
+ function computed<T>(getter: () => T): { value: T };
18
+ function defineComponent<T>(options: T): T;
19
+ function defineProps<T = {}>(): T;
20
+ function defineEmits<T = {}>(): T;
21
+ function defineExpose<T = {}>(exposed: T): void;
22
+ function onMounted(fn: () => void): void;
23
+ function onUnmounted(fn: () => void): void;
24
+ function onBeforeMount(fn: () => void): void;
25
+ function onBeforeUnmount(fn: () => void): void;
26
+ function onUpdated(fn: () => void): void;
27
+ function onBeforeUpdate(fn: () => void): void;
28
+ function provide<T>(key: string | symbol, value: T): void;
29
+ function inject<T>(key: string | symbol, defaultValue?: T): T | undefined;
30
+ function useSlots(): { [key: string]: (...args: any[]) => any };
31
+ function useAttrs(): { [key: string]: any };
32
+ function useModel<T>(modelName?: string): { value: T };
33
+ function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void): void;
34
+ function watchEffect(effect: () => void): void;
35
+ function nextTick(callback?: () => void): Promise<void>;
36
+ function getCurrentInstance(): any;
37
+ function mergeModels<T>(models: T): T;
38
+ }
39
+ declare module '*.vue' {
40
+ const component: any;
41
+ export default component;
42
+ }
43
+ export {};`;
44
+ };
9
45
  /**
10
46
  * Language Service Host para validación de tipos eficiente
11
47
  */
@@ -13,7 +49,11 @@ class TypeScriptLanguageServiceHost {
13
49
  files = new Map();
14
50
  compilerOptions;
15
51
  constructor(compilerOptions) {
16
- this.compilerOptions = compilerOptions;
52
+ this.compilerOptions = {
53
+ ...compilerOptions,
54
+ // Asegurar que las librerías DOM estén incluidas para archivos Vue
55
+ lib: compilerOptions.lib || ['ES2020', 'DOM', 'DOM.Iterable'],
56
+ };
17
57
  }
18
58
  addFile(fileName, content) {
19
59
  const existing = this.files.get(fileName);
@@ -84,58 +124,52 @@ class TypeScriptLanguageServiceHost {
84
124
  * @returns Resultado de la validación de tipos
85
125
  */
86
126
  export const validateTypesWithLanguageService = (fileName, content, compilerOptions) => {
87
- let actualFileName = fileName; // Declarar aquí para acceso en catch
88
127
  try {
89
- const scriptContent = content;
90
128
  // Si el script está vacío o es solo espacios en blanco, no validar
91
- if (!scriptContent.trim()) {
129
+ if (!content.trim()) {
92
130
  return { diagnostics: [], hasErrors: false };
93
- }
94
- // Crear Language Service Host
131
+ } // Crear Language Service Host
95
132
  const host = new TypeScriptLanguageServiceHost(compilerOptions);
96
133
  // Para archivos Vue, crear un archivo virtual .ts
134
+ let actualFileName = fileName;
97
135
  if (fileName.endsWith('.vue')) {
98
- // Usar ruta absoluta para el archivo virtual
99
- const absolutePath = path.isAbsolute(fileName)
100
- ? fileName
101
- : path.resolve(fileName);
102
- // Crear un nombre de archivo virtual único que no colisione
103
- const virtualFileName = absolutePath.replace('.vue', '.vue.ts');
104
- host.addFile(virtualFileName, scriptContent);
105
- actualFileName = virtualFileName;
106
- }
107
- else {
108
- // Para archivos virtuales, usar el nombre tal como viene (como en el worker)
109
- host.addFile(fileName, scriptContent);
110
- actualFileName = fileName;
136
+ // Crear un nombre de archivo virtual con extensión .ts
137
+ actualFileName = fileName.replace('.vue', '.vue.ts');
111
138
  }
112
- // Agregar declaraciones básicas de tipos para Vue si es necesario
139
+ // Agregar el archivo al host con el nombre correcto
140
+ host.addFile(actualFileName, content);
141
+ // Agregar declaraciones de tipos para Vue si es necesario
113
142
  if (fileName.endsWith('.vue')) {
114
- // Usar el directorio del archivo actual para las declaraciones
115
- const projectDir = path.dirname(actualFileName);
116
- const vueTypesPath = path.join(projectDir, 'vue-types.d.ts');
117
- const vueTypesDeclaration = `// Declaraciones de tipos Vue para validación
118
- declare global {
119
- function ref<T>(value: T): { value: T };
120
- function reactive<T extends object>(target: T): T;
121
- function computed<T>(getter: () => T): { value: T };
122
- function defineComponent<T>(options: T): T;
123
- function defineProps<T = {}>(): T;
124
- function defineEmits<T = {}>(): T;
125
- function onMounted(fn: () => void): void;
126
- function onUnmounted(fn: () => void): void;
127
- function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void): void;
128
- }
129
- export {}; `;
130
- host.addFile(vueTypesPath, vueTypesDeclaration);
143
+ // Cargar declaraciones de tipos Vue desde archivo shims
144
+ const projectRoot = process.cwd();
145
+ const vueShimsPath = path.join(projectRoot, 'src/types/vue-shims.d.ts');
146
+ try {
147
+ if (fs.existsSync(vueShimsPath)) {
148
+ const vueShimsContent = fs.readFileSync(vueShimsPath, 'utf-8');
149
+ host.addFile(vueShimsPath, vueShimsContent);
150
+ }
151
+ else {
152
+ // Fallback a declaraciones básicas si no se encuentra el archivo shims
153
+ const basicVueTypes = generateBasicVueTypes();
154
+ const fallbackTypesPath = path.join(path.dirname(fileName), 'vue-fallback.d.ts');
155
+ host.addFile(fallbackTypesPath, basicVueTypes);
156
+ }
157
+ }
158
+ catch (error) {
159
+ // Si hay error cargando los tipos, usar fallback básico
160
+ console.warn('Error al cargar tipos Vue:', error);
161
+ const basicVueTypes = generateBasicVueTypes();
162
+ const fallbackTypesPath = path.join(path.dirname(fileName), 'vue-fallback.d.ts');
163
+ host.addFile(fallbackTypesPath, basicVueTypes);
164
+ }
131
165
  } // Crear Language Service
132
166
  const languageService = typescript.createLanguageService(host);
133
167
  try {
134
168
  // Verificar que el archivo existe en el host antes de solicitar diagnósticos
135
169
  if (!host.fileExists(actualFileName)) {
170
+ console.log('File does not exist in host, returning empty result');
136
171
  return { diagnostics: [], hasErrors: false };
137
- }
138
- // Obtener diagnósticos de tipos con manejo de errores
172
+ } // Obtener diagnósticos de tipos con manejo de errores
139
173
  let syntacticDiagnostics = [];
140
174
  let semanticDiagnostics = [];
141
175
  try {
@@ -156,39 +190,73 @@ export const validateTypesWithLanguageService = (fileName, content, compilerOpti
156
190
  const allDiagnostics = [
157
191
  ...syntacticDiagnostics,
158
192
  ...semanticDiagnostics,
159
- ]; // Filtrar diagnósticos relevantes
193
+ ];
194
+ // Filtrar diagnósticos relevantes con mejor manejo para Vue
160
195
  const filteredDiagnostics = allDiagnostics.filter((diag) => {
161
196
  const messageText = typescript.flattenDiagnosticMessageText(diag.messageText, '\n');
162
- // Solo errores de categoría Error
197
+ // Solo errores de categoría Error (no warnings)
163
198
  if (diag.category !== typescript.DiagnosticCategory.Error) {
164
199
  return false;
200
+ } // Errores de infraestructura que siempre se filtran
201
+ const infrastructureErrors = [
202
+ 'Cannot find module',
203
+ 'Could not find source file',
204
+ "has no exported member 'mergeModels'",
205
+ 'Unable to resolve signature of method decorator',
206
+ 'The runtime will invoke the decorator with',
207
+ 'Module resolution kind is not specified',
208
+ 'Cannot resolve module',
209
+ "Cannot find name 'console'", // Error común al usar console en entorno sin DOM
210
+ 'Do you need to change your target library', // Sugerencia de librerías
211
+ ];
212
+ for (const errorPattern of infrastructureErrors) {
213
+ if (messageText.includes(errorPattern)) {
214
+ return false;
215
+ }
216
+ } // Códigos de error específicos que se filtran
217
+ const filteredErrorCodes = [
218
+ 1241, // decorator signature mismatch
219
+ 2307, // Cannot find module (redundant but explicit)
220
+ 2584, // Cannot find name (ej: console sin DOM lib)
221
+ 6133, // unused variables (warnings, not errors in this context)
222
+ ];
223
+ if (filteredErrorCodes.includes(diag.code)) {
224
+ return false;
225
+ }
226
+ // Para archivos Vue, filtrar solo errores específicos de infraestructura
227
+ if (fileName.endsWith('.vue')) {
228
+ // Parámetros implícitos generados automáticamente por Vue
229
+ const vueImplicitParams = [
230
+ '$props',
231
+ '$setup',
232
+ '$data',
233
+ '$options',
234
+ '$event',
235
+ '_ctx',
236
+ '_cache',
237
+ '__expose',
238
+ '__emit',
239
+ '__slots',
240
+ '__props',
241
+ '__defaults',
242
+ ];
243
+ // Solo filtrar errores de 'any' implícito para parámetros de infraestructura de Vue
244
+ if (messageText.includes("implicitly has an 'any' type")) {
245
+ const hasVueImplicitParam = vueImplicitParams.some(param => messageText.includes(`'${param}'`) ||
246
+ messageText.includes(`"${param}"`));
247
+ if (hasVueImplicitParam) {
248
+ return false;
249
+ }
250
+ }
251
+ // Filtrar errores específicos de setup function
252
+ if (messageText.includes('Parameter') &&
253
+ messageText.includes('implicitly has an') &&
254
+ vueImplicitParams.some(param => messageText.includes(param))) {
255
+ return false;
256
+ }
165
257
  }
166
- // Ignorar SOLO errores específicos de infraestructura Vue y rutas de módulos
167
- return (!messageText.includes('Cannot find module') &&
168
- !messageText.includes('Could not find source file') &&
169
- !messageText.includes("Parameter '$props' implicitly has an 'any' type") &&
170
- !messageText.includes("Parameter '$setup' implicitly has an 'any' type") &&
171
- !messageText.includes("Parameter '$data' implicitly has an 'any' type") &&
172
- !messageText.includes("Parameter '$options' implicitly has an 'any' type") &&
173
- !messageText.includes("Parameter '$event' implicitly has an 'any' type") &&
174
- !messageText.includes("Parameter '_ctx' implicitly has an 'any' type") &&
175
- !messageText.includes("Parameter '_cache' implicitly has an 'any' type") &&
176
- // Ignorar errores específicos de decorators cuando están mal configurados
177
- !messageText.includes('Unable to resolve signature of method decorator when called as an expression') &&
178
- !messageText.includes('The runtime will invoke the decorator with') &&
179
- // Ignorar errores TS7031 (binding element implicitly has any type)
180
- diag.code !== 7031 &&
181
- // Ignorar errores TS7006 (parameter implicitly has any type)
182
- diag.code !== 7006 &&
183
- // Ignorar errores TS1241 (decorator signature mismatch) durante desarrollo
184
- diag.code !== 1241 &&
185
- // Permitir errores de "Cannot find name" ya que son errores de código real
186
- // Solo filtrar parámetros implícitos de Vue generados automáticamente
187
- !(messageText.includes("implicitly has an 'any' type") &&
188
- (messageText.includes('_ctx') ||
189
- messageText.includes('_cache') ||
190
- messageText.includes('$props') ||
191
- messageText.includes('$setup'))));
258
+ // Mantener TODOS los demás errores - especialmente errores de tipos del usuario
259
+ return true;
192
260
  });
193
261
  return {
194
262
  diagnostics: filteredDiagnostics,
@@ -34,42 +34,43 @@ class WorkerTypeScriptLanguageServiceHost {
34
34
  createUltraCleanCompilerOptions(options) {
35
35
  // Usar las opciones del tsconfig.json pasadas desde el hilo principal
36
36
  const cleanOptions = {
37
- target: options.target || ts.ScriptTarget.ES2020,
38
- module: options.module || ts.ModuleKind.ES2020,
39
- strict: Boolean(options.strict),
40
- noEmitOnError: Boolean(options.noEmitOnError),
41
- skipLibCheck: Boolean(options.skipLibCheck !== false), // true por defecto
42
- skipDefaultLibCheck: Boolean(options.skipDefaultLibCheck !== false), // true por defecto
43
- allowJs: Boolean(options.allowJs !== false), // true por defecto
44
- esModuleInterop: Boolean(options.esModuleInterop !== false), // true por defecto
45
- allowSyntheticDefaultImports: Boolean(
46
- options.allowSyntheticDefaultImports !== false,
47
- ), // true por defecto
48
- declaration: Boolean(options.declaration),
49
- sourceMap: Boolean(options.sourceMap),
50
- noImplicitAny: Boolean(options.noImplicitAny),
51
- noImplicitReturns: Boolean(options.noImplicitReturns),
52
- noImplicitThis: Boolean(options.noImplicitThis),
53
- noUnusedLocals: Boolean(options.noUnusedLocals),
54
- noUnusedParameters: Boolean(options.noUnusedParameters),
55
- isolatedModules: Boolean(options.isolatedModules !== false), // true por defecto // Usar las librerías especificadas en el tsconfig.json
56
- lib: Array.isArray(options.lib)
57
- ? options.lib
58
- : ['es2020', 'dom', 'dom.iterable'],
59
-
60
- // Soporte para decorators
61
- experimentalDecorators: Boolean(
62
- options.experimentalDecorators !== false,
63
- ),
64
- emitDecoratorMetadata: Boolean(
65
- options.emitDecoratorMetadata !== false,
66
- ),
67
-
68
- // Opciones críticas para el worker pero manteniendo compatibilidad
69
- noLib: false, // Permitir librerías para APIs básicas (DOM, Promise, etc.)
70
- noResolve: true, // Evitar resolución de módulos compleja pero mantener tipos globales
71
- suppressOutputPathCheck: true,
72
- allowNonTsExtensions: true,
37
+ // target: options.target || ts.ScriptTarget.ES2020,
38
+ // module: options.module || ts.ModuleKind.ES2020,
39
+ // strict: Boolean(options.strict),
40
+ // noEmitOnError: Boolean(options.noEmitOnError),
41
+ // skipLibCheck: Boolean(options.skipLibCheck !== false), // true por defecto
42
+ // skipDefaultLibCheck: Boolean(options.skipDefaultLibCheck !== false), // true por defecto
43
+ // allowJs: Boolean(options.allowJs !== false), // true por defecto
44
+ // esModuleInterop: Boolean(options.esModuleInterop !== false), // true por defecto
45
+ // allowSyntheticDefaultImports: Boolean(
46
+ // options.allowSyntheticDefaultImports !== false,
47
+ // ), // true por defecto
48
+ // declaration: Boolean(options.declaration),
49
+ // sourceMap: Boolean(options.sourceMap),
50
+ // noImplicitAny: Boolean(options.noImplicitAny),
51
+ // noImplicitReturns: Boolean(options.noImplicitReturns),
52
+ // noImplicitThis: Boolean(options.noImplicitThis),
53
+ // noUnusedLocals: Boolean(options.noUnusedLocals),
54
+ // noUnusedParameters: Boolean(options.noUnusedParameters),
55
+ // isolatedModules: Boolean(options.isolatedModules !== false), // true por defecto // Usar las librerías especificadas en el tsconfig.json
56
+ // lib: Array.isArray(options.lib)
57
+ // ? options.lib
58
+ // : ['es2020', 'dom', 'dom.iterable'],
59
+
60
+ // // Soporte para decorators
61
+ // experimentalDecorators: Boolean(
62
+ // options.experimentalDecorators !== false,
63
+ // ),
64
+ // emitDecoratorMetadata: Boolean(
65
+ // options.emitDecoratorMetadata !== false,
66
+ // ),
67
+
68
+ // // Opciones críticas para el worker pero manteniendo compatibilidad
69
+ // noLib: false, // Permitir librerías para APIs básicas (DOM, Promise, etc.)
70
+ // noResolve: true, // Evitar resolución de módulos compleja pero mantener tipos globales
71
+ // suppressOutputPathCheck: true,
72
+ // allowNonTsExtensions: true,
73
+ ...options,
73
74
  };
74
75
 
75
76
  // console.log(
@@ -200,6 +201,13 @@ function validateTypesInWorker(fileName, content, compilerOptions) {
200
201
  function defineComponent<T>(options: T): T;
201
202
  function defineProps<T = {}>(): T;
202
203
  function defineEmits<T = {}>(): T;
204
+ function defineExpose<T = {}>(exposed: T): void;
205
+ function mergeModels<T>(models: T): T;
206
+ function provide<T>(key: string | symbol, value: T): void;
207
+ function inject<T>(key: string | symbol, defaultValue?: T): T | undefined;
208
+ function useSlots(): { [key: string]: (...args: any[]) => any };
209
+ function useAttrs(): { [key: string]: any };
210
+ function useModel<T>(modelName: string): { value: T };
203
211
  function onMounted(fn: () => void): void;
204
212
  function onUnmounted(fn: () => void): void;
205
213
  function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void): void;
@@ -282,6 +290,9 @@ function validateTypesInWorker(fileName, content, compilerOptions) {
282
290
  return (
283
291
  !messageText.includes('Cannot find module') &&
284
292
  !messageText.includes('Could not find source file') &&
293
+ !messageText.includes(
294
+ "has no exported member 'mergeModels'",
295
+ ) &&
285
296
  !messageText.includes(
286
297
  "Parameter '$props' implicitly has an 'any' type",
287
298
  ) &&
@@ -310,10 +321,9 @@ function validateTypesInWorker(fileName, content, compilerOptions) {
310
321
  !messageText.includes(
311
322
  'The runtime will invoke the decorator with',
312
323
  ) &&
313
- // Ignorar errores TS7031 (binding element implicitly has any type)
314
- diag.code !== 7031 &&
315
- // Ignorar errores TS7006 (parameter implicitly has any type)
316
- diag.code !== 7006 &&
324
+ // NO ignorar errores TS7031 y TS7006 de forma general, solo para parámetros específicos de Vue
325
+ // diag.code !== 7031 &&
326
+ // diag.code !== 7006 &&
317
327
  // Ignorar errores TS1241 (decorator signature mismatch) durante desarrollo
318
328
  diag.code !== 1241 &&
319
329
  !(
@@ -1,6 +1,8 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import path from 'node:path';
3
3
  import * as vCompiler from 'vue/compiler-sfc';
4
+ // Type casting para evitar problemas de tipos con Vue SFC
5
+ const vueCompiler = vCompiler;
4
6
  import { logger } from '../servicios/logger.js';
5
7
  import { parser } from './parser.js';
6
8
  // Lazy loading para chalk
@@ -160,16 +162,16 @@ export const preCompileVue = async (data, source, isProd = false) => {
160
162
  const { injectedData } = hmrInjectionCache.getOrGenerateHMRInjection(data, fileName);
161
163
  data = injectedData;
162
164
  }
163
- const { descriptor, errors } = vCompiler.parse(data, {
165
+ const { descriptor, errors } = vueCompiler.parse(data, {
164
166
  filename: fileName,
165
167
  sourceMap: !isProd,
166
168
  sourceRoot: path.dirname(source),
167
169
  });
168
170
  if (errors.length) {
169
- throw new Error(`Error al analizar el componente Vue ${source}:\n${errors.map(e => e.message).join('\n')}`);
171
+ throw new Error(`Error al analizar el componente Vue ${source}:\n${errors.map((e) => e.message).join('\n')}`);
170
172
  }
171
173
  const id = Math.random().toString(36).slice(2, 12);
172
- const scopeId = descriptor.styles.some(s => s.scoped)
174
+ const scopeId = descriptor.styles.some((s) => s.scoped)
173
175
  ? `data-v-${id}`
174
176
  : null;
175
177
  // --- 1. Compilación del Script ---
@@ -200,7 +202,7 @@ export const preCompileVue = async (data, source, isProd = false) => {
200
202
  },
201
203
  customElement: false,
202
204
  };
203
- const compiledScriptResult = vCompiler.compileScript(descriptor, scriptCompileOptions);
205
+ const compiledScriptResult = vueCompiler.compileScript(descriptor, scriptCompileOptions);
204
206
  scriptContent = compiledScriptResult.content;
205
207
  scriptLang =
206
208
  scriptToCompile.lang?.toLowerCase() === 'ts' ||
@@ -251,7 +253,7 @@ export const preCompileVue = async (data, source, isProd = false) => {
251
253
  directiveTransforms: {},
252
254
  },
253
255
  };
254
- const compiledTemplateResult = vCompiler.compileTemplate(templateCompileOptions);
256
+ const compiledTemplateResult = vueCompiler.compileTemplate(templateCompileOptions);
255
257
  if (compiledTemplateResult.errors?.length > 0) {
256
258
  logger.error('Template compilation errors:', compiledTemplateResult.errors);
257
259
  }
@@ -275,7 +277,7 @@ export const preCompileVue = async (data, source, isProd = false) => {
275
277
  descriptor.customBlocks[0]?.content.slice(0, -1) ?? '';
276
278
  }
277
279
  // Compile styles
278
- const compiledStyles = descriptor.styles.map(style => {
280
+ const compiledStyles = descriptor.styles.map((style) => {
279
281
  const lang = style.lang?.toLowerCase();
280
282
  let currentPreprocessLang = undefined;
281
283
  if (lang === 'scss' ||
@@ -285,7 +287,7 @@ export const preCompileVue = async (data, source, isProd = false) => {
285
287
  lang === 'stylus') {
286
288
  currentPreprocessLang = lang;
287
289
  }
288
- return vCompiler.compileStyle({
290
+ return vueCompiler.compileStyle({
289
291
  id,
290
292
  source: style.content,
291
293
  scoped: style.scoped,
@@ -299,7 +301,7 @@ export const preCompileVue = async (data, source, isProd = false) => {
299
301
  ? `(function(){
300
302
  let styleTag = document.createElement('style');
301
303
  styleTag.setAttribute('data-v-${id}', '');
302
- styleTag.innerHTML = \`${compiledStyles.map(s => s.code).join('\n')}\`;
304
+ styleTag.innerHTML = \`${compiledStyles.map((s) => s.code).join('\n')}\`;
303
305
  document.head.appendChild(styleTag);
304
306
  })();`
305
307
  : '';