Repository: swc-project/swc (rust)

Issue:
2022-03 Decorator not working in an exported class
### Describe the bug

parse error trying to use decorator in an exported class

### Input code

```typescript
@decorate()
export class Foo {

  @decorate()
  get name() {
    return "hello"
  }

  @decorate()
  sayHi() {
    return "hello"
  }
}

function decorate() {
  return function(target, {kind}) {
    console.log(target, kind)
  }
}
```


### Config

```json
{
    "test": ".*.tsx?$",
    "jsc": {
        "parser": {
            "syntax": "typescript",
            "decorators": true
        },
        "target": "es2020",
        "transform": {
            "decoratorVersion": "2022-03"
        }
    }
}
```


### Playground link

https://play.swc.rs/?version=1.3.56&code=H4sIAAAAAAAAA32OQQrCQAxF93OKT1ctiGfoSrzGMI11cExkJgWl9O6NrVVBMLvkv%2FdJ21GQ7JXqxtH9JlkRki8FBxGMzgHtFwH0pGB%2FtcVS2GTSITOqM6UklZ2mX6n4xzH%2BM8w5DRw0CuNjLvyL3uJafbYfdhgvkbtp6wzCRRLtk%2FRv4gk0a%2F0M7hpWieYAAAA%3D&config=H4sIAAAAAAAAA1WOwQqDMBBE7%2FkK2XMLwUIP%2FYdeew%2B6KSmayO4KDeK%2Fd43V2tvOvJllJlNV8OIGbtWkp4rBESPtWh3OUdxbHZA8IDcUBoHTRltsEjlJxJoQGrGAeeUg5CL7RP3x4V55IHFIcXld27o%2B2wuY%2F7qjJ8rCkTVhwXwZ9KkdO%2FzNXqatueshFGLwWW3vOsZiBb5vzTJ2%2FgCck9nlAgEAAA%3D%3D

### Expected behavior

decorator works, same as in node

```
ts-node src/index.ts                              
[Function: get name] getter
[Function: sayHi] method
[class Foo] class
hello
hello
```

### Actual behavior

```
SWCRC=true node -r @swc-node/register src/index.ts
/Users/ola/code/swc-jest-example/src/foo.ts:376
@decorate()
^

SyntaxError: Invalid or unexpected token
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1176:20)
    at Module._compile (node:internal/modules/cjs/loader:1218:27)
    at Module._compile (/Users/ola/code/swc-jest-example/node_modules/pirates/lib/index.js:136:24)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Object.newLoader [as .ts] (/Users/ola/code/swc-jest-example/node_modules/pirates/lib/index.js:141:7)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Function.Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)

Node.js v18.16.0

```

### Version

1.3.56

### Additional context

_No response_

Pull request:
feat(es/compat): Support `export class` from stage 3 decorator pass
**Description:**


**Related issue:**

 - Closes #7358.

Patch:
diff --git a/crates/swc_ecma_ast/src/decl.rs b/crates/swc_ecma_ast/src/decl.rs
index eae1493f82..bb493ca06d 100644
--- a/crates/swc_ecma_ast/src/decl.rs
+++ b/crates/swc_ecma_ast/src/decl.rs
@@ -86,6 +86,16 @@ pub struct ClassDecl {
     pub class: Box<Class>,
 }
 
+impl Take for ClassDecl {
+    fn dummy() -> Self {
+        ClassDecl {
+            ident: Take::dummy(),
+            declare: Default::default(),
+            class: Take::dummy(),
+        }
+    }
+}
+
 #[ast_node("VariableDeclaration")]
 #[derive(Eq, Hash, EqIgnoreSpan)]
 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
index 4926cf87e2..c21de0b2ef 100644
--- a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
+++ b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
@@ -39,6 +39,8 @@ struct Decorator202203 {
 
     extra_lets: Vec<VarDeclarator>,
 
+    extra_exports: Vec<ExportSpecifier>,
+
     rename_map: FxHashMap<Id, Id>,
 }
 
@@ -345,6 +347,249 @@ impl Decorator202203 {
 
         new_class_name
     }
