8000 Handle project reference redirects for the module and type reference … · microsoft/TypeScript@0132dc0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0132dc0

Browse files
committed
Handle project reference redirects for the module and type reference resolutions
1 parent 23cfc79 commit 0132dc0

24 files changed

+27462
-91
lines changed

src/compiler/builder.ts

Lines changed: 129 additions & 42 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,6 +2801,9 @@ export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAb
28012801
if (result.configFilePath) {
28022802
result.configFilePath = toAbsolutePath(result.configFilePath);
28032803
}
2804+
if (result.pathsBasePath) {
2805+
result.pathsBasePath = toAbsolutePath(result.pathsBasePath);
2806+
}
28042807
return result;
28052808
}
28062809

src/compiler/moduleNameResolver.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,10 @@ export interface ModeAwareCache<T> {
705705
* This assumes that any module id will have the same resolution for sibling files located in the same folder.
706706
*/
707707
export interface PerDirectoryResolutionCache<T> {
708+
/** @internal*/ perDirectoryMap: CacheWithRedirects<Path, ModeAwareCache<T>>;
708709
getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined;
709710
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache<T>;
711+
/** @internal*/ getOrCreateCacheForDirectoryWithPath(directory: Path, redirectedReference: ResolvedProjectReference | undefined): ModeAwareCache<T>;
710712
clear(): void;
711713
/**
712714
* Updates with the current compilerOptions the cache will operate with.
@@ -780,13 +782,18 @@ export function getKeyForCompilerOptions(options: CompilerOptions, affectingOpti
780782
export interface CacheWithRedirects<K, V> {
781783
getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V> | undefined;
782784
getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V>;
785+
getOrCreateMap(redirectOptions: CompilerOptions, create: true): Map<K, V>;
786+
getOrCreateMap(redirectOptions: CompilerOptions, create: false): Map<K, V> | undefined;
783787
update(newOptions: CompilerOptions): void;
784788
clear(): void;
789+
getOwnMap(): Map<K, V>;
790+
redirectsMap: Map<CompilerOptions, Map<K, V>>;
785791
}
786792

793+
/** @internal */
794+
export type RedirectsCacheKey = string & { __compilerOptionsKey: any; };
787795
/** @internal */
788796
export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | undefined): CacheWithRedirects<K, V> {
789-
type RedirectsCacheKey = string & { __compilerOptionsKey: any; };
790797
const redirectsMap = new Map<CompilerOptions, Map<K, V>>();
791798
const optionsToRedirectsKey = new Map<CompilerOptions, RedirectsCacheKey>();
792799
const redirectsKeyToMap = new Map<RedirectsCacheKey, Map<K, V>>();
@@ -795,8 +802,11 @@ export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | und
795802
return {
796803
getMapOfCacheRedirects,
797804
getOrCreateMapOfCacheRedirects,
805+
getOrCreateMap,
798806
update,
799807
clear,
808+
getOwnMap: () => ownMap,
809+
redirectsMap,
800810
};
801811

802812
function getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map<K, V> | undefined {
@@ -891,31 +901,40 @@ function getOrCreateCache<K, V>(cacheWithRedirects: CacheWithRedirects<K, V>, re
891901
return result;
892902
}
893903

894-
function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, options: CompilerOptions | undefined): PerDirectoryResolutionCache<T> {
895-
const directoryToModuleNameMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options);
904+
/** @internal */
905+
export function createPerDirectoryResolutionCache<T>(currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, options: CompilerOptions | undefined): PerDirectoryResolutionCache<T> {
906+
const perDirectoryMap = createCacheWithRedirects<Path, ModeAwareCache<T>>(options);
896907
return {
908+
perDirectoryMap,
897909
getFromDirectoryCache,
898910
getOrCreateCacheForDirectory,
911+
getOrCreateCacheForDirectoryWithPath,
899912
clear,
900913
update,
901914
};
902915

903916
function clear() {
904-
directoryToModuleNameMap.clear();
917+
perDirectoryMap.clear();
905918
}
906919

907920
function update(options: CompilerOptions) {
908-
directoryToModuleNameMap.update(options);
921+
perDirectoryMap.update(options);
909922
}
910923

911924
function getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference) {
912-
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
913-
return getOrCreateCache(directoryToModuleNameMap, redirectedReference, path, () => createModeAwareCache());
925+
return getOrCreateCacheForDirectoryWithPath(toPath(directoryName, currentDirectory, getCanonicalFileName), redirectedReference);
926+
}
927+
928+
function getOrCreateCacheForDirectoryWithPath(directory: Path, redirectedReference: ResolvedProjectReference | undefined) {
929+
return getOrCreateCache(perDirectoryMap, redirectedReference, directory, () => createModeAwareCache());
914930
}
915931

916932
function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) {
917-
const path = toPath(directoryName, currentDirectory, getCanonicalFileName);
918-
return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode);
933+
return getFromDirectoryCacheWithPath(name, mode, toPath(directoryName, currentDirectory, getCanonicalFileName), redirectedReference);
934+
}
935+
936+
function getFromDirectoryCacheWithPath(name: string, mode: ResolutionMode, directory: Path, redirectedReference: ResolvedProjectReference | undefined) {
937+
return perDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(directory)?.get(name, mode);
919938
}
920939
}
921940

