Skip to content

Commit 4ecf4f4

Browse files
committed
Merge pull request microsoft#5086 from Microsoft/abstract-semicolon-insertion
Automatic semicolon insertion for class modifiers
2 parents 1e3125b + be9548a commit 4ecf4f4

12 files changed

Lines changed: 309 additions & 35 deletions

src/compiler/parser.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ namespace ts {
856856
let saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
857857

858858
// Note: it is not actually necessary to save/restore the context flags here. That's
859-
// because the saving/restorating of these flags happens naturally through the recursive
859+
// because the saving/restoring of these flags happens naturally through the recursive
860860
// descent nature of our parser. However, we still store this here just so we can
861861
// assert that that invariant holds.
862862
let saveContextFlags = contextFlags;
@@ -1124,7 +1124,15 @@ namespace ts {
11241124
if (token === SyntaxKind.DefaultKeyword) {
11251125
return nextTokenIsClassOrFunction();
11261126
}
1127+
if (token === SyntaxKind.StaticKeyword) {
1128+
nextToken();
1129+
return canFollowModifier();
1130+
}
1131+
11271132
nextToken();
1133+
if (scanner.hasPrecedingLineBreak()) {
1134+
return false;
1135+
}
11281136
return canFollowModifier();
11291137
}
11301138

@@ -4157,8 +4165,12 @@ namespace ts {
41574165
case SyntaxKind.ModuleKeyword:
41584166
case SyntaxKind.NamespaceKeyword:
41594167
return nextTokenIsIdentifierOrStringLiteralOnSameLine();
4168+
case SyntaxKind.AbstractKeyword:
41604169
case SyntaxKind.AsyncKeyword:
41614170
case SyntaxKind.DeclareKeyword:
4171+
case SyntaxKind.PrivateKeyword:
4172+
case SyntaxKind.ProtectedKeyword:
4173+
case SyntaxKind.PublicKeyword:
41624174
nextToken();
41634175
// ASI takes effect for this modifier.
41644176
if (scanner.hasPrecedingLineBreak()) {
@@ -4178,11 +4190,7 @@ namespace ts {
41784190
}
41794191
continue;
41804192

4181-
case SyntaxKind.PublicKeyword:
4182-
case SyntaxKind.PrivateKeyword:
4183-
case SyntaxKind.ProtectedKeyword:
41844193
case SyntaxKind.StaticKeyword:
4185-
case SyntaxKind.AbstractKeyword:
41864194
nextToken();
41874195
continue;
41884196
default:

src/services/services.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3683,14 +3683,20 @@ namespace ts {
36833683

36843684
// Previous token may have been a keyword that was converted to an identifier.
36853685
switch (contextToken.getText()) {
3686+
case "abstract":
3687+
case "async":
36863688
case "class":
3687-
case "interface":
3689+
case "const":
3690+
case "declare":
36883691
case "enum":
36893692
case "function":
3690-
case "var":
3691-
case "static":
3693+
case "interface":
36923694
case "let":
3693-
case "const":
3695+
case "private":
3696+
case "protected":
3697+
case "public":
3698+
case "static":
3699+
case "var":
36943700
case "yield":
36953701
return true;
36963702
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
tests/cases/compiler/asiAbstract.ts(1,1): error TS2304: Cannot find name 'abstract'.
2+
tests/cases/compiler/asiAbstract.ts(3,3): error TS1244: Abstract methods can only appear within an abstract class.
3+
4+
5+
==== tests/cases/compiler/asiAbstract.ts (2 errors) ====
6+
abstract
7+
~~~~~~~~
8+
!!! error TS2304: Cannot find name 'abstract'.
9+
class NonAbstractClass {
10+
abstract s();
11+
~~~~~~~~
12+
!!! error TS1244: Abstract methods can only appear within an abstract class.
13+
}
14+
15+
class C2 {
16+
abstract
17+
nonAbstractFunction() {
18+
}
19+
}
20+
21+
class C3 {
22+
abstract
23+
}
24+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [asiAbstract.ts]
2+
abstract
3+
class NonAbstractClass {
4+
abstract s();
5+
}
6+
7+
class C2 {
8+
abstract
9+
nonAbstractFunction() {
10+
}
11+
}
12+
13+
class C3 {
14+
abstract
15+
}
16+
17+
18+
//// [asiAbstract.js]
19+
abstract;
20+
var NonAbstractClass = (function () {
21+
function NonAbstractClass() {
22+
}
23+
return NonAbstractClass;
24+
})();
25+
var C2 = (function () {
26+
function C2() {
27+
}
28+
C2.prototype.nonAbstractFunction = function () {
29+
};
30+
return C2;
31+
})();
32+
var C3 = (function () {
33+
function C3() {
34+
}
35+
return C3;
36+
})();
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
tests/cases/compiler/asiPublicPrivateProtected.ts(1,1): error TS2304: Cannot find name 'public'.
2+
tests/cases/compiler/asiPublicPrivateProtected.ts(12,1): error TS2304: Cannot find name 'private'.
3+
tests/cases/compiler/asiPublicPrivateProtected.ts(23,1): error TS2304: Cannot find name 'protected'.
4+
5+
6+
==== tests/cases/compiler/asiPublicPrivateProtected.ts (3 errors) ====
7+
public
8+
~~~~~~
9+
!!! error TS2304: Cannot find name 'public'.
10+
class NonPublicClass {
11+
public s() {
12+
}
13+
}
14+
15+
class NonPublicClass2 {
16+
public
17+
private nonPublicFunction() {
18+
}
19+
}
20+
private
21+
~~~~~~~
22+
!!! error TS2304: Cannot find name 'private'.
23+
class NonPrivateClass {
24+
private s() {
25+
}
26+
}
27+
28+
class NonPrivateClass2 {
29+
private
30+
public nonPrivateFunction() {
31+
}
32+
}
33+
protected
34+
~~~~~~~~~
35+
!!! error TS2304: Cannot find name 'protected'.
36+
class NonProtectedClass {
37+
protected s() {
38+
}
39+
}
40+
41+
class NonProtectedClass2 {
42+
protected
43+
public nonProtectedFunction() {
44+
}
45+
}
46+
47+
class ClassWithThreeMembers {
48+
public
49+
private
50+
protected
51+
}
52+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//// [asiPublicPrivateProtected.ts]
2+
public
3+
class NonPublicClass {
4+
public s() {
5+
}
6+
}
7+
8+
class NonPublicClass2 {
9+
public
10+
private nonPublicFunction() {
11+
}
12+
}
13+
private
14+
class NonPrivateClass {
15+
private s() {
16+
}
17+
}
18+
19+
class NonPrivateClass2 {
20+
private
21+
public nonPrivateFunction() {
22+
}
23+
}
24+
protected
25+
class NonProtectedClass {
26+
protected s() {
27+
}
28+
}
29+
30+
class NonProtectedClass2 {
31+
protected
32+
public nonProtectedFunction() {
33+
}
34+
}
35+
36+
class ClassWithThreeMembers {
37+
public
38+
private
39+
protected
40+
}
41+
42+
43+
//// [asiPublicPrivateProtected.js]
44+
public;
45+
var NonPublicClass = (function () {
46+
function NonPublicClass() {
47+
}
48+
NonPublicClass.prototype.s = function () {
49+
};
50+
return NonPublicClass;
51+
})();
52+
var NonPublicClass2 = (function () {
53+
function NonPublicClass2() {
54+
}
55+
NonPublicClass2.prototype.nonPublicFunction = function () {
56+
};
57+
return NonPublicClass2;
58+
})();
59+
private;
60+
var NonPrivateClass = (function () {
61+
function NonPrivateClass() {
62+
}
63+
NonPrivateClass.prototype.s = function () {
64+
};
65+
return NonPrivateClass;
66+
})();
67+
var NonPrivateClass2 = (function () {
68+
function NonPrivateClass2() {
69+
}
70+
NonPrivateClass2.prototype.nonPrivateFunction = function () {
71+
};
72+
return NonPrivateClass2;
73+
})();
74+
protected;
75+
var NonProtectedClass = (function () {
76+
function NonProtectedClass() {
77+
}
78+
NonProtectedClass.prototype.s = function () {
79+
};
80+
return NonProtectedClass;
81+
})();
82+
var NonProtectedClass2 = (function () {
83+
function NonProtectedClass2() {
84+
}
85+
NonProtectedClass2.prototype.nonProtectedFunction = function () {
86+
};
87+
return NonProtectedClass2;
88+
})();
89+
var ClassWithThreeMembers = (function () {
90+
function ClassWithThreeMembers() {
91+
}
92+
return ClassWithThreeMembers;
93+
})();

tests/baselines/reference/classAbstractMultiLineDecl.errors.txt

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSingleLineDecl.ts(3,1): error TS2304: Cannot find name 'abstract'.
2+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSingleLineDecl.ts(6,1): error TS2304: Cannot find name 'abstract'.
3+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSingleLineDecl.ts(10,1): error TS2511: Cannot create an instance of the abstract class 'A'.
4+
5+
6+
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractSingleLineDecl.ts (3 errors) ====
7+
abstract class A {}
8+
9+
abstract
10+
~~~~~~~~
11+
!!! error TS2304: Cannot find name 'abstract'.
12+
class B {}
13+
14+
abstract
15+
~~~~~~~~
16+
!!! error TS2304: Cannot find name 'abstract'.
17+
18+
class C {}
19+
20+
new A;
21+
~~~~~
22+
!!! error TS2511: Cannot create an instance of the abstract class 'A'.
23+
new B;
24+
new C;

tests/baselines/reference/classAbstractMultiLineDecl.js renamed to tests/baselines/reference/classAbstractSingleLineDecl.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//// [classAbstractMultiLineDecl.ts]
1+
//// [classAbstractSingleLineDecl.ts]
22
abstract class A {}
33

44
abstract
@@ -12,17 +12,19 @@ new A;
1212
new B;
1313
new C;
1414

15-
//// [classAbstractMultiLineDecl.js]
15+
//// [classAbstractSingleLineDecl.js]
1616
var A = (function () {
1717
function A() {
1818
}
1919
return A;
2020
})();
21+
abstract;
2122
var B = (function () {
2223
function B() {
2324
}
2425
return B;
2526
})();
27+
abstract;
2628
var C = (function () {
2729
function C() {
2830
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
abstract
2+
class NonAbstractClass {
3+
abstract s();
4+
}
5+
6+
class C2 {
7+
abstract
8+
nonAbstractFunction() {
9+
}
10+
}
11+
12+
class C3 {
13+
abstract
14+
}

0 commit comments

Comments
 (0)