@@ -47,7 +47,7 @@ namespace ts.moduleSpecifiers {
47
47
host : ModuleSpecifierResolutionHost ,
48
48
oldImportSpecifier : string ,
49
49
) : string | undefined {
50
- const res = getModuleSpecifierWorker ( compilerOptions , importingSourceFileName , toFileName , host , getPreferencesForUpdate ( compilerOptions , oldImportSpecifier ) ) ;
50
+ const res = getModuleSpecifierWorker ( compilerOptions , importingSourceFileName , toFileName , host , getPreferencesForUpdate ( compilerOptions , oldImportSpecifier ) , { } ) ;
51
51
if ( res === oldImportSpecifier ) return undefined ;
52
52
return res ;
53
53
}
@@ -59,19 +59,19 @@ namespace ts.moduleSpecifiers {
59
59
importingSourceFileName : Path ,
60
60
toFileName : string ,
61
61
host : ModuleSpecifierResolutionHost ,
62
- preferences : UserPreferences = { } ,
63
62
) : string {
64
- return getModuleSpecifierWorker ( compilerOptions , importingSourceFileName , toFileName , host , getPreferences ( preferences , compilerOptions , importingSourceFile ) ) ;
63
+ return getModuleSpecifierWorker ( compilerOptions , importingSourceFileName , toFileName , host , getPreferences ( { } , compilerOptions , importingSourceFile ) , { } ) ;
65
64
}
66
65
67
66
export function getNodeModulesPackageName (
68
67
compilerOptions : CompilerOptions ,
69
68
importingSourceFileName : Path ,
70
69
nodeModulesFileName : string ,
71
70
host : ModuleSpecifierResolutionHost ,
71
+ preferences : UserPreferences ,
72
72
) : string | undefined {
73
73
const info = getInfo ( importingSourceFileName , host ) ;
74
- const modulePaths = getAllModulePaths ( importingSourceFileName , nodeModulesFileName , host ) ;
74
+ const modulePaths = getAllModulePaths ( importingSourceFileName , nodeModulesFileName , host , preferences ) ;
75
75
return firstDefined ( modulePaths ,
76
76
modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , host , compilerOptions , /*packageNameOnly*/ true ) ) ;
77
77
}
@@ -81,10 +81,11 @@ namespace ts.moduleSpecifiers {
81
81
importingSourceFileName : Path ,
82
82
toFileName : string ,
83
83
host : ModuleSpecifierResolutionHost ,
84
- preferences : Preferences
84
+ preferences : Preferences ,
85
+ userPreferences : UserPreferences ,
85
86
) : string {
86
87
const info = getInfo ( importingSourceFileName , host ) ;
87
- const modulePaths = getAllModulePaths ( importingSourceFileName , toFileName , host ) ;
88
+ const modulePaths = getAllModulePaths ( importingSourceFileName , toFileName , host , userPreferences ) ;
88
89
return firstDefined ( modulePaths , modulePath => tryGetModuleNameAsNodeModule ( modulePath , info , host , compilerOptions ) ) ||
89
90
getLocalModuleSpecifier ( toFileName , info , compilerOptions , host , preferences ) ;
90
91
}
@@ -106,9 +107,17 @@ namespace ts.moduleSpecifiers {
106
107
if ( ! moduleSourceFile ) {
107
108
return [ ] ;
108
109
}
109
- const modulePaths = getAllModulePaths ( importingSourceFile . path , moduleSourceFile . originalFileName , host ) ;
110
- const preferences = getPreferences ( userPreferences , compilerOptions , importingSourceFile ) ;
111
110
111
+ const cache = host . getModuleSpecifierCache ?.( ) ;
112
+ const cached = cache ?. get ( importingSourceFile . path , moduleSourceFile . path , userPreferences ) ;
113
+ let modulePaths ;
114
+ if ( cached ) {
115
+ if ( cached . moduleSpecifiers ) return cached . moduleSpecifiers ;
116
+ modulePaths = cached . modulePaths ;
117
+ }
118
+
119
+ modulePaths ||= getAllModulePathsWorker ( importingSourceFile . path , moduleSourceFile . originalFileName , host ) ;
120
+ const preferences = getPreferences ( userPreferences , compilerOptions , importingSourceFile ) ;
112
121
const existingSpecifier = forEach ( modulePaths , modulePath => forEach (
113
122
host . getFileIncludeReasons ( ) . get ( toPath ( modulePath . path , host . getCurrentDirectory ( ) , info . getCanonicalFileName ) ) ,
114
123
reason => {
@@ -120,7 +129,11 @@ namespace ts.moduleSpecifiers {
120
129
undefined ;
121
130
}
122
131
) ) ;
123
- if ( existingSpecifier ) return [ existingSpecifier ] ;
132
+ if ( existingSpecifier ) {
133
+ const moduleSpecifiers = [ existingSpecifier ] ;
134
+ cache ?. set ( importingSourceFile . path , moduleSourceFile . path , userPreferences , modulePaths , moduleSpecifiers ) ;
135
+ return moduleSpecifiers ;
136
+ }
124
137
125
138
const importedFileIsInNodeModules = some ( modulePaths , p => p . isInNodeModules ) ;
126
139
@@ -138,6 +151,7 @@ namespace ts.moduleSpecifiers {
138
151
if ( specifier && modulePath . isRedirect ) {
139
152
// If we got a specifier for a redirect, it was a bare package specifier (e.g. "@foo/bar",
140
153
// not "@foo/bar/path/to/file"). No other specifier will be this good, so stop looking.
154
+ cache ?. set ( importingSourceFile . path , moduleSourceFile . path , userPreferences , modulePaths , nodeModulesSpecifiers ! ) ;
141
155
return nodeModulesSpecifiers ! ;
142
156
}
143
157
@@ -161,9 +175,11 @@ namespace ts.moduleSpecifiers {
161
175
}
162
176
}
163
177
164
- return pathsSpecifiers ?. length ? pathsSpecifiers :
178
+ const moduleSpecifiers = pathsSpecifiers ?. length ? pathsSpecifiers :
165
179
nodeModulesSpecifiers ?. length ? nodeModulesSpecifiers :
166
180
Debug . checkDefined ( relativeSpecifiers ) ;
181
+ cache ?. set ( importingSourceFile . path , moduleSourceFile . path , userPreferences , modulePaths , moduleSpecifiers ) ;
182
+ return moduleSpecifiers ;
167
183
}
168
184
169
185
interface Info {
@@ -329,13 +345,27 @@ namespace ts.moduleSpecifiers {
329
345
* Looks for existing imports that use symlinks to this module.
330
346
* Symlinks will be returned first so they are preferred over the real path.
331
347
*/
332
- function getAllModulePaths ( importingFileName : Path , importedFileName : string , host : ModuleSpecifierResolutionHost ) : readonly ModulePath [ ] {
348
+ function getAllModulePaths (
349
+ importingFilePath : Path ,
350
+ importedFileName : string ,
351
+ host : ModuleSpecifierResolutionHost ,
352
+ preferences : UserPreferences ,
353
+ importedFilePath = toPath ( importedFileName , host . getCurrentDirectory ( ) , hostGetCanonicalFileName ( host ) )
354
+ ) {
333
355
const cache = host . getModuleSpecifierCache ?.( ) ;
334
- const getCanonicalFileName = hostGetCanonicalFileName ( host ) ;
335
356
if ( cache ) {
336
- const cached = cache . get ( importingFileName , toPath ( importedFileName , host . getCurrentDirectory ( ) , getCanonicalFileName ) ) ;
337
- if ( typeof cached === "object" ) return cached ;
357
+ const cached = cache . get ( importingFilePath , importedFilePath , preferences ) ;
358
+ if ( cached ?. modulePaths ) return cached . modulePaths ;
359
+ }
360
+ const modulePaths = getAllModulePathsWorker ( importingFilePath , importedFileName , host ) ;
361
+ if ( cache ) {
362
+ cache . setModulePaths ( importingFilePath , importedFilePath , preferences , modulePaths ) ;
338
363
}
364
+ return modulePaths ;
365
+ }
366
+
367
+ function getAllModulePathsWorker ( importingFileName : Path , importedFileName : string , host : ModuleSpecifierResolutionHost ) : readonly ModulePath [ ] {
368
+ const getCanonicalFileName = hostGetCanonicalFileName ( host ) ;
339
369
const allFileNames = new Map < string , { path : string , isRedirect : boolean , isInNodeModules : boolean } > ( ) ;
340
370
let importedFileFromNodeModules = false ;
341
371
forEachFileNameOfModule (
@@ -381,9 +411,6 @@ namespace ts.moduleSpecifiers {
381
411
sortedPaths . push ( ...remainingPaths ) ;
382
412
}
383
413
384
- if ( cache ) {
385
- cache . set ( importingFileName , toPath ( importedFileName , host . getCurrentDirectory ( ) , getCanonicalFileName ) , sortedPaths ) ;
386
- }
387
414
return sortedPaths ;
388
415
}
389
416
0 commit comments