diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index ef3e4b4f349a..5251d5c299d8 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -60,6 +60,8 @@ type ParsingContext = | "TypeParametersOrArguments"; const TSErrors = Object.freeze({ + AbstractMethodHasImplementation: + "Method '%0' cannot have an implementation because it is marked abstract.", ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier", ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier", ConstructorHasTypeParameters: @@ -2933,4 +2935,24 @@ export default (superClass: Class): Class => this.unexpected(null, tt._class); } } + + parseMethod(...args: any[]) { + const method = super.parseMethod(...args); + if (method.abstract) { + const hasBody = this.hasPlugin("estree") + ? !!method.value.body + : !!method.body; + if (hasBody) { + const { key } = method; + this.raise( + method.start, + TSErrors.AbstractMethodHasImplementation, + key.type === "Identifier" + ? key.name + : `[${this.input.slice(key.start, key.end)}]`, + ); + } + } + return method; + } }; diff --git a/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/input.ts b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/input.ts new file mode 100644 index 000000000000..c1c84cdba8ef --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/input.ts @@ -0,0 +1,3 @@ +abstract class Foo { + abstract [foo()]() {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/output.json b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/output.json new file mode 100644 index 000000000000..35955f48a99a --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body-computed/output.json @@ -0,0 +1,61 @@ +{ + "type": "File", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: Method '[foo()]' cannot have an implementation because it is marked abstract. (2:2)" + ], + "program": { + "type": "Program", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "abstract": true, + "id": { + "type": "Identifier", + "start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":19,"end":46,"loc":{"start":{"line":1,"column":19},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":23,"end":44,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":23}}, + "abstract": true, + "static": false, + "computed": true, + "key": { + "type": "CallExpression", + "start":33,"end":38,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":17}}, + "callee": { + "type": "Identifier", + "start":33,"end":36,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":15},"identifierName":"foo"}, + "name": "foo" + }, + "arguments": [] + }, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":42,"end":44,"loc":{"start":{"line":2,"column":21},"end":{"line":2,"column":23}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/input.ts b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/input.ts new file mode 100644 index 000000000000..4dc8ad00a5ee --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/input.ts @@ -0,0 +1,3 @@ +abstract class Foo { + abstract method() {} +} diff --git a/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/output.json b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/output.json new file mode 100644 index 000000000000..27e781a2b908 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/class/abstract-method-with-body/output.json @@ -0,0 +1,56 @@ +{ + "type": "File", + "start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: Method 'method' cannot have an implementation because it is marked abstract. (2:2)" + ], + "program": { + "type": "Program", + "start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "abstract": true, + "id": { + "type": "Identifier", + "start":15,"end":18,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":18},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":19,"end":45,"loc":{"start":{"line":1,"column":19},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassMethod", + "start":23,"end":43,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":22}}, + "abstract": true, + "static": false, + "key": { + "type": "Identifier", + "start":32,"end":38,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":17},"identifierName":"method"}, + "name": "method" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":41,"end":43,"loc":{"start":{"line":2,"column":20},"end":{"line":2,"column":22}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/output.json b/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/output.json index 3fa9f58447d7..cb1e08d842ba 100644 --- a/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/output.json +++ b/packages/babel-parser/test/fixtures/typescript/class/generator-method-with-modifiers/output.json @@ -2,7 +2,8 @@ "type": "File", "start":0,"end":139,"loc":{"start":{"line":1,"column":0},"end":{"line":9,"column":1}}, "errors": [ - "SyntaxError: Abstract methods can only appear within an abstract class. (5:2)" + "SyntaxError: Abstract methods can only appear within an abstract class. (5:2)", + "SyntaxError: Method 'd' cannot have an implementation because it is marked abstract. (5:2)" ], "program": { "type": "Program",