Skip to content

Commit 149803b

Browse files
author
Andy
authored
Fix bug: don't insert a semicolon when inserting a FunctionDeclaration (#23240) (#23289)
1 parent 0e0ecbc commit 149803b

File tree

7 files changed

+31
-7
lines changed

7 files changed

+31
-7
lines changed

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5399,6 +5399,10 @@ namespace ts {
53995399
|| kind === SyntaxKind.MissingDeclaration;
54005400
}
54015401

5402+
export function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement {
5403+
return isTypeElement(node) || isClassElement(node);
5404+
}
5405+
54025406
export function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike {
54035407
const kind = node.kind;
54045408
return kind === SyntaxKind.PropertyAssignment

src/services/textChanges.ts

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

431431
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node): this {
432-
if (isStatementButNotDeclaration(after) ||
433-
after.kind === SyntaxKind.PropertyDeclaration ||
434-
after.kind === SyntaxKind.PropertySignature ||
435-
after.kind === SyntaxKind.MethodSignature) {
432+
if (needSemicolonBetween(after, newNode)) {
436433
// check if previous statement ends with semicolon
437434
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
438435
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
@@ -453,7 +450,7 @@ namespace ts.textChanges {
453450
if (isClassDeclaration(node) || isModuleDeclaration(node)) {
454451
return { prefix: this.newLineCharacter, suffix: this.newLineCharacter };
455452
}
456-
else if (isStatement(node) || isClassElement(node) || isTypeElement(node)) {
453+
else if (isStatement(node) || isClassOrTypeElement(node)) {
457454
return { suffix: this.newLineCharacter };
458455
}
459456
else if (isVariableDeclaration(node)) {
@@ -904,4 +901,9 @@ namespace ts.textChanges {
904901
}
905902
}
906903
}
904+
905+
function needSemicolonBetween(a: Node, b: Node): boolean {
906+
return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) && b.name.kind === SyntaxKind.ComputedPropertyName
907+
|| isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[`
908+
}
907909
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,6 +3219,7 @@ declare namespace ts {
32193219
function isClassLike(node: Node): node is ClassLikeDeclaration;
32203220
function isAccessor(node: Node): node is AccessorDeclaration;
32213221
function isTypeElement(node: Node): node is TypeElement;
3222+
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
32223223
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
32233224
/**
32243225
* 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
@@ -3274,6 +3274,7 @@ declare namespace ts {
32743274
function isClassLike(node: Node): node is ClassLikeDeclaration;
32753275
function isAccessor(node: Node): node is AccessorDeclaration;
32763276
function isTypeElement(node: Node): node is TypeElement;
3277+
function isClassOrTypeElement(node: Node): node is ClassElement | TypeElement;
32773278
function isObjectLiteralElementLike(node: Node): node is ObjectLiteralElementLike;
32783279
/**
32793280
* 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)