Skip to content

Commit 1d25792

Browse files
committed
Fix auto-import when paths points to project reference redirect
1 parent 2d5e372 commit 1d25792

File tree

4 files changed

+98
-12
lines changed

4 files changed

+98
-12
lines changed

src/compiler/moduleSpecifiers.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,12 @@ function computeModuleSpecifiers(
285285
return nodeModulesSpecifiers!;
286286
}
287287

288-
if (!specifier && !modulePath.isRedirect) {
288+
if (!specifier) {
289289
const local = getLocalModuleSpecifier(modulePath.path, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences);
290290
if (pathIsBareSpecifier(local)) {
291291
pathsSpecifiers = append(pathsSpecifiers, local);
292292
}
293-
else if (!importedFileIsInNodeModules || modulePath.isInNodeModules) {
293+
else if (!modulePath.isRedirect && (!importedFileIsInNodeModules || modulePath.isInNodeModules)) {
294294
// Why this extra conditional, not just an `else`? If some path to the file contained
295295
// 'node_modules', but we can't create a non-relative specifier (e.g. "@foo/bar/path/to/file"),
296296
// that means we had to go through a *sibling's* node_modules, not one we can access directly.
@@ -338,16 +338,16 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
338338
}
339339

340340
const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, getAllowedEndings(ending, compilerOptions, importMode), host, compilerOptions);
341-
const nonRelative = fromPaths === undefined && baseUrl !== undefined ? removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) : fromPaths;
342-
if (!nonRelative) {
341+
const maybeNonRelative = fromPaths === undefined && baseUrl !== undefined ? removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) : fromPaths;
342+
if (!maybeNonRelative) {
343343
return relativePath;
344344
}
345345

346-
if (relativePreference === RelativePreference.NonRelative) {
347-
return nonRelative;
346+
if (relativePreference === RelativePreference.NonRelative && !pathIsRelative(maybeNonRelative)) {
347+
return maybeNonRelative;
348348
}
349349

350-
if (relativePreference === RelativePreference.ExternalNonRelative) {
350+
if (relativePreference === RelativePreference.ExternalNonRelative && !pathIsRelative(maybeNonRelative)) {
351351
const projectDirectory = compilerOptions.configFilePath ?
352352
toPath(getDirectoryPath(compilerOptions.configFilePath), host.getCurrentDirectory(), info.getCanonicalFileName) :
353353
info.getCanonicalFileName(host.getCurrentDirectory());
@@ -363,7 +363,7 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
363363
// lib/ | (path crosses tsconfig.json)
364364
// imported.ts <---
365365
//
366-
return nonRelative;
366+
return maybeNonRelative;
367367
}
368368

369369
const nearestTargetPackageJson = getNearestAncestorDirectoryWithPackageJson(host, getDirectoryPath(modulePath));
@@ -378,16 +378,14 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
378378
// package.json |
379379
// component.ts <---
380380
//
381-
return nonRelative;
381+
return maybeNonRelative;
382382
}
383383

384384
return relativePath;
385385
}
386386

387-
if (relativePreference !== RelativePreference.Shortest) Debug.assertNever(relativePreference);
388-
389387
// Prefer a relative import over a baseUrl import if it has fewer components.
390-
return isPathRelativeToParent(nonRelative) || countPathComponents(relativePath) < countPathComponents(nonRelative) ? relativePath : nonRelative;
388+
return isPathRelativeToParent(maybeNonRelative) || countPathComponents(relativePath) < countPathComponents(maybeNonRelative) ? relativePath : maybeNonRelative;
391389
}
392390

393391
/** @internal */

src/harness/fourslashImpl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3041,6 +3041,10 @@ export class TestState {
30413041
* @param fileName Path to file where error should be retrieved from.
30423042
*/
30433043
private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions, position?: number): readonly ts.CodeFixAction[] {
3044+
if (this.testType === FourSlashTestType.Server) {
3045+
this.configure(preferences);
3046+
}
3047+
30443048
const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map(diagnostic => ({
30453049
start: diagnostic.start,
30463050
length: diagnostic.length,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/// <reference path="../fourslash.ts" />
2+
3+
// @Filename: /common/tsconfig.json
4+
//// {
5+
//// "compilerOptions": {
6+
//// "module": "commonjs",
7+
//// "outDir": "dist",
8+
//// "composite": true
9+
//// },
10+
//// "include": ["src"]
11+
//// }
12+
13+
// @Filename: /common/src/MyModule.ts
14+
//// export function square(n: number) {
15+
//// return n * 2;
16+
//// }
17+
18+
// @Filename: /web/tsconfig.json
19+
//// {
20+
//// "compilerOptions": {
21+
//// "module": "esnext",
22+
//// "moduleResolution": "node",
23+
//// "noEmit": true,
24+
//// "baseUrl": "."
25+
//// },
26+
//// "include": ["src"],
27+
//// "references": [{ "path": "../common" }]
28+
//// }
29+
30+
// @Filename: /web/src/MyApp.ts
31+
//// import { square } from "../../common/dist/src/MyModule";
32+
33+
// @Filename: /web/src/Helper.ts
34+
//// export function saveMe() {
35+
//// square/**/(2);
36+
//// }
37+
38+
goTo.file("/web/src/Helper.ts");
39+
verify.importFixModuleSpecifiers("", ["../../common/src/MyModule"], {
40+
importModuleSpecifierPreference: "non-relative"
41+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/// <reference path="../fourslash.ts" />
2+
3+
// @Filename: /common/tsconfig.json
4+
//// {
5+
//// "compilerOptions": {
6+
//// "module": "commonjs",
7+
//// "outDir": "dist",
8+
//// "composite": true
9+
//// },
10+
//// "include": ["src"]
11+
//// }
12+
13+
// @Filename: /common/src/MyModule.ts
14+
//// export function square(n: number) {
15+
//// return n * 2;
16+
//// }
17+
18+
// @Filename: /web/tsconfig.json
19+
//// {
20+
//// "compilerOptions": {
21+
//// "module": "esnext",
22+
//// "moduleResolution": "node",
23+
//// "noEmit": true,
24+
//// "paths": {
25+
//// "@common/*": ["../common/dist/src/*"]
26+
//// }
27+
//// },
28+
//// "include": ["src"],
29+
//// "references": [{ "path": "../common" }]
30+
//// }
31+
32+
// @Filename: /web/src/MyApp.ts
33+
//// import { square } from "@common/MyModule";
34+
35+
// @Filename: /web/src/Helper.ts
36+
//// export function saveMe() {
37+
//// square/**/(2);
38+
//// }
39+
40+
goTo.file("/web/src/Helper.ts");
41+
verify.importFixModuleSpecifiers("", ["@common/MyModule"], {
42+
importModuleSpecifierPreference: "non-relative"
43+
});

0 commit comments

Comments
 (0)