diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 090abfa978e7d..c8b32fa6010d2 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -421,6 +421,7 @@ namespace ts { */ export interface ModuleResolutionCache extends NonRelativeModuleNameResolutionCache { getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): Map; + /*@internal*/ directoryToModuleNameMap: CacheWithRedirects>; } /** @@ -429,6 +430,7 @@ namespace ts { */ export interface NonRelativeModuleNameResolutionCache { getOrCreateCacheForModuleName(nonRelativeModuleName: string, redirectedReference?: ResolvedProjectReference): PerModuleNameCache; + /*@internal*/ moduleNameToDirectoryMap: CacheWithRedirects; } export interface PerModuleNameCache { @@ -445,25 +447,38 @@ namespace ts { ); } + /*@internal*/ export interface CacheWithRedirects { ownMap: Map; redirectsMap: Map>; getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map; clear(): void; + setOwnOptions(newOptions: CompilerOptions): void; + setOwnMap(newOwnMap: Map): void; } /*@internal*/ export function createCacheWithRedirects(options?: CompilerOptions): CacheWithRedirects { - const ownMap: Map = createMap(); + let ownMap: Map = createMap(); const redirectsMap: Map> = createMap(); return { ownMap, redirectsMap, getOrCreateMapOfCacheRedirects, - clear + clear, + setOwnOptions, + setOwnMap }; + function setOwnOptions(newOptions: CompilerOptions) { + options = newOptions; + } + + function setOwnMap(newOwnMap: Map) { + ownMap = newOwnMap; + } + function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined) { if (!redirectedReference) { return ownMap; @@ -491,7 +506,7 @@ namespace ts { currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): ModuleResolutionCache { - return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName }; + return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName, directoryToModuleNameMap, moduleNameToDirectoryMap }; function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) { const path = toPath(directoryName, currentDirectory, getCanonicalFileName); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c6c592b0e7381..e8b2ba39b13a7 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -528,7 +528,8 @@ namespace ts { } } - function loadWithLocalCache(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] { + /* @internal */ + export function loadWithLocalCache(names: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, loader: (name: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => T): T[] { if (names.length === 0) { return []; } diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index f60641fe0cfe7..8bc66e95edc45 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -400,6 +400,10 @@ namespace ts { const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions); setGetSourceFileAsHashVersioned(compilerHost, host); + compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames); + compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); + let moduleResolutionCache = !compilerHost.resolveModuleNames ? createModuleResolutionCache(currentDirectory, getCanonicalFileName) : undefined; + const buildInfoChecked = createFileMap(toPath); // Watch state @@ -1097,6 +1101,30 @@ namespace ts { // TODO: handle resolve module name to cache result in project reference redirect projectCompilerOptions = configFile.options; + // Update module resolution cache if needed + if (moduleResolutionCache) { + const projPath = toPath(proj); + if (moduleResolutionCache.directoryToModuleNameMap.redirectsMap.size === 0) { + // The own map will be for projectCompilerOptions + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size === 0); + moduleResolutionCache.directoryToModuleNameMap.redirectsMap.set(projPath, moduleResolutionCache.directoryToModuleNameMap.ownMap); + moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.set(projPath, moduleResolutionCache.moduleNameToDirectoryMap.ownMap); + } + else { + // Set correct own map + Debug.assert(moduleResolutionCache.moduleNameToDirectoryMap.redirectsMap.size > 0); + + const ref: ResolvedProjectReference = { + sourceFile: projectCompilerOptions.configFile!, + commandLine: configFile + }; + moduleResolutionCache.directoryToModuleNameMap.setOwnMap(moduleResolutionCache.directoryToModuleNameMap.getOrCreateMapOfCacheRedirects(ref)); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnMap(moduleResolutionCache.moduleNameToDirectoryMap.getOrCreateMapOfCacheRedirects(ref)); + } + moduleResolutionCache.directoryToModuleNameMap.setOwnOptions(projectCompilerOptions); + moduleResolutionCache.moduleNameToDirectoryMap.setOwnOptions(projectCompilerOptions); + } + const program = host.createProgram( configFile.fileNames, configFile.options, @@ -1368,6 +1396,13 @@ namespace ts { readFileWithCache = newReadFileWithCache; compilerHost.getSourceFile = getSourceFileWithCache!; + const originalResolveModuleNames = compilerHost.resolveModuleNames; + if (!compilerHost.resolveModuleNames) { + const loader = (moduleName: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveModuleName(moduleName, containingFile, projectCompilerOptions, compilerHost, moduleResolutionCache, redirectedReference).resolvedModule!; + compilerHost.resolveModuleNames = (moduleNames, containingFile, _reusedNames, redirectedReference) => + loadWithLocalCache(Debug.assertEachDefined(moduleNames), containingFile, redirectedReference, loader); + } + const graph = getGlobalDependencyGraph(); reportBuildQueue(graph); let anyFailed = false; @@ -1428,6 +1463,8 @@ namespace ts { host.writeFile = originalWriteFile; compilerHost.getSourceFile = savedGetSourceFile; readFileWithCache = savedReadFileWithCache; + compilerHost.resolveModuleNames = originalResolveModuleNames; + moduleResolutionCache = undefined; return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success; }