src/compiler/program.ts

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
15771577
let oldProgram = typeof oldProgramOrOldBuildInfoProgramConstructor === "object" ? oldProgramOrOldBuildInfoProgramConstructor : undefined;
15781578
let oldBuildInfoProgram: OldBuildInfoProgram | undefined;
15791579
if (!oldProgram && typeof oldProgramOrOldBuildInfoProgramConstructor === "function") {
1580-
oldBuildInfoProgram = oldProgramOrOldBuildInfoProgramConstructor(host);
1580+
oldBuildInfoProgram = oldProgramOrOldBuildInfoProgramConstructor({
1581+
fileExists: fileName => host.fileExists(fileName),
1582+
getCompilerOptions: () => options,
1583+
});
15811584
}
15821585

15831586
// Map from a stringified PackageId to the source file with that id.
@@ -1810,6 +1813,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
18101813
getProjectReferenceRedirect,
18111814
getResolvedProjectReferenceToRedirect,
18121815
getResolvedProjectReferenceByPath,
1816+
getRedirectReferenceForResolution,
18131817
forEachResolvedProjectReference,
18141818
isSourceOfProjectReferenceRedirect,
18151819
emitBuildInfo,
@@ -1873,27 +1877,37 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
18731877
if (fromCache) addResolutionDiagnostics(fromCache);
18741878
}
18751879

1876-
function resolveModuleNamesWorker(moduleNames: readonly StringLiteralLike[], containingFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] {
1880+
function resolveModuleNamesWorker(
1881+
moduleNames: readonly StringLiteralLike[],
1882+
containingFile: SourceFile,
1883+
reusedNames: readonly StringLiteralLike[] | undefined,
1884+
redirectedReference: ResolvedProjectReference | false | undefined,
1885+
): readonly ResolvedModuleWithFailedLookupLocations[] {
18771886
if (!moduleNames.length) return emptyArray;
18781887
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1879-
const redirectedReference = getRedirectReferenceForResolution(containingFile);
1888+
if (redirectedReference === undefined) redirectedReference = getRedirectReferenceForResolution(containingFile);
18801889
tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
18811890
performance.mark("beforeResolveModule");
1882-
const result = actualResolveModuleNamesWorker(moduleNames, containingFileName, redirectedReference, options, containingFile, reusedNames);
1891+
const result = actualResolveModuleNamesWorker(moduleNames, containingFileName, redirectedReference || undefined, options, containingFile, reusedNames);
18831892
performance.mark("afterResolveModule");
18841893
performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
18851894
tracing?.pop();
18861895
return result;
18871896
}
18881897

1889-
function resolveTypeReferenceDirectiveNamesWorker<T extends FileReference | string>(typeDirectiveNames: T[], containingFile: string | SourceFile, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] {
1898+
function resolveTypeReferenceDirectiveNamesWorker<T extends FileReference | string>(
1899+
typeDirectiveNames: T[],
1900+
containingFile: string | SourceFile,
1901+
reusedNames: readonly T[] | undefined,
1902+
redirectedReference: ResolvedProjectReference | false | undefined,
1903+
): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] {
18901904
if (!typeDirectiveNames.length) return [];
18911905
const containingSourceFile = !isString(containingFile) ? containingFile : undefined;
18921906
const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
1893-
const redirectedReference = containingSourceFile && getRedirectReferenceForResolution(containingSourceFile);
1907+
if (redirectedReference === undefined && containingSourceFile) redirectedReference = getRedirectReferenceForResolution(containingSourceFile);
18941908
tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
18951909
performance.mark("beforeResolveTypeReference");
1896-
const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, options, containingSourceFile, reusedNames);
1910+
const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference || undefined, options, containingSourceFile, reusedNames);
18971911
performance.mark("afterResolveTypeReference");
18981912
performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference");
18991913
tracing?.pop();
@@ -1981,7 +1995,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
19811995
if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
19821996
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
19831997
// the best we can do is fallback to the default logic.
1984-
return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
1998+
return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined, /*redirectedReference*/ undefined);
19851999
}
19862000

