From b33823e7f8223143714523de6059a02136aeaccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 23 May 2018 21:26:35 +0200 Subject: [PATCH] Better error message for invalid decorators syntax (#7986) --- packages/babel-parser/src/parser/statement.js | 39 +++++++++++-------- .../options.json | 2 +- .../input.mjs | 1 + .../options.json | 7 ++++ .../input.js | 1 + .../options.json | 4 ++ .../options.json | 2 +- 7 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/input.mjs create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/options.json create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/options.json diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index e353a93193..309fc98320 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -243,13 +243,6 @@ export default class StatementParser extends ExpressionParser { } parseDecorators(allowExport?: boolean): void { - if ( - this.hasPlugin("decorators") && - !this.getPluginOption("decorators", "decoratorsBeforeExport") - ) { - allowExport = false; - } - const currentContextDecorators = this.state.decoratorStack[ this.state.decoratorStack.length - 1 ]; @@ -259,18 +252,22 @@ export default class StatementParser extends ExpressionParser { } if (this.match(tt._export)) { - if (allowExport) { - return; - } else { + if (!allowExport) { + this.unexpected(); + } + + if ( + this.hasPlugin("decorators") && + !this.getPluginOption("decorators", "decoratorsBeforeExport") + ) { this.raise( this.state.start, "Using the export keyword between a decorator and a class is not allowed. " + - "Please use `export @dec class` instead", + "Please use `export @dec class` instead, or set the " + + "'decoratorsBeforeExport' option to true.", ); } - } - - if (!this.canHaveLeadingDecorator()) { + } else if (!this.canHaveLeadingDecorator()) { this.raise( this.state.start, "Leading decorators must be attached to a class declaration", @@ -1442,7 +1439,12 @@ export default class StatementParser extends ExpressionParser { this.hasPlugin("decorators") && this.getPluginOption("decorators", "decoratorsBeforeExport") ) { - this.unexpected(); + this.unexpected( + this.state.start, + "Decorators must be placed *before* the 'export' keyword." + + " You can set the 'decoratorsBeforeExport' option to false to use" + + " the 'export @decorator class {}' syntax", + ); } this.parseDecorators(false); return this.parseClass(expr, true, true); @@ -1544,7 +1546,12 @@ export default class StatementParser extends ExpressionParser { this.expectOnePlugin(["decorators", "decorators-legacy"]); if (this.hasPlugin("decorators")) { if (this.getPluginOption("decorators", "decoratorsBeforeExport")) { - this.unexpected(); + this.unexpected( + this.state.start, + "Decorators must be placed *before* the 'export' keyword." + + " You can set the 'decoratorsBeforeExport' option to false to use" + + " the 'export @decorator class {}' syntax", + ); } else { return true; } diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExport-export-default-decorated-expression-without-parens/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExport-export-default-decorated-expression-without-parens/options.json index c9bed54c7f..19ed49f042 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExport-export-default-decorated-expression-without-parens/options.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExport-export-default-decorated-expression-without-parens/options.json @@ -3,5 +3,5 @@ "plugins": [ ["decorators", { "decoratorsBeforeExport": true }] ], - "throws": "Unexpected token (1:15)" + "throws": "Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax (1:15)" } diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/input.mjs b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/input.mjs new file mode 100644 index 0000000000..e9dc1d092b --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/input.mjs @@ -0,0 +1 @@ +export @decorator class Foo {} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/options.json new file mode 100644 index 0000000000..8d1cb160da --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/decoratorsBeforeExpoty-true-decorator-after-export/options.json @@ -0,0 +1,7 @@ +{ + "sourceType": "module", + "plugins": [ + ["decorators", { "decoratorsBeforeExport": true }] + ], + "throws": "Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax (1:7)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/input.js b/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/input.js new file mode 100644 index 0000000000..a76c9160fb --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/input.js @@ -0,0 +1 @@ +let MyClass = @foo export class {} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/options.json new file mode 100644 index 0000000000..b5dc7b8e07 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/export-after-expression-decorator/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "throws": "Unexpected token (1:19)" +} diff --git a/packages/babel-parser/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json b/packages/babel-parser/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json index a2ae8cf036..f428da505e 100644 --- a/packages/babel-parser/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json +++ b/packages/babel-parser/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json @@ -1,4 +1,4 @@ { "sourceType": "module", - "throws": "Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead (2:0)" + "throws": "Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead, or set the 'decoratorsBeforeExport' option to true. (2:0)" }