From 663261be97364911e7b57eab0560ee48e53d8f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 14 Mar 2024 10:30:49 +0900 Subject: [PATCH] fix(es/parser): Allow `export` after decorators when valid (#8739) **Related issue:** - Closes #5276 --- .../src/parser/class_and_fn.rs | 7 +- crates/swc_ecma_parser/tests/js.rs | 1 + .../tests/js/issue-5276/input.js | 4 + .../tests/js/issue-5276/input.js.json | 112 ++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 crates/swc_ecma_parser/tests/js/issue-5276/input.js create mode 100644 crates/swc_ecma_parser/tests/js/issue-5276/input.js.json diff --git a/crates/swc_ecma_parser/src/parser/class_and_fn.rs b/crates/swc_ecma_parser/src/parser/class_and_fn.rs index fce10ad3e4f5..e4e178923eba 100644 --- a/crates/swc_ecma_parser/src/parser/class_and_fn.rs +++ b/crates/swc_ecma_parser/src/parser/class_and_fn.rs @@ -263,11 +263,14 @@ impl Parser { } if is!(self, "export") { - if !allow_export { + if !self.ctx().in_class && !self.ctx().in_function && !allow_export { syntax_error!(self, self.input.cur_span(), SyntaxError::ExportNotAllowed); } - if !self.syntax().decorators_before_export() { + if !self.ctx().in_class + && !self.ctx().in_function + && !self.syntax().decorators_before_export() + { syntax_error!(self, span!(self, start), SyntaxError::DecoratorOnExport); } } else if !is!(self, "class") { diff --git a/crates/swc_ecma_parser/tests/js.rs b/crates/swc_ecma_parser/tests/js.rs index a7de707d50ad..45e736ed2211 100644 --- a/crates/swc_ecma_parser/tests/js.rs +++ b/crates/swc_ecma_parser/tests/js.rs @@ -93,6 +93,7 @@ where Syntax::Es(EsConfig { explicit_resource_management: true, import_attributes: true, + decorators: true, ..Default::default() }), EsVersion::Es2015, diff --git a/crates/swc_ecma_parser/tests/js/issue-5276/input.js b/crates/swc_ecma_parser/tests/js/issue-5276/input.js new file mode 100644 index 000000000000..6e42ef33cedb --- /dev/null +++ b/crates/swc_ecma_parser/tests/js/issue-5276/input.js @@ -0,0 +1,4 @@ +export class MyClass { + @MyDecorator() + export = true; +} diff --git a/crates/swc_ecma_parser/tests/js/issue-5276/input.js.json b/crates/swc_ecma_parser/tests/js/issue-5276/input.js.json new file mode 100644 index 000000000000..a2cb9ecd0363 --- /dev/null +++ b/crates/swc_ecma_parser/tests/js/issue-5276/input.js.json @@ -0,0 +1,112 @@ +{ + "type": "Module", + "span": { + "start": 1, + "end": 63, + "ctxt": 0 + }, + "body": [ + { + "type": "ExportDeclaration", + "span": { + "start": 1, + "end": 63, + "ctxt": 0 + }, + "declaration": { + "type": "ClassDeclaration", + "identifier": { + "type": "Identifier", + "span": { + "start": 14, + "end": 21, + "ctxt": 0 + }, + "value": "MyClass", + "optional": false + }, + "declare": false, + "span": { + "start": 8, + "end": 63, + "ctxt": 0 + }, + "decorators": [], + "body": [ + { + "type": "ClassProperty", + "span": { + "start": 28, + "end": 61, + "ctxt": 0 + }, + "key": { + "type": "Identifier", + "span": { + "start": 47, + "end": 53, + "ctxt": 0 + }, + "value": "export", + "optional": false + }, + "value": { + "type": "BooleanLiteral", + "span": { + "start": 56, + "end": 60, + "ctxt": 0 + }, + "value": true + }, + "typeAnnotation": null, + "isStatic": false, + "decorators": [ + { + "type": "Decorator", + "span": { + "start": 28, + "end": 42, + "ctxt": 0 + }, + "expression": { + "type": "CallExpression", + "span": { + "start": 29, + "end": 42, + "ctxt": 0 + }, + "callee": { + "type": "Identifier", + "span": { + "start": 29, + "end": 40, + "ctxt": 0 + }, + "value": "MyDecorator", + "optional": false + }, + "arguments": [], + "typeArguments": null + } + } + ], + "accessibility": null, + "isAbstract": false, + "isOptional": false, + "isOverride": false, + "readonly": false, + "declare": false, + "definite": false + } + ], + "superClass": null, + "isAbstract": false, + "typeParams": null, + "superTypeParams": null, + "implements": [] + } + } + ], + "interpreter": null +}