Skip to content

Commit aed1e9b

Browse files
committed
Replace fileExists and directoryExists to prefer fileNames instead of path
1 parent 2adcf26 commit aed1e9b

45 files changed

Lines changed: 408 additions & 353 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/compiler/moduleNameResolver.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
append,
33
appendIfUnique,
4-
arrayFrom,
54
arrayIsEqualTo,
65
changeAnyExtension,
76
CharacterCodes,
@@ -901,11 +900,19 @@ export interface NonRelativeModuleNameResolutionCache extends NonRelativeNameRes
901900
getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache;
902901
}
903902

903+
/** @internal */
904+
export interface MissingPackageJsonInfo {
905+
packageDirectory: string;
906+
contents: boolean;
907+
}
908+
909+
/** @internal */
910+
export type PackageJsonInfoCacheEntry = PackageJsonInfo | MissingPackageJsonInfo;
911+
904912
export interface PackageJsonInfoCache {
905-
/** @internal */ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfo | boolean | undefined;
906-
/** @internal */ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean): void;
907-
/** @internal */ entries(): [Path, PackageJsonInfo | boolean][];
908-
/** @internal */ getInternalMap(): Map<Path, PackageJsonInfo | boolean> | undefined;
913+
/** @internal */ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfoCacheEntry | undefined;
914+
/** @internal */ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfoCacheEntry): void;
915+
/** @internal */ getInternalMap(): Map<Path, PackageJsonInfoCacheEntry> | undefined;
909916
clear(): void;
910917
/** @internal */ isReadonly?: boolean;
911918
}
@@ -1021,21 +1028,17 @@ export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | und
10211028
}
10221029

10231030
function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): PackageJsonInfoCache {
1024-
let cache: Map<Path, PackageJsonInfo | boolean> | undefined;
1025-
return { getPackageJsonInfo, setPackageJsonInfo, clear, entries, getInternalMap };
1031+
let cache: Map<Path, PackageJsonInfoCacheEntry> | undefined;
1032+
return { getPackageJsonInfo, setPackageJsonInfo, clear, getInternalMap };
10261033
function getPackageJsonInfo(packageJsonPath: string) {
10271034
return cache?.get(toPath(packageJsonPath, currentDirectory, getCanonicalFileName));
10281035
}
1029-
function setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfo | boolean) {
1036+
function setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfoCacheEntry) {
10301037
(cache ||= new Map()).set(toPath(packageJsonPath, currentDirectory, getCanonicalFileName), info);
10311038
}
10321039
function clear() {
10331040
cache = undefined;
10341041
}
1035-
function entries() {
1036-
const iter = cache?.entries();
1037-
return iter ? arrayFrom(iter) : [];
1038-
}
10391042
function getInternalMap() {
10401043
return cache;
10411044
}
@@ -2391,15 +2394,15 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:
23912394

23922395
const existing = state.packageJsonInfoCache?.getPackageJsonInfo(packageJsonPath);
23932396
if (existing !== undefined) {
2394-
if (typeof existing !== "boolean") {
2397+
if (typeof existing.contents !== "boolean") {
23952398
if (traceEnabled) trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath);
23962399
state.affectingLocations?.push(packageJsonPath);
23972400
return existing.packageDirectory === packageDirectory ?
23982401
existing :
23992402
{ packageDirectory, contents: existing.contents };
24002403
}
24012404
else {
2402-
if (existing && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath);
2405+
if (existing.contents && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath);
24032406
state.failedLookupLocations?.push(packageJsonPath);
24042407
return undefined;
24052408
}
@@ -2419,7 +2422,7 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:
24192422
if (directoryExists && traceEnabled) {
24202423
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
24212424
}
2422-
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, directoryExists);
2425+
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, { packageDirectory, contents: directoryExists });
24232426
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
24242427
state.failedLookupLocations?.push(packageJsonPath);
24252428
}

