versacompiler 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler/typescript-compiler.js +8 -215
- package/dist/compiler/typescript-manager.js +98 -225
- package/dist/compiler/typescript-sync-validator.js +135 -67
- package/dist/compiler/typescript-worker-thread.cjs +50 -40
- package/dist/compiler/vuejs.js +10 -8
- package/dist/hrm/initHRM.js +1 -0
- package/dist/servicios/browserSync.js +22 -0
- package/dist/utils/proxyValidator.js +68 -0
- package/dist/utils/vue-types-setup.js +442 -0
- package/package.json +9 -8
|
@@ -4,6 +4,7 @@ import * as process from 'node:process';
|
|
|
4
4
|
import { env } from 'node:process';
|
|
5
5
|
import * as typescript from 'typescript';
|
|
6
6
|
import { createUnifiedErrorMessage, parseTypeScriptErrors, } from './typescript-error-parser.js';
|
|
7
|
+
import { validateTypesWithLanguageService } from './typescript-sync-validator.js';
|
|
7
8
|
import { TypeScriptWorkerManager } from './typescript-worker.js';
|
|
8
9
|
/**
|
|
9
10
|
* Cache para la configuración de TypeScript para evitar lecturas repetidas
|
|
@@ -26,16 +27,8 @@ export const loadTypeScriptConfig = (fileName) => {
|
|
|
26
27
|
try {
|
|
27
28
|
const { config, error: configError } = typescript.readConfigFile(configPath, typescript.sys.readFile);
|
|
28
29
|
if (!configError) {
|
|
29
|
-
const parsedConfig = typescript.parseJsonConfigFileContent(config, typescript.sys, path.dirname(configPath));
|
|
30
|
-
compilerOptions =
|
|
31
|
-
...parsedConfig.options,
|
|
32
|
-
// Asegurar opciones básicas necesarias
|
|
33
|
-
allowJs: parsedConfig.options.allowJs !== false,
|
|
34
|
-
esModuleInterop: parsedConfig.options.esModuleInterop !== false,
|
|
35
|
-
allowSyntheticDefaultImports: parsedConfig.options.allowSyntheticDefaultImports !==
|
|
36
|
-
false,
|
|
37
|
-
skipLibCheck: parsedConfig.options.skipLibCheck !== false,
|
|
38
|
-
};
|
|
30
|
+
const parsedConfig = typescript.parseJsonConfigFileContent(config, typescript.sys, path.dirname(configPath)); // Usar exactamente la configuración del tsconfig.json del usuario
|
|
31
|
+
compilerOptions = parsedConfig.options;
|
|
39
32
|
}
|
|
40
33
|
else {
|
|
41
34
|
throw new Error(`Error al leer tsconfig.json: ${configError.messageText}`);
|
|
@@ -75,214 +68,14 @@ const getDefaultCompilerOptions = () => ({
|
|
|
75
68
|
* @returns Opciones serializables seguras para workers
|
|
76
69
|
*/
|
|
77
70
|
const createSerializableCompilerOptions = (options) => {
|
|
78
|
-
//
|
|
79
|
-
const { target = typescript.ScriptTarget.ES2020, module = typescript.ModuleKind.ES2020, lib = ['es2020', 'dom', 'dom.iterable'], allowJs = true, jsx, strict = false, skipLibCheck = true, esModuleInterop = true, allowSyntheticDefaultImports = true, isolatedModules = true, } = options;
|
|
71
|
+
// Respetar completamente la configuración del usuario del tsconfig.json
|
|
80
72
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
jsx,
|
|
86
|
-
strict,
|
|
87
|
-
skipLibCheck,
|
|
88
|
-
skipDefaultLibCheck: true,
|
|
89
|
-
esModuleInterop,
|
|
90
|
-
allowSyntheticDefaultImports,
|
|
91
|
-
isolatedModules,
|
|
92
|
-
noEmitOnError: false,
|
|
93
|
-
declaration: false,
|
|
94
|
-
sourceMap: false,
|
|
73
|
+
...options,
|
|
74
|
+
// NO modificar configuraciones del usuario - solo optimizaciones internas del worker que no afectan la validación
|
|
75
|
+
declaration: false, // No necesitamos declaraciones en el worker
|
|
76
|
+
sourceMap: false, // No necesitamos source maps en el worker
|
|
95
77
|
};
|
|
96
78
|
};
|
|
97
|
-
/**
|
|
98
|
-
* Crea un Language Service Host optimizado para validación de tipos eficiente.
|
|
99
|
-
*/
|
|
100
|
-
class TypeScriptLanguageServiceHost {
|
|
101
|
-
files = new Map();
|
|
102
|
-
compilerOptions;
|
|
103
|
-
fileSystemCache = new Map();
|
|
104
|
-
constructor(compilerOptions) {
|
|
105
|
-
this.compilerOptions = compilerOptions;
|
|
106
|
-
}
|
|
107
|
-
addFile(fileName, content) {
|
|
108
|
-
const existing = this.files.get(fileName);
|
|
109
|
-
this.files.set(fileName, {
|
|
110
|
-
version: existing ? existing.version + 1 : 1,
|
|
111
|
-
content,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
getCompilationSettings() {
|
|
115
|
-
return this.compilerOptions;
|
|
116
|
-
}
|
|
117
|
-
getScriptFileNames() {
|
|
118
|
-
return Array.from(this.files.keys());
|
|
119
|
-
}
|
|
120
|
-
getScriptVersion(fileName) {
|
|
121
|
-
const file = this.files.get(fileName);
|
|
122
|
-
return file ? file.version.toString() : '0';
|
|
123
|
-
}
|
|
124
|
-
getScriptSnapshot(fileName) {
|
|
125
|
-
const file = this.files.get(fileName);
|
|
126
|
-
if (file) {
|
|
127
|
-
return typescript.ScriptSnapshot.fromString(file.content);
|
|
128
|
-
}
|
|
129
|
-
// Cache de sistema de archivos para evitar lecturas repetidas
|
|
130
|
-
if (this.fileSystemCache.has(fileName)) {
|
|
131
|
-
const cachedContent = this.fileSystemCache.get(fileName);
|
|
132
|
-
return cachedContent
|
|
133
|
-
? typescript.ScriptSnapshot.fromString(cachedContent)
|
|
134
|
-
: undefined;
|
|
135
|
-
}
|
|
136
|
-
// Intentar leer el archivo del sistema de archivos solo si es necesario
|
|
137
|
-
try {
|
|
138
|
-
if (fs.existsSync(fileName)) {
|
|
139
|
-
const content = fs.readFileSync(fileName, 'utf-8');
|
|
140
|
-
this.fileSystemCache.set(fileName, content);
|
|
141
|
-
return typescript.ScriptSnapshot.fromString(content);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
// Error al leer archivo
|
|
146
|
-
}
|
|
147
|
-
this.fileSystemCache.set(fileName, undefined);
|
|
148
|
-
return undefined;
|
|
149
|
-
}
|
|
150
|
-
getCurrentDirectory() {
|
|
151
|
-
return process.cwd();
|
|
152
|
-
}
|
|
153
|
-
getDefaultLibFileName(options) {
|
|
154
|
-
return typescript.getDefaultLibFilePath(options);
|
|
155
|
-
}
|
|
156
|
-
fileExists(path) {
|
|
157
|
-
if (this.files.has(path))
|
|
158
|
-
return true;
|
|
159
|
-
if (this.fileSystemCache.has(path)) {
|
|
160
|
-
return this.fileSystemCache.get(path) !== undefined;
|
|
161
|
-
}
|
|
162
|
-
const exists = fs.existsSync(path);
|
|
163
|
-
if (!exists)
|
|
164
|
-
this.fileSystemCache.set(path, undefined);
|
|
165
|
-
return exists;
|
|
166
|
-
}
|
|
167
|
-
readFile(path) {
|
|
168
|
-
const file = this.files.get(path);
|
|
169
|
-
if (file)
|
|
170
|
-
return file.content;
|
|
171
|
-
if (this.fileSystemCache.has(path)) {
|
|
172
|
-
return this.fileSystemCache.get(path);
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
if (fs.existsSync(path)) {
|
|
176
|
-
const content = fs.readFileSync(path, 'utf-8');
|
|
177
|
-
this.fileSystemCache.set(path, content);
|
|
178
|
-
return content;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
// Error al leer archivo
|
|
183
|
-
}
|
|
184
|
-
this.fileSystemCache.set(path, undefined);
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|
|
187
|
-
getNewLine() {
|
|
188
|
-
return typescript.sys.newLine;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Realiza validación de tipos optimizada usando TypeScript Language Service.
|
|
193
|
-
* @param fileName - Nombre del archivo
|
|
194
|
-
* @param content - Contenido del archivo
|
|
195
|
-
* @param compilerOptions - Opciones del compilador
|
|
196
|
-
* @returns Resultado de la validación de tipos
|
|
197
|
-
*/
|
|
198
|
-
const validateTypesWithLanguageService = (fileName, content, compilerOptions) => {
|
|
199
|
-
try {
|
|
200
|
-
// Validación temprana: contenido vacío
|
|
201
|
-
if (!content.trim()) {
|
|
202
|
-
return { diagnostics: [], hasErrors: false };
|
|
203
|
-
}
|
|
204
|
-
// Crear Language Service Host optimizado
|
|
205
|
-
const host = new TypeScriptLanguageServiceHost(compilerOptions);
|
|
206
|
-
// Determinar nombre de archivo efectivo
|
|
207
|
-
let actualFileName = path.isAbsolute(fileName)
|
|
208
|
-
? fileName
|
|
209
|
-
: path.resolve(fileName);
|
|
210
|
-
// Para archivos Vue, crear archivo virtual
|
|
211
|
-
if (fileName.endsWith('.vue')) {
|
|
212
|
-
actualFileName = actualFileName.replace('.vue', '.vue.ts');
|
|
213
|
-
host.addFile(actualFileName, content);
|
|
214
|
-
// Añadir declaraciones Vue básicas solo si es necesario
|
|
215
|
-
const vueTypesPath = path.join(path.dirname(actualFileName), 'vue-types.d.ts');
|
|
216
|
-
const vueTypesDeclaration = `
|
|
217
|
-
declare global {
|
|
218
|
-
function ref<T>(value: T): { value: T };
|
|
219
|
-
function reactive<T extends object>(target: T): T;
|
|
220
|
-
function computed<T>(getter: () => T): { value: T };
|
|
221
|
-
function defineComponent<T>(options: T): T;
|
|
222
|
-
function defineProps<T = {}>(): T;
|
|
223
|
-
function defineEmits<T = {}>(): T;
|
|
224
|
-
function onMounted(fn: () => void): void;
|
|
225
|
-
function onUnmounted(fn: () => void): void;
|
|
226
|
-
function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void): void;
|
|
227
|
-
}
|
|
228
|
-
export {};`;
|
|
229
|
-
host.addFile(vueTypesPath, vueTypesDeclaration);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
host.addFile(actualFileName, content);
|
|
233
|
-
} // Crear Language Service
|
|
234
|
-
const languageService = typescript.createLanguageService(host);
|
|
235
|
-
// Verificar existencia del archivo
|
|
236
|
-
if (!host.fileExists(actualFileName)) {
|
|
237
|
-
return { diagnostics: [], hasErrors: false };
|
|
238
|
-
}
|
|
239
|
-
// Obtener diagnósticos con manejo de errores optimizado
|
|
240
|
-
const allDiagnostics = [];
|
|
241
|
-
try {
|
|
242
|
-
allDiagnostics.push(...languageService.getSyntacticDiagnostics(actualFileName));
|
|
243
|
-
allDiagnostics.push(...languageService.getSemanticDiagnostics(actualFileName));
|
|
244
|
-
}
|
|
245
|
-
catch {
|
|
246
|
-
// Ignorar errores de diagnósticos
|
|
247
|
-
return { diagnostics: [], hasErrors: false };
|
|
248
|
-
} // Filtrado optimizado de diagnósticos
|
|
249
|
-
const filteredDiagnostics = allDiagnostics.filter(diag => {
|
|
250
|
-
if (diag.category !== typescript.DiagnosticCategory.Error)
|
|
251
|
-
return false;
|
|
252
|
-
const messageText = typescript.flattenDiagnosticMessageText(diag.messageText, '\n');
|
|
253
|
-
// Lista optimizada de patrones a ignorar
|
|
254
|
-
const ignorePatterns = [
|
|
255
|
-
'Cannot find module',
|
|
256
|
-
'Could not find source file',
|
|
257
|
-
"Parameter '$props' implicitly has an 'any' type",
|
|
258
|
-
"Parameter '$setup' implicitly has an 'any' type",
|
|
259
|
-
"Parameter '_ctx' implicitly has an 'any' type",
|
|
260
|
-
"Parameter '_cache' implicitly has an 'any' type",
|
|
261
|
-
];
|
|
262
|
-
return !ignorePatterns.some(pattern => messageText.includes(pattern));
|
|
263
|
-
});
|
|
264
|
-
return {
|
|
265
|
-
diagnostics: filteredDiagnostics,
|
|
266
|
-
hasErrors: filteredDiagnostics.length > 0,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
catch (error) {
|
|
270
|
-
// Error handling simplificado
|
|
271
|
-
return {
|
|
272
|
-
diagnostics: [
|
|
273
|
-
{
|
|
274
|
-
file: undefined,
|
|
275
|
-
start: undefined,
|
|
276
|
-
length: undefined,
|
|
277
|
-
messageText: `Error en validación de tipos: ${error instanceof Error ? error.message : 'Error desconocido'}`,
|
|
278
|
-
category: typescript.DiagnosticCategory.Error,
|
|
279
|
-
code: 0,
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
hasErrors: true,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
79
|
/**
|
|
287
80
|
* Valida tipos en archivos Vue antes de la compilación
|
|
288
81
|
* @param vueContent - Contenido del archivo Vue
|
|
@@ -4,6 +4,7 @@ import * as process from 'node:process';
|
|
|
4
4
|
import { env } from 'node:process';
|
|
5
5
|
import * as typescript from 'typescript';
|
|
6
6
|
import { createUnifiedErrorMessage, parseTypeScriptErrors, } from './typescript-error-parser.js';
|
|
7
|
+
import { validateTypesWithLanguageService } from './typescript-sync-validator.js';
|
|
7
8
|
import { TypeScriptWorkerPool } from './typescript-worker-pool.js';
|
|
8
9
|
/**
|
|
9
10
|
* Cache para la configuración de TypeScript para evitar lecturas repetidas
|
|
@@ -15,8 +16,13 @@ let configCache = {};
|
|
|
15
16
|
* @returns Opciones del compilador TypeScript
|
|
16
17
|
*/
|
|
17
18
|
export const loadTypeScriptConfig = (fileName) => {
|
|
19
|
+
// Siempre buscar primero en la raíz del proyecto
|
|
20
|
+
const rootConfigPath = path.resolve(process.cwd(), 'tsconfig.json');
|
|
21
|
+
// Si no existe en la raíz, buscar desde el directorio del archivo
|
|
18
22
|
const fileDir = path.dirname(fileName);
|
|
19
|
-
const configPath =
|
|
23
|
+
const configPath = fs.existsSync(rootConfigPath)
|
|
24
|
+
? rootConfigPath
|
|
25
|
+
: typescript.findConfigFile(fileDir, typescript.sys.fileExists, 'tsconfig.json');
|
|
20
26
|
// Usar cache si el path no ha cambiado
|
|
21
27
|
if (configCache.path === configPath && configCache.options) {
|
|
22
28
|
return configCache.options;
|
|
@@ -26,16 +32,12 @@ export const loadTypeScriptConfig = (fileName) => {
|
|
|
26
32
|
try {
|
|
27
33
|
const { config, error: configError } = typescript.readConfigFile(configPath, typescript.sys.readFile);
|
|
28
34
|
if (!configError) {
|
|
29
|
-
const parsedConfig = typescript.parseJsonConfigFileContent(config, typescript.sys, path.dirname(configPath));
|
|
30
|
-
compilerOptions =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
allowSyntheticDefaultImports: parsedConfig.options.allowSyntheticDefaultImports !==
|
|
36
|
-
false,
|
|
37
|
-
skipLibCheck: parsedConfig.options.skipLibCheck !== false,
|
|
38
|
-
};
|
|
35
|
+
const parsedConfig = typescript.parseJsonConfigFileContent(config, typescript.sys, path.dirname(configPath)); // Usar exactamente la configuración del tsconfig.json del usuario sin modificaciones
|
|
36
|
+
compilerOptions = parsedConfig.options;
|
|
37
|
+
// DEBUG: Verificar las opciones cargadas
|
|
38
|
+
// console.log(`[DEBUG] Opciones de TypeScript cargadas desde ${configPath}:`);
|
|
39
|
+
// console.log(` noImplicitAny: ${compilerOptions.noImplicitAny}`);
|
|
40
|
+
// console.log(` strict: ${compilerOptions.strict}`);
|
|
39
41
|
}
|
|
40
42
|
else {
|
|
41
43
|
throw new Error(`Error al leer tsconfig.json: ${configError.messageText}`);
|
|
@@ -43,255 +45,124 @@ export const loadTypeScriptConfig = (fileName) => {
|
|
|
43
45
|
}
|
|
44
46
|
catch (error) {
|
|
45
47
|
console.warn(`[loadTypeScriptConfig] Error cargando ${configPath}:`, error);
|
|
46
|
-
|
|
47
|
-
compilerOptions = getDefaultCompilerOptions();
|
|
48
|
+
throw new Error(`No se puede continuar sin un tsconfig.json válido. Error: ${error}`);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
else {
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
throw new Error(`No se encontró tsconfig.json en la raíz del proyecto (${rootConfigPath}) ni en el directorio del archivo. ` +
|
|
53
|
+
`El compilador requiere un tsconfig.json para funcionar correctamente.`);
|
|
53
54
|
}
|
|
54
55
|
// Guardar en cache
|
|
55
56
|
configCache = { path: configPath, options: compilerOptions };
|
|
56
57
|
return compilerOptions;
|
|
57
58
|
};
|
|
58
|
-
/**
|
|
59
|
-
* Obtiene las opciones por defecto del compilador TypeScript
|
|
60
|
-
*/
|
|
61
|
-
const getDefaultCompilerOptions = () => ({
|
|
62
|
-
target: typescript.ScriptTarget.ES2020,
|
|
63
|
-
module: typescript.ModuleKind.ES2020,
|
|
64
|
-
lib: ['es2020', 'dom', 'dom.iterable'],
|
|
65
|
-
strict: false,
|
|
66
|
-
skipLibCheck: true,
|
|
67
|
-
allowJs: true,
|
|
68
|
-
esModuleInterop: true,
|
|
69
|
-
allowSyntheticDefaultImports: true,
|
|
70
|
-
isolatedModules: true,
|
|
71
|
-
});
|
|
72
59
|
/**
|
|
73
60
|
* Crea una versión optimizada y serializable de las opciones del compilador typescript.
|
|
74
61
|
* @param options - Opciones originales del compilador
|
|
75
62
|
* @returns Opciones serializables seguras para workers
|
|
76
63
|
*/
|
|
77
64
|
const createSerializableCompilerOptions = (options) => {
|
|
78
|
-
//
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
module,
|
|
83
|
-
lib: Array.isArray(lib) ? lib : ['es2020', 'dom', 'dom.iterable'],
|
|
84
|
-
allowJs,
|
|
85
|
-
jsx,
|
|
86
|
-
strict,
|
|
87
|
-
skipLibCheck,
|
|
88
|
-
skipDefaultLibCheck: true,
|
|
89
|
-
esModuleInterop,
|
|
90
|
-
allowSyntheticDefaultImports,
|
|
91
|
-
isolatedModules,
|
|
92
|
-
noEmitOnError: false,
|
|
93
|
-
declaration: false,
|
|
94
|
-
sourceMap: false,
|
|
95
|
-
};
|
|
65
|
+
// Respetar exactamente las opciones del tsconfig.json del usuario // Respetar completamente la configuración del usuario del tsconfig.json
|
|
66
|
+
const result = { ...options };
|
|
67
|
+
// NO modificar ninguna opción del usuario - usar configuración exacta del tsconfig.json
|
|
68
|
+
return result;
|
|
96
69
|
};
|
|
97
70
|
/**
|
|
98
71
|
* Crea un Language Service Host optimizado para validación de tipos eficiente.
|
|
99
72
|
*/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Valida tipos en archivos Vue antes de la compilación con soporte mejorado
|
|
75
|
+
* @param vueContent - Contenido del archivo Vue
|
|
76
|
+
* @param fileName - Nombre del archivo Vue
|
|
77
|
+
* @param options - Opciones adicionales para la validación
|
|
78
|
+
* @returns Resultado de la validación de tipos
|
|
79
|
+
*/
|
|
80
|
+
export const validateVueTypes = (vueContent, fileName, options) => {
|
|
81
|
+
// Extraer contenido del script de Vue
|
|
82
|
+
let scriptContent = '';
|
|
83
|
+
if (fileName.endsWith('.vue')) {
|
|
84
|
+
// Extraer contenido entre <script> y </script>
|
|
85
|
+
const scriptMatch = vueContent.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
|
|
86
|
+
if (scriptMatch && scriptMatch[1]) {
|
|
87
|
+
scriptContent = scriptMatch[1].trim();
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Si no hay script, no hay nada que validar
|
|
91
|
+
return { diagnostics: [], hasErrors: false };
|
|
92
|
+
}
|
|
106
93
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
version: existing ? existing.version + 1 : 1,
|
|
111
|
-
content,
|
|
112
|
-
});
|
|
94
|
+
else {
|
|
95
|
+
// Para archivos .ts/.js normales, usar todo el contenido
|
|
96
|
+
scriptContent = vueContent;
|
|
113
97
|
}
|
|
114
|
-
|
|
115
|
-
|
|
98
|
+
// Si el script está vacío, no validar
|
|
99
|
+
if (!scriptContent.trim()) {
|
|
100
|
+
return { diagnostics: [], hasErrors: false };
|
|
116
101
|
}
|
|
117
|
-
|
|
118
|
-
|
|
102
|
+
// Cargar la configuración del usuario como base
|
|
103
|
+
const userConfig = loadTypeScriptConfig(fileName);
|
|
104
|
+
// Crear opciones del compilador respetando la configuración del usuario
|
|
105
|
+
let compilerOptions;
|
|
106
|
+
if (options?.compilerOptions) {
|
|
107
|
+
// Si se proporcionaron opciones explícitas, usarlas como base
|
|
108
|
+
compilerOptions = { ...options.compilerOptions };
|
|
119
109
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
110
|
+
else {
|
|
111
|
+
// Usar la configuración del usuario como base
|
|
112
|
+
compilerOptions = { ...userConfig };
|
|
123
113
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
114
|
+
// Solo forzar las opciones ABSOLUTAMENTE necesarias para Vue
|
|
115
|
+
// Estas opciones se fuerzan porque son técnicamente requeridas para el funcionamiento correcto
|
|
116
|
+
if (fileName.endsWith('.vue')) {
|
|
117
|
+
// JSX: Necesario para que funcione el template compilation de Vue
|
|
118
|
+
compilerOptions.jsx = typescript.JsxEmit.Preserve;
|
|
119
|
+
// ModuleResolution: Necesario para resolver módulos Vue correctamente
|
|
120
|
+
if (!compilerOptions.moduleResolution) {
|
|
121
|
+
compilerOptions.moduleResolution =
|
|
122
|
+
typescript.ModuleResolutionKind.NodeJs;
|
|
128
123
|
}
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// Intentar leer el archivo del sistema de archivos solo si es necesario
|
|
137
|
-
try {
|
|
138
|
-
if (fs.existsSync(fileName)) {
|
|
139
|
-
const content = fs.readFileSync(fileName, 'utf-8');
|
|
140
|
-
this.fileSystemCache.set(fileName, content);
|
|
141
|
-
return typescript.ScriptSnapshot.fromString(content);
|
|
142
|
-
}
|
|
124
|
+
// Lib: Asegurar que DOM esté disponible para archivos Vue, pero respetar otras libs del usuario
|
|
125
|
+
const currentLibs = compilerOptions.lib || userConfig.lib || ['ES2020'];
|
|
126
|
+
const hasDOM = currentLibs.some(lib => typeof lib === 'string' &&
|
|
127
|
+
(lib.toLowerCase().includes('dom') ||
|
|
128
|
+
lib.toLowerCase() === 'dom'));
|
|
129
|
+
if (!hasDOM) {
|
|
130
|
+
compilerOptions.lib = [...currentLibs, 'DOM', 'DOM.Iterable'];
|
|
143
131
|
}
|
|
144
|
-
|
|
145
|
-
|
|
132
|
+
// Types: Agregar 'vue' si no está presente, pero mantener otros types del usuario
|
|
133
|
+
const currentTypes = compilerOptions.types || userConfig.types || [];
|
|
134
|
+
if (!currentTypes.includes('vue')) {
|
|
135
|
+
compilerOptions.types = [...currentTypes, 'vue'];
|
|
146
136
|
}
|
|
147
|
-
this.fileSystemCache.set(fileName, undefined);
|
|
148
|
-
return undefined;
|
|
149
137
|
}
|
|
150
|
-
|
|
151
|
-
|
|
138
|
+
// Configuraciones que mejoran la detección de errores pero respetan preferencias del usuario
|
|
139
|
+
// Solo se aplican si el usuario no las ha configurado explícitamente
|
|
140
|
+
if (compilerOptions.skipLibCheck === undefined) {
|
|
141
|
+
compilerOptions.skipLibCheck = true; // Para evitar errores en librerías externas
|
|
152
142
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (this.files.has(path))
|
|
158
|
-
return true;
|
|
159
|
-
if (this.fileSystemCache.has(path)) {
|
|
160
|
-
return this.fileSystemCache.get(path) !== undefined;
|
|
161
|
-
}
|
|
162
|
-
const exists = fs.existsSync(path);
|
|
163
|
-
if (!exists)
|
|
164
|
-
this.fileSystemCache.set(path, undefined);
|
|
165
|
-
return exists;
|
|
166
|
-
}
|
|
167
|
-
readFile(path) {
|
|
168
|
-
const file = this.files.get(path);
|
|
169
|
-
if (file)
|
|
170
|
-
return file.content;
|
|
171
|
-
if (this.fileSystemCache.has(path)) {
|
|
172
|
-
return this.fileSystemCache.get(path);
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
if (fs.existsSync(path)) {
|
|
176
|
-
const content = fs.readFileSync(path, 'utf-8');
|
|
177
|
-
this.fileSystemCache.set(path, content);
|
|
178
|
-
return content;
|
|
179
|
-
}
|
|
143
|
+
// Aplicar strictMode solo si el usuario no ha configurado estas opciones individualmente
|
|
144
|
+
if (options?.strictMode !== undefined) {
|
|
145
|
+
if (compilerOptions.noImplicitReturns === undefined) {
|
|
146
|
+
compilerOptions.noImplicitReturns = options.strictMode;
|
|
180
147
|
}
|
|
181
|
-
|
|
182
|
-
|
|
148
|
+
if (compilerOptions.noImplicitThis === undefined) {
|
|
149
|
+
compilerOptions.noImplicitThis = options.strictMode;
|
|
183
150
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
getNewLine() {
|
|
188
|
-
return typescript.sys.newLine;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Realiza validación de tipos optimizada usando TypeScript Language Service.
|
|
193
|
-
* @param fileName - Nombre del archivo
|
|
194
|
-
* @param content - Contenido del archivo
|
|
195
|
-
* @param compilerOptions - Opciones del compilador
|
|
196
|
-
* @returns Resultado de la validación de tipos
|
|
197
|
-
*/
|
|
198
|
-
const validateTypesWithLanguageService = (fileName, content, compilerOptions) => {
|
|
199
|
-
try {
|
|
200
|
-
// Validación temprana: contenido vacío
|
|
201
|
-
if (!content.trim()) {
|
|
202
|
-
return { diagnostics: [], hasErrors: false };
|
|
151
|
+
if (compilerOptions.strictNullChecks === undefined) {
|
|
152
|
+
compilerOptions.strictNullChecks = options.strictMode;
|
|
203
153
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// Determinar nombre de archivo efectivo
|
|
207
|
-
let actualFileName = path.isAbsolute(fileName)
|
|
208
|
-
? fileName
|
|
209
|
-
: path.resolve(fileName);
|
|
210
|
-
// Para archivos Vue, crear archivo virtual
|
|
211
|
-
if (fileName.endsWith('.vue')) {
|
|
212
|
-
actualFileName = actualFileName.replace('.vue', '.vue.ts');
|
|
213
|
-
host.addFile(actualFileName, content);
|
|
214
|
-
// Añadir declaraciones Vue básicas solo si es necesario
|
|
215
|
-
const vueTypesPath = path.join(path.dirname(actualFileName), 'vue-types.d.ts');
|
|
216
|
-
const vueTypesDeclaration = `
|
|
217
|
-
declare global {
|
|
218
|
-
function ref<T>(value: T): { value: T };
|
|
219
|
-
function reactive<T extends object>(target: T): T;
|
|
220
|
-
function computed<T>(getter: () => T): { value: T };
|
|
221
|
-
function defineComponent<T>(options: T): T;
|
|
222
|
-
function defineProps<T = {}>(): T;
|
|
223
|
-
function defineEmits<T = {}>(): T;
|
|
224
|
-
function onMounted(fn: () => void): void;
|
|
225
|
-
function onUnmounted(fn: () => void): void;
|
|
226
|
-
function watch<T>(source: () => T, callback: (newValue: T, oldValue: T) => void): void;
|
|
227
|
-
}
|
|
228
|
-
export {};`;
|
|
229
|
-
host.addFile(vueTypesPath, vueTypesDeclaration);
|
|
154
|
+
if (compilerOptions.strictFunctionTypes === undefined) {
|
|
155
|
+
compilerOptions.strictFunctionTypes = options.strictMode;
|
|
230
156
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
} // Crear Language Service
|
|
234
|
-
const languageService = typescript.createLanguageService(host);
|
|
235
|
-
// Verificar existencia del archivo
|
|
236
|
-
if (!host.fileExists(actualFileName)) {
|
|
237
|
-
return { diagnostics: [], hasErrors: false };
|
|
157
|
+
if (compilerOptions.exactOptionalPropertyTypes === undefined) {
|
|
158
|
+
compilerOptions.exactOptionalPropertyTypes = false; // Menos estricto por defecto
|
|
238
159
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
allDiagnostics.push(...languageService.getSyntacticDiagnostics(actualFileName));
|
|
243
|
-
allDiagnostics.push(...languageService.getSemanticDiagnostics(actualFileName));
|
|
160
|
+
if (compilerOptions.noFallthroughCasesInSwitch === undefined) {
|
|
161
|
+
compilerOptions.noFallthroughCasesInSwitch = options.strictMode;
|
|
244
162
|
}
|
|
245
|
-
catch {
|
|
246
|
-
// Ignorar errores de diagnósticos
|
|
247
|
-
return { diagnostics: [], hasErrors: false };
|
|
248
|
-
} // Filtrado optimizado de diagnósticos
|
|
249
|
-
const filteredDiagnostics = allDiagnostics.filter(diag => {
|
|
250
|
-
if (diag.category !== typescript.DiagnosticCategory.Error)
|
|
251
|
-
return false;
|
|
252
|
-
const messageText = typescript.flattenDiagnosticMessageText(diag.messageText, '\n');
|
|
253
|
-
// Lista optimizada de patrones a ignorar
|
|
254
|
-
const ignorePatterns = [
|
|
255
|
-
'Cannot find module',
|
|
256
|
-
'Could not find source file',
|
|
257
|
-
"Parameter '$props' implicitly has an 'any' type",
|
|
258
|
-
"Parameter '$setup' implicitly has an 'any' type",
|
|
259
|
-
"Parameter '_ctx' implicitly has an 'any' type",
|
|
260
|
-
"Parameter '_cache' implicitly has an 'any' type",
|
|
261
|
-
];
|
|
262
|
-
return !ignorePatterns.some(pattern => messageText.includes(pattern));
|
|
263
|
-
});
|
|
264
|
-
return {
|
|
265
|
-
diagnostics: filteredDiagnostics,
|
|
266
|
-
hasErrors: filteredDiagnostics.length > 0,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
catch (error) {
|
|
270
|
-
// Error handling simplificado
|
|
271
|
-
return {
|
|
272
|
-
diagnostics: [
|
|
273
|
-
{
|
|
274
|
-
file: undefined,
|
|
275
|
-
start: undefined,
|
|
276
|
-
length: undefined,
|
|
277
|
-
messageText: `Error en validación de tipos: ${error instanceof Error ? error.message : 'Error desconocido'}`,
|
|
278
|
-
category: typescript.DiagnosticCategory.Error,
|
|
279
|
-
code: 0,
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
hasErrors: true,
|
|
283
|
-
};
|
|
284
163
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* Valida tipos en archivos Vue antes de la compilación
|
|
288
|
-
* @param vueContent - Contenido del archivo Vue
|
|
289
|
-
* @param fileName - Nombre del archivo Vue
|
|
290
|
-
* @returns Resultado de la validación de tipos
|
|
291
|
-
*/
|
|
292
|
-
export const validateVueTypes = (vueContent, fileName) => {
|
|
293
|
-
const compilerOptions = loadTypeScriptConfig(fileName);
|
|
294
|
-
return validateTypesWithLanguageService(fileName, vueContent, compilerOptions);
|
|
164
|
+
return validateTypesWithLanguageService(fileName, scriptContent, // Usar solo el contenido del script
|
|
165
|
+
compilerOptions);
|
|
295
166
|
};
|
|
296
167
|
/**
|
|
297
168
|
* Precompila el código TypeScript con pipeline optimizado para máxima performance.
|
|
@@ -340,7 +211,9 @@ export const preCompileTS = async (data, fileName) => {
|
|
|
340
211
|
};
|
|
341
212
|
}
|
|
342
213
|
} // PASO 2: Type checking opcional (solo si está habilitado)
|
|
214
|
+
// console.log(`[DEBUG] env.typeCheck: ${env.typeCheck}`);
|
|
343
215
|
if (env.typeCheck === 'true') {
|
|
216
|
+
// console.log(`[DEBUG] Iniciando verificación de tipos para: ${fileName}`);
|
|
344
217
|
try {
|
|
345
218
|
const workerPool = TypeScriptWorkerPool.getInstance();
|
|
346
219
|
const serializableOptions = createSerializableCompilerOptions(compilerOptions);
|