19872001
const oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
@@ -2021,6 +2035,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
20212035
let reusedNames: StringLiteralLike[] | undefined;
20222036
/** A transient placeholder used to mark predicted resolution in the result list. */
20232037
const predictedToResolveToAmbientModuleMarker: ResolvedModuleWithFailedLookupLocations = emptyResolution;
2038+
let redirectedReference: ResolvedProjectReference | false | undefined;
20242039

20252040
for (let i = 0; i < moduleNames.length; i++) {
20262041
const moduleName = moduleNames[i];
@@ -2029,7 +2044,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
20292044
const mode = getModeForUsageLocation(file, moduleName);
20302045
const oldResolution = !oldBuildInfoProgram ?
20312046
oldSourceFile?.resolvedModules?.get(moduleName.text, mode) :
2032-
oldBuildInfoProgram.getResolvedModule(moduleName.text, mode, getDirectoryPath(file.path));
2047+
oldBuildInfoProgram.getResolvedModule(
2048+
moduleName.text,
2049+
mode,
2050+
getDirectoryPath(file.path),
2051+
(redirectedReference === undefined ? (redirectedReference = getRedirectReferenceForResolution(file) || false) : redirectedReference) || undefined,
2052+
);
20332053
if (oldResolution?.resolvedModule) {
20342054
if (isTraceEnabled(options, host)) {
20352055
const fileLocation = getNormalizedAbsolutePath(file.originalFileName, currentDirectory);
@@ -2087,7 +2107,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
20872107
}
20882108

20892109
const resolutions = unknownModuleNames && unknownModuleNames.length
2090-
? resolveModuleNamesWorker(unknownModuleNames, file, reusedNames)
2110+
? resolveModuleNamesWorker(unknownModuleNames, file, reusedNames, redirectedReference)
20912111
: emptyArray;
20922112

20932113
// Combine results of resolutions and predicted results
@@ -2141,7 +2161,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
21412161
if (structureIsReused === StructureIsReused.Not) {
21422162
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
21432163
// the best we can do is fallback to the default logic.
2144-
return resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFile, /*resuedNames*/ undefined);
2164+
return resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFile, /*resuedNames*/ undefined, /*redirectedReference*/ undefined);
21452165
}
21462166

