Repository: swc-project/swc (rust)

Issue:
legacy decorators with decorate before exports makes bugs
### Describe the bug

When I use the legacy decorator while using the esm default export, swc will transform the code be like this:

![image](https://user-images.githubusercontent.com/16952163/221106882-32b25986-8d2f-4579-af53-50068469ca6a.png)
Then when running the code, an error will be reported: Uncaught ReferenceError: App is not defined.

**I think the decorate method should be executed inside the iife.**

### Input code
```javascript

import React from 'react'
import { withRouter } from 'react-router-dom'

export default
@withRouter
class App extends React.Component {
    render() {
        console.log(this.props)
        return <div>134</div>
    }
}
```

### Config
```json
{
  "jsc": {
    "externalHelpers": true,
    "parser": {
      "syntax": "ecmascript",
      "jsx": true,
      "decorators": true,
      "dynamicImport": true,
      "decoratorsBeforeExport": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "minify": {
      "compress": false
    }
  },
  "isModule": "unknown",
  "env": {
    "mode": "usage",
    "coreJs": "3",
    "dynamicImport": true
  }
}
```

### Playground link

https://play.swc.rs/?version=1.3.36&code=H4sIAAAAAAAAA02NwQ6CQAxE7%2F2K3sADGKNHYjT%2BAX9A2CKbLNtNtyiJ4d9dwKhzms6bZuwQWBRralrFTnjATBafgd3IC59W%2B5pHJcH5v1LIGhaGhwyAprVuqGtGp3D5fUHrmhjxGgLSpORN3ObKG6cJTz6NACZJYiT57nMuatlHdlQ6vufa21gG4RB3Xy6ko3isjH2cD8dTtV%2FMSmeY4Q2v7l5S3QAAAA%3D%3D&config=H4sIAAAAAAAAA22PvW7DQAyD30Wzt24egxRIC%2BQhhDs6uPb%2BIMmtjcDvHjlAmiFdSX6UeKUvDTReCYtBKucTcocojSYzBuosCtkDulbjhUZCKKxBUjcanF4e0YjQhK094bhWLil8lN7EXmMHTE3wvjzdbSATrup62W9mXDisxwfxUnGGcWTjP7qkmqZ1R0MrXaD%2By8RZsbmZ9NzinOEb5vpd22%2F1Aag%2Fe7y0eNeVL3DV%2B%2FHpLL3RvzO27QYUx7KWOQEAAA%3D%3D

### Expected behavior

 The class should be correctly decorated before exporting

### Actual behavior

The decorate method call with using the no define class, then make an error: Uncaught ReferenceError: App is not defined.

### Version

1.3.36

### Additional context

_No response_

Pull request:
fix(es/parser): parse decorators after export
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #6984 

Patch:
diff --git a/crates/swc_ecma_parser/src/error.rs b/crates/swc_ecma_parser/src/error.rs
index aa32d4208e..6ea6f96708 100644
--- a/crates/swc_ecma_parser/src/error.rs
+++ b/crates/swc_ecma_parser/src/error.rs
@@ -270,6 +270,7 @@ pub enum SyntaxError {
     TS2499,
     TS2703,
     TS4112,
+    TS8038,
     TSTypeAnnotationAfterAssign,
     TsNonNullAssertionNotAllowed(JsWord),
 
@@ -691,6 +692,9 @@ impl SyntaxError {
             SyntaxError::TS4112 => "This member cannot have an 'override' modifier because its \
                                     containing class does not extend another class."
                 .into(),
+            SyntaxError::TS8038 => "Decorators may not appear after `export` or `export default` \
+                                    if they also appear before `export`."
+                .into(),
             SyntaxError::TSTypeAnnotationAfterAssign => {
                 "Type annotations must come before default assignments".into()
             }
diff --git a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs
index d32acd01eb..d2b2003f2d 100644
--- a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs
+++ b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs
@@ -327,7 +327,7 @@ impl<I: Tokens> Parser<I> {
         Ok(self.with_ctx(ctx).parse_binding_ident()?.id)
     }
 
-    fn parse_export(&mut self, decorators: Vec<Decorator>) -> PResult<ModuleDecl> {
+    fn parse_export(&mut self, mut decorators: Vec<Decorator>) -> PResult<ModuleDecl> {
         if !self.ctx().module {
             // Switch to module mode
             let ctx = Context {
@@ -417,6 +417,17 @@ impl<I: Tokens> Parser<I> {
         let mut export_default = None;
 
         if !type_only && eat!(self, "default") {
+            if is!(self, '@') {
+                let start = cur_pos!(self);
+                let after_decorators = self.parse_decorators(false)?;
+
+                if !decorators.is_empty() {
+                    syntax_error!(self, span!(self, start), SyntaxError::TS8038);
+                }
+
+                decorators = after_decorators;
+            }
+
             if self.input.syntax().typescript() {
                 if is!(self, "abstract")
                     && peeked_is!(self, "class")
@@ -477,6 +488,17 @@ impl<I: Tokens> Parser<I> {
             }
         }
 
+        if is!(self, '@') {
+            let start = cur_pos!(self);
+            let after_decorators = self.parse_decorators(false)?;
+
+            if !decorators.is_empty() {
+                syntax_error!(self, span!(self, start), SyntaxError::TS8038);
+            }
+
+            decorators = after_decorators;
+        }
+
         let decl = if !type_only && is!(self, "class") {
             let class_start = cur_pos!(self);
             self.parse_class_decl(start, class_start, decorators, false)?


Test patch:
diff --git a/crates/swc/tests/fixture/issues-6xxx/6984/1/input/.swcrc b/crates/swc/tests/fixture/issues-6xxx/6984/1/input/.swcrc
new file mode 100644
index 0000000000..98c5126e09
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-6xxx/6984/1/input/.swcrc
@@ -0,0 +1,25 @@
+{
+    "jsc": {
+        "externalHelpers": true,
+        "parser": {
+            "syntax": "ecmascript",
+            "jsx": true,
+            "decorators": true,
+            "dynamicImport": true,
+            "decoratorsBeforeExport": true
+        },
+        "transform": {
+            "legacyDecorator": true,
+            "decoratorMetadata": true
+        },
+        "minify": {
+            "compress": false
+        }
+    },
+    "isModule": "unknown",
+    "env": {
+        "mode": "usage",
+        "coreJs": "3",
+        "dynamicImport": true
+    }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-6xxx/6984/1/input/index.js b/crates/swc/tests/fixture/issues-6xxx/6984/1/input/index.js
new file mode 100644
index 0000000000..82062f1984
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-6xxx/6984/1/input/index.js
@@ -0,0 +1,12 @@
+
+import React from 'react'
+import { withRouter } from 'react-router-dom'
+
+export default
+@withRouter
+class App extends React.Component {
+    render() {
+        console.log(this.props)
+        return <div>134</div>
+    }
+}
\ No newline at end of file
diff --git a/crates/swc/tests/fixture/issues-6xxx/6984/1/output/index.js b/crates/swc/tests/fixture/issues-6xxx/6984/1/output/index.js
new file mode 100644
index 0000000000..4bd3d30fd9
--- /dev/null
+++ b/crates/swc/tests/fixture/issues-6xxx/6984/1/output/index.js
@@ -0,0 +1,30 @@
+import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
+import { _ as _create_class } from "@swc/helpers/_/_create_class";
+import { _ as _inherits } from "@swc/helpers/_/_inherits";
+import { _ as _create_super } from "@swc/helpers/_/_create_super";
+import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
+import React from "react";
+import { withRouter } from "react-router-dom";
+var App = function(_React_Component) {
+    "use strict";
+    _inherits(App, _React_Component);
+    var _super = _create_super(App);
+    function App() {
+        _class_call_check(this, App);
+        return _super.apply(this, arguments);
+    }
+    _create_class(App, [
+        {
+            key: "render",
+            value: function render() {
+                console.log(this.props);
+                return React.createElement("div", null, "134");
+            }
+        }
+    ]);
+    return App;
+}(React.Component);
+App = _ts_decorate([
+    withRouter
+], App);
+export { App as default };
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts
new file mode 100644
index 0000000000..09184b6b16
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts
@@ -0,0 +1,4 @@
+// @filename: file3.js
+
+// error
+export @dec default class C3 {}
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts.swc-stderr
new file mode 100644
index 0000000000..99edb01fee
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts.swc-stderr
@@ -0,0 +1,7 @@
+
+  x Expected '{', got 'default'
+   ,-[$DIR/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file3.ts:3:1]
+ 3 | // error
+ 4 | export @dec default class C3 {}
+   :             ^^^^^^^
+   `----
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts
new file mode 100644
index 0000000000..19263ffddb
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts
@@ -0,0 +1,5 @@
+// @filename: file6.js
+
+// error
+@dec export @dec class C6 {}
+
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts.swc-stderr
new file mode 100644
index 0000000000..7f1019d5c8
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts.swc-stderr
@@ -0,0 +1,7 @@
+
+  x Decorators may not appear after `export` or `export default` if they also appear before `export`.
+   ,-[$DIR/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file6.ts:3:1]
+ 3 | // error
+ 4 | @dec export @dec class C6 {}
+   :             ^^^^
+   `----
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts
new file mode 100644
index 0000000000..ce21b253d2
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts
@@ -0,0 +1,4 @@
+// @filename: file7.js
+
+// error
+@dec export default @dec class C7 {}
diff --git a/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts.swc-stderr
new file mode 100644
index 0000000000..137a45a6ec
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts.swc-stderr
@@ -0,0 +1,7 @@
+
+  x Decorators may not appear after `export` or `export default` if they also appear before `export`.
+   ,-[$DIR/tests/typescript-errors/esDecorators/classDeclaration/esDecorators-classDeclaration-exportModifier/file7.ts:3:1]
+ 3 | // error
+ 4 | @dec export default @dec class C7 {}
+   :                     ^^^^
+   `----
diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/decl-to-expression/class-decorators/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/decl-to-expression/class-decorators/output.ts
index c58f8a3dab..f41d99f64d 100644
--- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/decl-to-expression/class-decorators/output.ts
+++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/decl-to-expression/class-decorators/output.ts
@@ -1,4 +1,4 @@
-export default class A {
+let A = class A {
 };
 A = _ts_decorate([
     dec
@@ -8,3 +8,4 @@ let B = class B {
 B = _ts_decorate([
     dec
 ], B);
+export { A as default };