+
+    fn handle_class_decl(&mut self, c: &mut ClassDecl) -> Option<Stmt> {
+        if !c.class.decorators.is_empty() {
+            let decorators = self.preserve_side_effect_of_decorators(c.class.decorators.take());
+
+            let init_class = private_ident!("_initClass");
+
+            self.extra_vars.push(VarDeclarator {
+                span: DUMMY_SP,
+                name: Pat::Ident(init_class.clone().into()),
+                init: None,
+                definite: false,
+            });
+
+            let preserved_class_name = c.ident.clone().private();
+            let new_class_name = private_ident!(format!("_{}", c.ident.sym));
+
+            self.extra_lets.push(VarDeclarator {
+                span: DUMMY_SP,
+                name: Pat::Ident(new_class_name.clone().into()),
+                init: None,
+                definite: false,
+            });
+
+            self.rename_map
+                .insert(c.ident.to_id(), new_class_name.to_id());
+
+            self.class_lhs.push(Some(new_class_name.clone().into()));
+            self.class_lhs.push(Some(init_class.clone().into()));
+
+            self.class_decorators.extend(decorators);
+
+            let mut body = c.class.body.take();
+
+            let has_static_member = body.iter().any(|m| match m {
+                ClassMember::Method(m) => m.is_static,
+                ClassMember::PrivateMethod(m) => m.is_static,
+                ClassMember::ClassProp(ClassProp { is_static, .. })
+                | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => *is_static,
+                ClassMember::StaticBlock(_) => true,
+                _ => false,
+            });
+
+            if has_static_member {
+                let mut last_static_block = None;
+
+                for m in body.iter_mut() {
+                    match m {
+                        ClassMember::Method(method) => {
+                            if method.is_static {
+                                c.class.body.push(m.take());
+                            }
+                        }
+                        ClassMember::PrivateMethod(m) => {
+                            m.is_static = false;
+                        }
+                        ClassMember::ClassProp(ClassProp { value, .. })
+                        | ClassMember::PrivateProp(PrivateProp { value, .. }) => {
+                            if let Some(value) = value {
+                                if let Some(last_static_block) = last_static_block.take() {
+                                    **value = Expr::Seq(SeqExpr {
+                                        span: DUMMY_SP,
+                                        exprs: vec![
+                                            Box::new(Expr::Call(CallExpr {
+                                                span: DUMMY_SP,
+                                                callee: ArrowExpr {
+                                                    span: DUMMY_SP,
+                                                    params: vec![],
+                                                    body: Box::new(BlockStmtOrExpr::BlockStmt(
+                                                        BlockStmt {
+                                                            span: DUMMY_SP,
+                                                            stmts: last_static_block,
+                                                        },
+                                                    )),
+                                                    is_async: false,
+                                                    is_generator: false,
+                                                    type_params: Default::default(),
+                                                    return_type: Default::default(),
+                                                }
+                                                .as_callee(),
+                                                args: vec![],
+                                                type_args: Default::default(),
+                                            })),
+                                            value.take(),
+                                        ],
+                                    })
+                                }
+                            }
+                        }
+                        ClassMember::StaticBlock(s) => match &mut last_static_block {
+                            None => {
+                                last_static_block = Some(s.body.stmts.take());
+                            }
+                            Some(v) => {
+                                v.append(&mut s.body.stmts);
+                            }
+                        },
+                        _ => {}
+                    }
+                }
+
+                body.retain(|m| {
+                    !matches!(m, ClassMember::StaticBlock(..) | ClassMember::Empty(..))
+                });
+
+                body.visit_mut_with(self);
+
+                self.cur_inits.splice(0..0, self.static_inits.drain(..));
+
+                c.visit_mut_with(self);
+
+                // Make static members non-static
+                for m in body.iter_mut() {
+                    match m {
+                        ClassMember::Method(m) => {
+                            m.is_static = false;
+                        }
+                        ClassMember::PrivateMethod(m) => {
+                            m.is_static = false;
+                        }
+                        ClassMember::ClassProp(ClassProp { is_static, .. })
+                        | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => {
+                            *is_static = false;
+                        }
+                        _ => {}
+                    }
+                }
+
+                replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
+
+                return Some(
+                    NewExpr {
+                        span: DUMMY_SP,
+                        callee: ClassExpr {
+                            ident: None,
+                            class: Box::new(Class {
+                                span: DUMMY_SP,
+                                decorators: vec![],
+                                body: once(ClassMember::StaticBlock(StaticBlock {
+                                    span: DUMMY_SP,
+                                    body: BlockStmt {
+                                        span: DUMMY_SP,
+                                        stmts: vec![Stmt::Decl(Decl::Class(ClassDecl {
+                                            ident: preserved_class_name,
+                                            declare: Default::default(),
+                                            class: c.class.take(),
+                                        }))],
+                                    },
+                                }))
+                                .chain(body)
+                                .chain(once(ClassMember::Constructor(Constructor {
+                                    span: DUMMY_SP,
+                                    key: PropName::Ident(quote_ident!("constructor")),
+                                    params: vec![],
+                                    body: Some(BlockStmt {
+                                        span: DUMMY_SP,
+                                        stmts: vec![SeqExpr {
+                                            span: DUMMY_SP,
+                                            exprs: once(Box::new(Expr::Call(CallExpr {
+                                                span: DUMMY_SP,
+                                                callee: Callee::Super(Super { span: DUMMY_SP }),
+                                                args: vec![new_class_name.as_arg()],
+                                                type_args: Default::default(),
+                                            })))
+                                            .chain(last_static_block.map(|stmts| {
+                                                Box::new(Expr::Call(CallExpr {
+                                                    span: DUMMY_SP,
+                                                    callee: ArrowExpr {
+                                                        span: DUMMY_SP,
+                                                        params: vec![],
+                                                        body: Box::new(BlockStmtOrExpr::BlockStmt(
+                                                            BlockStmt {
+                                                                span: DUMMY_SP,
+                                                                stmts,
+                                                            },
+                                                        )),
+                                                        is_async: false,
+                                                        is_generator: false,
+                                                        type_params: Default::default(),
+                                                        return_type: Default::default(),
+                                                    }
+                                                    .as_callee(),
+                                                    args: vec![],
+                                                    type_args: Default::default(),
+                                                }))
+                                            }))
+                                            .chain(once(Box::new(Expr::Call(CallExpr {
+                                                span: DUMMY_SP,
+                                                callee: init_class.as_callee(),
+                                                args: vec![],
+                                                type_args: Default::default(),
+                                            }))))
+                                            .collect(),
+                                        }
+                                        .into_stmt()],
+                                    }),
+                                    accessibility: Default::default(),
+                                    is_optional: Default::default(),
+                                })))
+                                .collect(),
+                                super_class: Some(Box::new(helper_expr!(identity))),
+                                is_abstract: Default::default(),
+                                type_params: Default::default(),
+                                super_type_params: Default::default(),
+                                implements: Default::default(),
+                            }),
+                        }
+                        .into(),
+                        args: Some(vec![]),
+                        type_args: Default::default(),
+                    }
+                    .into_stmt(),
+                );
+            } else {
+                body.visit_mut_with(self);
+
+                c.visit_mut_with(self);
+
+                c.ident = preserved_class_name.clone();
+                replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
+
+                c.class.body.extend(body);
+
+                c.class.body.push(ClassMember::StaticBlock(StaticBlock {
+                    span: DUMMY_SP,
+                    body: BlockStmt {
+                        span: DUMMY_SP,
+                        stmts: vec![CallExpr {
+                            span: DUMMY_SP,
+                            callee: init_class.as_callee(),
+                            args: vec![],
+                            type_args: Default::default(),
+                        }
+                        .into_stmt()],
+                    },
+                }));
+
+                return Some(Stmt::Decl(Decl::Class(c.take())));
+            }
+        }
+
+        None
+    }
 }
 
 impl VisitMut for Decorator202203 {
@@ -633,6 +878,36 @@ impl VisitMut for Decorator202203 {
         e.visit_mut_children_with(self);
     }
 
+    fn visit_mut_module_item(&mut self, s: &mut ModuleItem) {
+        match s {
+            ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
+                span,
+                decl: Decl::Class(c),
+            })) => {
+                let ident = c.ident.clone();
+                let span = *span;
+                let new_stmt = self.handle_class_decl(c);
+
+                if let Some(new_stmt) = new_stmt {
+                    *s = ModuleItem::Stmt(new_stmt);
+                    self.extra_exports
+                        .push(ExportSpecifier::Named(ExportNamedSpecifier {
+                            span,
+                            orig: ModuleExportName::Ident(ident),
+                            exported: None,
+                            is_type_only: false,
+                        }));
+                    return;
+                }
+
+                s.visit_mut_children_with(self);
+            }
+            _ => {
+                s.visit_mut_children_with(self);
+            }
+        }
+    }
+
     fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
         let old_extra_lets = self.extra_lets.take();
 
