Skip to content

Commit 8de1cdc

Browse files
johnsoncodehkcoderfreii
authored andcommitted
fix(typescript-plugin): TS not working in template when tsconfig missing (vuejs#4452)
1 parent 671bddd commit 8de1cdc

File tree

8 files changed

+62
-42
lines changed

8 files changed

+62
-42
lines changed

packages/component-meta/lib/base.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,14 @@ export function baseCreate(
161161
const vueLanguagePlugin = createVueLanguagePlugin<string>(
162162
ts,
163163
id => id,
164-
ts.sys.useCaseSensitiveFileNames,
165164
() => projectHost.getProjectVersion?.() ?? '',
166-
() => projectHost.getScriptFileNames(),
165+
fileName => {
166+
const fileMap = new FileMap(ts.sys.useCaseSensitiveFileNames);
167+
for (const vueFileName of projectHost.getScriptFileNames()) {
168+
fileMap.set(vueFileName, undefined);
169+
}
170+
return fileMap.has(fileName);
171+
},
167172
projectHost.getCompilationSettings(),
168173
vueCompilerOptions,
169174
);

packages/language-core/lib/languageModule.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,14 @@ function getFileRegistryKey(
5353
return JSON.stringify(values);
5454
}
5555

56-
export interface _Plugin<T> extends LanguagePlugin<T, VueVirtualCode> {
57-
getCanonicalFileName: (fileName: string) => string;
58-
pluginContext: Parameters<VueLanguagePlugin>[0];
59-
}
60-
6156
export function createVueLanguagePlugin<T>(
6257
ts: typeof import('typescript'),
6358
asFileName: (scriptId: T) => string,
64-
useCaseSensitiveFileNames: boolean,
6559
getProjectVersion: () => string,
66-
getScriptFileNames: () => string[] | Set<string>,
60+
isRootFile: (fileName: string) => boolean,
6761
compilerOptions: ts.CompilerOptions,
68-
vueCompilerOptions: VueCompilerOptions,
69-
): _Plugin<T> {
62+
vueCompilerOptions: VueCompilerOptions
63+
): LanguagePlugin<T, VueVirtualCode> {
7064
const pluginContext: Parameters<VueLanguagePlugin>[0] = {
7165
modules: {
7266
'@vue/compiler-dom': vueCompilerOptions.target < 3
@@ -85,16 +79,10 @@ export function createVueLanguagePlugin<T>(
8579
const vueSfcPlugin = useVueFilePlugin(pluginContext);
8680
const vitePressSfcPlugin = useMdFilePlugin(pluginContext);
8781
const petiteVueSfcPlugin = useHtmlFilePlugin(pluginContext);
88-
const getCanonicalFileName = useCaseSensitiveFileNames
89-
? (fileName: string) => fileName
90-
: (fileName: string) => fileName.toLowerCase();
9182

92-
let canonicalRootFileNames = new Set<string>();
9383
let canonicalRootFileNamesVersion: string | undefined;
9484

9585
return {
96-
getCanonicalFileName,
97-
pluginContext,
9886
getLanguageId(scriptId) {
9987
if (vueCompilerOptions.extensions.some(ext => asFileName(scriptId).endsWith(ext))) {
10088
return 'vue';
@@ -109,13 +97,11 @@ export function createVueLanguagePlugin<T>(
10997
createVirtualCode(scriptId, languageId, snapshot) {
11098
if (languageId === 'vue' || languageId === 'markdown' || languageId === 'html' || languageId === 'typescriptreact-vtx') {
11199
const fileName = asFileName(scriptId);
112-
const projectVersion = getProjectVersion();
113-
if (projectVersion !== canonicalRootFileNamesVersion) {
114-
canonicalRootFileNames = new Set([...getScriptFileNames()].map(getCanonicalFileName));
115-
canonicalRootFileNamesVersion = projectVersion;
116-
}
117-
if (!pluginContext.globalTypesHolder && canonicalRootFileNames.has(getCanonicalFileName(fileName))) {
118-
pluginContext.globalTypesHolder = fileName;
100+
if (!pluginContext.globalTypesHolder && getProjectVersion() !== canonicalRootFileNamesVersion) {
101+
canonicalRootFileNamesVersion = getProjectVersion();
102+
if (isRootFile(fileName)) {
103+
pluginContext.globalTypesHolder = fileName;
104+
}
119105
}
120106
const fileRegistry = getFileRegistry(pluginContext.globalTypesHolder === fileName);
121107
const code = fileRegistry.get(fileName);

packages/language-server/node.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { GetLanguagePlugin, createHybridModeProjectFacade } from './lib/hybridMo
99
import { DetectNameCasingRequest, GetConnectedNamedPipeServerRequest, GetConvertAttrCasingEditsRequest, GetConvertTagCasingEditsRequest, ParseSFCRequest } from './lib/protocol';
1010
import type { VueInitializationOptions } from './lib/types';
1111
import { createTypeScriptProjectFacade, type LanguagePluginProvider } from '@volar/language-server/lib/project/typescriptProjectFacade';
12+
import { FileMap } from '@volar/language-core/lib/utils';
1213

1314

1415

@@ -135,11 +136,16 @@ const getLanguagePlugins: GetLanguagePlugin<URI> = async ({ serviceEnv, configFi
135136
const vueLanguagePlugin = createVueLanguagePlugin(
136137
tsdk.typescript,
137138
asFileName,
138-
sys?.useCaseSensitiveFileNames ?? false,
139139
() => projectHost?.getProjectVersion?.() ?? '',
140-
() => projectHost?.getScriptFileNames() ?? [],
140+
fileName => {
141+
const fileMap = new FileMap(sys?.useCaseSensitiveFileNames ?? false);
142+
for (const vueFileName of projectHost?.getScriptFileNames() ?? []) {
143+
fileMap.set(vueFileName, undefined);
144+
}
145+
return fileMap.has(fileName);
146+
},
141147
commandLine?.options ?? {},
142-
vueOptions,
148+
vueOptions
143149
);
144150
if (!hybridMode) {
145151
const extensions = [

packages/language-service/tests/utils/createTester.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createLanguage, createLanguageService, createUriMap } from '@volar/language-service';
1+
import { FileMap, createLanguage, createLanguageService, createUriMap } from '@volar/language-service';
22
import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript';
33
import * as path from 'path';
44
import * as ts from 'typescript';
@@ -27,11 +27,16 @@ function createTester(rootUri: URI) {
2727
const vueLanguagePlugin = createVueLanguagePlugin(
2828
ts,
2929
uriToFileName,
30-
ts.sys.useCaseSensitiveFileNames,
3130
() => projectHost.getProjectVersion?.() ?? '',
32-
() => projectHost.getScriptFileNames(),
31+
fileName => {
32+
const fileMap = new FileMap(ts.sys.useCaseSensitiveFileNames);
33+
for (const vueFileName of projectHost.getScriptFileNames()) {
34+
fileMap.set(vueFileName, undefined);
35+
}
36+
return fileMap.has(fileName);
37+
},
3338
parsedCommandLine.options,
34-
parsedCommandLine.vueOptions,
39+
parsedCommandLine.vueOptions
3540
);
3641
const vueServicePlugins = getVueLanguageServicePlugins(ts, () => parsedCommandLine.vueOptions);
3742
const defaultVSCodeSettings: any = {
@@ -60,7 +65,7 @@ function createTester(rootUri: URI) {
6065
else {
6166
language.scripts.delete(uri);
6267
}
63-
},
68+
}
6469
);
6570
language.typescript = {
6671
configFileName: realTsConfig,

packages/language-service/tests/utils/format.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ const resolvedVueOptions = resolveVueCompilerOptions({});
88
const vueLanguagePlugin = createVueLanguagePlugin<URI>(
99
ts,
1010
() => '',
11-
false,
1211
() => '',
13-
() => [],
12+
() => false,
1413
{},
1514
resolvedVueOptions,
1615
);

packages/tsc/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { runTsc } from '@volar/typescript/lib/quickstart/runTsc';
22
import * as vue from '@vue/language-core';
3+
import { FileMap } from '@volar/language-core/lib/utils';
34

45
const windowsPathReg = /\\/g;
56

@@ -32,9 +33,14 @@ export function run() {
3233
const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
3334
ts,
3435
id => id,
35-
options.host?.useCaseSensitiveFileNames?.() ?? false,
3636
() => '',
37-
() => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')),
37+
fileName => {
38+
const fileMap = new FileMap(options.host?.useCaseSensitiveFileNames?.() ?? false);
39+
for (const vueFileName of options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/'))) {
40+
fileMap.set(vueFileName, undefined);
41+
}
42+
return fileMap.has(fileName);
43+
},
3844
options.options,
3945
vueOptions,
4046
);

packages/tsc/tests/dts.spec.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ describe('vue-tsc-dts', () => {
3434
const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
3535
ts,
3636
id => id,
37-
options.host?.useCaseSensitiveFileNames?.() ?? false,
3837
() => '',
39-
() => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')),
38+
fileName => {
39+
const fileMap = new vue.FileMap(options.host?.useCaseSensitiveFileNames?.() ?? false);
40+
for (const vueFileName of options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/'))) {
41+
fileMap.set(vueFileName, undefined);
42+
}
43+
return fileMap.has(fileName);
44+
},
4045
options.options,
41-
vueOptions,
46+
vueOptions
4247
);
4348
return [vueLanguagePlugin];
4449
});
@@ -62,7 +67,7 @@ describe('vue-tsc-dts', () => {
6267
outputText = text;
6368
},
6469
undefined,
65-
true,
70+
true
6671
);
6772
expect(outputText ? normalizeNewline(outputText) : undefined).toMatchSnapshot();
6873
});

packages/typescript-plugin/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { createLanguageServicePlugin, externalFiles } from '@volar/typescript/li
22
import * as vue from '@vue/language-core';
33
import { decorateLanguageServiceForVue } from './lib/common';
44
import { projects, startNamedPipeServer } from './lib/server';
5+
import { FileMap } from '@volar/language-core/lib/utils';
56

67
const windowsPathReg = /\\/g;
78

@@ -11,9 +12,16 @@ const plugin = createLanguageServicePlugin(
1112
const languagePlugin = vue.createVueLanguagePlugin<string>(
1213
ts,
1314
id => id,
14-
info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false,
1515
() => info.languageServiceHost.getProjectVersion?.() ?? '',
16-
() => externalFiles.get(info.project) ?? [],
16+
info.project.projectKind === ts.server.ProjectKind.Inferred
17+
? () => true
18+
: fileName => {
19+
const fileMap = new FileMap(info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false);
20+
for (const vueFileName of externalFiles.get(info.project) ?? []) {
21+
fileMap.set(vueFileName, undefined);
22+
}
23+
return fileMap.has(fileName);
24+
},
1725
info.languageServiceHost.getCompilationSettings(),
1826
vueOptions
1927
);

0 commit comments

Comments
 (0)