@@ -101,9 +101,11 @@ namespace ts {
101
101
traceEnabled : boolean ;
102
102
failedLookupLocations : Push < string > ;
103
103
resultFromCache ?: ResolvedModuleWithFailedLookupLocations ;
104
+ packageJsonInfoCache : PackageJsonInfoCache | undefined ;
104
105
}
105
106
106
107
/** Just the fields that we use for module resolution. */
108
+ /*@internal */
107
109
interface PackageJsonPathFields {
108
110
typings ?: string ;
109
111
types ?: string ;
@@ -179,6 +181,7 @@ namespace ts {
179
181
return typesVersions ;
180
182
}
181
183
184
+ /*@internal */
182
185
interface VersionPaths {
183
186
version : string ;
184
187
paths : MapLike < string [ ] > ;
@@ -281,13 +284,13 @@ namespace ts {
281
284
* This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
282
285
* is assumed to be the same as root directory of the project.
283
286
*/
284
- export function resolveTypeReferenceDirective ( typeReferenceDirectiveName : string , containingFile : string | undefined , options : CompilerOptions , host : ModuleResolutionHost , redirectedReference ?: ResolvedProjectReference ) : ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
287
+ export function resolveTypeReferenceDirective ( typeReferenceDirectiveName : string , containingFile : string | undefined , options : CompilerOptions , host : ModuleResolutionHost , redirectedReference ?: ResolvedProjectReference , packageJsonInfoCache ?: PackageJsonInfoCache ) : ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
285
288
const traceEnabled = isTraceEnabled ( options , host ) ;
286
289
if ( redirectedReference ) {
287
290
options = redirectedReference . commandLine . options ;
288
291
}
289
292
const failedLookupLocations : string [ ] = [ ] ;
290
- const moduleResolutionState : ModuleResolutionState = { compilerOptions : options , host, traceEnabled, failedLookupLocations } ;
293
+ const moduleResolutionState : ModuleResolutionState = { compilerOptions : options , host, traceEnabled, failedLookupLocations, packageJsonInfoCache } ;
291
294
292
295
const typeRoots = getEffectiveTypeRoots ( options , host ) ;
293
296
if ( traceEnabled ) {
@@ -441,7 +444,7 @@ namespace ts {
441
444
* Cached module resolutions per containing directory.
442
445
* This assumes that any module id will have the same resolution for sibling files located in the same folder.
443
446
*/
444
- export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache {
447
+ export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache , PackageJsonInfoCache {
445
448
getOrCreateCacheForDirectory ( directoryName : string , redirectedReference ?: ResolvedProjectReference ) : Map < ResolvedModuleWithFailedLookupLocations > ;
446
449
clear ( ) : void ;
447
450
/**
@@ -455,10 +458,16 @@ namespace ts {
455
458
* Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
456
459
* We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
457
460
*/
458
- export interface NonRelativeModuleNameResolutionCache {
461
+ export interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
459
462
getOrCreateCacheForModuleName ( nonRelativeModuleName : string , redirectedReference ?: ResolvedProjectReference ) : PerModuleNameCache ;
460
463
}
461
464
465
+ export interface PackageJsonInfoCache {
466
+ /*@internal */ getPackageJsonInfo ( packageJsonPath : string ) : PackageJsonInfo | false | undefined ;
467
+ /*@internal */ setPackageJsonInfo ( packageJsonPath : string , info : PackageJsonInfo | false ) : void ;
468
+ clear ( ) : void ;
469
+ }
470
+
462
471
export interface PerModuleNameCache {
463
472
get ( directory : string ) : ResolvedModuleWithFailedLookupLocations | undefined ;
464
473
set ( directory : string , result : ResolvedModuleWithFailedLookupLocations ) : void ;
@@ -525,14 +534,29 @@ namespace ts {
525
534
}
526
535
}
527
536
537
+ export function createPackageJsonInfoCache ( currentDirectory : string , getCanonicalFileName : ( s : string ) => string ) : PackageJsonInfoCache {
538
+ let cache : ESMap < Path , PackageJsonInfo | false > | undefined ;
539
+ return { getPackageJsonInfo, setPackageJsonInfo, clear } ;
540
+ function getPackageJsonInfo ( packageJsonPath : string ) {
541
+ return cache ?. get ( toPath ( packageJsonPath , currentDirectory , getCanonicalFileName ) ) ;
542
+ }
543
+ function setPackageJsonInfo ( packageJsonPath : string , info : PackageJsonInfo | false ) {
544
+ ( cache ||= new Map ( ) ) . set ( toPath ( packageJsonPath , currentDirectory , getCanonicalFileName ) , info ) ;
545
+ }
546
+ function clear ( ) {
547
+ cache = undefined ;
548
+ }
549
+ }
550
+
528
551
/*@internal */
529
552
export function createModuleResolutionCacheWithMaps (
530
553
directoryToModuleNameMap : CacheWithRedirects < ESMap < string , ResolvedModuleWithFailedLookupLocations > > ,
531
554
moduleNameToDirectoryMap : CacheWithRedirects < PerModuleNameCache > ,
532
555
currentDirectory : string ,
533
556
getCanonicalFileName : GetCanonicalFileName ) : ModuleResolutionCache {
534
-
557
+ const packageJsonInfoCache = createPackageJsonInfoCache ( currentDirectory , getCanonicalFileName ) ;
535
558
return {
559
+ ...packageJsonInfoCache ,
536
560
getOrCreateCacheForDirectory,
537
561
getOrCreateCacheForModuleName,
538
562
clear,
@@ -542,6 +566,7 @@ namespace ts {
542
566
function clear ( ) {
543
567
directoryToModuleNameMap . clear ( ) ;
544
568
moduleNameToDirectoryMap . clear ( ) ;
569
+ packageJsonInfoCache . clear ( ) ;
545
570
}
546
571
547
572
function update ( options : CompilerOptions ) {
@@ -969,7 +994,7 @@ namespace ts {
969
994
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
970
995
971
996
const failedLookupLocations : string [ ] = [ ] ;
972
- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
997
+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache : cache } ;
973
998
974
999
const result = forEach ( extensions , ext => tryResolve ( ext ) ) ;
975
1000
return createResolvedModuleWithFailedLookupLocations ( result ?. value ?. resolved , result ?. value ?. isExternalLibraryImport , failedLookupLocations , state . resultFromCache ) ;
@@ -1175,6 +1200,7 @@ namespace ts {
1175
1200
return withPackageId ( packageInfo , loadNodeModuleFromDirectoryWorker ( extensions , candidate , onlyRecordFailures , state , packageJsonContent , versionPaths ) ) ;
1176
1201
}
1177
1202
1203
+ /*@internal */
1178
1204
interface PackageJsonInfo {
1179
1205
packageDirectory : string ;
1180
1206
packageJsonContent : PackageJsonPathFields ;
@@ -1183,21 +1209,40 @@ namespace ts {
1183
1209
1184
1210
function getPackageJsonInfo ( packageDirectory : string , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PackageJsonInfo | undefined {
1185
1211
const { host, traceEnabled } = state ;
1186
- const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( packageDirectory , host ) ;
1187
1212
const packageJsonPath = combinePaths ( packageDirectory , "package.json" ) ;
1213
+ if ( onlyRecordFailures ) {
1214
+ state . failedLookupLocations . push ( packageJsonPath ) ;
1215
+ return undefined ;
1216
+ }
1217
+
1218
+ const existing = state . packageJsonInfoCache ?. getPackageJsonInfo ( packageJsonPath ) ;
1219
+ if ( existing !== undefined ) {
1220
+ if ( existing ) {
1221
+ if ( traceEnabled ) trace ( host , Diagnostics . Using_cached_result_of_package_json_at_0_that_indicates_it_was_found , packageJsonPath ) ;
1222
+ return existing ;
1223
+ }
1224
+ else {
1225
+ if ( traceEnabled ) trace ( host , Diagnostics . Using_cached_result_of_package_json_at_0_that_indicates_it_was_not_found , packageJsonPath ) ;
1226
+ state . failedLookupLocations . push ( packageJsonPath ) ;
1227
+ return undefined ;
1228
+ }
1229
+ }
1230
+ const directoryExists = directoryProbablyExists ( packageDirectory , host ) ;
1188
1231
if ( directoryExists && host . fileExists ( packageJsonPath ) ) {
1189
1232
const packageJsonContent = readJson ( packageJsonPath , host ) as PackageJson ;
1190
1233
if ( traceEnabled ) {
1191
1234
trace ( host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
1192
1235
}
1193
1236
const versionPaths = readPackageJsonTypesVersionPaths ( packageJsonContent , state ) ;
1194
- return { packageDirectory, packageJsonContent, versionPaths } ;
1237
+ const result = { packageDirectory, packageJsonContent, versionPaths } ;
1238
+ state . packageJsonInfoCache ?. setPackageJsonInfo ( packageJsonPath , result ) ;
1239
+ return result ;
1195
1240
}
1196
1241
else {
1197
1242
if ( directoryExists && traceEnabled ) {
1198
1243
trace ( host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
1199
1244
}
1200
-
1245
+ state . packageJsonInfoCache ?. setPackageJsonInfo ( packageJsonPath , false ) ;
1201
1246
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
1202
1247
state . failedLookupLocations . push ( packageJsonPath ) ;
1203
1248
}
@@ -1486,7 +1531,7 @@ namespace ts {
1486
1531
export function classicNameResolver ( moduleName : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost , cache ?: NonRelativeModuleNameResolutionCache , redirectedReference ?: ResolvedProjectReference ) : ResolvedModuleWithFailedLookupLocations {
1487
1532
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
1488
1533
const failedLookupLocations : string [ ] = [ ] ;
1489
- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
1534
+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache : cache } ;
1490
1535
const containingDirectory = getDirectoryPath ( containingFile ) ;
1491
1536
1492
1537
const resolved = tryResolve ( Extensions . TypeScript ) || tryResolve ( Extensions . JavaScript ) ;
@@ -1530,13 +1575,13 @@ namespace ts {
1530
1575
* This is the minumum code needed to expose that functionality; the rest is in the host.
1531
1576
*/
1532
1577
/* @internal */
1533
- export function loadModuleFromGlobalCache ( moduleName : string , projectName : string | undefined , compilerOptions : CompilerOptions , host : ModuleResolutionHost , globalCache : string ) : ResolvedModuleWithFailedLookupLocations {
1578
+ export function loadModuleFromGlobalCache ( moduleName : string , projectName : string | undefined , compilerOptions : CompilerOptions , host : ModuleResolutionHost , globalCache : string , packageJsonInfoCache : PackageJsonInfoCache ) : ResolvedModuleWithFailedLookupLocations {
1534
1579
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
1535
1580
if ( traceEnabled ) {
1536
1581
trace ( host , Diagnostics . Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2 , projectName , moduleName , globalCache ) ;
1537
1582
}
1538
1583
const failedLookupLocations : string [ ] = [ ] ;
1539
- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
1584
+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache } ;
1540
1585
const resolved = loadModuleFromImmediateNodeModulesDirectory ( Extensions . DtsOnly , moduleName , globalCache , state , /*typesScopeOnly*/ false ) ;
1541
1586
return createResolvedModuleWithFailedLookupLocations ( resolved , /*isExternalLibraryImport*/ true , failedLookupLocations , state . resultFromCache ) ;
1542
1587
}
0 commit comments