In insertNodeAfter, handle file with no trailing newline (#23814)

This commit is contained in:
Andy 2018-05-03 12:58:42 -07:00 committed by GitHub
parent 94d94f6335
commit bad3a44bb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 44 additions and 13 deletions

View file

@ -2662,10 +2662,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;
@ -2684,7 +2684,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);
}

View file

@ -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 {

View file

@ -20,6 +20,7 @@ namespace M {
// comment 6
var a = 4; // comment 7
}
public class class1 implements interface1
{
property1: boolean;

View file

@ -18,6 +18,7 @@ verify.codeFix({
()=>{ this.foo === 10 };
}
}
C.foo = undefined;
`
});

View file

@ -14,6 +14,7 @@ verify.codeFix({
newFileContent: `class C {
static p = ()=>{ this.foo === 10 };
}
C.foo = undefined;
`
});

View file

@ -8,7 +8,8 @@
verify.codeFix({
description: "Convert function to an ES2015 class",
newFileContent:
`/** Doc */
`
/** Doc */
class C {
constructor() { this.x = 0; }
}

View file

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
// @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";
`,
]);

View file

@ -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;`,
]);

View file

@ -13,11 +13,11 @@
// @Filename: /c.tsx
////import { React } from "react";
////[|<Foo />;|]
////<Foo />;
// @Filename: /d.tsx
////[|import { Foo } from "./Foo";
////<Foo />;|]
////import { Foo } from "./Foo";
////<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";
<Foo />;`]);
// When JSX namespace is missing, provide fix for that