Skip to content

Commit 8bc1932

Browse files
author
Andy
authored
moduleSpecifiers: Don't return a relative path to node_modules (microsoft#24460)
1 parent 160b667 commit 8bc1932

File tree

3 files changed

+42
-23
lines changed

3 files changed

+42
-23
lines changed

src/services/codefixes/moduleSpecifiers.ts

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ namespace ts.moduleSpecifiers {
1616
const getCanonicalFileName = hostGetCanonicalFileName(host);
1717
const sourceDirectory = getDirectoryPath(importingSourceFile.fileName);
1818

19-
return getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()).map(moduleFileName => {
20-
const global = tryGetModuleNameFromAmbientModule(moduleSymbol)
21-
|| tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
22-
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory)
23-
|| rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName);
24-
if (global) {
25-
return [global];
26-
}
19+
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
20+
if (ambient) return [[ambient]];
21+
22+
const modulePaths = getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile());
2723

24+
const global = mapDefined(modulePaths, moduleFileName =>
25+
tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) ||
26+
tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory) ||
27+
rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName));
28+
if (global.length) return global.map(g => [g]);
29+
30+
return modulePaths.map(moduleFileName => {
2831
const relativePath = removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
2932
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
3033
return [relativePath];
@@ -191,11 +194,12 @@ namespace ts.moduleSpecifiers {
191194
// Simplify the full file path to something that can be resolved by Node.
192195

193196
// If the module could be imported by a directory name, use that directory's name
194-
let moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
197+
const moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
195198
// Get a path that's relative to node_modules or the importing file's path
196-
moduleSpecifier = getNodeResolvablePath(moduleSpecifier);
199+
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
200+
if (!startsWith(sourceDirectory, moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex))) return undefined;
197201
// If the module was found in @types, get the actual Node package name
198-
return getPackageNameFromAtTypesDirectory(moduleSpecifier);
202+
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
199203

200204
function getDirectoryOrExtensionlessFileName(path: string): string {
201205
// If the file is the main module, it can be imported by the package name
@@ -224,17 +228,6 @@ namespace ts.moduleSpecifiers {
224228

225229
return fullModulePathWithoutExtension;
226230
}
227-
228-
function getNodeResolvablePath(path: string): string {
229-
const basePath = path.substring(0, parts.topLevelNodeModulesIndex);
230-
if (sourceDirectory.indexOf(basePath) === 0) {
231-
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
232-
return path.substring(parts.topLevelPackageNameIndex + 1);
233-
}
234-
else {
235-
return ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, path, getCanonicalFileName));
236-
}
237-
}
238231
}
239232

240233
interface NodeModulePathParts {

tests/cases/fourslash/completionsImport_tsx.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/// <reference path="fourslash.ts" />
22

33
// @noLib: true
4-
// @nolib: true
54
// @jsx: preserve
65

76
// @Filename: /a.tsx
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /a/index.d.ts
4+
// @Symlink: /b/node_modules/a/index.d.ts
5+
// @Symlink: /c/node_modules/a/index.d.ts
6+
////export const a: number;
7+
8+
// @Filename: /b/index.ts
9+
// @Symlink: /c/node_modules/b/index.d.ts
10+
////import { a } from 'a'
11+
////export const b: number;
12+
13+
// @Filename: /c/a_user.ts
14+
// Importing from "a" to get /c/node_modules/a in the project.
15+
// Must do this in a separate file to avoid import fixes attempting to share the import.
16+
////import { a } from "a";
17+
18+
// @Filename: /c/foo.ts
19+
////[|import { b } from "b";
20+
////a;|]
21+
22+
goTo.file("/c/foo.ts");
23+
verify.importFixAtPosition([
24+
`import { b } from "b";
25+
import { a } from "a";
26+
a;`,
27+
]);

0 commit comments

Comments
 (0)