Skip to content

Commit 2386f27

Browse files
author
Andy Hanson
committed
moduleSpecifiers: Simpler criteria for preferring relative path vs baseUrl
1 parent 37277e8 commit 2386f27

File tree

2 files changed

+33
-43
lines changed

2 files changed

+33
-43
lines changed

src/compiler/moduleSpecifiers.ts

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,9 @@ namespace ts.moduleSpecifiers {
8989
}
9090

9191
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
92-
if (paths) {
93-
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
94-
if (fromPaths) {
95-
return [fromPaths];
96-
}
92+
const fromPaths = paths && tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
93+
if (fromPaths) {
94+
return [fromPaths];
9795
}
9896

9997
if (preferences.importModuleSpecifierPreference === "non-relative") {
@@ -106,38 +104,19 @@ namespace ts.moduleSpecifiers {
106104
return [relativePath];
107105
}
108106

109-
/*
110-
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
111-
112-
Suppose we have:
113-
baseUrl = /base
114-
sourceDirectory = /base/a/b
115-
moduleFileName = /base/foo/bar
116-
Then:
117-
relativePath = ../../foo/bar
118-
getRelativePathNParents(relativePath) = 2
119-
pathFromSourceToBaseUrl = ../../
120-
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
121-
2 < 2 = false
122-
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
123-
124-
Suppose we have:
125-
baseUrl = /base
126-
sourceDirectory = /base/foo/a
127-
moduleFileName = /base/foo/bar
128-
Then:
129-
relativePath = ../a
130-
getRelativePathNParents(relativePath) = 1
131-
pathFromSourceToBaseUrl = ../../
132-
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
133-
1 < 2 = true
134-
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
135-
*/
136-
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
137-
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
107+
// Prefer a relative import over a baseUrl import if it has fewer components.
108+
const relativeFirst = countPathComponents(relativePath) < countPathComponents(importRelativeToBaseUrl);
138109
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
139110
}
140111

112+
function countPathComponents(path: string): number {
113+
let count = 0;
114+
for (let i = startsWith(path, "./") ? 2 : 0; i < path.length; i++) {
115+
if (path.charCodeAt(i) === CharacterCodes.slash) count++;
116+
}
117+
return count;
118+
}
119+
141120
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
142121
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
143122
}
@@ -197,15 +176,6 @@ namespace ts.moduleSpecifiers {
197176
return symlinks.length === 0 ? getAllModulePathsUsingIndirectSymlinks(files, getNormalizedAbsolutePath(importedFileName, host.getCurrentDirectory ? host.getCurrentDirectory() : ""), getCanonicalFileName, host) : symlinks;
198177
}
199178

200-
function getRelativePathNParents(relativePath: string): number {
201-
const components = getPathComponents(relativePath);
202-
if (components[0] || components.length === 1) return 0;
203-
for (let i = 1; i < components.length; i++) {
204-
if (components[i] !== "..") return i - 1;
205-
}
206-
return components.length - 1;
207-
}
208-
209179
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
210180
const decl = moduleSymbol.valueDeclaration;
211181
if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /tsconfig.json
4+
////{ "compilerOptions": { "baseUrl": "./src" } }
5+
6+
// @Filename: /src/d0/d1/d2/file.ts
7+
////foo/**/;
8+
9+
// @Filename: /src/d0/a.ts
10+
////export const foo = 0;
11+
12+
goTo.file("/src/d0/d1/d2/file.ts");
13+
verify.importFixAtPosition([
14+
`import { foo } from "d0/a";
15+
16+
foo;`,
17+
`import { foo } from "../../a";
18+
19+
foo;`,
20+
]);

0 commit comments

Comments
 (0)