diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 5e932050bfd7f..c8cb9de72ec29 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -2652,10 +2652,10 @@ Actual: ${stringify(fullActual)}`);
public verifyImportFixAtPosition(expectedTextArray: string[], errorCode: number | undefined, preferences: ts.UserPreferences | undefined) {
const { fileName } = this.activeFile;
const ranges = this.getRanges().filter(r => r.fileName === fileName);
- if (ranges.length !== 1) {
+ if (ranges.length > 1) {
this.raiseError("Exactly one range should be specified in the testfile.");
}
- const range = ts.first(ranges);
+ const range = ts.firstOrUndefined(ranges);
const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => f.fixId === undefined); // TODO: GH#20315 filter out those that use the import fix ID;
@@ -2674,7 +2674,7 @@ Actual: ${stringify(fullActual)}`);
const change = ts.first(codeFix.changes);
ts.Debug.assert(change.fileName === fileName);
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
- const text = this.rangeText(range);
+ const text = range ? this.rangeText(range) : this.getFileContent(this.activeFile.fileName);
actualTextArray.push(text);
scriptInfo.updateContent(originalContent);
}
diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts
index 648ab77a922e9..d5ef90ff3ef1f 100644
--- a/src/services/textChanges.ts
+++ b/src/services/textChanges.ts
@@ -177,10 +177,10 @@ namespace ts.textChanges {
}
function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: ConfigurableEnd) {
+ const { end } = node;
if (options.useNonAdjustedEndPosition || isExpression(node)) {
- return node.getEnd();
+ return end;
}
- const end = node.getEnd();
const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true);
return newEnd !== end && isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))
? newEnd
@@ -466,7 +466,11 @@ namespace ts.textChanges {
}
}
const endPosition = getAdjustedEndPosition(sourceFile, after, {});
- return this.replaceRange(sourceFile, createTextRange(endPosition), newNode, this.getInsertNodeAfterOptions(after));
+ const options = this.getInsertNodeAfterOptions(after);
+ return this.replaceRange(sourceFile, createTextRange(endPosition), newNode, {
+ ...options,
+ prefix: after.end === sourceFile.end && isStatement(after) ? (options.prefix ? `\n${options.prefix}` : "\n") : options.prefix,
+ });
}
private getInsertNodeAfterOptions(node: Node): InsertNodeOptions {
diff --git a/tests/baselines/reference/textChanges/insertNodeAfter2.js b/tests/baselines/reference/textChanges/insertNodeAfter2.js
index fbd24e2b75e8e..47907322fe9d2 100644
--- a/tests/baselines/reference/textChanges/insertNodeAfter2.js
+++ b/tests/baselines/reference/textChanges/insertNodeAfter2.js
@@ -20,6 +20,7 @@ namespace M {
// comment 6
var a = 4; // comment 7
}
+
public class class1 implements interface1
{
property1: boolean;
diff --git a/tests/cases/fourslash/codeFixAddMissingMember5.ts b/tests/cases/fourslash/codeFixAddMissingMember5.ts
index 64a62b8268a4c..363a8e2b38e0d 100644
--- a/tests/cases/fourslash/codeFixAddMissingMember5.ts
+++ b/tests/cases/fourslash/codeFixAddMissingMember5.ts
@@ -18,6 +18,7 @@ verify.codeFix({
()=>{ this.foo === 10 };
}
}
+
C.foo = undefined;
`
});
diff --git a/tests/cases/fourslash/codeFixAddMissingMember7.ts b/tests/cases/fourslash/codeFixAddMissingMember7.ts
index 6b80901a7bbc6..95fbb4be18cba 100644
--- a/tests/cases/fourslash/codeFixAddMissingMember7.ts
+++ b/tests/cases/fourslash/codeFixAddMissingMember7.ts
@@ -14,6 +14,7 @@ verify.codeFix({
newFileContent: `class C {
static p = ()=>{ this.foo === 10 };
}
+
C.foo = undefined;
`
});
diff --git a/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts b/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts
index 417bf0bc9053d..07ca6ea70d65b 100644
--- a/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts
+++ b/tests/cases/fourslash/convertFunctionToEs6Class_commentOnVariableDeclaration.ts
@@ -8,7 +8,8 @@
verify.codeFix({
description: "Convert function to an ES2015 class",
newFileContent:
-`/** Doc */
+`
+/** Doc */
class C {
constructor() { this.x = 0; }
}
diff --git a/tests/cases/fourslash/importNameCodeFix_fileWithNoTrailingNewline.ts b/tests/cases/fourslash/importNameCodeFix_fileWithNoTrailingNewline.ts
new file mode 100644
index 0000000000000..89d6398a5538b
--- /dev/null
+++ b/tests/cases/fourslash/importNameCodeFix_fileWithNoTrailingNewline.ts
@@ -0,0 +1,19 @@
+///
+
+// @Filename: /a.ts
+////export const foo = 0;
+
+// @Filename: /b.ts
+////export const bar = 0;
+
+// @Filename: /c.ts
+////foo;
+////import { bar } from "./b";
+
+goTo.file("/c.ts");
+verify.importFixAtPosition([
+`foo;
+import { bar } from "./b";
+import { foo } from "./a";
+`,
+]);
diff --git a/tests/cases/fourslash/importNameCodeFix_jsExtension.ts b/tests/cases/fourslash/importNameCodeFix_jsExtension.ts
index 98c7c9e6cad28..e719f1aeee889 100644
--- a/tests/cases/fourslash/importNameCodeFix_jsExtension.ts
+++ b/tests/cases/fourslash/importNameCodeFix_jsExtension.ts
@@ -13,10 +13,13 @@
////import * as g from "global"; // Global imports skipped
////import { a } from "./a.js";
////import { a as a2 } from "./a"; // Ignored, only the first relative import is considered
-////[|b;|]
+////b;
goTo.file("/c.ts");
verify.importFixAtPosition([
-`import { b } from "./b.js";
+`import * as g from "global"; // Global imports skipped
+import { a } from "./a.js";
+import { a as a2 } from "./a"; // Ignored, only the first relative import is considered
+import { b } from "./b.js";
b;`,
]);
diff --git a/tests/cases/fourslash/importNameCodeFix_jsx.ts b/tests/cases/fourslash/importNameCodeFix_jsx.ts
index f16f1f1bd769c..5e09074ba1c75 100644
--- a/tests/cases/fourslash/importNameCodeFix_jsx.ts
+++ b/tests/cases/fourslash/importNameCodeFix_jsx.ts
@@ -13,11 +13,11 @@
// @Filename: /c.tsx
////import { React } from "react";
-////[|;|]
+////;
// @Filename: /d.tsx
-////[|import { Foo } from "./Foo";
-////;|]
+////import { Foo } from "./Foo";
+////;
// Tests that we don't crash at non-identifier location.
goTo.file("/a.tsx");
@@ -26,7 +26,8 @@ verify.importFixAtPosition([]);
// When constructor is missing, provide fix for that
goTo.file("/c.tsx");
verify.importFixAtPosition([
-`import { Foo } from "./Foo";
+`import { React } from "react";
+import { Foo } from "./Foo";
;`]);
// When JSX namespace is missing, provide fix for that