From 7c8646ef0fd703b44a6caa8f5693c860603a549d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 21 Mar 2022 15:54:51 -0400 Subject: [PATCH 1/4] fix: mark non-simple decorator expressions as parenthesized --- packages/babel-parser/src/parser/statement.js | 3 +- .../nested-class-decorator/output.json | 6 +- .../nested-method-decorator/output.json | 4 ++ .../decorators-2/parenthesized/input.js | 4 +- .../decorators-2/parenthesized/output.json | 66 +++++++++++++++++-- .../output.json | 6 +- .../output.json | 6 +- .../output.json | 6 +- .../output.json | 6 +- .../placeholders/class/decorators/output.json | 6 +- 10 files changed, 100 insertions(+), 13 deletions(-) diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 1ca7c1a5ef04..cf065a3a3932 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -539,9 +539,8 @@ export default class StatementParser extends ExpressionParser { const startLoc = this.state.startLoc; let expr: N.Expression; - if (this.eat(tt.parenL)) { + if (this.match(tt.parenL)) { expr = this.parseExpression(); - this.expect(tt.parenR); } else { expr = this.parseIdentifier(false); diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-class-decorator/output.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-class-decorator/output.json index d95e3a91918c..756131a8000a 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-class-decorator/output.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-class-decorator/output.json @@ -56,7 +56,11 @@ } } } - ] + ], + "extra": { + "parenthesized": true, + "parenStart": 1 + } } } ], diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-method-decorator/output.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-method-decorator/output.json index b3050a539249..dc418f4e3a94 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-method-decorator/output.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/nested-method-decorator/output.json @@ -81,6 +81,10 @@ } } ] + }, + "extra": { + "parenthesized": true, + "parenStart": 14 } } } diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js index 79f9aa697108..322f5e2e3446 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js @@ -3,4 +3,6 @@ class Foo { @(member[expression]) method() {} @(foo + bar) method2() {} -} \ No newline at end of file + + @(this).bar method3() {} +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json index c2b57d346967..9feb9f765a3d 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json @@ -1,15 +1,15 @@ { "type": "File", - "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":91}}, + "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, "program": { "type": "Program", - "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":91}}, + "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, "sourceType": "script", "interpreter": null, "body": [ { "type": "ClassDeclaration", - "start":0,"end":91,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":6,"column":1,"index":91}}, + "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, "decorators": [ { "type": "Decorator", @@ -32,6 +32,10 @@ "type": "Identifier", "start":8,"end":11,"loc":{"start":{"line":1,"column":8,"index":8},"end":{"line":1,"column":11,"index":11},"identifierName":"bar"}, "name": "bar" + }, + "extra": { + "parenthesized": true, + "parenStart": 1 } } } @@ -44,7 +48,7 @@ "superClass": null, "body": { "type": "ClassBody", - "start":23,"end":91,"loc":{"start":{"line":2,"column":10,"index":23},"end":{"line":6,"column":1,"index":91}}, + "start":23,"end":119,"loc":{"start":{"line":2,"column":10,"index":23},"end":{"line":8,"column":1,"index":119}}, "body": [ { "type": "ClassMethod", @@ -66,6 +70,10 @@ "type": "Identifier", "start":36,"end":46,"loc":{"start":{"line":3,"column":11,"index":36},"end":{"line":3,"column":21,"index":46},"identifierName":"expression"}, "name": "expression" + }, + "extra": { + "parenthesized": true, + "parenStart": 28 } } } @@ -109,6 +117,10 @@ "type": "Identifier", "start":72,"end":75,"loc":{"start":{"line":5,"column":10,"index":72},"end":{"line":5,"column":13,"index":75},"identifierName":"bar"}, "name": "bar" + }, + "extra": { + "parenthesized": true, + "parenStart": 65 } } } @@ -131,6 +143,52 @@ "body": [], "directives": [] } + }, + { + "type": "ClassMethod", + "start":93,"end":117,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":26,"index":117}}, + "decorators": [ + { + "type": "Decorator", + "start":93,"end":104,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":13,"index":104}}, + "expression": { + "type": "MemberExpression", + "start":94,"end":104,"loc":{"start":{"line":7,"column":3,"index":94},"end":{"line":7,"column":13,"index":104}}, + "object": { + "type": "ThisExpression", + "start":95,"end":99,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":8,"index":99}}, + "extra": { + "parenthesized": true, + "parenStart": 94 + } + }, + "computed": false, + "property": { + "type": "Identifier", + "start":101,"end":104,"loc":{"start":{"line":7,"column":10,"index":101},"end":{"line":7,"column":13,"index":104},"identifierName":"bar"}, + "name": "bar" + } + } + } + ], + "static": false, + "key": { + "type": "Identifier", + "start":105,"end":112,"loc":{"start":{"line":7,"column":14,"index":105},"end":{"line":7,"column":21,"index":112},"identifierName":"method3"}, + "name": "method3" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":115,"end":117,"loc":{"start":{"line":7,"column":24,"index":115},"end":{"line":7,"column":26,"index":117}}, + "body": [], + "directives": [] + } } ] } diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-identifier/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-identifier/output.json index 9cd91e15c027..54408c3fe6d0 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-identifier/output.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-identifier/output.json @@ -29,7 +29,11 @@ "expression": { "type": "Identifier", "start":11,"end":14,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":14,"index":14},"identifierName":"foo"}, - "name": "foo" + "name": "foo", + "extra": { + "parenthesized": true, + "parenStart": 10 + } } } ], diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-topic/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-topic/output.json index 1f8c51fdcca0..cf4c957c0729 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-topic/output.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-at-proposal-class-decorator-with-parenthesized-topic/output.json @@ -28,7 +28,11 @@ "start":9,"end":14,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":14,"index":14}}, "expression": { "type": "TopicReference", - "start":11,"end":13,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":13,"index":13}} + "start":11,"end":13,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":13,"index":13}}, + "extra": { + "parenthesized": true, + "parenStart": 10 + } } } ], diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-identifier/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-identifier/output.json index 9cd91e15c027..54408c3fe6d0 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-identifier/output.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-identifier/output.json @@ -29,7 +29,11 @@ "expression": { "type": "Identifier", "start":11,"end":14,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":14,"index":14},"identifierName":"foo"}, - "name": "foo" + "name": "foo", + "extra": { + "parenthesized": true, + "parenStart": 10 + } } } ], diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-topic/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-topic/output.json index 1f8c51fdcca0..cf4c957c0729 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-topic/output.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-double-caret-proposal-class-decorator-with-parenthesized-topic/output.json @@ -28,7 +28,11 @@ "start":9,"end":14,"loc":{"start":{"line":1,"column":9,"index":9},"end":{"line":1,"column":14,"index":14}}, "expression": { "type": "TopicReference", - "start":11,"end":13,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":13,"index":13}} + "start":11,"end":13,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":13,"index":13}}, + "extra": { + "parenthesized": true, + "parenStart": 10 + } } } ], diff --git a/packages/babel-parser/test/fixtures/placeholders/class/decorators/output.json b/packages/babel-parser/test/fixtures/placeholders/class/decorators/output.json index 0e81241ff555..ef4404a37fd4 100644 --- a/packages/babel-parser/test/fixtures/placeholders/class/decorators/output.json +++ b/packages/babel-parser/test/fixtures/placeholders/class/decorators/output.json @@ -22,7 +22,11 @@ "start":4,"end":7,"loc":{"start":{"line":1,"column":4,"index":4},"end":{"line":1,"column":7,"index":7},"identifierName":"FOO"}, "name": "FOO" }, - "expectedNode": "Expression" + "expectedNode": "Expression", + "extra": { + "parenthesized": true, + "parenStart": 1 + } } } ], From 102e4a23f9a9fbdf72913fbadca04fb764005960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 21 Mar 2022 16:04:17 -0400 Subject: [PATCH 2/4] fix: parenthesize non-simple decorator expression --- .../src/generators/expressions.ts | 38 ++++++++++++++++++- .../options.json | 6 ++- .../decorator-call-expression/input.js | 6 +++ .../decorator-call-expression/output.js | 6 +++ .../decorator-member-expression/input.js | 6 +++ .../decorator-member-expression/output.js | 6 +++ .../input.js | 30 +++++++++++++++ .../options.json | 5 +++ .../output.js | 32 ++++++++++++++++ .../input.js | 34 +++++++++++++++++ .../output.js | 36 ++++++++++++++++++ .../test/fixtures/decorators/options.json | 7 +--- 12 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-call-expression/input.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-call-expression/output.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-member-expression/input.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-member-expression/output.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/input.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/options.json create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/output.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/input.js create mode 100644 packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/output.js diff --git a/packages/babel-generator/src/generators/expressions.ts b/packages/babel-generator/src/generators/expressions.ts index a5bdc1e6b2a3..146c21113a36 100644 --- a/packages/babel-generator/src/generators/expressions.ts +++ b/packages/babel-generator/src/generators/expressions.ts @@ -113,9 +113,45 @@ export function Super(this: Printer) { this.word("super"); } +function isDecoratorMemberExpression( + node: t.Expression | t.V8IntrinsicIdentifier, +) { + switch (node.type) { + case "Identifier": + return true; + case "MemberExpression": + return ( + !node.computed && + node.property.type === "Identifier" && + isDecoratorMemberExpression(node.object) + ); + default: + return false; + } +} +function shouldParenthesizeDecoratorExpression( + node: t.Expression | t.V8IntrinsicIdentifier, +) { + if (node.type === "CallExpression") { + node = node.callee; + } + if (node.type === "ParenthesizedExpression") { + // We didn't check extra?.parenthesized here because we don't track decorators in needsParen + return false; + } + return !isDecoratorMemberExpression(node); +} + export function Decorator(this: Printer, node: t.Decorator) { this.token("@"); - this.print(node.expression, node); + const { expression } = node; + if (shouldParenthesizeDecoratorExpression(expression)) { + this.token("("); + this.print(expression, node); + this.token(")"); + } else { + this.print(expression, node); + } this.newline(); } diff --git a/packages/babel-generator/test/fixtures/decorators-legacy/ts-class-modifier-with-retainlines/options.json b/packages/babel-generator/test/fixtures/decorators-legacy/ts-class-modifier-with-retainlines/options.json index ab2bf8d8c808..e084a5f55dbf 100644 --- a/packages/babel-generator/test/fixtures/decorators-legacy/ts-class-modifier-with-retainlines/options.json +++ b/packages/babel-generator/test/fixtures/decorators-legacy/ts-class-modifier-with-retainlines/options.json @@ -1 +1,5 @@ -{ "plugins": ["classProperties", "decorators-legacy", "typescript"], "decoratorsBeforeExport": true, "retainLines": true } +{ + "plugins": ["decorators-legacy", "typescript"], + "decoratorsBeforeExport": true, + "retainLines": true +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/input.js b/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/input.js new file mode 100644 index 000000000000..9a4b711e3f86 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/input.js @@ -0,0 +1,6 @@ +class C { + @dec(0) + @globalThis.dec(0) + @(globalThis["dec"])(0) + p +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/output.js b/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/output.js new file mode 100644 index 000000000000..29da7bae2050 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-call-expression/output.js @@ -0,0 +1,6 @@ +class C { + @dec(0) + @globalThis.dec(0) + @(globalThis["dec"](0)) + p; +} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/input.js b/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/input.js new file mode 100644 index 000000000000..b2200c0546aa --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/input.js @@ -0,0 +1,6 @@ +class C { + @dec + @globalThis.dec + @globalThis.self.dec + p +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/output.js b/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/output.js new file mode 100644 index 000000000000..b975b0de24a7 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-member-expression/output.js @@ -0,0 +1,6 @@ +class C { + @dec + @globalThis.dec + @globalThis.self.dec + p; +} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/input.js b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/input.js new file mode 100644 index 000000000000..8cec169bc925 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/input.js @@ -0,0 +1,30 @@ +class C extends class {} { + #x; + constructor() { + class ShouldPreserveParens { + @(decs[0]) + @(decs`1`) + @(this?.two) + @(self.#x) + @(this.dec) + @(super.dec) + @(new DecFactory) + @(decs[three])() + p; + } + + class ShouldNotAddParens { + @decs + @decs.one + @decs.two() + p; + } + + class WillPreserveParens { + @(decs) + @(decs.one) + @(decs.two()) + p; + } + } +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/options.json b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/options.json new file mode 100644 index 000000000000..2c4e18802e58 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/options.json @@ -0,0 +1,5 @@ +{ + "plugins": [["decorators", { "decoratorsBeforeExport": false }]], + "decoratorsBeforeExport": true, + "parserOpts": { "createParenthesizedExpressions": true } +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/output.js b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/output.js new file mode 100644 index 000000000000..a3e2fb794feb --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression-createParenthesizedExpression/output.js @@ -0,0 +1,32 @@ +class C extends class {} { + #x; + + constructor() { + class ShouldPreserveParens { + @(decs[0]) + @(decs`1`) + @(this?.two) + @(self.#x) + @(this.dec) + @(super.dec) + @(new DecFactory()) + @(decs[three])() + p; + } + + class ShouldNotAddParens { + @decs + @decs.one + @decs.two() + p; + } + + class WillPreserveParens { + @(decs) + @(decs.one) + @(decs.two()) + p; + } + } + +} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/input.js b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/input.js new file mode 100644 index 000000000000..2681044f93ad --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/input.js @@ -0,0 +1,34 @@ +class C extends class {} { + #x; + constructor() { + class ShouldPreserveParens { + @(decs[0]) + @(decs`1`) + @(this?.two) + @(self.#x) + @(this.dec) + @(super.dec) + @(new DecFactory) + p; + } + + class ShouldNotAddParens { + @decs + @decs.one + @decs.two() + p; + } + + class ShouldAddParens { + @(decs[three])() + p; + } + + class ShouldRemoveParens { + @(decs) + @(decs.one) + @(decs.two()) + p; + } + } +} diff --git a/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/output.js b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/output.js new file mode 100644 index 000000000000..2c2780aee874 --- /dev/null +++ b/packages/babel-generator/test/fixtures/decorators/decorator-parenthesized-expression/output.js @@ -0,0 +1,36 @@ +class C extends class {} { + #x; + + constructor() { + class ShouldPreserveParens { + @(decs[0]) + @(decs`1`) + @(this?.two) + @(self.#x) + @(this.dec) + @(super.dec) + @(new DecFactory()) + p; + } + + class ShouldNotAddParens { + @decs + @decs.one + @decs.two() + p; + } + + class ShouldAddParens { + @(decs[three]()) + p; + } + + class ShouldRemoveParens { + @decs + @decs.one + @decs.two() + p; + } + } + +} \ No newline at end of file diff --git a/packages/babel-generator/test/fixtures/decorators/options.json b/packages/babel-generator/test/fixtures/decorators/options.json index a91f97747064..234fb2bac889 100644 --- a/packages/babel-generator/test/fixtures/decorators/options.json +++ b/packages/babel-generator/test/fixtures/decorators/options.json @@ -1,9 +1,4 @@ { - "plugins": [ - ["decorators", { "decoratorsBeforeExport": false }], - "classProperties", - "classPrivateProperties", - "classPrivateMethods" - ], + "plugins": [["decorators", { "decoratorsBeforeExport": false }]], "decoratorsBeforeExport": true } From dd5982dd33e865ed052d8b98e2f8dbe3b424c7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Mon, 21 Mar 2022 16:32:33 -0400 Subject: [PATCH 3/4] fix: handle parenthesis in parseDecorator --- .../babel-parser/src/parser/expression.js | 18 +++++-- packages/babel-parser/src/parser/statement.js | 5 ++ .../invalid-unparenthesized-arrow/input.js | 3 ++ .../options.json | 3 ++ .../decorators-2/parenthesized/input.js | 2 +- .../decorators-2/parenthesized/output.json | 49 ++++++++++++------- 6 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/options.json diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index a6318ef65905..1b58a874696e 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1770,21 +1770,29 @@ export default class ExpressionParser extends LValParser { val = exprList[0]; } + return this.wrapParenthesis(startPos, startLoc, val); + } + + wrapParenthesis( + startPos: number, + startLoc: Position, + expression: N.Expression, + ): N.Expression { if (!this.options.createParenthesizedExpressions) { - this.addExtra(val, "parenthesized", true); - this.addExtra(val, "parenStart", startPos); + this.addExtra(expression, "parenthesized", true); + this.addExtra(expression, "parenStart", startPos); this.takeSurroundingComments( - val, + expression, startPos, this.state.lastTokEndLoc.index, ); - return val; + return expression; } const parenExpression = this.startNodeAt(startPos, startLoc); - parenExpression.expression = val; + parenExpression.expression = expression; this.finishNode(parenExpression, "ParenthesizedExpression"); return parenExpression; } diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index cf065a3a3932..968c48261f76 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -540,7 +540,12 @@ export default class StatementParser extends ExpressionParser { let expr: N.Expression; if (this.match(tt.parenL)) { + const startPos = this.state.start; + const startLoc = this.state.startLoc; + this.next(); // eat '(' expr = this.parseExpression(); + this.expect(tt.parenR); + expr = this.wrapParenthesis(startPos, startLoc, expr); } else { expr = this.parseIdentifier(false); diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/input.js b/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/input.js new file mode 100644 index 000000000000..47c595e2795f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/input.js @@ -0,0 +1,3 @@ +class Foo { + @() => () => "bar" p; +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/options.json new file mode 100644 index 000000000000..b2f4797ad803 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/invalid-unparenthesized-arrow/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (2:4)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js index 322f5e2e3446..28509117bf29 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/input.js @@ -4,5 +4,5 @@ class Foo { @(foo + bar) method2() {} - @(this).bar method3() {} + @(this.foo)(bar) method3() {} } diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json index 9feb9f765a3d..0d826cdd1f1d 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized/output.json @@ -1,15 +1,15 @@ { "type": "File", - "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, "program": { "type": "Program", - "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, "sourceType": "script", "interpreter": null, "body": [ { "type": "ClassDeclaration", - "start":0,"end":119,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":119}}, + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, "decorators": [ { "type": "Decorator", @@ -48,7 +48,7 @@ "superClass": null, "body": { "type": "ClassBody", - "start":23,"end":119,"loc":{"start":{"line":2,"column":10,"index":23},"end":{"line":8,"column":1,"index":119}}, + "start":23,"end":124,"loc":{"start":{"line":2,"column":10,"index":23},"end":{"line":8,"column":1,"index":124}}, "body": [ { "type": "ClassMethod", @@ -146,35 +146,46 @@ }, { "type": "ClassMethod", - "start":93,"end":117,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":26,"index":117}}, + "start":93,"end":122,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":31,"index":122}}, "decorators": [ { "type": "Decorator", - "start":93,"end":104,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":13,"index":104}}, + "start":93,"end":109,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":18,"index":109}}, "expression": { - "type": "MemberExpression", - "start":94,"end":104,"loc":{"start":{"line":7,"column":3,"index":94},"end":{"line":7,"column":13,"index":104}}, - "object": { - "type": "ThisExpression", - "start":95,"end":99,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":8,"index":99}}, + "type": "CallExpression", + "start":95,"end":109,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":18,"index":109}}, + "callee": { + "type": "MemberExpression", + "start":95,"end":103,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":12,"index":103}}, + "object": { + "type": "ThisExpression", + "start":95,"end":99,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":8,"index":99}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":100,"end":103,"loc":{"start":{"line":7,"column":9,"index":100},"end":{"line":7,"column":12,"index":103},"identifierName":"foo"}, + "name": "foo" + }, "extra": { "parenthesized": true, "parenStart": 94 } }, - "computed": false, - "property": { - "type": "Identifier", - "start":101,"end":104,"loc":{"start":{"line":7,"column":10,"index":101},"end":{"line":7,"column":13,"index":104},"identifierName":"bar"}, - "name": "bar" - } + "arguments": [ + { + "type": "Identifier", + "start":105,"end":108,"loc":{"start":{"line":7,"column":14,"index":105},"end":{"line":7,"column":17,"index":108},"identifierName":"bar"}, + "name": "bar" + } + ] } } ], "static": false, "key": { "type": "Identifier", - "start":105,"end":112,"loc":{"start":{"line":7,"column":14,"index":105},"end":{"line":7,"column":21,"index":112},"identifierName":"method3"}, + "start":110,"end":117,"loc":{"start":{"line":7,"column":19,"index":110},"end":{"line":7,"column":26,"index":117},"identifierName":"method3"}, "name": "method3" }, "computed": false, @@ -185,7 +196,7 @@ "params": [], "body": { "type": "BlockStatement", - "start":115,"end":117,"loc":{"start":{"line":7,"column":24,"index":115},"end":{"line":7,"column":26,"index":117}}, + "start":120,"end":122,"loc":{"start":{"line":7,"column":29,"index":120},"end":{"line":7,"column":31,"index":122}}, "body": [], "directives": [] } From 5629da719ee469284b18ac902d325c4ceb3916f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 22 Mar 2022 13:55:01 -0400 Subject: [PATCH 4/4] add new test case --- .../input.js | 8 + .../options.json | 4 + .../output.json | 210 ++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/options.json create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/output.json diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/input.js b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/input.js new file mode 100644 index 000000000000..28509117bf29 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/input.js @@ -0,0 +1,8 @@ +@(foo().bar) +class Foo { + @(member[expression]) method() {} + + @(foo + bar) method2() {} + + @(this.foo)(bar) method3() {} +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/options.json new file mode 100644 index 000000000000..50270cedd0d4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["decorators", { "decoratorsBeforeExport": false }]], + "createParenthesizedExpressions": true +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/output.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/output.json new file mode 100644 index 000000000000..ba5245995c60 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/parenthesized-createParenthesizedExpressions/output.json @@ -0,0 +1,210 @@ +{ + "type": "File", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, + "program": { + "type": "Program", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":124,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":124}}, + "decorators": [ + { + "type": "Decorator", + "start":0,"end":12,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":12,"index":12}}, + "expression": { + "type": "ParenthesizedExpression", + "start":1,"end":12,"loc":{"start":{"line":1,"column":1,"index":1},"end":{"line":1,"column":12,"index":12}}, + "expression": { + "type": "MemberExpression", + "start":2,"end":11,"loc":{"start":{"line":1,"column":2,"index":2},"end":{"line":1,"column":11,"index":11}}, + "object": { + "type": "CallExpression", + "start":2,"end":7,"loc":{"start":{"line":1,"column":2,"index":2},"end":{"line":1,"column":7,"index":7}}, + "callee": { + "type": "Identifier", + "start":2,"end":5,"loc":{"start":{"line":1,"column":2,"index":2},"end":{"line":1,"column":5,"index":5},"identifierName":"foo"}, + "name": "foo" + }, + "arguments": [] + }, + "computed": false, + "property": { + "type": "Identifier", + "start":8,"end":11,"loc":{"start":{"line":1,"column":8,"index":8},"end":{"line":1,"column":11,"index":11},"identifierName":"bar"}, + "name": "bar" + } + } + } + } + ], + "id": { + "type": "Identifier", + "start":19,"end":22,"loc":{"start":{"line":2,"column":6,"index":19},"end":{"line":2,"column":9,"index":22},"identifierName":"Foo"}, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":23,"end":124,"loc":{"start":{"line":2,"column":10,"index":23},"end":{"line":8,"column":1,"index":124}}, + "body": [ + { + "type": "ClassMethod", + "start":27,"end":60,"loc":{"start":{"line":3,"column":2,"index":27},"end":{"line":3,"column":35,"index":60}}, + "decorators": [ + { + "type": "Decorator", + "start":27,"end":48,"loc":{"start":{"line":3,"column":2,"index":27},"end":{"line":3,"column":23,"index":48}}, + "expression": { + "type": "ParenthesizedExpression", + "start":28,"end":48,"loc":{"start":{"line":3,"column":3,"index":28},"end":{"line":3,"column":23,"index":48}}, + "expression": { + "type": "MemberExpression", + "start":29,"end":47,"loc":{"start":{"line":3,"column":4,"index":29},"end":{"line":3,"column":22,"index":47}}, + "object": { + "type": "Identifier", + "start":29,"end":35,"loc":{"start":{"line":3,"column":4,"index":29},"end":{"line":3,"column":10,"index":35},"identifierName":"member"}, + "name": "member" + }, + "computed": true, + "property": { + "type": "Identifier", + "start":36,"end":46,"loc":{"start":{"line":3,"column":11,"index":36},"end":{"line":3,"column":21,"index":46},"identifierName":"expression"}, + "name": "expression" + } + } + } + } + ], + "static": false, + "key": { + "type": "Identifier", + "start":49,"end":55,"loc":{"start":{"line":3,"column":24,"index":49},"end":{"line":3,"column":30,"index":55},"identifierName":"method"}, + "name": "method" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":58,"end":60,"loc":{"start":{"line":3,"column":33,"index":58},"end":{"line":3,"column":35,"index":60}}, + "body": [], + "directives": [] + } + }, + { + "type": "ClassMethod", + "start":64,"end":89,"loc":{"start":{"line":5,"column":2,"index":64},"end":{"line":5,"column":27,"index":89}}, + "decorators": [ + { + "type": "Decorator", + "start":64,"end":76,"loc":{"start":{"line":5,"column":2,"index":64},"end":{"line":5,"column":14,"index":76}}, + "expression": { + "type": "ParenthesizedExpression", + "start":65,"end":76,"loc":{"start":{"line":5,"column":3,"index":65},"end":{"line":5,"column":14,"index":76}}, + "expression": { + "type": "BinaryExpression", + "start":66,"end":75,"loc":{"start":{"line":5,"column":4,"index":66},"end":{"line":5,"column":13,"index":75}}, + "left": { + "type": "Identifier", + "start":66,"end":69,"loc":{"start":{"line":5,"column":4,"index":66},"end":{"line":5,"column":7,"index":69},"identifierName":"foo"}, + "name": "foo" + }, + "operator": "+", + "right": { + "type": "Identifier", + "start":72,"end":75,"loc":{"start":{"line":5,"column":10,"index":72},"end":{"line":5,"column":13,"index":75},"identifierName":"bar"}, + "name": "bar" + } + } + } + } + ], + "static": false, + "key": { + "type": "Identifier", + "start":77,"end":84,"loc":{"start":{"line":5,"column":15,"index":77},"end":{"line":5,"column":22,"index":84},"identifierName":"method2"}, + "name": "method2" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":87,"end":89,"loc":{"start":{"line":5,"column":25,"index":87},"end":{"line":5,"column":27,"index":89}}, + "body": [], + "directives": [] + } + }, + { + "type": "ClassMethod", + "start":93,"end":122,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":31,"index":122}}, + "decorators": [ + { + "type": "Decorator", + "start":93,"end":109,"loc":{"start":{"line":7,"column":2,"index":93},"end":{"line":7,"column":18,"index":109}}, + "expression": { + "type": "CallExpression", + "start":94,"end":109,"loc":{"start":{"line":7,"column":3,"index":94},"end":{"line":7,"column":18,"index":109}}, + "callee": { + "type": "ParenthesizedExpression", + "start":94,"end":104,"loc":{"start":{"line":7,"column":3,"index":94},"end":{"line":7,"column":13,"index":104}}, + "expression": { + "type": "MemberExpression", + "start":95,"end":103,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":12,"index":103}}, + "object": { + "type": "ThisExpression", + "start":95,"end":99,"loc":{"start":{"line":7,"column":4,"index":95},"end":{"line":7,"column":8,"index":99}} + }, + "computed": false, + "property": { + "type": "Identifier", + "start":100,"end":103,"loc":{"start":{"line":7,"column":9,"index":100},"end":{"line":7,"column":12,"index":103},"identifierName":"foo"}, + "name": "foo" + } + } + }, + "arguments": [ + { + "type": "Identifier", + "start":105,"end":108,"loc":{"start":{"line":7,"column":14,"index":105},"end":{"line":7,"column":17,"index":108},"identifierName":"bar"}, + "name": "bar" + } + ] + } + } + ], + "static": false, + "key": { + "type": "Identifier", + "start":110,"end":117,"loc":{"start":{"line":7,"column":19,"index":110},"end":{"line":7,"column":26,"index":117},"identifierName":"method3"}, + "name": "method3" + }, + "computed": false, + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":120,"end":122,"loc":{"start":{"line":7,"column":29,"index":120},"end":{"line":7,"column":31,"index":122}}, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +}