Parse static blocks with typescript plugin (#13243)

* Support static blocks with typescript

* Add tests

* Reuse isStatic var

* Disallow parsing static blocks with modifiers

* Add tests

* Raise recoverable errors

* Address review

* Add tests for static static {}
This commit is contained in:
Sosuke Suzuki 2021-05-04 05:17:08 +09:00 committed by GitHub
parent 175a51f94e
commit ef87648f3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 565 additions and 12 deletions

View File

@ -131,6 +131,8 @@ const TSErrors = makeErrorTemplates(
"A 'set' accessor cannot have rest parameter.", "A 'set' accessor cannot have rest parameter.",
SetAccesorCannotHaveReturnType: SetAccesorCannotHaveReturnType:
"A 'set' accessor cannot have a return type annotation.", "A 'set' accessor cannot have a return type annotation.",
StaticBlockCannotHaveModifier:
"Static class blocks cannot have any modifier.",
TypeAnnotationAfterAssign: TypeAnnotationAfterAssign:
"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.",
TypeImportCannotSpecifyDefaultAndNamed: TypeImportCannotSpecifyDefaultAndNamed:
@ -2317,34 +2319,49 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.tsParseModifier(["public", "protected", "private"]); return this.tsParseModifier(["public", "protected", "private"]);
} }
tsHasSomeModifiers(member: any, modifiers: TsModifier[]): boolean {
return modifiers.some(modifier => {
if (tsIsAccessModifier(modifier)) {
return member.accessibility === modifier;
}
return !!member[modifier];
});
}
parseClassMember( parseClassMember(
classBody: N.ClassBody, classBody: N.ClassBody,
member: any, member: any,
state: N.ParseClassMemberState, state: N.ParseClassMemberState,
): void { ): void {
this.tsParseModifiers(member, [ const invalidModifersForStaticBlocks = [
"declare", "declare",
"private", "private",
"public", "public",
"protected", "protected",
"override", "override",
"static",
"abstract", "abstract",
"readonly", "readonly",
]); ];
this.tsParseModifiers(
member,
invalidModifersForStaticBlocks.concat(["static"]),
);
const callParseClassMember = () => { const callParseClassMemberWithIsStatic = () => {
this.parseClassMemberWithIsStatic( const isStatic = !!member.static;
classBody, if (isStatic && this.eat(tt.braceL)) {
member, if (this.tsHasSomeModifiers(member, invalidModifersForStaticBlocks)) {
state, this.raise(this.state.pos, TSErrors.StaticBlockCannotHaveModifier);
!!member.static, }
); this.parseClassStaticBlock(classBody, ((member: any): N.StaticBlock));
} else {
this.parseClassMemberWithIsStatic(classBody, member, state, isStatic);
}
}; };
if (member.declare) { if (member.declare) {
this.tsInAmbientContext(callParseClassMember); this.tsInAmbientContext(callParseClassMemberWithIsStatic);
} else { } else {
callParseClassMember(); callParseClassMemberWithIsStatic();
} }
} }

View File

@ -0,0 +1,3 @@
class Foo {
static private {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'private' modifier must precede 'static' modifier. (2:9)",
"SyntaxError: Static class blocks cannot have any modifier. (2:19)"
],
"program": {
"type": "Program",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":33,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":31,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":19}},
"static": true,
"accessibility": "private",
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
static protected {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'protected' modifier must precede 'static' modifier. (2:9)",
"SyntaxError: Static class blocks cannot have any modifier. (2:21)"
],
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":35,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":21}},
"static": true,
"accessibility": "protected",
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
static public {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'public' modifier must precede 'static' modifier. (2:9)",
"SyntaxError: Static class blocks cannot have any modifier. (2:18)"
],
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":32,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
"static": true,
"accessibility": "public",
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
abstract static {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'static' modifier cannot be used with 'abstract' modifier. (2:11)",
"SyntaxError: Static class blocks cannot have any modifier. (2:20)"
],
"program": {
"type": "Program",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":34,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":32,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":20}},
"abstract": true,
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
override static {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'static' modifier must precede 'override' modifier. (2:11)",
"SyntaxError: Static class blocks cannot have any modifier. (2:20)"
],
"program": {
"type": "Program",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":34,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":32,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":20}},
"override": true,
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
static static {}
}

View File

@ -0,0 +1,38 @@
{
"type": "File",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: Duplicate modifier: 'static'. (2:9)"
],
"program": {
"type": "Program",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":32,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
declare static {}
}

View File

@ -0,0 +1,39 @@
{
"type": "File",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: Static class blocks cannot have any modifier. (2:19)"
],
"program": {
"type": "Program",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":33,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":31,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":19}},
"declare": true,
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
readonly static {}
}

View File

@ -0,0 +1,40 @@
{
"type": "File",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'static' modifier must precede 'readonly' modifier. (2:11)",
"SyntaxError: Static class blocks cannot have any modifier. (2:20)"
],
"program": {
"type": "Program",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":34,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":34,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":32,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":20}},
"readonly": true,
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,4 @@
{
"plugins": ["classStaticBlock", "typescript"],
"sourceType": "module"
}

View File

@ -0,0 +1,4 @@
class Foo {
static;
static {}
}

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":35,"loc":{"start":{"line":1,"column":10},"end":{"line":4,"column":1}},
"body": [
{
"type": "ClassProperty",
"start":14,"end":21,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":9}},
"static": false,
"key": {
"type": "Identifier",
"start":14,"end":20,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":8},"identifierName":"static"},
"name": "static"
},
"computed": false,
"value": null
},
{
"type": "StaticBlock",
"start":24,"end":33,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}},
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,4 @@
class Foo {
static static;
static {}
}

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"program": {
"type": "Program",
"start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":42,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":42,"loc":{"start":{"line":1,"column":10},"end":{"line":4,"column":1}},
"body": [
{
"type": "ClassProperty",
"start":14,"end":28,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":16}},
"static": true,
"key": {
"type": "Identifier",
"start":21,"end":27,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":15},"identifierName":"static"},
"name": "static"
},
"computed": false,
"value": null
},
{
"type": "StaticBlock",
"start":31,"end":40,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}},
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,4 @@
class Foo {
static foo;
static {}
}

View File

@ -0,0 +1,47 @@
{
"type": "File",
"start":0,"end":39,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"program": {
"type": "Program",
"start":0,"end":39,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":39,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":39,"loc":{"start":{"line":1,"column":10},"end":{"line":4,"column":1}},
"body": [
{
"type": "ClassProperty",
"start":14,"end":25,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13}},
"static": true,
"key": {
"type": "Identifier",
"start":21,"end":24,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":12},"identifierName":"foo"},
"name": "foo"
},
"computed": false,
"value": null
},
{
"type": "StaticBlock",
"start":28,"end":37,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}},
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class Foo {
static {}
}

View File

@ -0,0 +1,35 @@
{
"type": "File",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"program": {
"type": "Program",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":6,"end":9,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":9},"identifierName":"Foo"},
"name": "Foo"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":10,"end":25,"loc":{"start":{"line":1,"column":10},"end":{"line":3,"column":1}},
"body": [
{
"type": "StaticBlock",
"start":14,"end":23,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":11}},
"static": true,
"body": []
}
]
}
}
],
"directives": []
}
}