Fix auto-imports from auto type acquisition definitions (#33766)

* Fix auto-imports from ATA typings

* Compare canonical filenames in isImportablePath
This commit is contained in:
Andrew Branch
2019-10-17 13:59:09 -07:00
committed by GitHub
parent 6d969f729d
commit 454a3a0b0f
7 changed files with 47 additions and 4 deletions

View File

@@ -317,9 +317,13 @@ namespace ts.moduleSpecifiers {
// If the module could be imported by a directory name, use that directory's name
const moduleSpecifier = packageNameOnly ? moduleFileName : getDirectoryOrExtensionlessFileName(moduleFileName);
const globalTypingsCacheLocation = host.getGlobalTypingsCacheLocation && host.getGlobalTypingsCacheLocation();
// Get a path that's relative to node_modules or the importing file's path
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
if (!startsWith(sourceDirectory, getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)))) return undefined;
const pathToTopLevelNodeModules = getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex));
if (!(startsWith(sourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) {
return undefined;
}
// If the module was found in @types, get the actual Node package name
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);

View File

@@ -6170,6 +6170,8 @@ namespace ts {
readFile?(path: string): string | undefined;
/* @internal */
getProbableSymlinks?(files: readonly SourceFile[]): ReadonlyMap<string>;
/* @internal */
getGlobalTypingsCacheLocation?(): string | undefined;
}
// Note: this used to be deprecated in our public API, but is still used internally

View File

@@ -220,6 +220,10 @@ namespace Harness.LanguageService {
return !!this.typesRegistry && this.typesRegistry.has(name);
}
getGlobalTypingsCacheLocation() {
return "/Library/Caches/typescript";
}
installPackage = ts.notImplemented;
getCompilationSettings() { return this.settings; }

View File

@@ -307,6 +307,11 @@ namespace ts.server {
return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
}
/*@internal*/
getGlobalTypingsCacheLocation() {
return this.getGlobalCache();
}
private get typingsCache(): TypingsCache {
return this.projectService.typingsCache;
}

View File

@@ -631,6 +631,7 @@ namespace ts.codefix {
let filteredCount = 0;
const packageJson = filterByPackageJson && createAutoImportFilter(from, program, host);
const allSourceFiles = program.getSourceFiles();
const globalTypingsCache = host.getGlobalTypingsCacheLocation && host.getGlobalTypingsCacheLocation();
forEachExternalModule(program.getTypeChecker(), allSourceFiles, (module, sourceFile) => {
if (sourceFile === undefined) {
if (!packageJson || packageJson.allowsImportingAmbientModule(module, allSourceFiles)) {
@@ -640,7 +641,10 @@ namespace ts.codefix {
filteredCount++;
}
}
else if (sourceFile && sourceFile !== from && isImportablePath(from.fileName, sourceFile.fileName)) {
else if (sourceFile &&
sourceFile !== from &&
isImportablePath(from.fileName, sourceFile.fileName, hostGetCanonicalFileName(host), globalTypingsCache)
) {
if (!packageJson || packageJson.allowsImportingSourceFile(sourceFile, allSourceFiles)) {
cb(module);
}
@@ -669,10 +673,13 @@ namespace ts.codefix {
* Don't include something from a `node_modules` that isn't actually reachable by a global import.
* A relative import to node_modules is usually a bad idea.
*/
function isImportablePath(fromPath: string, toPath: string): boolean {
function isImportablePath(fromPath: string, toPath: string, getCanonicalFileName: GetCanonicalFileName, globalCachePath?: string): boolean {
// If it's in a `node_modules` but is not reachable from here via a global import, don't bother.
const toNodeModules = forEachAncestorDirectory(toPath, ancestor => getBaseFileName(ancestor) === "node_modules" ? ancestor : undefined);
return toNodeModules === undefined || startsWith(fromPath, getDirectoryPath(toNodeModules));
const toNodeModulesParent = toNodeModules && getDirectoryPath(getCanonicalFileName(toNodeModules));
return toNodeModulesParent === undefined
|| startsWith(getCanonicalFileName(fromPath), toNodeModulesParent)
|| (!!globalCachePath && startsWith(getCanonicalFileName(globalCachePath), toNodeModulesParent));
}
export function moduleSymbolToValidIdentifier(moduleSymbol: Symbol, target: ScriptTarget): string {
@@ -718,6 +725,7 @@ namespace ts.codefix {
readFile: maybeBind(host, host.readFile),
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
getProbableSymlinks: maybeBind(host, host.getProbableSymlinks) || program.getProbableSymlinks,
getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation),
};
let usesNodeCoreModules: boolean | undefined;

View File

@@ -243,6 +243,8 @@ namespace ts {
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
/* @internal */
getGlobalTypingsCacheLocation?(): string | undefined;
/*
* Required for full import and type reference completions.