Use realpathSync.native on case-insensitive file systems (#44966)
* Make getSourceOfProjectReferenceRedirect take a Path * Add useCaseSensitiveFileNames to ModuleResolutionHost ...so that path comparisons can use it during module resolution. * Re-enable realpathSync.native for case-insensitive file systems
This commit is contained in:
parent
983ddf5bb5
commit
7fc1cb4b36
|
@ -280,6 +280,11 @@ namespace ts {
|
|||
}
|
||||
const nodeModulesAtTypes = combinePaths("node_modules", "@types");
|
||||
|
||||
function arePathsEqual(path1: string, path2: string, host: ModuleResolutionHost): boolean {
|
||||
const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames;
|
||||
return comparePaths(path1, path2, !useCaseSensitiveFileNames) === Comparison.EqualTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.
|
||||
* This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
|
||||
|
@ -343,7 +348,7 @@ namespace ts {
|
|||
resolvedTypeReferenceDirective = {
|
||||
primary,
|
||||
resolvedFileName,
|
||||
originalPath: fileName === resolvedFileName ? undefined : fileName,
|
||||
originalPath: arePathsEqual(fileName, resolvedFileName, host) ? undefined : fileName,
|
||||
packageId,
|
||||
isExternalLibraryImport: pathContainsNodeModules(fileName),
|
||||
};
|
||||
|
@ -1122,7 +1127,7 @@ namespace ts {
|
|||
let resolvedValue = resolved.value;
|
||||
if (!compilerOptions.preserveSymlinks && resolvedValue && !resolvedValue.originalPath) {
|
||||
const path = realPath(resolvedValue.path, host, traceEnabled);
|
||||
const originalPath = path === resolvedValue.path ? undefined : resolvedValue.path;
|
||||
const originalPath = arePathsEqual(path, resolvedValue.path, host) ? undefined : resolvedValue.path;
|
||||
resolvedValue = { ...resolvedValue, path, originalPath };
|
||||
}
|
||||
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
|
||||
|
|
|
@ -1163,7 +1163,7 @@ namespace ts {
|
|||
|
||||
// The originalFileName could not be actual source file name if file found was d.ts from referecned project
|
||||
// So in this case try to look up if this is output from referenced project, if it is use the redirected project in that case
|
||||
const resultFromDts = getRedirectReferenceForResolutionFromSourceOfProject(file.originalFileName, file.path);
|
||||
const resultFromDts = getRedirectReferenceForResolutionFromSourceOfProject(file.path);
|
||||
if (resultFromDts) return resultFromDts;
|
||||
|
||||
// If preserveSymlinks is true, module resolution wont jump the symlink
|
||||
|
@ -1171,13 +1171,12 @@ namespace ts {
|
|||
// Note:: Currently we try the real path only if the
|
||||
// file is from node_modules to avoid having to run real path on all file paths
|
||||
if (!host.realpath || !options.preserveSymlinks || !stringContains(file.originalFileName, nodeModulesPathPart)) return undefined;
|
||||
const realDeclarationFileName = host.realpath(file.originalFileName);
|
||||
const realDeclarationPath = toPath(realDeclarationFileName);
|
||||
return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationFileName, realDeclarationPath);
|
||||
const realDeclarationPath = toPath(host.realpath(file.originalFileName));
|
||||
return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath);
|
||||
}
|
||||
|
||||
function getRedirectReferenceForResolutionFromSourceOfProject(fileName: string, filePath: Path) {
|
||||
const source = getSourceOfProjectReferenceRedirect(fileName);
|
||||
function getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path) {
|
||||
const source = getSourceOfProjectReferenceRedirect(filePath);
|
||||
if (isString(source)) return getResolvedProjectReferenceToRedirect(source);
|
||||
if (!source) return undefined;
|
||||
// Output of .d.ts file so return resolved ref that matches the out file name
|
||||
|
@ -2472,7 +2471,7 @@ namespace ts {
|
|||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
|
||||
getSourceFileFromReferenceWorker(
|
||||
fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
|
||||
fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
|
||||
reason
|
||||
);
|
||||
|
@ -2514,20 +2513,21 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
tracing?.push(tracing.Phase.Program, "findSourceFile", {
|
||||
fileName,
|
||||
isDefaultLib: isDefaultLib || undefined,
|
||||
fileIncludeKind: (FileIncludeKind as any)[reason.kind],
|
||||
});
|
||||
const result = findSourceFileWorker(fileName, path, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
|
||||
const result = findSourceFileWorker(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
|
||||
tracing?.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
function findSourceFileWorker(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
const path = toPath(fileName);
|
||||
if (useSourceOfProjectReferenceRedirect) {
|
||||
let source = getSourceOfProjectReferenceRedirect(fileName);
|
||||
let source = getSourceOfProjectReferenceRedirect(path);
|
||||
// If preserveSymlinks is true, module resolution wont jump the symlink
|
||||
// but the resolved real path may be the .d.ts from project reference
|
||||
// Note:: Currently we try the real path only if the
|
||||
|
@ -2537,12 +2537,12 @@ namespace ts {
|
|||
options.preserveSymlinks &&
|
||||
isDeclarationFileName(fileName) &&
|
||||
stringContains(fileName, nodeModulesPathPart)) {
|
||||
const realPath = host.realpath(fileName);
|
||||
if (realPath !== fileName) source = getSourceOfProjectReferenceRedirect(realPath);
|
||||
const realPath = toPath(host.realpath(fileName));
|
||||
if (realPath !== path) source = getSourceOfProjectReferenceRedirect(realPath);
|
||||
}
|
||||
if (source) {
|
||||
const file = isString(source) ?
|
||||
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
|
||||
findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) :
|
||||
undefined;
|
||||
if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
|
||||
return file;
|
||||
|
@ -2750,8 +2750,8 @@ namespace ts {
|
|||
return ts.forEachResolvedProjectReference(resolvedProjectReferences, cb);
|
||||
}
|
||||
|
||||
function getSourceOfProjectReferenceRedirect(file: string) {
|
||||
if (!isDeclarationFileName(file)) return undefined;
|
||||
function getSourceOfProjectReferenceRedirect(path: Path) {
|
||||
if (!isDeclarationFileName(path)) return undefined;
|
||||
if (mapFromToProjectReferenceRedirectSource === undefined) {
|
||||
mapFromToProjectReferenceRedirectSource = new Map();
|
||||
forEachResolvedProjectReference(resolvedRef => {
|
||||
|
@ -2772,7 +2772,7 @@ namespace ts {
|
|||
}
|
||||
});
|
||||
}
|
||||
return mapFromToProjectReferenceRedirectSource.get(toPath(file));
|
||||
return mapFromToProjectReferenceRedirectSource.get(path);
|
||||
}
|
||||
|
||||
function isSourceOfProjectReferenceRedirect(fileName: string) {
|
||||
|
@ -2954,10 +2954,8 @@ namespace ts {
|
|||
modulesWithElidedImports.set(file.path, true);
|
||||
}
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
findSourceFile(
|
||||
resolvedFileName,
|
||||
path,
|
||||
/*isDefaultLib*/ false,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
{ kind: FileIncludeKind.Import, file: file.path, index, },
|
||||
|
@ -3691,7 +3689,7 @@ namespace ts {
|
|||
useSourceOfProjectReferenceRedirect: boolean;
|
||||
toPath(fileName: string): Path;
|
||||
getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
|
||||
getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined;
|
||||
getSourceOfProjectReferenceRedirect(path: Path): SourceOfProjectReferenceRedirect | undefined;
|
||||
forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
|
||||
}
|
||||
|
||||
|
@ -3778,9 +3776,9 @@ namespace ts {
|
|||
}
|
||||
|
||||
function fileExistsIfProjectReferenceDts(file: string) {
|
||||
const source = host.getSourceOfProjectReferenceRedirect(file);
|
||||
const source = host.getSourceOfProjectReferenceRedirect(host.toPath(file));
|
||||
return source !== undefined ?
|
||||
isString(source) ? originalFileExists.call(host.compilerHost, source) : true :
|
||||
isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true :
|
||||
undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -1279,7 +1279,7 @@ namespace ts {
|
|||
|
||||
const platform: string = _os.platform();
|
||||
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
|
||||
const realpathSync = useCaseSensitiveFileNames ? (_fs.realpathSync.native ?? _fs.realpathSync) : _fs.realpathSync;
|
||||
const realpathSync = _fs.realpathSync.native ?? _fs.realpathSync;
|
||||
|
||||
const fsSupportsRecursiveFsWatch = isNode4OrLater && (process.platform === "win32" || process.platform === "darwin");
|
||||
const getCurrentDirectory = memoize(() => process.cwd());
|
||||
|
|
|
@ -6461,6 +6461,7 @@ namespace ts {
|
|||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
useCaseSensitiveFileNames?: boolean | (() => boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6210,7 +6210,9 @@ namespace ts {
|
|||
}
|
||||
|
||||
export interface SymlinkedDirectory {
|
||||
/** Matches the casing returned by `realpath`. Used to compute the `realpath` of children. */
|
||||
real: string;
|
||||
/** toPath(real). Stored to avoid repeated recomputation. */
|
||||
realPath: Path;
|
||||
}
|
||||
|
||||
|
|
|
@ -325,7 +325,8 @@ namespace Harness.LanguageService {
|
|||
readFile: fileName => {
|
||||
const scriptInfo = this.getScriptInfo(fileName);
|
||||
return scriptInfo && scriptInfo.content;
|
||||
}
|
||||
},
|
||||
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames()
|
||||
};
|
||||
this.getModuleResolutionsForFile = (fileName) => {
|
||||
const scriptInfo = this.getScriptInfo(fileName)!;
|
||||
|
|
|
@ -1706,6 +1706,7 @@ namespace ts.server {
|
|||
readFile: this.projectService.host.readFile.bind(this.projectService.host),
|
||||
getDirectories: this.projectService.host.getDirectories.bind(this.projectService.host),
|
||||
trace: this.projectService.host.trace?.bind(this.projectService.host),
|
||||
useCaseSensitiveFileNames: this.program.useCaseSensitiveFileNames(),
|
||||
};
|
||||
}
|
||||
return this.projectService.host;
|
||||
|
|
|
@ -65,11 +65,12 @@ namespace ts {
|
|||
fileExists: path => {
|
||||
assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
|
||||
return map.has(path);
|
||||
}
|
||||
},
|
||||
useCaseSensitiveFileNames: true
|
||||
};
|
||||
}
|
||||
else {
|
||||
return { readFile, realpath, fileExists: path => map.has(path) };
|
||||
return { readFile, realpath, fileExists: path => map.has(path), useCaseSensitiveFileNames: true };
|
||||
}
|
||||
function readFile(path: string): string | undefined {
|
||||
const file = map.get(path);
|
||||
|
|
|
@ -3059,6 +3059,7 @@ declare namespace ts {
|
|||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
useCaseSensitiveFileNames?: boolean | (() => boolean);
|
||||
}
|
||||
/**
|
||||
* Represents the result of module resolution.
|
||||
|
|
|
@ -3059,6 +3059,7 @@ declare namespace ts {
|
|||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
useCaseSensitiveFileNames?: boolean | (() => boolean);
|
||||
}
|
||||
/**
|
||||
* Represents the result of module resolution.
|
||||
|
|
Loading…
Reference in a new issue