versacompiler 1.0.4 → 2.0.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.
- package/README.md +357 -145
- package/dist/compiler/compile.js +1120 -0
- package/dist/compiler/error-reporter.js +467 -0
- package/dist/compiler/linter.js +72 -0
- package/dist/{services → compiler}/minify.js +40 -31
- package/dist/compiler/parser.js +30 -0
- package/dist/compiler/tailwindcss.js +39 -0
- package/dist/compiler/transformTStoJS.js +16 -0
- package/dist/compiler/transforms.js +544 -0
- package/dist/compiler/typescript-error-parser.js +282 -0
- package/dist/compiler/typescript-sync-validator.js +230 -0
- package/dist/compiler/typescript-worker-thread.cjs +457 -0
- package/dist/compiler/typescript-worker.js +309 -0
- package/dist/compiler/typescript.js +382 -0
- package/dist/compiler/vuejs.js +296 -0
- package/dist/hrm/VueHRM.js +353 -0
- package/dist/hrm/errorScreen.js +23 -1
- package/dist/hrm/getInstanciaVue.js +313 -0
- package/dist/hrm/initHRM.js +140 -0
- package/dist/main.js +287 -0
- package/dist/servicios/browserSync.js +177 -0
- package/dist/servicios/chokidar.js +178 -0
- package/dist/servicios/logger.js +33 -0
- package/dist/servicios/readConfig.js +429 -0
- package/dist/utils/module-resolver.js +506 -0
- package/dist/utils/promptUser.js +48 -0
- package/dist/utils/resolve-bin.js +29 -0
- package/dist/utils/utils.js +21 -48
- package/dist/wrappers/eslint-node.js +145 -0
- package/dist/wrappers/oxlint-node.js +120 -0
- package/dist/wrappers/tailwind-node.js +92 -0
- package/package.json +62 -15
- package/dist/hrm/devMode.js +0 -249
- package/dist/hrm/instanciaVue.js +0 -35
- package/dist/hrm/setupHMR.js +0 -57
- package/dist/index.js +0 -873
- package/dist/services/acorn.js +0 -29
- package/dist/services/linter.js +0 -55
- package/dist/services/typescript.js +0 -89
- package/dist/services/vueLoader.js +0 -324
- package/dist/services/vuejs.js +0 -259
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Parsea errores de TypeScript y los convierte a un formato limpio
|
|
4
|
+
* que incluye solo: archivo, mensaje, severidad y ubicación como ayuda
|
|
5
|
+
*/
|
|
6
|
+
export function parseTypeScriptErrors(diagnostics, fileName, sourceCode) {
|
|
7
|
+
return diagnostics.map(diagnostic => {
|
|
8
|
+
// Usar el mejorador de errores para obtener mensaje detallado
|
|
9
|
+
const enhancedMessage = enhanceErrorMessage(diagnostic, fileName, sourceCode);
|
|
10
|
+
// Determinar la severidad
|
|
11
|
+
let severity;
|
|
12
|
+
switch (diagnostic.category) {
|
|
13
|
+
case ts.DiagnosticCategory.Error:
|
|
14
|
+
severity = 'error';
|
|
15
|
+
break;
|
|
16
|
+
case ts.DiagnosticCategory.Warning:
|
|
17
|
+
severity = 'warning';
|
|
18
|
+
break;
|
|
19
|
+
default:
|
|
20
|
+
severity = 'info';
|
|
21
|
+
break;
|
|
22
|
+
} // Construir información de ubicación limpia
|
|
23
|
+
let help = `Código TS${diagnostic.code}`;
|
|
24
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
25
|
+
const sourceFile = diagnostic.file;
|
|
26
|
+
// Verificar que el método getLineAndCharacterOfPosition existe (para compatibilidad con mocks)
|
|
27
|
+
if (typeof sourceFile.getLineAndCharacterOfPosition === 'function') {
|
|
28
|
+
try {
|
|
29
|
+
const lineAndChar = sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
|
|
30
|
+
help += ` | Línea ${lineAndChar.line + 1}, Columna ${lineAndChar.character + 1}`;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Si falla, solo mostrar la posición de carácter
|
|
34
|
+
help += ` | Posición ${diagnostic.start}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// Fallback para cuando no está disponible el método (como en tests)
|
|
39
|
+
help += ` | Posición ${diagnostic.start}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
file: fileName,
|
|
44
|
+
message: enhancedMessage,
|
|
45
|
+
severity,
|
|
46
|
+
help,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Limpia el mensaje de error eliminando información redundante
|
|
52
|
+
*/
|
|
53
|
+
function cleanErrorMessage(message) {
|
|
54
|
+
return (message
|
|
55
|
+
// Remover prefijos verbosos
|
|
56
|
+
.replace(/^error TS\d+:\s*/i, '')
|
|
57
|
+
// Remover información de archivo duplicada al inicio
|
|
58
|
+
.replace(/^.*\.ts\(\d+,\d+\):\s*/, '')
|
|
59
|
+
// Limpiar espacios múltiples
|
|
60
|
+
.replace(/\s+/g, ' ')
|
|
61
|
+
.trim());
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Mejora significativamente el mensaje de error TypeScript con contexto visual
|
|
65
|
+
*/
|
|
66
|
+
function enhanceErrorMessage(diagnostic, fileName, sourceCode) {
|
|
67
|
+
// Extraer el mensaje del error
|
|
68
|
+
const message = typeof diagnostic.messageText === 'string'
|
|
69
|
+
? diagnostic.messageText
|
|
70
|
+
: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
71
|
+
let enhancedMessage = cleanErrorMessage(message); // Información de ubicación
|
|
72
|
+
let location = `Código TS${diagnostic.code}`;
|
|
73
|
+
let codeContext = '';
|
|
74
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
75
|
+
const sourceFile = diagnostic.file;
|
|
76
|
+
// Verificar que el método getLineAndCharacterOfPosition existe (para compatibilidad con mocks)
|
|
77
|
+
if (typeof sourceFile.getLineAndCharacterOfPosition === 'function') {
|
|
78
|
+
try {
|
|
79
|
+
const lineAndChar = sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
|
|
80
|
+
const line = lineAndChar.line + 1;
|
|
81
|
+
const column = lineAndChar.character + 1;
|
|
82
|
+
location = `Línea ${line}, Columna ${column} | Código TS${diagnostic.code}`;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Si falla, solo mostrar la posición de carácter
|
|
86
|
+
location = `Posición ${diagnostic.start} | Código TS${diagnostic.code}`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Fallback para cuando no está disponible el método (como en tests)
|
|
91
|
+
location = `Posición ${diagnostic.start} | Código TS${diagnostic.code}`;
|
|
92
|
+
} // Agregar contexto del código si está disponible
|
|
93
|
+
if ((sourceCode || sourceFile.text) &&
|
|
94
|
+
typeof sourceFile.getLineAndCharacterOfPosition === 'function') {
|
|
95
|
+
try {
|
|
96
|
+
const lineAndChar = sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
|
|
97
|
+
const text = sourceCode || sourceFile.text;
|
|
98
|
+
const lines = text.split('\n');
|
|
99
|
+
const errorLine = lines[lineAndChar.line];
|
|
100
|
+
if (errorLine) {
|
|
101
|
+
// Mostrar hasta 2 líneas antes y después para contexto
|
|
102
|
+
const startLine = Math.max(0, lineAndChar.line - 2);
|
|
103
|
+
const endLine = Math.min(lines.length - 1, lineAndChar.line + 2);
|
|
104
|
+
codeContext = '\n\n📝 Contexto del código:\n';
|
|
105
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
106
|
+
const currentLine = i + 1;
|
|
107
|
+
const lineContent = lines[i] || '';
|
|
108
|
+
const isErrorLine = i === lineAndChar.line;
|
|
109
|
+
if (isErrorLine) {
|
|
110
|
+
codeContext += ` ${currentLine.toString().padStart(3, ' ')} ❌ ${lineContent}\n`;
|
|
111
|
+
// Agregar flecha apuntando al error
|
|
112
|
+
const arrow = ' '.repeat(6 + lineAndChar.character + 1) +
|
|
113
|
+
'^^^';
|
|
114
|
+
codeContext += ` ${arrow}\n`;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
codeContext += ` ${currentLine.toString().padStart(3, ' ')} ${lineContent}\n`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Si falla obtener el contexto, continuar sin él
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Agregar sugerencias basadas en el tipo de error
|
|
128
|
+
const suggestions = getErrorSuggestions(diagnostic.code, enhancedMessage);
|
|
129
|
+
const suggestionsText = suggestions.length > 0
|
|
130
|
+
? `\n\n💡 Sugerencias:\n${suggestions.map(s => ` • ${s}`).join('\n')}`
|
|
131
|
+
: '';
|
|
132
|
+
return `${enhancedMessage}\n 📍 ${location}${codeContext}${suggestionsText}`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Proporciona sugerencias específicas basadas en el código de error TypeScript
|
|
136
|
+
*/
|
|
137
|
+
function getErrorSuggestions(errorCode, message) {
|
|
138
|
+
const suggestions = [];
|
|
139
|
+
switch (errorCode) {
|
|
140
|
+
case 2304: // Cannot find name
|
|
141
|
+
suggestions.push('Verifica que la variable esté declarada');
|
|
142
|
+
suggestions.push('Asegúrate de importar el módulo correspondiente');
|
|
143
|
+
suggestions.push('Revisa la ortografía del nombre');
|
|
144
|
+
break;
|
|
145
|
+
case 2322: // Type assignment error
|
|
146
|
+
suggestions.push('Verifica que los tipos sean compatibles');
|
|
147
|
+
suggestions.push('Considera usar type assertion: valor as TipoEsperado');
|
|
148
|
+
break;
|
|
149
|
+
case 2307: // Cannot find module
|
|
150
|
+
suggestions.push('Verifica que el archivo exista en la ruta especificada');
|
|
151
|
+
suggestions.push('Revisa las rutas en tsconfig.json');
|
|
152
|
+
suggestions.push('Asegúrate de que el paquete esté instalado');
|
|
153
|
+
break;
|
|
154
|
+
case 2451: // Cannot redeclare block-scoped variable
|
|
155
|
+
suggestions.push('Cambia el nombre de la variable');
|
|
156
|
+
suggestions.push('Usa un scope diferente (function, block)');
|
|
157
|
+
break;
|
|
158
|
+
case 7006: // Parameter implicitly has 'any' type
|
|
159
|
+
suggestions.push('Agrega tipos explícitos a los parámetros');
|
|
160
|
+
suggestions.push('Considera habilitar "noImplicitAny": false en tsconfig.json');
|
|
161
|
+
break;
|
|
162
|
+
case 1155: // 'const' declarations must be initialized
|
|
163
|
+
suggestions.push('Agrega un valor inicial: const variable = valor;');
|
|
164
|
+
suggestions.push('O cambia a "let" si quieres asignar después');
|
|
165
|
+
break;
|
|
166
|
+
case 2339: // Property does not exist
|
|
167
|
+
suggestions.push('Verifica que la propiedad exista en el tipo');
|
|
168
|
+
suggestions.push('Considera usar optional chaining: objeto?.propiedad');
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
// Sugerencias genéricas basadas en el mensaje
|
|
172
|
+
if (message.includes('Cannot find')) {
|
|
173
|
+
suggestions.push('Verifica que el elemento exista y esté importado');
|
|
174
|
+
}
|
|
175
|
+
if (message.includes('Type')) {
|
|
176
|
+
suggestions.push('Revisa la compatibilidad de tipos');
|
|
177
|
+
}
|
|
178
|
+
if (message.includes('missing')) {
|
|
179
|
+
suggestions.push('Agrega el elemento faltante');
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
return suggestions;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Crea un mensaje de error unificado para errores múltiples
|
|
187
|
+
*/
|
|
188
|
+
export function createUnifiedErrorMessage(errors) {
|
|
189
|
+
if (errors.length === 0) {
|
|
190
|
+
return 'Error de TypeScript desconocido';
|
|
191
|
+
}
|
|
192
|
+
if (errors.length === 1) {
|
|
193
|
+
const error = errors[0];
|
|
194
|
+
if (error) {
|
|
195
|
+
return `${error.message}\n └─ ${error.help}`;
|
|
196
|
+
}
|
|
197
|
+
return 'Error de TypeScript desconocido';
|
|
198
|
+
}
|
|
199
|
+
const errorCount = errors.filter(e => e.severity === 'error').length;
|
|
200
|
+
const warningCount = errors.filter(e => e.severity === 'warning').length;
|
|
201
|
+
// Mostrar hasta los primeros 10 errores con detalles
|
|
202
|
+
const maxErrorsToShow = 10;
|
|
203
|
+
const errorsToShow = errors.slice(0, maxErrorsToShow);
|
|
204
|
+
const hasMoreErrors = errors.length > maxErrorsToShow;
|
|
205
|
+
let result = '';
|
|
206
|
+
// Agregar resumen
|
|
207
|
+
let summary = '';
|
|
208
|
+
if (errorCount > 0) {
|
|
209
|
+
summary += `${errorCount} error${errorCount > 1 ? 'es' : ''}`;
|
|
210
|
+
}
|
|
211
|
+
if (warningCount > 0) {
|
|
212
|
+
if (summary)
|
|
213
|
+
summary += ', ';
|
|
214
|
+
summary += `${warningCount} advertencia${warningCount > 1 ? 's' : ''}`;
|
|
215
|
+
}
|
|
216
|
+
result += `TypeScript: ${summary} encontrado${errorCount + warningCount > 1 ? 's' : ''}:\n\n`;
|
|
217
|
+
// Agregar detalles de cada error
|
|
218
|
+
errorsToShow.forEach((error, index) => {
|
|
219
|
+
const icon = error.severity === 'error'
|
|
220
|
+
? '❌'
|
|
221
|
+
: error.severity === 'warning'
|
|
222
|
+
? '⚠️'
|
|
223
|
+
: 'ℹ️';
|
|
224
|
+
result += `${icon} ${error.message}\n`;
|
|
225
|
+
result += ` └─ ${error.help}\n`;
|
|
226
|
+
if (index < errorsToShow.length - 1)
|
|
227
|
+
result += '\n';
|
|
228
|
+
});
|
|
229
|
+
// Si hay más errores, indicarlo
|
|
230
|
+
if (hasMoreErrors) {
|
|
231
|
+
const remainingCount = errors.length - maxErrorsToShow;
|
|
232
|
+
result += `\n... y ${remainingCount} error${remainingCount > 1 ? 'es' : ''} más`;
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Crea un mensaje de error simplificado para modo normal
|
|
238
|
+
*/
|
|
239
|
+
export function createSimpleErrorMessage(diagnostics, _fileName) {
|
|
240
|
+
if (diagnostics.length === 0)
|
|
241
|
+
return '';
|
|
242
|
+
const firstDiagnostic = diagnostics[0];
|
|
243
|
+
if (!firstDiagnostic)
|
|
244
|
+
return '';
|
|
245
|
+
const message = ts.flattenDiagnosticMessageText(firstDiagnostic.messageText, '\n');
|
|
246
|
+
// Extraer solo la primera línea del mensaje para simplicidad
|
|
247
|
+
const simplifiedMessage = message.split('\n')[0];
|
|
248
|
+
let location = '';
|
|
249
|
+
if (firstDiagnostic.file && firstDiagnostic.start !== undefined) {
|
|
250
|
+
const sourceFile = firstDiagnostic.file;
|
|
251
|
+
// Verificar que el método getLineAndCharacterOfPosition existe (para compatibilidad con mocks)
|
|
252
|
+
if (typeof sourceFile.getLineAndCharacterOfPosition === 'function') {
|
|
253
|
+
try {
|
|
254
|
+
const lineAndChar = sourceFile.getLineAndCharacterOfPosition(firstDiagnostic.start);
|
|
255
|
+
location = ` (línea ${lineAndChar.line + 1})`;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Si falla, continuar sin información de ubicación
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const errorCount = diagnostics.length;
|
|
263
|
+
const countText = errorCount > 1 ? ` (+${errorCount - 1} más)` : '';
|
|
264
|
+
return `${simplifiedMessage}${location}${countText}`;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Crea un mensaje de error detallado para modo verbose
|
|
268
|
+
*/
|
|
269
|
+
export function createDetailedErrorMessage(diagnostics, fileName, sourceCode) {
|
|
270
|
+
const cleanErrors = parseTypeScriptErrors(diagnostics, fileName, sourceCode);
|
|
271
|
+
return createUnifiedErrorMessage(cleanErrors);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Registra errores de TypeScript en el inventario usando el parser limpio
|
|
275
|
+
*/
|
|
276
|
+
export function registerCleanTypeScriptErrors(diagnostics, fileName, registerInventoryError) {
|
|
277
|
+
const cleanErrors = parseTypeScriptErrors(diagnostics, fileName);
|
|
278
|
+
cleanErrors.forEach(error => {
|
|
279
|
+
registerInventoryError(error.file, error.message, error.severity, error.help);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=typescript-error-parser.js.map
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Sync Validator - Validación síncrona de tipos como fallback
|
|
3
|
+
* Contiene la lógica extraída del módulo principal para cuando el worker no está disponible
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as ts from 'typescript';
|
|
8
|
+
/**
|
|
9
|
+
* Language Service Host para validación de tipos eficiente
|
|
10
|
+
*/
|
|
11
|
+
class TypeScriptLanguageServiceHost {
|
|
12
|
+
files = new Map();
|
|
13
|
+
compilerOptions;
|
|
14
|
+
constructor(compilerOptions) {
|
|
15
|
+
this.compilerOptions = compilerOptions;
|
|
16
|
+
}
|
|
17
|
+
addFile(fileName, content) {
|
|
18
|
+
const existing = this.files.get(fileName);
|
|
19
|
+
this.files.set(fileName, {
|
|
20
|
+
version: existing ? existing.version + 1 : 1,
|
|
21
|
+
content,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
getCompilationSettings() {
|
|
25
|
+
return this.compilerOptions;
|
|
26
|
+
}
|
|
27
|
+
getScriptFileNames() {
|
|
28
|
+
return Array.from(this.files.keys());
|
|
29
|
+
}
|
|
30
|
+
getScriptVersion(fileName) {
|
|
31
|
+
const file = this.files.get(fileName);
|
|
32
|
+
return file ? file.version.toString() : '0';
|
|
33
|
+
}
|
|
34
|
+
getScriptSnapshot(fileName) {
|
|
35
|
+
const file = this.files.get(fileName);
|
|
36
|
+
if (file) {
|
|
37
|
+
return ts.ScriptSnapshot.fromString(file.content);
|
|
38
|
+
}
|
|
39
|
+
// Intentar leer el archivo del sistema de archivos para dependencias
|
|
40
|
+
if (fs.existsSync(fileName)) {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(fileName, 'utf-8');
|
|
43
|
+
return ts.ScriptSnapshot.fromString(content);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
getCurrentDirectory() {
|
|
52
|
+
return process.cwd();
|
|
53
|
+
}
|
|
54
|
+
getDefaultLibFileName(options) {
|
|
55
|
+
return ts.getDefaultLibFilePath(options);
|
|
56
|
+
}
|
|
57
|
+
fileExists(path) {
|
|
58
|
+
return this.files.has(path) || fs.existsSync(path);
|
|
59
|
+
}
|
|
60
|
+
readFile(path) {
|
|
61
|
+
const file = this.files.get(path);
|
|
62
|
+
if (file) {
|
|
63
|
+
return file.content;
|
|
64
|
+
}
|
|
65
|
+
if (fs.existsSync(path)) {
|
|
66
|
+
try {
|
|
67
|
+
return fs.readFileSync(path, 'utf-8');
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
getNewLine() {
|
|
76
|
+
return ts.sys.newLine;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Realiza validación de tipos usando TypeScript Language Service (versión síncrona)
|
|
81
|
+
* @param fileName - Nombre del archivo
|
|
82
|
+
* @param content - Contenido del archivo
|
|
83
|
+
* @param compilerOptions - Opciones del compilador
|
|
84
|
+
* @returns Resultado de la validación de tipos
|
|
85
|
+
*/
|
|
86
|
+
export const validateTypesWithLanguageService = (fileName, content, compilerOptions) => {
|
|
87
|
+
let actualFileName = fileName; // Declarar aquí para acceso en catch
|
|
88
|
+
try {
|
|
89
|
+
let scriptContent = content;
|
|
90
|
+
// Si el script está vacío o es solo espacios en blanco, no validar
|
|
91
|
+
if (!scriptContent.trim()) {
|
|
92
|
+
return { diagnostics: [], hasErrors: false };
|
|
93
|
+
}
|
|
94
|
+
// Crear Language Service Host
|
|
95
|
+
const host = new TypeScriptLanguageServiceHost(compilerOptions);
|
|
96
|
+
// Para archivos Vue, crear un archivo virtual .ts
|
|
97
|
+
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;
|
|
111
|
+
}
|
|
112
|
+
// Agregar declaraciones básicas de tipos para Vue si es necesario
|
|
113
|
+
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);
|
|
131
|
+
}
|
|
132
|
+
// Crear Language Service
|
|
133
|
+
const languageService = ts.createLanguageService(host);
|
|
134
|
+
try {
|
|
135
|
+
// Verificar que el archivo existe en el host antes de solicitar diagnósticos
|
|
136
|
+
if (!host.fileExists(actualFileName)) {
|
|
137
|
+
return { diagnostics: [], hasErrors: false };
|
|
138
|
+
}
|
|
139
|
+
// Obtener diagnósticos de tipos con manejo de errores
|
|
140
|
+
let syntacticDiagnostics = [];
|
|
141
|
+
let semanticDiagnostics = [];
|
|
142
|
+
try {
|
|
143
|
+
syntacticDiagnostics =
|
|
144
|
+
languageService.getSyntacticDiagnostics(actualFileName);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Ignorar errores de diagnósticos sintácticos
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
semanticDiagnostics =
|
|
151
|
+
languageService.getSemanticDiagnostics(actualFileName);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Ignorar errores de diagnósticos semánticos
|
|
155
|
+
}
|
|
156
|
+
// Combinar todos los diagnósticos
|
|
157
|
+
const allDiagnostics = [
|
|
158
|
+
...syntacticDiagnostics,
|
|
159
|
+
...semanticDiagnostics,
|
|
160
|
+
];
|
|
161
|
+
// Filtrar diagnósticos relevantes
|
|
162
|
+
const filteredDiagnostics = allDiagnostics.filter((diag) => {
|
|
163
|
+
const messageText = ts.flattenDiagnosticMessageText(diag.messageText, '\n');
|
|
164
|
+
// Solo errores de categoría Error
|
|
165
|
+
if (diag.category !== ts.DiagnosticCategory.Error) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
// Ignorar SOLO errores específicos de infraestructura Vue y rutas de módulos
|
|
169
|
+
return (!messageText.includes('Cannot find module') &&
|
|
170
|
+
!messageText.includes('Could not find source file') &&
|
|
171
|
+
!messageText.includes("Parameter '$props' implicitly has an 'any' type") &&
|
|
172
|
+
!messageText.includes("Parameter '$setup' implicitly has an 'any' type") &&
|
|
173
|
+
!messageText.includes("Parameter '$data' implicitly has an 'any' type") &&
|
|
174
|
+
!messageText.includes("Parameter '$options' implicitly has an 'any' type") &&
|
|
175
|
+
!messageText.includes("Parameter '$event' implicitly has an 'any' type") &&
|
|
176
|
+
!messageText.includes("Parameter '_ctx' implicitly has an 'any' type") &&
|
|
177
|
+
!messageText.includes("Parameter '_cache' implicitly has an 'any' type") &&
|
|
178
|
+
// Ignorar errores específicos de decorators cuando están mal configurados
|
|
179
|
+
!messageText.includes('Unable to resolve signature of method decorator when called as an expression') &&
|
|
180
|
+
!messageText.includes('The runtime will invoke the decorator with') &&
|
|
181
|
+
// Ignorar errores TS7031 (binding element implicitly has any type)
|
|
182
|
+
diag.code !== 7031 &&
|
|
183
|
+
// Ignorar errores TS7006 (parameter implicitly has any type)
|
|
184
|
+
diag.code !== 7006 &&
|
|
185
|
+
// Ignorar errores TS1241 (decorator signature mismatch) durante desarrollo
|
|
186
|
+
diag.code !== 1241 &&
|
|
187
|
+
// Permitir errores de "Cannot find name" ya que son errores de código real
|
|
188
|
+
// Solo filtrar parámetros implícitos de Vue generados automáticamente
|
|
189
|
+
!(messageText.includes("implicitly has an 'any' type") &&
|
|
190
|
+
(messageText.includes('_ctx') ||
|
|
191
|
+
messageText.includes('_cache') ||
|
|
192
|
+
messageText.includes('$props') ||
|
|
193
|
+
messageText.includes('$setup'))));
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
diagnostics: filteredDiagnostics,
|
|
197
|
+
hasErrors: filteredDiagnostics.length > 0,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return { diagnostics: [], hasErrors: false };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
// En caso de error, devolver diagnóstico de error
|
|
206
|
+
const errorDiagnostic = {
|
|
207
|
+
file: undefined,
|
|
208
|
+
start: undefined,
|
|
209
|
+
length: undefined,
|
|
210
|
+
messageText: `Error en validación de tipos: ${error instanceof Error ? error.message : 'Error desconocido'}`,
|
|
211
|
+
category: ts.DiagnosticCategory.Error,
|
|
212
|
+
code: 0,
|
|
213
|
+
};
|
|
214
|
+
return {
|
|
215
|
+
diagnostics: [errorDiagnostic],
|
|
216
|
+
hasErrors: true,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Valida tipos en archivos Vue antes de la compilación (versión síncrona)
|
|
222
|
+
* @param vueContent - Contenido del archivo Vue
|
|
223
|
+
* @param fileName - Nombre del archivo Vue
|
|
224
|
+
* @param compilerOptions - Opciones del compilador
|
|
225
|
+
* @returns Resultado de la validación de tipos
|
|
226
|
+
*/
|
|
227
|
+
export const validateVueTypes = (vueContent, fileName, compilerOptions) => {
|
|
228
|
+
return validateTypesWithLanguageService(fileName, vueContent, compilerOptions);
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=typescript-sync-validator.js.map
|