@@ -101,9 +101,11 @@ namespace ts {
101101 traceEnabled : boolean ;
102102 failedLookupLocations : Push < string > ;
103103 resultFromCache ?: ResolvedModuleWithFailedLookupLocations ;
104+ packageJsonInfoCache : PackageJsonInfoCache | undefined ;
104105 }
105106
106107 /** Just the fields that we use for module resolution. */
108+ /*@internal */
107109 interface PackageJsonPathFields {
108110 typings ?: string ;
109111 types ?: string ;
@@ -179,6 +181,7 @@ namespace ts {
179181 return typesVersions ;
180182 }
181183
184+ /*@internal */
182185 interface VersionPaths {
183186 version : string ;
184187 paths : MapLike < string [ ] > ;
@@ -281,13 +284,13 @@ namespace ts {
281284 * This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
282285 * is assumed to be the same as root directory of the project.
283286 */
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 {
285288 const traceEnabled = isTraceEnabled ( options , host ) ;
286289 if ( redirectedReference ) {
287290 options = redirectedReference . commandLine . options ;
288291 }
289292 const failedLookupLocations : string [ ] = [ ] ;
290- const moduleResolutionState : ModuleResolutionState = { compilerOptions : options , host, traceEnabled, failedLookupLocations } ;
293+ const moduleResolutionState : ModuleResolutionState = { compilerOptions : options , host, traceEnabled, failedLookupLocations, packageJsonInfoCache } ;
291294
292295 const typeRoots = getEffectiveTypeRoots ( options , host ) ;
293296 if ( traceEnabled ) {
@@ -441,7 +444,7 @@ namespace ts {
441444 * Cached module resolutions per containing directory.
442445 * This assumes that any module id will have the same resolution for sibling files located in the same folder.
443446 */
444- export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache {
447+ export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache , PackageJsonInfoCache {
445448 getOrCreateCacheForDirectory ( directoryName : string , redirectedReference ?: ResolvedProjectReference ) : Map < ResolvedModuleWithFailedLookupLocations > ;
446449 clear ( ) : void ;
447450 /**
@@ -455,10 +458,16 @@ namespace ts {
455458 * Stored map from non-relative module name to a table: directory -> result of module lookup in this directory
456459 * We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive.
457460 */
458- export interface NonRelativeModuleNameResolutionCache {
461+ export interface NonRelativeModuleNameResolutionCache extends PackageJsonInfoCache {
459462 getOrCreateCacheForModuleName ( nonRelativeModuleName : string , redirectedReference ?: ResolvedProjectReference ) : PerModuleNameCache ;
460463 }
461464
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+
462471 export interface PerModuleNameCache {
463472 get ( directory : string ) : ResolvedModuleWithFailedLookupLocations | undefined ;
464473 set ( directory : string , result : ResolvedModuleWithFailedLookupLocations ) : void ;
@@ -525,14 +534,29 @@ namespace ts {
525534 }
526535 }
527536
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+
528551 /*@internal */
529552 export function createModuleResolutionCacheWithMaps (
530553 directoryToModuleNameMap : CacheWithRedirects < ESMap < string , ResolvedModuleWithFailedLookupLocations > > ,
531554 moduleNameToDirectoryMap : CacheWithRedirects < PerModuleNameCache > ,
532555 currentDirectory : string ,
533556 getCanonicalFileName : GetCanonicalFileName ) : ModuleResolutionCache {
534-
557+ const packageJsonInfoCache = createPackageJsonInfoCache ( currentDirectory , getCanonicalFileName ) ;
535558 return {
559+ ...packageJsonInfoCache ,
536560 getOrCreateCacheForDirectory,
537561 getOrCreateCacheForModuleName,
538562 clear,
@@ -542,6 +566,7 @@ namespace ts {
542566 function clear ( ) {
543567 directoryToModuleNameMap . clear ( ) ;
544568 moduleNameToDirectoryMap . clear ( ) ;
569+ packageJsonInfoCache . clear ( ) ;
545570 }
546571
547572 function update ( options : CompilerOptions ) {
@@ -969,7 +994,7 @@ namespace ts {
969994 const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
970995
971996 const failedLookupLocations : string [ ] = [ ] ;
972- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
997+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache : cache } ;
973998
974999 const result = forEach ( extensions , ext => tryResolve ( ext ) ) ;
9751000 return createResolvedModuleWithFailedLookupLocations ( result ?. value ?. resolved , result ?. value ?. isExternalLibraryImport , failedLookupLocations , state . resultFromCache ) ;
@@ -1175,6 +1200,7 @@ namespace ts {
11751200 return withPackageId ( packageInfo , loadNodeModuleFromDirectoryWorker ( extensions , candidate , onlyRecordFailures , state , packageJsonContent , versionPaths ) ) ;
11761201 }
11771202
1203+ /*@internal */
11781204 interface PackageJsonInfo {
11791205 packageDirectory : string ;
11801206 packageJsonContent : PackageJsonPathFields ;
@@ -1183,21 +1209,40 @@ namespace ts {
11831209
11841210 function getPackageJsonInfo ( packageDirectory : string , onlyRecordFailures : boolean , state : ModuleResolutionState ) : PackageJsonInfo | undefined {
11851211 const { host, traceEnabled } = state ;
1186- const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( packageDirectory , host ) ;
11871212 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 ) ;
11881231 if ( directoryExists && host . fileExists ( packageJsonPath ) ) {
11891232 const packageJsonContent = readJson ( packageJsonPath , host ) as PackageJson ;
11901233 if ( traceEnabled ) {
11911234 trace ( host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
11921235 }
11931236 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 ;
11951240 }
11961241 else {
11971242 if ( directoryExists && traceEnabled ) {
11981243 trace ( host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
11991244 }
1200-
1245+ state . packageJsonInfoCache ?. setPackageJsonInfo ( packageJsonPath , false ) ;
12011246 // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
12021247 state . failedLookupLocations . push ( packageJsonPath ) ;
12031248 }
@@ -1486,7 +1531,7 @@ namespace ts {
14861531 export function classicNameResolver ( moduleName : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost , cache ?: NonRelativeModuleNameResolutionCache , redirectedReference ?: ResolvedProjectReference ) : ResolvedModuleWithFailedLookupLocations {
14871532 const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
14881533 const failedLookupLocations : string [ ] = [ ] ;
1489- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
1534+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache : cache } ;
14901535 const containingDirectory = getDirectoryPath ( containingFile ) ;
14911536
14921537 const resolved = tryResolve ( Extensions . TypeScript ) || tryResolve ( Extensions . JavaScript ) ;
@@ -1530,13 +1575,13 @@ namespace ts {
15301575 * This is the minumum code needed to expose that functionality; the rest is in the host.
15311576 */
15321577 /* @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 {
15341579 const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
15351580 if ( traceEnabled ) {
15361581 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 ) ;
15371582 }
15381583 const failedLookupLocations : string [ ] = [ ] ;
1539- const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations } ;
1584+ const state : ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache } ;
15401585 const resolved = loadModuleFromImmediateNodeModulesDirectory ( Extensions . DtsOnly , moduleName , globalCache , state , /*typesScopeOnly*/ false ) ;
15411586 return createResolvedModuleWithFailedLookupLocations ( resolved , /*isExternalLibraryImport*/ true , failedLookupLocations , state . resultFromCache ) ;
15421587 }
0 commit comments