Skip to content

Commit 0cf75cf

Browse files
authored
(fix) patch resolveModuleNameLiterals for ts 5.0 (#1799)
1 parent 044348d commit 0cf75cf

File tree

1 file changed

+109
-22
lines changed

1 file changed

+109
-22
lines changed

packages/typescript-plugin/src/module-loader.ts

+109-22
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,52 @@ import { SvelteSnapshotManager } from './svelte-snapshots';
55
import { createSvelteSys } from './svelte-sys';
66
import { ensureRealSvelteFilePath, isVirtualSvelteFilePath } from './utils';
77

8+
// TODO remove when we update to typescript 5.0
9+
declare module 'typescript/lib/tsserverlibrary' {
10+
interface LanguageServiceHost {
11+
/** @deprecated supply resolveModuleNameLiterals instead for resolution that can handle newer resolution modes like nodenext */
12+
resolveModuleNames?(
13+
moduleNames: string[],
14+
containingFile: string,
15+
reusedNames: string[] | undefined,
16+
redirectedReference: ts.ResolvedProjectReference | undefined,
17+
options: ts.CompilerOptions,
18+
containingSourceFile?: ts.SourceFile
19+
): (ts.ResolvedModule | undefined)[];
20+
resolveModuleNameLiterals?(
21+
moduleLiterals: readonly ts.StringLiteralLike[],
22+
containingFile: string,
23+
redirectedReference: ts.ResolvedProjectReference | undefined,
24+
options: ts.CompilerOptions,
25+
containingSourceFile: ts.SourceFile,
26+
reusedNames: readonly ts.StringLiteralLike[] | undefined
27+
): readonly ts.ResolvedModuleWithFailedLookupLocations[];
28+
}
29+
}
30+
831
/**
932
* Caches resolved modules.
1033
*/
1134
class ModuleResolutionCache {
1235
constructor(private readonly projectService: ts.server.ProjectService) {}
1336

14-
private cache = new Map<string, ts.ResolvedModule>();
37+
private cache = new Map<string, ts.ResolvedModuleFull>();
1538

1639
/**
1740
* Tries to get a cached module.
1841
*/
19-
get(moduleName: string, containingFile: string): ts.ResolvedModule | undefined {
42+
get(moduleName: string, containingFile: string): ts.ResolvedModuleFull | undefined {
2043
return this.cache.get(this.getKey(moduleName, containingFile));
2144
}
2245

2346
/**
2447
* Caches resolved module, if it is not undefined.
2548
*/
26-
set(moduleName: string, containingFile: string, resolvedModule: ts.ResolvedModule | undefined) {
49+
set(
50+
moduleName: string,
51+
containingFile: string,
52+
resolvedModule: ts.ResolvedModuleFull | undefined
53+
) {
2754
if (!resolvedModule) {
2855
return;
2956
}
@@ -78,8 +105,13 @@ export function patchModuleLoader(
78105
const svelteSys = createSvelteSys(logger);
79106
const moduleCache = new ModuleResolutionCache(project.projectService);
80107
const origResolveModuleNames = lsHost.resolveModuleNames?.bind(lsHost);
108+
const origResolveModuleNamLiterals = lsHost.resolveModuleNameLiterals?.bind(lsHost);
81109

82-
lsHost.resolveModuleNames = resolveModuleNames;
110+
if (lsHost.resolveModuleNameLiterals) {
111+
lsHost.resolveModuleNameLiterals = resolveModuleNameLiterals;
112+
} else {
113+
lsHost.resolveModuleNames = resolveModuleNames;
114+
}
83115

84116
const origRemoveFile = project.removeFile.bind(project);
85117
project.removeFile = (info, fileExists, detachFromProject) => {
@@ -119,32 +151,22 @@ export function patchModuleLoader(
119151
return resolved;
120152
}
121153

122-
return resolved.map((moduleName, idx) => {
123-
const fileName = moduleNames[idx];
124-
if (moduleName || !ensureRealSvelteFilePath(fileName).endsWith('.svelte')) {
125-
return moduleName;
154+
return resolved.map((tsResolvedModule, idx) => {
155+
const moduleName = moduleNames[idx];
156+
if (tsResolvedModule || !ensureRealSvelteFilePath(moduleName).endsWith('.svelte')) {
157+
return tsResolvedModule;
126158
}
127159

128-
const cachedModule = moduleCache.get(fileName, containingFile);
129-
if (cachedModule) {
130-
return cachedModule;
131-
}
132-
133-
const resolvedModule = resolveSvelteModuleName(
134-
fileName,
135-
containingFile,
136-
compilerOptions
137-
);
138-
moduleCache.set(fileName, containingFile, resolvedModule);
139-
return resolvedModule;
160+
return resolveSvelteModuleNameFromCache(moduleName, containingFile, compilerOptions)
161+
.resolvedModule;
140162
});
141163
}
142164

143165
function resolveSvelteModuleName(
144166
name: string,
145167
containingFile: string,
146168
compilerOptions: ts.CompilerOptions
147-
): ts.ResolvedModule | undefined {
169+
): ts.ResolvedModuleFull | undefined {
148170
const svelteResolvedModule = typescript.resolveModuleName(
149171
name,
150172
containingFile,
@@ -168,8 +190,73 @@ export function patchModuleLoader(
168190

169191
const resolvedSvelteModule: ts.ResolvedModuleFull = {
170192
extension: snapshot.isTsFile ? typescript.Extension.Ts : typescript.Extension.Js,
171-
resolvedFileName
193+
resolvedFileName,
194+
isExternalLibraryImport: svelteResolvedModule.isExternalLibraryImport
172195
};
173196
return resolvedSvelteModule;
174197
}
198+
199+
function resolveModuleNameLiterals(
200+
moduleLiterals: readonly ts.StringLiteralLike[],
201+
containingFile: string,
202+
redirectedReference: ts.ResolvedProjectReference | undefined,
203+
options: ts.CompilerOptions,
204+
containingSourceFile: ts.SourceFile,
205+
reusedNames: readonly ts.StringLiteralLike[] | undefined
206+
): readonly ts.ResolvedModuleWithFailedLookupLocations[] {
207+
logger.log('Resolving modules names for ' + containingFile);
208+
// Try resolving all module names with the original method first.
209+
// The ones that are undefined will be re-checked if they are a
210+
// Svelte file and if so, are resolved, too. This way we can defer
211+
// all module resolving logic except for Svelte files to TypeScript.
212+
const resolved =
213+
origResolveModuleNamLiterals?.(
214+
moduleLiterals,
215+
containingFile,
216+
redirectedReference,
217+
options,
218+
containingSourceFile,
219+
reusedNames
220+
) ??
221+
moduleLiterals.map(
222+
(): ts.ResolvedModuleWithFailedLookupLocations => ({
223+
resolvedModule: undefined
224+
})
225+
);
226+
227+
if (!configManager.getConfig().enable) {
228+
return resolved;
229+
}
230+
231+
return resolved.map((tsResolvedModule, idx) => {
232+
const moduleName = moduleLiterals[idx].text;
233+
if (
234+
tsResolvedModule.resolvedModule ||
235+
!ensureRealSvelteFilePath(moduleName).endsWith('.svelte')
236+
) {
237+
return tsResolvedModule;
238+
}
239+
240+
return resolveSvelteModuleNameFromCache(moduleName, containingFile, options);
241+
});
242+
}
243+
244+
function resolveSvelteModuleNameFromCache(
245+
moduleName: string,
246+
containingFile: string,
247+
options: ts.CompilerOptions
248+
) {
249+
const cachedModule = moduleCache.get(moduleName, containingFile);
250+
if (cachedModule) {
251+
return {
252+
resolvedModule: cachedModule
253+
};
254+
}
255+
256+
const resolvedModule = resolveSvelteModuleName(moduleName, containingFile, options);
257+
moduleCache.set(moduleName, containingFile, resolvedModule);
258+
return {
259+
resolvedModule: resolvedModule
260+
};
261+
}
175262
}

0 commit comments

Comments
 (0)