/
languageModule.ts
110 lines (104 loc) · 3.61 KB
/
languageModule.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import type * as embedded from '@volar/language-core';
import { posix as path } from 'path';
import { getDefaultVueLanguagePlugins } from './plugins';
import { VueFile } from './sourceFile';
import { VueLanguagePlugin, VueCompilerOptions } from './types';
import * as localTypes from './utils/localTypes';
import { resolveVueCompilerOptions } from './utils/ts';
import type * as ts from 'typescript/lib/tsserverlibrary';
export function createLanguageModules(
ts: typeof import('typescript/lib/tsserverlibrary'),
rootDir: string,
compilerOptions: ts.CompilerOptions,
_vueCompilerOptions: VueCompilerOptions,
extraPlugins: VueLanguagePlugin[] = [],
): embedded.LanguageModule[] {
const vueCompilerOptions = resolveVueCompilerOptions(_vueCompilerOptions);
const vueLanguagePlugin = getDefaultVueLanguagePlugins(
ts,
rootDir,
compilerOptions,
_vueCompilerOptions,
extraPlugins,
);
// from https://github.com/johnsoncodehk/volar/pull/1543
if (!((ts as any).__VLS_pitched_resolveModuleNames)) {
(ts as any).__VLS_pitched_resolveModuleNames = true;
const resolveModuleNames = ts.resolveModuleName;
ts.resolveModuleName = (...args) => {
if (args[6] === ts.ModuleKind.ESNext && vueCompilerOptions.extensions.some(ext => args[0].endsWith(ext))) {
args[6] = ts.ModuleKind.CommonJS;
}
return resolveModuleNames(...args);
};
}
const sharedTypesSnapshot = ts.ScriptSnapshot.fromString(localTypes.getTypesCode(vueCompilerOptions.target, vueCompilerOptions));
const languageModule: embedded.LanguageModule = {
createFile(fileName, snapshot) {
if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) {
return new VueFile(fileName, snapshot, ts, vueLanguagePlugin);
}
},
updateFile(sourceFile: VueFile, snapshot) {
sourceFile.update(snapshot);
},
proxyLanguageServiceHost(host) {
return {
fileExists(fileName) {
const basename = path.basename(fileName);
if (basename === localTypes.typesFileName) {
return true;
}
return host.fileExists(fileName);
},
getScriptFileNames() {
const fileNames = host.getScriptFileNames();
return [
...getSharedTypesFiles(fileNames),
...fileNames,
];
},
getScriptVersion(fileName) {
const basename = path.basename(fileName);
if (basename === localTypes.typesFileName) {
return '';
}
return host.getScriptVersion(fileName);
},
getScriptSnapshot(fileName) {
const basename = path.basename(fileName);
if (basename === localTypes.typesFileName) {
return sharedTypesSnapshot;
}
let snapshot = host.getScriptSnapshot(fileName);
if (snapshot) {
if (!vueCompilerOptions.strictTemplates && (
// for vue 2.6 and vue 3
basename === 'runtime-dom.d.ts' ||
// for vue 2.7
basename === 'jsx.d.ts'
)) {
// allow arbitrary attributes
let tsScriptText = snapshot.getText(0, snapshot.getLength());
tsScriptText = tsScriptText.replace(
'type ReservedProps = {',
'type ReservedProps = { [name: string]: any',
);
snapshot = ts.ScriptSnapshot.fromString(tsScriptText);
}
}
return snapshot;
},
};
},
};
return [
languageModule,
...vueCompilerOptions.experimentalAdditionalLanguageModules?.map(module => require(module)) ?? [],
];
function getSharedTypesFiles(fileNames: string[]) {
const moduleFiles = fileNames.filter(fileName => vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext)));
const moduleFileDirs = [...new Set(moduleFiles.map(path.dirname))];
return moduleFileDirs.map(dir => path.join(dir, localTypes.typesFileName));
}
}