@@ -676,6 +951,18 @@ impl VisitMut for Decorator202203 {
             );
         }
 
+        if !self.extra_exports.is_empty() {
+            new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
+                NamedExport {
+                    span: DUMMY_SP,
+                    specifiers: self.extra_exports.take(),
+                    src: None,
+                    type_only: false,
+                    asserts: None,
+                },
+            )));
+        }
+
         *n = new;
 
         if !self.rename_map.is_empty() {
@@ -797,240 +1084,10 @@ impl VisitMut for Decorator202203 {
 
     fn visit_mut_stmt(&mut self, s: &mut Stmt) {
         if let Stmt::Decl(Decl::Class(c)) = s {
-            if !c.class.decorators.is_empty() {
-                let decorators = self.preserve_side_effect_of_decorators(c.class.decorators.take());
-
-                let init_class = private_ident!("_initClass");
-
-                self.extra_vars.push(VarDeclarator {
-                    span: DUMMY_SP,
-                    name: Pat::Ident(init_class.clone().into()),
-                    init: None,
-                    definite: false,
-                });
-
-                let preserved_class_name = c.ident.clone().private();
-                let new_class_name = private_ident!(format!("_{}", c.ident.sym));
-
-                self.extra_lets.push(VarDeclarator {
-                    span: DUMMY_SP,
-                    name: Pat::Ident(new_class_name.clone().into()),
-                    init: None,
-                    definite: false,
-                });
-
-                self.rename_map
-                    .insert(c.ident.to_id(), new_class_name.to_id());
-
-                self.class_lhs.push(Some(new_class_name.clone().into()));
-                self.class_lhs.push(Some(init_class.clone().into()));
-
-                self.class_decorators.extend(decorators);
-
-                let mut body = c.class.body.take();
-
-                let has_static_member = body.iter().any(|m| match m {
-                    ClassMember::Method(m) => m.is_static,
-                    ClassMember::PrivateMethod(m) => m.is_static,
-                    ClassMember::ClassProp(ClassProp { is_static, .. })
-                    | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => *is_static,
-                    ClassMember::StaticBlock(_) => true,
-                    _ => false,
-                });
-
-                if has_static_member {
-                    let mut last_static_block = None;
-
-                    for m in body.iter_mut() {
-                        match m {
-                            ClassMember::Method(method) => {
-                                if method.is_static {
-                                    c.class.body.push(m.take());
-                                }
-                            }
-                            ClassMember::PrivateMethod(m) => {
-                                m.is_static = false;
-                            }
-                            ClassMember::ClassProp(ClassProp { value, .. })
-                            | ClassMember::PrivateProp(PrivateProp { value, .. }) => {
-                                if let Some(value) = value {
-                                    if let Some(last_static_block) = last_static_block.take() {
-                                        **value = Expr::Seq(SeqExpr {
-                                            span: DUMMY_SP,
-                                            exprs: vec![
-                                                Box::new(Expr::Call(CallExpr {
-                                                    span: DUMMY_SP,
-                                                    callee: ArrowExpr {
-                                                        span: DUMMY_SP,
-                                                        params: vec![],
-                                                        body: Box::new(BlockStmtOrExpr::BlockStmt(
-                                                            BlockStmt {
-                                                                span: DUMMY_SP,
-                                                                stmts: last_static_block,
-                                                            },
-                                                        )),
-                                                        is_async: false,
-                                                        is_generator: false,
-                                                        type_params: Default::default(),
-                                                        return_type: Default::default(),
-                                                    }
-                                                    .as_callee(),
-                                                    args: vec![],
-                                                    type_args: Default::default(),
-                                                })),
-                                                value.take(),
-                                            ],
-                                        })
-                                    }
-                                }
-                            }
-                            ClassMember::StaticBlock(s) => match &mut last_static_block {
-                                None => {
-                                    last_static_block = Some(s.body.stmts.take());
-                                }
-                                Some(v) => {
-                                    v.append(&mut s.body.stmts);
-                                }
-                            },
-                            _ => {}
-                        }
-                    }
-
-                    body.retain(|m| {
-                        !matches!(m, ClassMember::StaticBlock(..) | ClassMember::Empty(..))
-                    });
-
-                    body.visit_mut_with(self);
-
-                    self.cur_inits.splice(0..0, self.static_inits.drain(..));
-
-                    c.visit_mut_with(self);
-
-                    // Make static members non-static
-                    for m in body.iter_mut() {
-                        match m {
-                            ClassMember::Method(m) => {
-                                m.is_static = false;
-                            }
-                            ClassMember::PrivateMethod(m) => {
-                                m.is_static = false;
-                            }
-                            ClassMember::ClassProp(ClassProp { is_static, .. })
-                            | ClassMember::PrivateProp(PrivateProp { is_static, .. }) => {
-                                *is_static = false;
-                            }
-                            _ => {}
-                        }
-                    }
-
-                    replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
-
-                    *s = NewExpr {
-                        span: DUMMY_SP,
-                        callee: ClassExpr {
-                            ident: None,
-                            class: Box::new(Class {
-                                span: DUMMY_SP,
-                                decorators: vec![],
-                                body: once(ClassMember::StaticBlock(StaticBlock {
-                                    span: DUMMY_SP,
-                                    body: BlockStmt {
-                                        span: DUMMY_SP,
-                                        stmts: vec![Stmt::Decl(Decl::Class(ClassDecl {
-                                            ident: preserved_class_name,
-                                            declare: Default::default(),
-                                            class: c.class.take(),
-                                        }))],
-                                    },
-                                }))
-                                .chain(body)
-                                .chain(once(ClassMember::Constructor(Constructor {
-                                    span: DUMMY_SP,
-                                    key: PropName::Ident(quote_ident!("constructor")),
-                                    params: vec![],
-                                    body: Some(BlockStmt {
-                                        span: DUMMY_SP,
-                                        stmts: vec![SeqExpr {
-                                            span: DUMMY_SP,
-                                            exprs: once(Box::new(Expr::Call(CallExpr {
-                                                span: DUMMY_SP,
-                                                callee: Callee::Super(Super { span: DUMMY_SP }),
-                                                args: vec![new_class_name.as_arg()],
-                                                type_args: Default::default(),
-                                            })))
-                                            .chain(last_static_block.map(|stmts| {
-                                                Box::new(Expr::Call(CallExpr {
-                                                    span: DUMMY_SP,
-                                                    callee: ArrowExpr {
-                                                        span: DUMMY_SP,
-                                                        params: vec![],
-                                                        body: Box::new(BlockStmtOrExpr::BlockStmt(
-                                                            BlockStmt {
-                                                                span: DUMMY_SP,
-                                                                stmts,
-                                                            },
-                                                        )),
-                                                        is_async: false,
-                                                        is_generator: false,
-                                                        type_params: Default::default(),
-                                                        return_type: Default::default(),
-                                                    }
-                                                    .as_callee(),
-                                                    args: vec![],
-                                                    type_args: Default::default(),
-                                                }))
-                                            }))
-                                            .chain(once(Box::new(Expr::Call(CallExpr {
-                                                span: DUMMY_SP,
-                                                callee: init_class.as_callee(),
-                                                args: vec![],
-                                                type_args: Default::default(),
-                                            }))))
-                                            .collect(),
-                                        }
-                                        .into_stmt()],
-                                    }),
-                                    accessibility: Default::default(),
-                                    is_optional: Default::default(),
-                                })))
-                                .collect(),
-                                super_class: Some(Box::new(helper_expr!(identity))),
-                                is_abstract: Default::default(),
-                                type_params: Default::default(),
-                                super_type_params: Default::default(),
-                                implements: Default::default(),
-                            }),
-                        }
-                        .into(),
-                        args: Some(vec![]),
-                        type_args: Default::default(),
-                    }
-                    .into_stmt();
-                } else {
-                    body.visit_mut_with(self);
-
-                    c.visit_mut_with(self);
-
-                    c.ident = preserved_class_name.clone();
-                    replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
-
-                    c.class.body.extend(body);
-
-                    c.class.body.push(ClassMember::StaticBlock(StaticBlock {
-                        span: DUMMY_SP,
-                        body: BlockStmt {
-                            span: DUMMY_SP,
-                            stmts: vec![CallExpr {
-                                span: DUMMY_SP,
-                                callee: init_class.as_callee(),
-                                args: vec![],
-                                type_args: Default::default(),
-                            }
-                            .into_stmt()],
-                        },
-                    }));
-                }
+            let new_stmt = self.handle_class_decl(c);
 
+            if let Some(new_stmt) = new_stmt {
+                *s = new_stmt;
                 return;
             }
         }
diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs
index 938755a14f..df0fbd412f 100644
--- a/crates/swc_ecma_utils/src/lib.rs
+++ b/crates/swc_ecma_utils/src/lib.rs
@@ -2949,6 +2949,25 @@ impl VisitMut for IdentRenamer<'_> {
             node.span.ctxt = new.1;
         }
     }
+
+    fn visit_mut_export_named_specifier(&mut self, node: &mut ExportNamedSpecifier) {
+        if node.exported.is_some() {
+            node.orig.visit_mut_children_with(self);
+            return;
+        }
+
+        match &mut node.orig {
+            ModuleExportName::Ident(orig) => {
+                if let Some(new) = self.map.get(&orig.to_id()) {
+                    node.exported = Some(ModuleExportName::Ident(orig.clone()));
+
+                    orig.sym = new.0.clone();
+                    orig.span.ctxt = new.1;
+                }
+            }
+            ModuleExportName::Str(_) => {}
+        }
+    }
 }
 
 #[cfg(test)]


Test patch:
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators.rs b/crates/swc_ecma_transforms_proposal/tests/decorators.rs
index 06054daa2a..35d5e12a12 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators.rs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators.rs
@@ -18,6 +18,7 @@ fn syntax_default() -> Syntax {
         decorators: true,
         auto_accessors: true,
         allow_super_outside_method: true,
+        decorators_before_export: true,
         ..Default::default()
     })
 }
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/input.js b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/input.js
new file mode 100644
index 0000000000..b5b6869122
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/input.js
@@ -0,0 +1,19 @@
+@decorate()
+export class Foo {
+
+    @decorate()
+    get name() {
+        return "hello"
+    }
+
+    @decorate()
+    sayHi() {
+        return "hello"
+    }
+}
+
+function decorate() {
+    return function (target, { kind }) {
+        console.log(target, kind)
+    }
+}
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/options.json
new file mode 100644
index 0000000000..4ad37b6e47
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/options.json
@@ -0,0 +1,3 @@
+{
+    "plugins": [["proposal-decorators", { "version": "2022-03" }]]
+}
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/output.js
new file mode 100644
index 0000000000..f14444dce7
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/issue-7358/1/output.js
@@ -0,0 +1,39 @@
+var _dec, _initClass, _dec1, _dec2, _initProto;
+let _Foo;
+_dec = decorate(), _dec1 = decorate(), _dec2 = decorate();
+class Foo {
+    static{
+        ({ e: [_initProto] , c: [_Foo, _initClass]  } = _apply_decs_2203_r(this, [
+            [
+                _dec1,
+                3,
+                "name"
+            ],
+            [
+                _dec2,
+                2,
+                "sayHi"
+            ]
+        ], [
+            _dec
+        ]));
+    }
+    constructor(){
+        _initProto(this);
+    }
+    get name() {
+        return "hello";
+    }
+    sayHi() {
+        return "hello";
+    }
+    static{
+        _initClass();
+    }
+}
+function decorate() {
+    return function(target, { kind  }) {
+        console.log(target, kind);
+    };
+}
+export { _Foo as Foo };