diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index d27a5455843..5cae55705ce 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -609,7 +609,7 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string affectingLocations: initializeResolutionField(affectingLocations), resolutionDiagnostics: initializeResolutionField(diagnostics), }; - if (containingDirectory) { + if (containingDirectory !== undefined) { cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) { cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result); @@ -823,6 +823,7 @@ export interface ModeAwareCache { * This assumes that any module id will have the same resolution for sibling files located in the same folder. */ export interface PerDirectoryResolutionCache { + /** @internal */ directoryToModuleNameMap: CacheWithRedirects>; getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined; getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache; clear(): void; @@ -834,6 +835,7 @@ export interface PerDirectoryResolutionCache { } export interface NonRelativeNameResolutionCache { + /** @internal */ moduleNameToDirectoryMap: CacheWithRedirects>; getFromNonRelativeNameCache(nonRelativeName: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined; getOrCreateCacheForNonRelativeName(nonRelativeName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache; clear(): void; @@ -901,6 +903,13 @@ export interface CacheWithRedirects { getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map; update(newOptions: CompilerOptions): void; clear(): void; + getState(): { + ownOptions: CompilerOptions | undefined; + optionsToRedirectsKey: Map; + redirectsKeyToMap: Map>; + ownMap: Map; + redirectsMap: Map>; + }; } /** @internal */ @@ -917,6 +926,7 @@ export function createCacheWithRedirects(ownOptions: CompilerOptions | und getOrCreateMapOfCacheRedirects, update, clear, + getState: () => ({ ownOptions, optionsToRedirectsKey, redirectsKeyToMap, ownMap, redirectsMap }), }; function getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map | undefined { @@ -1019,6 +1029,7 @@ function createPerDirectoryResolutionCache( ): PerDirectoryResolutionCache { const directoryToModuleNameMap = createCacheWithRedirects>(options, optionsToRedirectsKey); return { + directoryToModuleNameMap, getFromDirectoryCache, getOrCreateCacheForDirectory, clear, @@ -1107,6 +1118,7 @@ function createNonRelativeNameResolutionCache( ): NonRelativeNameResolutionCache { const moduleNameToDirectoryMap = createCacheWithRedirects>(options, optionsToRedirectsKey); return { + moduleNameToDirectoryMap, getFromNonRelativeNameCache, getOrCreateCacheForNonRelativeName, clear, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e95e525f473..3e8f815b08b 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -258,6 +258,7 @@ import { Path, pathIsAbsolute, pathIsRelative, + PerDirectoryResolutionCache, Program, ProgramHost, ProjectReference, @@ -271,6 +272,7 @@ import { removeSuffix, resolutionExtensionIsTSOrJson, ResolutionMode, + ResolutionStorageCaches, ResolutionWithFailedLookupLocations, resolveConfigFileProjectName, ResolvedConfigFileName, @@ -1558,6 +1560,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const hasEmitBlockingDiagnostics = new Map(); let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression | false | undefined; + let resolutionStorageCaches: ResolutionStorageCaches | undefined = host.getResolutionStorageCaches?.(); let moduleResolutionCache: ModuleResolutionCache | undefined; let actualResolveModuleNamesWorker: ( moduleNames: readonly StringLiteralLike[], @@ -1604,6 +1607,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg moduleResolutionCache, createModuleResolutionLoader, ); + (resolutionStorageCaches ??= {}).moduleResolutionCache = moduleResolutionCache; } let actualResolveTypeReferenceDirectiveNamesWorker: ( @@ -1646,6 +1650,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg typeReferenceDirectiveResolutionCache, createTypeReferenceResolutionLoader, ); + (resolutionStorageCaches ??= {}).typeReferenceDirectiveResolutionCache = typeReferenceDirectiveResolutionCache; } const hasInvalidatedLibResolutions = host.hasInvalidatedLibResolutions || returnFalse; @@ -1886,6 +1891,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg usesUriStyleNodeCoreModules, resolvedModules, resolvedTypeReferenceDirectiveNames, + getResolutionStorageCaches: () => resolutionStorageCaches, resolvedLibReferences, getResolvedModule, getResolvedTypeReferenceDirective, @@ -1941,34 +1947,121 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return program; function getResolvedModule(file: SourceFile, moduleName: string, mode: ResolutionMode) { - return resolvedModules?.get(file.path)?.get(moduleName, mode); + return getResolution( + file, + moduleName, + mode, + resolvedModules, + resolutionStorageCaches?.moduleResolutionCache, + getModuleNames, + moduleResolutionNameAndModeGetter, + ); } function getResolvedTypeReferenceDirective(file: SourceFile, typeDirectiveName: string, mode: ResolutionMode) { - return resolvedTypeReferenceDirectiveNames?.get(file.path)?.get(typeDirectiveName, mode); + return getResolution( + file, + typeDirectiveName, + mode, + resolvedTypeReferenceDirectiveNames, + resolutionStorageCaches?.typeReferenceDirectiveResolutionCache, + file => file.typeReferenceDirectives, + typeReferenceResolutionNameAndModeGetter, + ); + } + + function getResolution( + file: SourceFile, + name: string, + mode: ResolutionMode, + perFileCache: Map> | undefined, + resolutionCache: PerDirectoryResolutionCache | undefined, + getEntries: (file: SourceFile) => readonly Entry[], + nameAndMode: ResolutionNameAndModeGetter, + ) { + const result = perFileCache?.get(file.path)?.get(name, mode); + if (resolutionCache) { + const fileFromProgram = getSourceFileByPath(file.path); + if ( + !fileFromProgram || + fileFromProgram.path !== file.path || + // There can be case where the resolution was resolved in directory with "mode" but not in file. + !forEach(getEntries(fileFromProgram), entry => + nameAndMode.getName(entry) === name && + nameAndMode.getMode(entry, fileFromProgram) === mode) + ) { + Debug.assert(result === undefined); + return undefined; + } + const containingDirectory = getDirectoryPath(file.path); + const redirectedReference = getRedirectReferenceForResolution(file); + // May be we need to update ownOptions + const { ownOptions } = resolutionCache.directoryToModuleNameMap.getState(); + if (ownOptions) resolutionCache.directoryToModuleNameMap.update(options); + const fromCache = resolutionCache.getFromDirectoryCache(name, mode, containingDirectory, redirectedReference); + Debug.assert( + result === fromCache || + // Currently resolutionCache in tsserver or tsc-watch doesnt retain per directory resolutions through program update + // So cache might have different result than actual resolution - which will be fixed as part of sharing resolutions across projects + JSON.stringify((result as ResolvedModuleWithFailedLookupLocations)?.resolvedModule) === JSON.stringify((fromCache as ResolvedModuleWithFailedLookupLocations)?.resolvedModule) || + JSON.stringify((result as ResolvedTypeReferenceDirectiveWithFailedLookupLocations)?.resolvedTypeReferenceDirective) === JSON.stringify((fromCache as ResolvedTypeReferenceDirectiveWithFailedLookupLocations)?.resolvedTypeReferenceDirective), + ); + if (ownOptions) resolutionCache.directoryToModuleNameMap.update(ownOptions); + return fromCache; + } + return result; } function forEachResolvedModule( callback: (resolution: ResolvedModuleWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void, file?: SourceFile, ) { - forEachResolution(resolvedModules, callback, file); + forEachResolution( + callback, + file, + resolvedModules, + resolutionStorageCaches?.moduleResolutionCache, + getModuleNames, + moduleResolutionNameAndModeGetter, + ); } function forEachResolvedTypeReferenceDirective( callback: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void, file?: SourceFile, ): void { - forEachResolution(resolvedTypeReferenceDirectiveNames, callback, file); + forEachResolution( + callback, + file, + resolvedTypeReferenceDirectiveNames, + resolutionStorageCaches?.typeReferenceDirectiveResolutionCache, + file => file.typeReferenceDirectives, + typeReferenceResolutionNameAndModeGetter, + ); } - function forEachResolution( - resolutionCache: Map> | undefined, + function forEachResolution( callback: (resolution: T, moduleName: string, mode: ResolutionMode, filePath: Path) => void, file: SourceFile | undefined, + perFileCache: Map> | undefined, + resolutionCache: PerDirectoryResolutionCache | undefined, + getEntries: (file: SourceFile) => readonly Entry[], + nameAndMode: ResolutionNameAndModeGetter, ) { - if (file) resolutionCache?.get(file.path)?.forEach((resolution, name, mode) => callback(resolution, name, mode, file.path)); - else resolutionCache?.forEach((resolutions, filePath) => resolutions.forEach((resolution, name, mode) => callback(resolution, name, mode, filePath))); + if (file) { + perFileCache?.get(file.path)?.forEach((resolution, name, mode) => { + getResolution(file, name, mode, perFileCache, resolutionCache, getEntries, nameAndMode); + callback(resolution, name, mode, file.path); + }); + } + else { + perFileCache?.forEach((resolutions, filePath) => + resolutions.forEach((resolution, name, mode) => { + getResolution(getSourceFileByPath(filePath)!, name, mode, perFileCache, resolutionCache, getEntries, nameAndMode); + callback(resolution, name, mode, filePath); + }) + ); + } } function getPackagesMap() { @@ -2594,6 +2687,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg usesUriStyleNodeCoreModules = oldProgram.usesUriStyleNodeCoreModules; resolvedModules = oldProgram.resolvedModules; resolvedTypeReferenceDirectiveNames = oldProgram.resolvedTypeReferenceDirectiveNames; + resolutionStorageCaches = oldProgram.getResolutionStorageCaches(); resolvedLibReferences = oldProgram.resolvedLibReferences; packageMap = oldProgram.getCurrentPackagesMap(); @@ -3845,13 +3939,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectives, file); const resolutionsInFile = createModeAwareCache(); (resolvedTypeReferenceDirectiveNames ??= new Map()).set(file.path, resolutionsInFile); + const redirectedReference = getRedirectReferenceForResolution(file); + const resolutionsInCache = resolutionStorageCaches?.typeReferenceDirectiveResolutionCache?.getOrCreateCacheForDirectory(getDirectoryPath(file.path), redirectedReference); for (let index = 0; index < typeDirectives.length; index++) { const ref = file.typeReferenceDirectives[index]; const resolvedTypeReferenceDirective = resolutions[index]; // store resolved type directive on the file const fileName = toFileNameLowerCase(ref.fileName); - resolutionsInFile.set(fileName, getModeForFileReference(ref, file.impliedNodeFormat), resolvedTypeReferenceDirective); - const mode = ref.resolutionMode || file.impliedNodeFormat; + const mode = getModeForFileReference(ref, file.impliedNodeFormat); + resolutionsInFile.set(fileName, mode, resolvedTypeReferenceDirective); + // We have to set this resolution if say this was done as part of reusing program where not every resolution is re-valudated + if (resolutionsInCache && !resolutionsInCache.has(fileName, mode)) resolutionsInCache.set(fileName, mode, resolutions[index]); if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) { (fileProcessingDiagnostics ??= []).push({ kind: FilePreprocessingDiagnosticsKind.ResolutionDiagnostics, @@ -4021,14 +4119,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const resolutions = resolvedModulesProcessing?.get(file.path) || resolveModuleNamesReusingOldState(moduleNames, file); Debug.assert(resolutions.length === moduleNames.length); - const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options; + const redirectedReference = getRedirectReferenceForResolution(file); + const optionsForFile = (useSourceOfProjectReferenceRedirect ? redirectedReference?.commandLine.options : undefined) || options; const resolutionsInFile = createModeAwareCache(); (resolvedModules ??= new Map()).set(file.path, resolutionsInFile); + const resolutionsInCache = resolutionStorageCaches?.moduleResolutionCache?.getOrCreateCacheForDirectory(getDirectoryPath(file.path), redirectedReference); for (let index = 0; index < moduleNames.length; index++) { const resolution = resolutions[index].resolvedModule; const moduleName = moduleNames[index].text; const mode = getModeForUsageLocation(file, moduleNames[index]); resolutionsInFile.set(moduleName, mode, resolutions[index]); + // We have to set this resolution if say this was done as part of reusing program where not every resolution is re-valudated + if (resolutionsInCache && !resolutionsInCache.has(moduleName, mode)) resolutionsInCache.set(moduleName, mode, resolutions[index]); addResolutionDiagnosticsFromResolutionOrCache(file, moduleName, resolutions[index], mode); if (!resolution) { diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 35c03d294ed..48585e5f111 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -75,6 +75,7 @@ import { startsWith, StringLiteralLike, trace, + TypeReferenceDirectiveResolutionCache, updateResolutionField, WatchDirectoryFlags, } from "./_namespaces/ts"; @@ -156,6 +157,7 @@ export interface ResolutionCache { closeTypeRootsWatch(): void; getModuleResolutionCache(): ModuleResolutionCache; + getTypeReferenceDirectiveResolutionCache(): TypeReferenceDirectiveResolutionCache; clear(): void; onChangesAffectModuleResolution(): void; @@ -535,27 +537,18 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD // The key in the map is source file's path. // The values are Map of resolutions with key being name lookedup. const resolvedModuleNames = new Map>(); - const moduleResolutionCache = createModuleResolutionCache( - getCurrentDirectory(), - resolutionHost.getCanonicalFileName, - resolutionHost.getCompilationSettings(), - ); + let moduleResolutionCache: ModuleResolutionCache; const resolvedTypeReferenceDirectives = new Map>(); - const typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( - getCurrentDirectory(), - resolutionHost.getCanonicalFileName, - resolutionHost.getCompilationSettings(), - moduleResolutionCache.getPackageJsonInfoCache(), - moduleResolutionCache.optionsToRedirectsKey, - ); + let typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache; + createResolutionCaches(); const resolvedLibraries = new Map(); const libraryResolutionCache = createModuleResolutionCache( getCurrentDirectory(), resolutionHost.getCanonicalFileName, getOptionsForLibraryResolution(resolutionHost.getCompilationSettings()), - moduleResolutionCache.getPackageJsonInfoCache(), + moduleResolutionCache!.getPackageJsonInfoCache(), ); const directoryWatchesOfFailedLookups = new Map(); @@ -579,6 +572,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD fileWatchesOfAffectingLocations, watchFailedLookupLocationsOfExternalModuleResolutions, getModuleResolutionCache: () => moduleResolutionCache, + getTypeReferenceDirectiveResolutionCache: () => typeReferenceDirectiveResolutionCache, startRecordingFilesWithChangedResolutions, finishRecordingFilesWithChangedResolutions, // perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update @@ -603,6 +597,22 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD onChangesAffectModuleResolution, }; + function createResolutionCaches() { + moduleResolutionCache = createModuleResolutionCache( + getCurrentDirectory(), + resolutionHost.getCanonicalFileName, + resolutionHost.getCompilationSettings(), + moduleResolutionCache?.getPackageJsonInfoCache(), + ); + typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( + getCurrentDirectory(), + resolutionHost.getCanonicalFileName, + resolutionHost.getCompilationSettings(), + moduleResolutionCache.getPackageJsonInfoCache(), + moduleResolutionCache.optionsToRedirectsKey, + ); + } + function getResolvedModule(resolution: CachedResolvedModuleWithFailedLookupLocations) { return resolution.resolvedModule; } @@ -627,10 +637,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD affectingPathChecks = undefined; affectingPathChecksForFile = undefined; allModuleAndTypeResolutionsAreInvalidated = false; - moduleResolutionCache.clear(); - typeReferenceDirectiveResolutionCache.clear(); - moduleResolutionCache.update(resolutionHost.getCompilationSettings()); - typeReferenceDirectiveResolutionCache.update(resolutionHost.getCompilationSettings()); + createResolutionCaches(); libraryResolutionCache.clear(); impliedFormatPackageJsons.clear(); resolvedLibraries.clear(); @@ -639,10 +646,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD function onChangesAffectModuleResolution() { allModuleAndTypeResolutionsAreInvalidated = true; - moduleResolutionCache.clearAllExceptPackageJsonInfoCache(); - typeReferenceDirectiveResolutionCache.clearAllExceptPackageJsonInfoCache(); - moduleResolutionCache.update(resolutionHost.getCompilationSettings()); - typeReferenceDirectiveResolutionCache.update(resolutionHost.getCompilationSettings()); + createResolutionCaches(); } function startRecordingFilesWithChangedResolutions() { @@ -686,8 +690,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD } function startCachingPerDirectoryResolution() { - moduleResolutionCache.clearAllExceptPackageJsonInfoCache(); - typeReferenceDirectiveResolutionCache.clearAllExceptPackageJsonInfoCache(); + // Not all resolutions are re-resolved so wont be in the cache. -- Hmm, + createResolutionCaches(); libraryResolutionCache.clearAllExceptPackageJsonInfoCache(); // perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update // (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution) diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 8512e52f07f..e2696425800 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -393,8 +393,8 @@ interface SolutionBuilderState extends WatchFactory; readonly compilerHost: CompilerHost & ReadBuildProgramHost; - readonly moduleResolutionCache: ModuleResolutionCache | undefined; - readonly typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined; + moduleResolutionCache: ModuleResolutionCache | undefined; + typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined; readonly libraryResolutionCache: ModuleResolutionCache | undefined; // Mutable state @@ -449,10 +449,10 @@ function createSolutionBuilderState(watch: boolean, ho options, containingSourceFile, host, - moduleResolutionCache, + state.moduleResolutionCache, createModuleResolutionLoader, ); - compilerHost.getModuleResolutionCache = () => moduleResolutionCache; + compilerHost.getModuleResolutionCache = () => state.moduleResolutionCache; } if (!compilerHost.resolveTypeReferenceDirectiveReferences && !compilerHost.resolveTypeReferenceDirectives) { typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( @@ -470,10 +470,14 @@ function createSolutionBuilderState(watch: boolean, ho options, containingSourceFile, host, - typeReferenceDirectiveResolutionCache, + state.typeReferenceDirectiveResolutionCache, createTypeReferenceResolutionLoader, ); } + compilerHost.getResolutionStorageCaches = () => ({ + moduleResolutionCache: state.moduleResolutionCache, + typeReferenceDirectiveResolutionCache: state.typeReferenceDirectiveResolutionCache, + }); let libraryResolutionCache: ModuleResolutionCache | undefined; if (!compilerHost.resolveLibrary) { libraryResolutionCache = createModuleResolutionCache(compilerHost.getCurrentDirectory(), compilerHost.getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache()); @@ -784,8 +788,24 @@ function disableCache(state: SolutionBuilderState) compilerHost.getSourceFile = cache.originalGetSourceFile; state.readFileWithCache = cache.originalReadFileWithCache; extendedConfigCache.clear(); - moduleResolutionCache?.clear(); - typeReferenceDirectiveResolutionCache?.clear(); + if (moduleResolutionCache) { + moduleResolutionCache.getPackageJsonInfoCache().clear(); + state.moduleResolutionCache = createModuleResolutionCache( + compilerHost.getCurrentDirectory(), + compilerHost.getCanonicalFileName, + /*options*/ undefined, + moduleResolutionCache.getPackageJsonInfoCache(), + ); + } + if (typeReferenceDirectiveResolutionCache) { + state.typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( + compilerHost.getCurrentDirectory(), + compilerHost.getCanonicalFileName, + /*options*/ undefined, + moduleResolutionCache?.getPackageJsonInfoCache(), + moduleResolutionCache?.optionsToRedirectsKey, + ); + } libraryResolutionCache?.clear(); state.cache = undefined; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1f796f8b2a0..d8f76638d84 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -17,6 +17,7 @@ import { ProgramBuildInfo, SymlinkCache, ThisContainer, + TypeReferenceDirectiveResolutionCache, } from "./_namespaces/ts"; // branded string type used to store absolute, normalized and canonicalized paths @@ -4623,6 +4624,12 @@ export interface LibResolution; /** @internal */ @@ -7771,6 +7780,8 @@ export interface CompilerHost extends ModuleResolutionHost { reusedNames: readonly T[] | undefined, ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; /** @internal */ + getResolutionStorageCaches?(): ResolutionStorageCaches | undefined; + /** @internal */ resolveLibrary?( libraryName: string, resolveFrom: string, diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 135c8bdc538..413f10c79f4 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -535,6 +535,12 @@ export function createWatchProgram(host: WatchCompiler compilerHost.getModuleResolutionCache = host.resolveModuleNameLiterals || host.resolveModuleNames ? maybeBind(host, host.getModuleResolutionCache) : (() => resolutionCache.getModuleResolutionCache()); + compilerHost.getResolutionStorageCaches = () => ({ + moduleResolutionCache: !host.resolveModuleNameLiterals && !host.resolveModuleNames ? + resolutionCache.getModuleResolutionCache() : undefined, + typeReferenceDirectiveResolutionCache: !host.resolveTypeReferenceDirectiveReferences && !host.resolveTypeReferenceDirectives ? + resolutionCache.getTypeReferenceDirectiveResolutionCache() : undefined, + }); const userProvidedResolution = !!host.resolveModuleNameLiterals || !!host.resolveTypeReferenceDirectiveReferences || !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; // All resolutions are invalid if user provided resolutions and didnt supply hasInvalidatedResolutions diff --git a/src/server/project.ts b/src/server/project.ts index a73933227b4..91c44b3685d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -102,6 +102,7 @@ import { removeFileExtension, ResolutionCache, resolutionExtensionIsTSOrJson, + ResolutionStorageCaches, ResolvedModuleWithFailedLookupLocations, ResolvedProjectReference, ResolvedTypeReferenceDirectiveWithFailedLookupLocations, @@ -730,6 +731,14 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.resolutionCache.getModuleResolutionCache(); } + /** @internal */ + getResolutionStorageCaches(): ResolutionStorageCaches { + return { + moduleResolutionCache: this.resolutionCache.getModuleResolutionCache(), + typeReferenceDirectiveResolutionCache: this.resolutionCache.getTypeReferenceDirectiveResolutionCache(), + }; + } + /** @internal */ resolveTypeReferenceDirectiveReferences(typeDirectiveReferences: readonly T[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { return this.resolutionCache.resolveTypeReferenceDirectiveReferences( @@ -2666,7 +2675,7 @@ export class AutoImportProviderProject extends Project { } /** @internal */ - override getModuleResolutionCache() { + override getModuleResolutionCache() { // This will be wrong when program has its own module resolutionCache? return this.hostProject.getCurrentProgram()?.getModuleResolutionCache(); } } diff --git a/src/services/services.ts b/src/services/services.ts index 56af0f72d70..c699181a3dc 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1686,6 +1686,7 @@ export function createLanguageService( trace: maybeBind(host, host.trace), resolveModuleNames: maybeBind(host, host.resolveModuleNames), getModuleResolutionCache: maybeBind(host, host.getModuleResolutionCache), + getResolutionStorageCaches: maybeBind(host, host.getResolutionStorageCaches), createHash: maybeBind(host, host.createHash), resolveTypeReferenceDirectives: maybeBind(host, host.resolveTypeReferenceDirectives), resolveModuleNameLiterals: maybeBind(host, host.resolveModuleNameLiterals), diff --git a/src/services/types.ts b/src/services/types.ts index c1d92f808dc..c185d981718 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -24,6 +24,7 @@ import { Program, ProjectReference, ResolutionMode, + ResolutionStorageCaches, ResolvedModule, ResolvedModuleWithFailedLookupLocations, ResolvedProjectReference, @@ -398,6 +399,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR /** @internal */ getSymlinkCache?(files?: readonly SourceFile[]): SymlinkCache; /* Lets the Program from a AutoImportProviderProject use its host project's ModuleResolutionCache */ /** @internal */ getModuleResolutionCache?(): ModuleResolutionCache | undefined; + /** @internal */ getResolutionStorageCaches?(): ResolutionStorageCaches | undefined; /* * Required for full import and type reference completions.