Repository: swc-project/swc (rust)

Issue:
Default exported class with decorators are not transformed correctly
### Describe the bug

Decorators 2022-03 proposal transformer does not transform decorators on default-exported classes

### Input code

```typescript
export default @dec class {}
```


### Config

_No response_

### Playground link

_No response_

### SWC Info output

_No response_

### Expected behavior

Valid transformed code is emitted

### Actual behavior

Decorator is ignored and not transformed.

### Version

main

### Additional context

A couple of tests are present in the `swc_ecma_transforms_proposal` crate to ensure the correct behaviour is respected, but they are not executed in the test suite as the glob does not include the `.mjs` files

Pull request:
fix(es/compat): Transform default-exported class decorators correctly
**Description:**

Process decorators on the class expression on `export default` declaration and ensure to execute tests for the feature.

**Related issue:**

 - Closes #8049


Patch:
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 ba5da77d9c..ce9392de99 100644
--- a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
+++ b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
@@ -1446,6 +1446,13 @@ impl VisitMut for Decorator202203 {
 
                 s.visit_mut_children_with(self);
             }
+            ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(ExportDefaultDecl {
+                span: _,
+                decl: DefaultDecl::Class(c),
+            })) => {
+                self.handle_class_expr(&mut c.class, c.ident.as_ref());
+                s.visit_mut_children_with(self);
+            }
             _ => {
                 s.visit_mut_children_with(self);
             }


Test patch:
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators.rs b/crates/swc_ecma_transforms_proposal/tests/decorators.rs
index 433aeb0ae5..9f0383b2f4 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators.rs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators.rs
@@ -43,6 +43,7 @@ fn exec_inner(input: PathBuf) {
 }
 
 #[testing::fixture("tests/decorators/**/input.js")]
+#[testing::fixture("tests/decorators/**/input.mjs")]
 fn fixture(input: PathBuf) {
     fixture_inner(input)
 }
@@ -50,7 +51,10 @@ fn fixture(input: PathBuf) {
 fn fixture_inner(input: PathBuf) {
     let src = std::fs::read_to_string(&input).unwrap();
 
-    let output = input.with_file_name("output.js");
+    let output = input.with_file_name(format!(
+        "output.{}",
+        input.extension().unwrap().to_string_lossy()
+    ));
 
     test_fixture(
         syntax_default(),
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs
index bff5c609df..da1847afab 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-anonymous/output.mjs
@@ -1,12 +1,11 @@
-var _initClass, _dec;
-let _A;
-_dec = dec;
-class A {
-  static {
-    [_A, _initClass] = _applyDecs2203R(this, [], [_dec]).c;
-  }
-  static {
-    _initClass();
-  }
+var _initClass, _A;
+export default class A {
+    static{
+        ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [
+            dec
+        ]));
+    }
+    static{
+        _initClass();
+    }
 }
-export { _A as default };
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs
index 23bee6e67e..44309dff69 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/default-named/output.mjs
@@ -1,12 +1,11 @@
-var _initClass, _dec;
-let _default2;
-_dec = dec;
-class _default {
-  static {
-    [_default2, _initClass] = _applyDecs2203R(this, [], [_dec]).c;
-  }
-  static {
-    _initClass();
-  }
+var _initClass, _class;
+export default class {
+    static{
+        ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [
+            dec
+        ]));
+    }
+    static{
+        _initClass();
+    }
 }
-export { _default2 as default };
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs
index 00ad7a03bb..32ce221ec4 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/member-decorator/output.mjs
@@ -1,8 +1,13 @@
-var _dec, _init_x;
-_dec = dec;
+var _init_x;
 export class A {
-  static {
-    [_init_x] = _applyDecs2203R(this, [[_dec, 0, "x"]], []).e;
+  static{
+    ({ e: [_init_x] } = _apply_decs_2203_r(this, [
+        [
+            dec,
+            0,
+            "x"
+        ]
+    ], []));
   }
   x = _init_x(this);
 }
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs
index 7942408dbb..cd7e9a5d0b 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-exported/named/output.mjs
@@ -1,12 +1,13 @@
-var _initClass, _dec;
+var _initClass;
 let _A;
-_dec = dec;
 class A {
-  static {
-    [_A, _initClass] = _applyDecs2203R(this, [], [_dec]).c;
-  }
-  static {
-    _initClass();
-  }
+    static {
+        ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [
+            dec
+        ]));
+    }
+    static {
+        _initClass();
+    }
 }
 export { _A as A };