Skip to content

Commit 162446f

Browse files
author
Andy Hanson
committed
Fix bug: don't insert a semicolon when inserting a FunctionDeclaration
1 parent c466a45 commit 162446f

File tree

8 files changed

+32
-8
lines changed

8 files changed

+32
-8
lines changed

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5618,6 +5618,10 @@ namespace ts {
56185618
|| kind === SyntaxKind.MissingDeclaration;
56195619
}
56205620

5621+
export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {
5622+
return isTypeElement(node) || isClassElement(node);
5623+
}
5624+
56215625
export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike {
56225626
const kind = node.kind;
56235627
return kind === SyntaxKind.PropertyAssignment

src/services/completions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2248,7 +2248,7 @@ namespace ts.Completions {
22482248

22492249
// TODO: GH#19856 Would like to return `node is Node & { parent: (ClassElement | TypeElement) & { parent: ObjectTypeDeclaration } }` but then compilation takes > 10 minutes
22502250
function isFromObjectTypeDeclaration(node: Node): boolean {
2251-
return node.parent && (isClassElement(node.parent) || isTypeElement(node.parent)) && isObjectTypeDeclaration(node.parent.parent);
2251+
return node.parent && isClassOrTypeElement(node.parent) && isObjectTypeDeclaration(node.parent.parent);
22522252
}
22532253

22542254
function hasIndexSignature(type: Type): boolean {

src/services/textChanges.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,7 @@ namespace ts.textChanges {
447447
}
448448

449449
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node): this {
450-
if (isStatementButNotDeclaration(after) ||
451-
after.kind === SyntaxKind.PropertyDeclaration ||
452-
after.kind === SyntaxKind.PropertySignature ||
453-
after.kind === SyntaxKind.MethodSignature) {
450+
if (needSemicolonBetween(after, newNode)) {
454451
// check if previous statement ends with semicolon
455452
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
456453
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
@@ -465,7 +462,7 @@ namespace ts.textChanges {
465462
if (isClassDeclaration(node) || isModuleDeclaration(node)) {
466463
return { prefix: this.newLineCharacter, suffix: this.newLineCharacter };
467464
}
468-
else if (isStatement(node) || isClassElement(node) || isTypeElement(node)) {
465+
else if (isStatement(node) || isClassOrTypeElement(node)) {
469466
return { suffix: this.newLineCharacter };
470467
}
471468
else if (isVariableDeclaration(node)) {
@@ -893,4 +890,9 @@ namespace ts.textChanges {
893890
export function isValidLocationToAddComment(sourceFile: SourceFile, position: number) {
894891
return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position);
895892
}
893+
894+
function needSemicolonBetween(a: Node, b: Node): boolean {
895+
return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) && b.name.kind === SyntaxKind.ComputedPropertyName
896+
|| isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[`
897+
}
896898
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,6 +3243,7 @@ declare namespace ts {
32433243
function isClassLike(node: Node): node is ClassLikeDeclaration;
32443244
function isAccessor(node: Node): node is AccessorDeclaration;
32453245
function isTypeElement(node: Node): node is TypeElement;
3246+
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
32463247
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
32473248
/**
32483249
* Node test that determines whether a node is a valid type node.

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3298,6 +3298,7 @@ declare namespace ts {
32983298
function isClassLike(node: Node): node is ClassLikeDeclaration;
32993299
function isAccessor(node: Node): node is AccessorDeclaration;
33003300
function isTypeElement(node: Node): node is TypeElement;
3301+
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
33013302
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
33023303
/**
33033304
* Node test that determines whether a node is a valid type node.

tests/baselines/reference/textChanges/insertNodeAfterInClass1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ class A {
77
===MODIFIED===
88

99
class A {
10-
x;
10+
x
1111
a: boolean;
1212
}

tests/baselines/reference/textChanges/insertNodeInInterfaceAfterNodeWithoutSeparator2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ interface A {
77
===MODIFIED===
88

99
interface A {
10-
x();
10+
x()
1111
[1]: any;
1212
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowJs: true
4+
5+
// @Filename: /a.js
6+
////var C = function() { this.x = 0; }
7+
////0;
8+
9+
verify.codeFix({
10+
description: "Convert function to an ES2015 class",
11+
newFileContent:
12+
`class C {
13+
constructor() { this.x = 0; }
14+
}
15+
0;`,
16+
});

0 commit comments

Comments
 (0)