Skip to content

Commit

Permalink
Generate shortest rootDirs module specifier instead of first possib…
Browse files Browse the repository at this point in the history
…le (#51244)

* Generate shortest rootDirs module specifier instead of first possible

* Simplify `min`
  • Loading branch information
andrewbranch committed Oct 21, 2022
1 parent bbb42f4 commit ef69116
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/compiler/core.ts
Expand Up @@ -1937,8 +1937,10 @@ namespace ts {
return compareValues(a?.start, b?.start) || compareValues(a?.length, b?.length);
}

export function min<T>(a: T, b: T, compare: Comparer<T>): T {
return compare(a, b) === Comparison.LessThan ? a : b;
export function min<T>(items: readonly [T, ...T[]], compare: Comparer<T>): T;
export function min<T>(items: readonly T[], compare: Comparer<T>): T | undefined;
export function min<T>(items: readonly T[], compare: Comparer<T>): T | undefined {
return reduceLeft(items, (x, y) => compare(x, y) === Comparison.LessThan ? x : y);
}

/**
Expand Down
23 changes: 15 additions & 8 deletions src/compiler/moduleSpecifiers.ts
Expand Up @@ -726,16 +726,23 @@ namespace ts.moduleSpecifiers {
}

function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, ending: Ending, compilerOptions: CompilerOptions): string | undefined {
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
if (normalizedTargetPath === undefined) {
const normalizedTargetPaths = getPathsRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
if (normalizedTargetPaths === undefined) {
return undefined;
}

const normalizedSourcePaths = getPathsRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
const relativePaths = flatMap(normalizedSourcePaths, sourcePath => {
return map(normalizedTargetPaths, targetPath => ensurePathIsNonModuleName(getRelativePathFromDirectory(sourcePath, targetPath, getCanonicalFileName)));
});
const shortest = min(relativePaths, compareNumberOfDirectorySeparators);
if (!shortest) {
return undefined;
}

const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath;
return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs
? removeExtensionAndIndexPostFix(relativePath, ending, compilerOptions)
: removeFileExtension(relativePath);
? removeExtensionAndIndexPostFix(shortest, ending, compilerOptions)
: removeFileExtension(shortest);
}

function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, sourceDirectory }: Info, importingSourceFile: SourceFile , host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ModuleKind.ESNext | ModuleKind.CommonJS): string | undefined {
Expand Down Expand Up @@ -882,8 +889,8 @@ namespace ts.moduleSpecifiers {
}
}

function getPathRelativeToRootDirs(path: string, rootDirs: readonly string[], getCanonicalFileName: GetCanonicalFileName): string | undefined {
return firstDefined(rootDirs, rootDir => {
function getPathsRelativeToRootDirs(path: string, rootDirs: readonly string[], getCanonicalFileName: GetCanonicalFileName): string[] | undefined {
return mapDefined(rootDirs, rootDir => {
const relativePath = getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName);
return relativePath !== undefined && isPathRelativeToParent(relativePath) ? undefined : relativePath;
});
Expand Down
2 changes: 1 addition & 1 deletion src/services/patternMatcher.ts
Expand Up @@ -259,7 +259,7 @@ namespace ts {
}

function betterMatch(a: PatternMatch | undefined, b: PatternMatch | undefined): PatternMatch | undefined {
return min(a, b, compareMatches);
return min([a, b], compareMatches);
}
function compareMatches(a: PatternMatch | undefined, b: PatternMatch | undefined): Comparison {
return a === undefined ? Comparison.GreaterThan : b === undefined ? Comparison.LessThan
Expand Down
17 changes: 17 additions & 0 deletions tests/cases/fourslash/autoImportRootDirs.ts
@@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />

// @Filename: /tsconfig.json
//// {
//// "compilerOptions": {
//// "module": "commonjs",
//// "rootDirs": [".", "./some/other/root"]
//// }
//// }

// @Filename: /some/other/root/types.ts
//// export type Something = {};

// @Filename: /index.ts
//// const s: Something/**/

verify.importFixModuleSpecifiers("", ["./types"]);

0 comments on commit ef69116

Please sign in to comment.