@@ -5,25 +5,52 @@ import { SvelteSnapshotManager } from './svelte-snapshots';
5
5
import { createSvelteSys } from './svelte-sys' ;
6
6
import { ensureRealSvelteFilePath , isVirtualSvelteFilePath } from './utils' ;
7
7
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
+
8
31
/**
9
32
* Caches resolved modules.
10
33
*/
11
34
class ModuleResolutionCache {
12
35
constructor ( private readonly projectService : ts . server . ProjectService ) { }
13
36
14
- private cache = new Map < string , ts . ResolvedModule > ( ) ;
37
+ private cache = new Map < string , ts . ResolvedModuleFull > ( ) ;
15
38
16
39
/**
17
40
* Tries to get a cached module.
18
41
*/
19
- get ( moduleName : string , containingFile : string ) : ts . ResolvedModule | undefined {
42
+ get ( moduleName : string , containingFile : string ) : ts . ResolvedModuleFull | undefined {
20
43
return this . cache . get ( this . getKey ( moduleName , containingFile ) ) ;
21
44
}
22
45
23
46
/**
24
47
* Caches resolved module, if it is not undefined.
25
48
*/
26
- set ( moduleName : string , containingFile : string , resolvedModule : ts . ResolvedModule | undefined ) {
49
+ set (
50
+ moduleName : string ,
51
+ containingFile : string ,
52
+ resolvedModule : ts . ResolvedModuleFull | undefined
53
+ ) {
27
54
if ( ! resolvedModule ) {
28
55
return ;
29
56
}
@@ -78,8 +105,13 @@ export function patchModuleLoader(
78
105
const svelteSys = createSvelteSys ( logger ) ;
79
106
const moduleCache = new ModuleResolutionCache ( project . projectService ) ;
80
107
const origResolveModuleNames = lsHost . resolveModuleNames ?. bind ( lsHost ) ;
108
+ const origResolveModuleNamLiterals = lsHost . resolveModuleNameLiterals ?. bind ( lsHost ) ;
81
109
82
- lsHost . resolveModuleNames = resolveModuleNames ;
110
+ if ( lsHost . resolveModuleNameLiterals ) {
111
+ lsHost . resolveModuleNameLiterals = resolveModuleNameLiterals ;
112
+ } else {
113
+ lsHost . resolveModuleNames = resolveModuleNames ;
114
+ }
83
115
84
116
const origRemoveFile = project . removeFile . bind ( project ) ;
85
117
project . removeFile = ( info , fileExists , detachFromProject ) => {
@@ -119,32 +151,22 @@ export function patchModuleLoader(
119
151
return resolved ;
120
152
}
121
153
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 ;
126
158
}
127
159
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 ;
140
162
} ) ;
141
163
}
142
164
143
165
function resolveSvelteModuleName (
144
166
name : string ,
145
167
containingFile : string ,
146
168
compilerOptions : ts . CompilerOptions
147
- ) : ts . ResolvedModule | undefined {
169
+ ) : ts . ResolvedModuleFull | undefined {
148
170
const svelteResolvedModule = typescript . resolveModuleName (
149
171
name ,
150
172
containingFile ,
@@ -168,8 +190,73 @@ export function patchModuleLoader(
168
190
169
191
const resolvedSvelteModule : ts . ResolvedModuleFull = {
170
192
extension : snapshot . isTsFile ? typescript . Extension . Ts : typescript . Extension . Js ,
171
- resolvedFileName
193
+ resolvedFileName,
194
+ isExternalLibraryImport : svelteResolvedModule . isExternalLibraryImport
172
195
} ;
173
196
return resolvedSvelteModule ;
174
197
}
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
+ }
175
262
}
0 commit comments