diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index f3dd99ee5bfde..0d6be577d5054 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -2169,6 +2169,10 @@ namespace ts {
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
}
+ export function removeSuffix(str: string, suffix: string): string {
+ return endsWith(str, suffix) ? str.slice(0, str.length - suffix.length) : str;
+ }
+
export function stringContains(str: string, substring: string): boolean {
return str.indexOf(substring) !== -1;
}
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 2687a660ca8e4..fb801e474613c 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -2549,6 +2549,9 @@ Actual: ${stringify(fullActual)}`);
}
const sortedExpectedArray = expectedTextArray.sort();
const sortedActualArray = actualTextArray.sort();
+ if (sortedExpectedArray.length !== sortedActualArray.length) {
+ this.raiseError(`Expected ${sortedExpectedArray.length} import fixes, got ${sortedActualArray.length}`);
+ }
ts.zipWith(sortedExpectedArray, sortedActualArray, (expected, actual, index) => {
if (expected !== actual) {
this.raiseError(`Import fix at index ${index} doesn't match.\n${showTextDiff(expected, actual)}`);
@@ -2867,7 +2870,7 @@ Actual: ${stringify(fullActual)}`);
if (negative) {
if (codeFixes.length) {
- this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
+ this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found ${codeFixes.map(c => c.description)}.`);
}
return;
}
diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts
index 838e19fa35de1..ed6a3d485a4e2 100644
--- a/src/services/codefixes/importFixes.ts
+++ b/src/services/codefixes/importFixes.ts
@@ -322,7 +322,7 @@ namespace ts.codefix {
tryGetModuleNameAsNodeModule(options, moduleFileName, host, getCanonicalFileName, sourceDirectory) ||
tryGetModuleNameFromBaseUrl(options, moduleFileName, getCanonicalFileName) ||
options.rootDirs && tryGetModuleNameFromRootDirs(options.rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
- removeFileExtension(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName));
+ removeExtensionAndIndexPostFix(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName), options);
}
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
@@ -343,7 +343,7 @@ namespace ts.codefix {
}
const relativeNameWithIndex = removeFileExtension(relativeName);
- relativeName = removeExtensionAndIndexPostFix(relativeName);
+ relativeName = removeExtensionAndIndexPostFix(relativeName, options);
if (options.paths) {
for (const key in options.paths) {
@@ -393,7 +393,7 @@ namespace ts.codefix {
return roots && firstDefined(roots, unNormalizedTypeRoot => {
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
if (startsWith(moduleFileName, typeRoot)) {
- return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1));
+ return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), options);
}
});
}
@@ -527,12 +527,9 @@ namespace ts.codefix {
return firstDefined(rootDirs, rootDir => getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName));
}
- function removeExtensionAndIndexPostFix(fileName: string) {
- fileName = removeFileExtension(fileName);
- if (endsWith(fileName, "/index")) {
- fileName = fileName.substr(0, fileName.length - 6/* "/index".length */);
- }
- return fileName;
+ function removeExtensionAndIndexPostFix(fileName: string, options: CompilerOptions): string {
+ const noExtension = removeFileExtension(fileName);
+ return getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeJs ? removeSuffix(noExtension, "/index") : noExtension;
}
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: (fileName: string) => string): string | undefined {
diff --git a/tests/cases/fourslash/importNameCodeFixNewImportIndex.ts b/tests/cases/fourslash/importNameCodeFixNewImportIndex.ts
new file mode 100644
index 0000000000000..2840424c468a7
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFixNewImportIndex.ts
@@ -0,0 +1,16 @@
+///
+
+// @Filename: /a/index.ts
+////export const foo = 0;
+
+// @Filename: /b.ts
+////[|/**/foo;|]
+
+goTo.file("/a/index.ts");
+goTo.file("/b.ts");
+
+verify.importFixAtPosition([
+`import { foo } from "./a";
+
+foo;`
+]);
diff --git a/tests/cases/fourslash/importNameCodeFixNewImportIndex_notForClassicResolution.ts b/tests/cases/fourslash/importNameCodeFixNewImportIndex_notForClassicResolution.ts
new file mode 100644
index 0000000000000..3fa9b91b264a4
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFixNewImportIndex_notForClassicResolution.ts
@@ -0,0 +1,27 @@
+///
+
+// @moduleResolution: classic
+
+// @Filename: /a/index.ts
+////export const foo = 0;
+
+// @Filename: /node_modules/x/index.d.ts
+////export const bar = 0;
+
+// @Filename: /b.ts
+////[|foo;|]
+
+// @Filename: /c.ts
+////bar;
+
+goTo.file("/a/index.ts");
+
+goTo.file("/b.ts");
+verify.importFixAtPosition([
+`import { foo } from "./a/index";
+
+foo;`
+]);
+
+goTo.file("/c.ts");
+// TODO: GH#20050 verify.not.codeFixAvailable();
diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts
index 5b6df7a517349..cd3d25030fa5e 100644
--- a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts
+++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts
@@ -3,6 +3,7 @@
// @jsx: react
// @allowSyntheticDefaultImports: false
// @module: es2015
+// @moduleResolution: node
// @Filename: /node_modules/@types/react/index.d.ts
////export = React;
diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts
index 669db55342b04..9dba0f3988256 100644
--- a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts
+++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts
@@ -3,6 +3,7 @@
// @jsx: react
// @allowSyntheticDefaultImports: false
// @module: es2015
+// @moduleResolution: node
// @Filename: /node_modules/@types/react/index.d.ts
////export = React;