Skip to content

Commit 7b4f864

Browse files
author
Andy
authored
moduleSpecifiers: Simpler criteria for preferring relative path vs baseUrl (#25803)
* moduleSpecifiers: Simpler criteria for preferring relative path vs baseUrl * Don't unconditonally use a path mapping
1 parent 02e1a32 commit 7b4f864

9 files changed

+62
-53
lines changed

src/compiler/moduleSpecifiers.ts

+15-47
Original file line numberDiff line numberDiff line change
@@ -127,53 +127,30 @@ namespace ts.moduleSpecifiers {
127127
}
128128

129129
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions);
130-
if (paths) {
131-
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
132-
if (fromPaths) {
133-
return [fromPaths];
134-
}
135-
}
130+
const fromPaths = paths && tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
131+
const nonRelative = fromPaths === undefined ? importRelativeToBaseUrl : fromPaths;
136132

137133
if (relativePreference === RelativePreference.NonRelative) {
138-
return [importRelativeToBaseUrl];
134+
return [nonRelative];
139135
}
140136

141137
if (relativePreference !== RelativePreference.Auto) Debug.assertNever(relativePreference);
142138

143-
if (isPathRelativeToParent(relativeToBaseUrl)) {
139+
if (isPathRelativeToParent(nonRelative)) {
144140
return [relativePath];
145141
}
146142

147-
/*
148-
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
149-
150-
Suppose we have:
151-
baseUrl = /base
152-
sourceDirectory = /base/a/b
153-
moduleFileName = /base/foo/bar
154-
Then:
155-
relativePath = ../../foo/bar
156-
getRelativePathNParents(relativePath) = 2
157-
pathFromSourceToBaseUrl = ../../
158-
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
159-
2 < 2 = false
160-
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
161-
162-
Suppose we have:
163-
baseUrl = /base
164-
sourceDirectory = /base/foo/a
165-
moduleFileName = /base/foo/bar
166-
Then:
167-
relativePath = ../a
168-
getRelativePathNParents(relativePath) = 1
169-
pathFromSourceToBaseUrl = ../../
170-
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
171-
1 < 2 = true
172-
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
173-
*/
174-
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
175-
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
176-
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
143+
// Prefer a relative import over a baseUrl import if it has fewer components.
144+
const relativeFirst = countPathComponents(relativePath) < countPathComponents(nonRelative);
145+
return relativeFirst ? [relativePath, nonRelative] : [nonRelative, relativePath];
146+
}
147+
148+
function countPathComponents(path: string): number {
149+
let count = 0;
150+
for (let i = startsWith(path, "./") ? 2 : 0; i < path.length; i++) {
151+
if (path.charCodeAt(i) === CharacterCodes.slash) count++;
152+
}
153+
return count;
177154
}
178155

179156
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
@@ -245,15 +222,6 @@ namespace ts.moduleSpecifiers {
245222
return result;
246223
}
247224

248-
function getRelativePathNParents(relativePath: string): number {
249-
const components = getPathComponents(relativePath);
250-
if (components[0] || components.length === 1) return 0;
251-
for (let i = 1; i < components.length; i++) {
252-
if (components[i] !== "..") return i - 1;
253-
}
254-
return components.length - 1;
255-
}
256-
257225
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
258226
const decl = find(moduleSymbol.declarations,
259227
d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name)))

tests/cases/fourslash/importNameCodeFixNewImportPaths0.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@
1818
verify.importFixAtPosition([
1919
`import { foo } from "a";
2020
21-
foo();`
21+
foo();`,
22+
`import { foo } from "./folder_a/f2";
23+
24+
foo();`,
2225
]);

tests/cases/fourslash/importNameCodeFixNewImportPaths1.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@
1818
verify.importFixAtPosition([
1919
`import { foo } from "b/f2";
2020
21-
foo();`
21+
foo();`,
22+
`import { foo } from "./folder_b/f2";
23+
24+
foo();`,
2225
]);

tests/cases/fourslash/importNameCodeFixNewImportPaths2.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@
2424
verify.importFixAtPosition([
2525
`import { foo } from "b";
2626
27-
foo();`
27+
foo();`,
28+
`import { foo } from "./folder_b";
29+
30+
foo();`,
2831
]);

tests/cases/fourslash/importNameCodeFixNewImportPaths_withExtension.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
verify.importFixAtPosition([
2020
`import { foo } from "foo";
2121
22-
foo`
22+
foo`,
23+
`import { foo } from "./thisHasPathMapping";
24+
25+
foo`,
2326
]);

tests/cases/fourslash/importNameCodeFixNewImportPaths_withLeadingDotSlash.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
verify.importFixAtPosition([
2020
`import { foo } from "foo";
2121
22-
foo`
22+
foo`,
23+
`import { foo } from "./thisHasPathMapping";
24+
25+
foo`,
2326
]);

tests/cases/fourslash/importNameCodeFixNewImportPaths_withParentRelativePath.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
verify.importFixAtPosition([
2020
`import { foo } from "foo";
2121
22-
foo`
22+
foo`,
23+
`import { foo } from "../thisHasPathMapping";
24+
25+
foo`,
2326
]);

tests/cases/fourslash/importNameCodeFix_fromPathMapping.ts

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
goTo.file("/b.ts");
2020
verify.importFixAtPosition([
21+
`import { foo } from "./a";
22+
23+
foo;`,
2124
`import { foo } from "@root/a";
2225
2326
foo;`,
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)