21472167
const oldSourceFile = !isString(containingFile) ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined;
@@ -2170,20 +2190,27 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
21702190
let result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] | undefined;
21712191
let reusedNames: T[] | undefined;
21722192
const containingSourceFile = !isString(containingFile) ? containingFile : undefined;
2193+
const inferredTypeFile = !isString(containingFile) ? undefined : containingFile;
21732194
const canReuseResolutions = oldBuildInfoProgram || (!isString(containingFile) ?
21742195
containingFile === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path) :
21752196
!hasInvalidatedResolutions(toPath(containingFile)));
2197+
let redirectedReference: ResolvedProjectReference | false | undefined;
21762198
for (let i = 0; i < typeDirectiveNames.length; i++) {
21772199
const entry = typeDirectiveNames[i];
21782200
if (canReuseResolutions) {
21792201
const typeDirectiveName = getTypeReferenceResolutionName(entry);
21802202
const mode = getModeForFileReference(entry, containingSourceFile?.impliedNodeFormat);
21812203
const oldResolution = !oldBuildInfoProgram ?
2182-
(!isString(containingFile) ? oldSourceFile?.resolvedTypeReferenceDirectiveNames : oldProgram?.getAutomaticTypeDirectiveResolutions())?.get(typeDirectiveName, mode) :
2183-
oldBuildInfoProgram.getResolvedTypeReferenceDirective(typeDirectiveName, mode, getDirectoryPath(!isString(containingFile) ? containingFile.path : toPath(containingFile)));
2204+
(containingSourceFile ? oldSourceFile?.resolvedTypeReferenceDirectiveNames : oldProgram?.getAutomaticTypeDirectiveResolutions())?.get(typeDirectiveName, mode) :
2205+
oldBuildInfoProgram.getResolvedTypeReferenceDirective(
2206+
typeDirectiveName,
2207+
mode,
2208+
getDirectoryPath(containingSourceFile ? containingSourceFile.path : toPath(inferredTypeFile!)),
2209+
containingSourceFile && (redirectedReference === undefined ? (redirectedReference = getRedirectReferenceForResolution(containingSourceFile) || false) : redirectedReference) || undefined,
2210+
);
21842211
if (oldResolution?.resolvedTypeReferenceDirective) {
21852212
if (isTraceEnabled(options, host)) {
2186-
const fileLocation = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
2213+
const fileLocation = containingSourceFile ? getNormalizedAbsolutePath(containingSourceFile.originalFileName, currentDirectory) : inferredTypeFile!;
21872214
if (!oldBuildInfoProgram) {
21882215
trace(host,
21892216
oldResolution.resolvedTypeReferenceDirective.packageId ?
@@ -2222,6 +2249,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
22222249
unknownTypeReferenceDirectiveNames,
22232250
containingFile,
22242251
reusedNames,
2252+
redirectedReference,
22252253
);
22262254

22272255
// Combine results of resolutions

src/compiler/resolutionCache.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
417417
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
418418
nonRelativeExternalModuleResolutions.forEach(watchFailedLookupLocationOfNonRelativeModuleResolutions);
419419
nonRelativeExternalModuleResolutions.clear();
420+
moduleResolutionCache.update(resolutionHost.getCompilationSettings());
421+
typeReferenceDirectiveResolutionCache.update(resolutionHost.getCompilationSettings());
420422
}
421423

422424
function finishCachingPerDirectoryResolution(newProgram: Program | undefined, oldProgram: Program | undefined) {

src/compiler/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4538,6 +4538,7 @@ export interface Program extends ScriptReferenceHost {
45384538
/** @internal */ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
45394539
/** @internal */ forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
45404540
/** @internal */ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
4541+
/** @internal */ getRedirectReferenceForResolution(file: SourceFile): ResolvedProjectReference | undefined;
45414542
/** @internal */ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
45424543
/** @internal */ getBuildInfo?(bundle: BundleBuildInfo | undefined, buildInfoPath: string): BuildInfo;
45434544
/** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
@@ -6972,13 +6973,14 @@ export interface CreateProgramOptions {
69726973
/** @internal */
69736974
export interface OldBuildInfoProgram {
69746975
getCompilerOptions(): CompilerOptions;
6975-
getResolvedModule(name: string, mode: ResolutionMode, dirPath: Path): ResolvedModuleWithFailedLookupLocations | undefined;
6976-
getResolvedTypeReferenceDirective(name: string, mode: ResolutionMode, dirPath: Path): ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined;
6976+
getResolvedModule(name: string, mode: ResolutionMode, dirPath: Path, redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations | undefined;
6977+
getResolvedTypeReferenceDirective(name: string, mode: ResolutionMode, dirPath: Path, redirectedReference: ResolvedProjectReference | undefined): ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined;
69776978
}
69786979

69796980
/** @internal */
69806981
export interface OldBuildInfoProgramHost {
69816982
fileExists(fileName: string): boolean;
6983+
getCompilerOptions(): CompilerOptions;
69826984
}
69836985

69846986
/** @internal */

0 commit comments

Comments
 (0)
0