src/compiler/moduleSpecifiers.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ import {
8484
NodeFlags,
8585
NodeModulePathParts,
8686
normalizePath,
87-
Path,
8887
pathContainsNodeModules,
8988
pathIsBareSpecifier,
9089
pathIsRelative,
@@ -200,7 +199,7 @@ function getPreferences(
200199
export function updateModuleSpecifier(
201200
compilerOptions: CompilerOptions,
202201
importingSourceFile: SourceFile,
203-
importingSourceFileName: Path,
202+
importingSourceFileName: string,
204203
toFileName: string,
205204
host: ModuleSpecifierResolutionHost,
206205
oldImportSpecifier: string,
@@ -221,7 +220,7 @@ export function updateModuleSpecifier(
221220
export function getModuleSpecifier(
222221
compilerOptions: CompilerOptions,
223222
importingSourceFile: SourceFile,
224-
importingSourceFileName: Path,
223+
importingSourceFileName: string,
225224
toFileName: string,
226225
host: ModuleSpecifierResolutionHost,
227226
options: ModuleSpecifierOptions = {},
@@ -238,23 +237,23 @@ export function getNodeModulesPackageName(
238237
preferences: UserPreferences,
239238
options: ModuleSpecifierOptions = {},
240239
): string | undefined {
241-
const info = getInfo(importingSourceFile.path, host);
242-
const modulePaths = getAllModulePaths(importingSourceFile.path, nodeModulesFileName, host, preferences, options);
240+
const info = getInfo(importingSourceFile.fileName, host);
241+
const modulePaths = getAllModulePaths(info, nodeModulesFileName, host, preferences, options);
243242
return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, preferences, /*packageNameOnly*/ true, options.overrideImportMode));
244243
}
245244

246245
function getModuleSpecifierWorker(
247246
compilerOptions: CompilerOptions,
248247
importingSourceFile: SourceFile,
249-
importingSourceFileName: Path,
248+
importingSourceFileName: string,
250249
toFileName: string,
251250
host: ModuleSpecifierResolutionHost,
252251
preferences: Preferences,
253252
userPreferences: UserPreferences,
254253
options: ModuleSpecifierOptions = {},
255254
): string {
256255
const info = getInfo(importingSourceFileName, host);
257-
const modulePaths = getAllModulePaths(importingSourceFileName, toFileName, host, userPreferences, options);
256+
const modulePaths = getAllModulePaths(info, toFileName, host, userPreferences, options);
258257
return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode)) ||
259258
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences);
260259
}
@@ -346,7 +345,7 @@ export function getModuleSpecifiersWithCacheInfo(
346345
if (!moduleSourceFile) return { moduleSpecifiers: emptyArray, computedWithoutCache };
347346

348347
computedWithoutCache = true;
349-
modulePaths ||= getAllModulePathsWorker(importingSourceFile.path, moduleSourceFile.originalFileName, host);
348+
modulePaths ||= getAllModulePathsWorker(getInfo(importingSourceFile.fileName, host), moduleSourceFile.originalFileName, host);
350349
const result = computeModuleSpecifiers(
351350
modulePaths,
352351
compilerOptions,
@@ -369,7 +368,7 @@ function computeModuleSpecifiers(
369368
options: ModuleSpecifierOptions = {},
370369
forAutoImport: boolean,
371370
): readonly string[] {
372-
const info = getInfo(importingSourceFile.path, host);
371+
const info = getInfo(importingSourceFile.fileName, host);
373372
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
374373
const existingSpecifier = forEach(modulePaths, modulePath =>
375374
forEach(
@@ -455,14 +454,21 @@ function computeModuleSpecifiers(
455454

456455
interface Info {
457456
readonly getCanonicalFileName: GetCanonicalFileName;
458-
readonly importingSourceFileName: Path;
459-
readonly sourceDirectory: Path;
457+
readonly importingSourceFileName: string;
458+
readonly sourceDirectory: string;
459+
readonly canonicalSourceDirectory: string;
460460
}
461461
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
462-
function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
462+
function getInfo(importingSourceFileName: string, host: ModuleSpecifierResolutionHost): Info {
463+
importingSourceFileName = getNormalizedAbsolutePath(importingSourceFileName, host.getCurrentDirectory());
463464
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
464465
const sourceDirectory = getDirectoryPath(importingSourceFileName);
465-
return { getCanonicalFileName, importingSourceFileName, sourceDirectory };
466+
return {
467+
getCanonicalFileName,
468+
importingSourceFileName,
469+
sourceDirectory,
470+
canonicalSourceDirectory: getCanonicalFileName(sourceDirectory),
471+
};
466472
}
467473

468474
function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: ResolutionMode, preferences: Preferences): string;
@@ -473,7 +479,7 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
473479
return undefined;
474480
}
475481

476-
const { sourceDirectory, getCanonicalFileName } = info;
482+
const { sourceDirectory, canonicalSourceDirectory, getCanonicalFileName } = info;
477483
const allowedEndings = getAllowedEndingsInPrefererredOrder(importMode);
478484
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, allowedEndings, compilerOptions) ||
479485
processEnding(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), allowedEndings, compilerOptions);
@@ -506,7 +512,7 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
506512
toPath(getDirectoryPath(compilerOptions.configFilePath), host.getCurrentDirectory(), info.getCanonicalFileName) :
507513
info.getCanonicalFileName(host.getCurrentDirectory());
508514
const modulePath = toPath(moduleFileName, projectDirectory, getCanonicalFileName);
509-
const sourceIsInternal = startsWith(sourceDirectory, projectDirectory);
515+
const sourceIsInternal = startsWith(canonicalSourceDirectory, projectDirectory);
510516
const targetIsInternal = startsWith(modulePath, projectDirectory);
511517
if (sourceIsInternal && !targetIsInternal || !sourceIsInternal && targetIsInternal) {
512518
// 1. The import path crosses the boundary of the tsconfig.json-containing directory.
@@ -623,37 +629,37 @@ export function forEachFileNameOfModule<T>(
623629
* Symlinks will be returned first so they are preferred over the real path.
624630
*/
625631
function getAllModulePaths(
626-
importingFilePath: Path,
632+
info: Info,
627633
importedFileName: string,
628634
host: ModuleSpecifierResolutionHost,
629635
preferences: UserPreferences,
630636
options: ModuleSpecifierOptions = {},
631637
) {
638+
const importingFilePath = toPath(info.importingSourceFileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host));
632639
const importedFilePath = toPath(importedFileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host));
633640
const cache = host.getModuleSpecifierCache?.();
634641
if (cache) {
635642
const cached = cache.get(importingFilePath, importedFilePath, preferences, options);
636643
if (cached?.modulePaths) return cached.modulePaths;
637644
}
638-
const modulePaths = getAllModulePathsWorker(importingFilePath, importedFileName, host);
645+
const modulePaths = getAllModulePathsWorker(info, importedFileName, host);
639646
if (cache) {
640647
cache.setModulePaths(importingFilePath, importedFilePath, preferences, options, modulePaths);
641648
}
642649
return modulePaths;
643650
}
644651

645-
function getAllModulePathsWorker(importingFileName: Path, importedFileName: string, host: ModuleSpecifierResolutionHost): readonly ModulePath[] {
646-
const getCanonicalFileName = hostGetCanonicalFileName(host);
652+
function getAllModulePathsWorker(info: Info, importedFileName: string, host: ModuleSpecifierResolutionHost): readonly ModulePath[] {
647653
const allFileNames = new Map<string, { path: string; isRedirect: boolean; isInNodeModules: boolean; }>();
648654
let importedFileFromNodeModules = false;
649655
forEachFileNameOfModule(
650-
importingFileName,
656+
info.importingSourceFileName,
651657
importedFileName,
652658
host,
653659
/*preferSymlinks*/ true,
654660
(path, isRedirect) => {
655661
const isInNodeModules = pathContainsNodeModules(path);
656-
allFileNames.set(path, { path: getCanonicalFileName(path), isRedirect, isInNodeModules });
662+
allFileNames.set(path, { path: info.getCanonicalFileName(path), isRedirect, isInNodeModules });
657663
importedFileFromNodeModules = importedFileFromNodeModules || isInNodeModules;
658664
// don't return value, so we collect everything
659665
},
@@ -662,7 +668,7 @@ function getAllModulePathsWorker(importingFileName: Path, importedFileName: stri
662668
// Sort by paths closest to importing file Name directory
663669
const sortedPaths: ModulePath[] = [];
664670
for (
665-
let directory = getDirectoryPath(importingFileName);
671+
let directory = info.canonicalSourceDirectory;
666672
allFileNames.size !== 0;
667673
) {
668674
const directoryStart = ensureTrailingDirectorySeparator(directory);
@@ -684,7 +690,10 @@ function getAllModulePathsWorker(importingFileName: Path, importedFileName: stri
684690
directory = newDirectory;
685691
}
686692
if (allFileNames.size) {
687-
const remainingPaths = arrayFrom(allFileNames.values());
693+
const remainingPaths = arrayFrom(
694+
allFileNames.entries(),
695+
([fileName, { isRedirect, isInNodeModules }]): ModulePath => ({ path: fileName, isRedirect, isInNodeModules }),
696+
);
688697
if (remainingPaths.length > 1) remainingPaths.sort(comparePathsByRedirectAndNumberOfDirectorySeparators);
689698
sortedPaths.push(...remainingPaths);
690699
}
@@ -914,7 +923,7 @@ function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileNam
914923
return processEnding(shortest, allowedEndings, compilerOptions);
915924
}
916925

917-
function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, sourceDirectory }: Info, importingSourceFile: SourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ResolutionMode): string | undefined {
926+
function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, canonicalSourceDirectory }: Info, importingSourceFile: SourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ResolutionMode): string | undefined {
918927
if (!host.fileExists || !host.readFile) {
919928
return undefined;
920929
}
@@ -967,7 +976,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
967976
// Get a path that's relative to node_modules or the importing file's path
968977
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
969978
const pathToTopLevelNodeModules = getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex));
970-
if (!(startsWith(sourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) {
979+
if (!(startsWith(canonicalSourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) {
971980
return undefined;
972981
}
973982

@@ -983,7 +992,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
983992
let moduleFileToTry = path;
984993
let maybeBlockedByTypesVersions = false;
985994
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
986-
if (typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
995+
if (typeof cachedPackageJson?.contents === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
987996
const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!);
988997
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
989998
if (getResolvePackageJsonExports(options)) {

0 commit comments

Comments
 (0)