Fix bug: don't insert a semicolon when inserting a FunctionDeclaration (#23240)

This commit is contained in:
Andy
2018-04-09 15:03:24 -07:00
committed by GitHub
parent 83ab341531
commit ce5d22fef0
8 changed files with 32 additions and 8 deletions

View File

@@ -5629,6 +5629,10 @@ namespace ts {
|| kind === SyntaxKind.MissingDeclaration;
}
export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {
return isTypeElement(node) || isClassElement(node);
}
export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike {
const kind = node.kind;
return kind === SyntaxKind.PropertyAssignment

View File

@@ -2248,7 +2248,7 @@ namespace ts.Completions {
// TODO: GH#19856 Would like to return `node is Node & { parent: (ClassElement | TypeElement) & { parent: ObjectTypeDeclaration } }` but then compilation takes > 10 minutes
function isFromObjectTypeDeclaration(node: Node): boolean {
return node.parent && (isClassElement(node.parent) || isTypeElement(node.parent)) && isObjectTypeDeclaration(node.parent.parent);
return node.parent && isClassOrTypeElement(node.parent) && isObjectTypeDeclaration(node.parent.parent);
}
function hasIndexSignature(type: Type): boolean {

View File

@@ -447,10 +447,7 @@ namespace ts.textChanges {
}
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node): this {
if (isStatementButNotDeclaration(after) ||
after.kind === SyntaxKind.PropertyDeclaration ||
after.kind === SyntaxKind.PropertySignature ||
after.kind === SyntaxKind.MethodSignature) {
if (needSemicolonBetween(after, newNode)) {
// check if previous statement ends with semicolon
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
@@ -465,7 +462,7 @@ namespace ts.textChanges {
if (isClassDeclaration(node) || isModuleDeclaration(node)) {
return { prefix: this.newLineCharacter, suffix: this.newLineCharacter };
}
else if (isStatement(node) || isClassElement(node) || isTypeElement(node)) {
else if (isStatement(node) || isClassOrTypeElement(node)) {
return { suffix: this.newLineCharacter };
}
else if (isVariableDeclaration(node)) {
@@ -893,4 +890,9 @@ namespace ts.textChanges {
export function isValidLocationToAddComment(sourceFile: SourceFile, position: number) {
return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position);
}
function needSemicolonBetween(a: Node, b: Node): boolean {
return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) && b.name.kind === SyntaxKind.ComputedPropertyName
|| isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[`
}
}

View File

@@ -3247,6 +3247,7 @@ declare namespace ts {
function isClassLike(node: Node): node is ClassLikeDeclaration;
function isAccessor(node: Node): node is AccessorDeclaration;
function isTypeElement(node: Node): node is TypeElement;
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
/**
* Node test that determines whether a node is a valid type node.

View File

@@ -3302,6 +3302,7 @@ declare namespace ts {
function isClassLike(node: Node): node is ClassLikeDeclaration;
function isAccessor(node: Node): node is AccessorDeclaration;
function isTypeElement(node: Node): node is TypeElement;
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
/**
* Node test that determines whether a node is a valid type node.

View File

@@ -7,6 +7,6 @@ class A {
===MODIFIED===
class A {
x;
x
a: boolean;
}

View File

@@ -7,6 +7,6 @@ interface A {
===MODIFIED===
interface A {
x();
x()
[1]: any;
}

View File

@@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////var C = function() { this.x = 0; }
////0;
verify.codeFix({
description: "Convert function to an ES2015 class",
newFileContent:
`class C {
constructor() { this.x = 0; }
}
0;`,
});