Repository: swc-project/swc (rust)

Issue:
`undefined` is passed for the "context.metadata" field in a decorator metadata
### Describe the bug

When switching from tsc to swc to transpile TypeScript to JavaScript code I have noticed that `context.metadata` argument for decorators becomes undefined.

More context:
* I am trying to replace tsc with swc for faster source code transpilation in a relatively modern Node.js app.
* I am using '2022-03' decorators ("stage 3 decorators"), see swc config below.
* I am using the latest version of TypeScript (5.2+).
* I am using SWC within Rollup bundler, thanks to [rollup-plugin-swc3](https://www.npmjs.com/package/rollup-plugin-swc3) package.
* I have polyfilled decorator-metadata feature for my node.js with `core-js/proposals/decorator-metadata-v2.js`.

### Input code

```typescript
type ClassTarget = abstract new (...args: unknown[]) => unknown;

function inject<Class extends ClassTarget>(
  target: Class,
  context: ClassDecoratorContext<Class>
): void {
  console.debug(context.metadata); // undefined
}

@inject
class App {

  foo() {
    return 'bar';
  }

}

const app = new App()
app.foo();
```


### Config

```js
const config = {
    // --- Plugin options
    include: /\.ts$/,
    exclude: /node_modules/,
    tsconfig: 'tsconfig.json',
    // --- SWC options
    env: {
      targets: 'node >= 18.14',
      // 'entry' mode imports too much polyfills
      // 'usage' mode doesn't work as expected
      mode: undefined,
      coreJs: coreJsPackageManifest.version,
      dynamicImport: true,
    },
    jsc: {
      parser: {
        syntax: 'typescript',
        tsx: false,
        decorators: true,
        dynamicImport: true,
      },
      transform: {
        // Stage 3 decorators
        decoratorVersion: '2022-03',
      },
      externalHelpers: true,
      keepClassNames: true,
      // Use `env` option instead
      target: null,
    },
    minify: PRODUCTION_BUILD,
    sourceMaps: true,
  }
```


### Playground link

https://play.swc.rs/?version=1.3.74&code=H4sIAAAAAAAAA02QwU7EIBCG7zzF3BYSw95b22jWR%2FBm9jCF6aa6Dg1MdzXGd3eENTHhwPzwffxBPleCwxlLecZ8IoEBcCqSMQgwXcF67%2FWgdLDxG6crvxwdDOPf1BszbxxkSQwLv1KQ%2ByoD%2BhDiWP6rR2sApG67lt9pEBKLXr4lTxRSRkn50OJmG43r4JKWCF%2BNKOlMPtK0neyN9%2B8kGFHQ9bDfa71I88IUzbcxD62ZCbXZ47qqRj1zStZVI0Am2TLDbsK86zVRStfvSwKowFA%2FQ1HrjM6%2Bsr35AYrFObg%2BAQAA&config=H4sIAAAAAAAAA22QPQ%2BCQAyGd3%2FFpbMaQQdjoouLLo7uDRSDwt2lrQZC%2BO8efiAap7bv0%2B9mZAycJYGVaYIbAo8sxH0cFKmtYhUU0NqTJJx7hfGbqnQow0Ko11JKHKM6loCUrwNSWyzzZF96x%2FoF26cBZbSSOS6HK%2FQNj8SSO9stE8%2FieDKbw3c5VUpssdhR4elnPlyI%2FLZAkQOWNGSPaiB7%2B%2FxBkU%2BkXRJYl5LZrE20nEaL17y%2Fl3SdRu0dcYStD1QBAAA%3D

### SWC Info output


    Operating System:
        Platform: darwin
        Arch: arm64
        Machine Type: arm64
        Version: Darwin Kernel Version 22.6.0: Wed Jul  5 22:22:52 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T8103
        CPU: (8 cores)
            Models: Apple M1

    Binaries:
        Node: 18.17.0
        npm: 9.8.1
        Yarn: 1.22.19
        pnpm: N/A

    Relevant Packages:
        @swc/core: 1.3.82
        @swc/helpers: 0.5.1
        @swc/types: 0.1.4
        typescript: 5.2.2

    SWC Config:
        output: N/A
        .swcrc path: N/A

    Next.js info:
        output: N/A



### Expected behavior

With tsc:

```
function someDecorator(...) {
  console.log(context.metadata) // [Object: null prototype] {}
}
```

### Actual behavior

With swc:

```
function someDecorator(...) {
  console.log(context.metadata) // undefined
}
```

### Version

1.3.82

### Additional context

Maybe this could be helpful:
https://github.com/microsoft/TypeScript/issues/55453

Pull request description:
feat(es/compat): Implement decorator metadata proposal
**Description:**

This PR implements the [decorator metadata](https://github.com/tc39/proposal-decorator-metadata) proposal, that is now at Stage 3.

As the decorator metadata proposal is a small extension of the decorator proposal and is not possible to compile the metadata without transpiling decorators, I opted to implement it into the existing decorator transformer (and helper)

**Related issue:**

 - Closes #7957 

Patch:
diff --git a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
index 8662d6ff4f..718c02a068 100644
--- a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
+++ b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
@@ -35,6 +35,7 @@ function applyDecs2203RFactory() {
         kind,
         isStatic,
         isPrivate,
+        metadata,
         value
     ) {
         var kindStr;
@@ -61,6 +62,7 @@ function applyDecs2203RFactory() {
             name: isPrivate ? "#" + name : name,
             static: isStatic,
             private: isPrivate,
+            metadata: metadata,
         };
 
         var decoratorFinishedRef = { v: false };
@@ -168,7 +170,8 @@ function applyDecs2203RFactory() {
         kind,
         isStatic,
         isPrivate,
-        initializers
+        initializers,
+        metadata
     ) {
         var decs = decInfo[0];
 
@@ -221,6 +224,7 @@ function applyDecs2203RFactory() {
                 kind,
                 isStatic,
                 isPrivate,
+                metadata,
                 value
             );
 
@@ -251,6 +255,7 @@ function applyDecs2203RFactory() {
                     kind,
                     isStatic,
                     isPrivate,
+                    metadata,
                     value
                 );
 
@@ -345,7 +350,7 @@ function applyDecs2203RFactory() {
         }
     }
 
-    function applyMemberDecs(Class, decInfos) {
+    function applyMemberDecs(Class, decInfos, metadata) {
         var ret = [];
         var protoInitializers;
         var staticInitializers;
@@ -415,7 +420,8 @@ function applyDecs2203RFactory() {
                 kind,
                 isStatic,
                 isPrivate,
-                initializers
+                initializers,
+                metadata
             );
         }
 
@@ -435,7 +441,7 @@ function applyDecs2203RFactory() {
         }
     }
 
-    function applyClassDecs(targetClass, classDecs) {
+    function applyClassDecs(targetClass, classDecs, metadata) {
         if (classDecs.length > 0) {
             var initializers = [];
             var newClass = targetClass;
@@ -452,6 +458,7 @@ function applyDecs2203RFactory() {
                             initializers,
                             decoratorFinishedRef
                         ),
+                        metadata,
                     });
                 } finally {
                     decoratorFinishedRef.v = true;
@@ -464,7 +471,7 @@ function applyDecs2203RFactory() {
             }
 
             return [
-                newClass,
+                defineMetadata(newClass, metadata),
                 function () {
                     for (var i = 0; i < initializers.length; i++) {
                         initializers[i].call(newClass);
@@ -476,6 +483,14 @@ function applyDecs2203RFactory() {
         // so we don't have to return an empty array here.
     }
 
+    function defineMetadata(Class, metadata) {
+        return Object.defineProperty(
+            Class,
+            Symbol.metadata || Symbol.for("Symbol.metadata"),
+            { configurable: true, enumerable: true, value: metadata }
+        );
+    }
+
     /**
     Basic usage:
   
@@ -622,21 +637,31 @@ function applyDecs2203RFactory() {
     initializeClass(Class);
    */
 
-    return function applyDecs2203R(targetClass, memberDecs, classDecs) {
+    return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) {
+        if (parentClass !== void 0) {
+            var parentMetadata =
+                parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
+        }
+        var metadata = Object.create(
+            parentMetadata === void 0 ? null : parentMetadata
+        );
+        var e = applyMemberDecs(targetClass, memberDecs, metadata);
+        if (!classDecs.length) defineMetadata(targetClass, metadata);
         return {
-            e: applyMemberDecs(targetClass, memberDecs),
+            e: e,
             // Lazily apply class decorations so that member init locals can be properly bound.
             get c() {
-                return applyClassDecs(targetClass, classDecs);
+                return applyClassDecs(targetClass, classDecs, metadata);
             },
         };
     };
 }
 
-function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
+function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
     return (_apply_decs_2203_r = applyDecs2203RFactory())(
         targetClass,
         memberDecs,
-        classDecs
+        classDecs,
+        parentClass
     );
-}
\ No newline at end of file
+}
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 987d85aed1..5368144b84 100644
--- a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
+++ b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
@@ -9,8 +9,9 @@ use swc_common::{util::take::Take, Spanned, SyntaxContext, DUMMY_SP};
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::{helper, helper_expr};
 use swc_ecma_utils::{
-    constructor::inject_after_super, default_constructor, prepend_stmt, private_ident,
-    prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt, IdentRenamer,
+    alias_ident_for, constructor::inject_after_super, default_constructor, prepend_stmt,
+    private_ident, prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt,
+    IdentRenamer,
 };
 use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
 
@@ -53,6 +54,8 @@ struct ClassState {
 
     class_lhs: Vec<Option<Pat>>,
     class_decorators: Vec<Option<ExprOrSpread>>,
+
+    super_class: Option<Ident>,
 }
 
 impl Decorator202203 {
@@ -154,6 +157,10 @@ impl Decorator202203 {
             .as_arg(),
         );
 
+        if let Some(super_class) = self.state.super_class.as_ref() {
+            combined_args.push(super_class.clone().as_arg());
+        }
+
         let e_pat = if e_lhs.is_empty() {
             None
         } else {
@@ -323,6 +330,27 @@ impl Decorator202203 {
         unreachable!()
     }
 
+    fn handle_super_class(&mut self, class: &mut Class) {
+        if let Some(super_class) = class.super_class.take() {
+            let id = alias_ident_for(&super_class, "_super");
+            self.extra_vars.push(VarDeclarator {
+                span: DUMMY_SP,
+                name: Pat::Ident(id.clone().into()),
+                init: None,
+                definite: false,
+            });
+
+            class.super_class = Some(Box::new(Expr::Assign(AssignExpr {
+                span: DUMMY_SP,
+                op: AssignOp::Assign,
+                left: PatOrExpr::Pat(Box::new(Pat::Ident(id.clone().into()))),
+                right: super_class,
+            })));
+
+            self.state.super_class = Some(id);
+        }
+    }
+
     fn handle_class_expr(&mut self, class: &mut Class, ident: Option<&Ident>) -> Ident {
         debug_assert!(
             !class.decorators.is_empty(),
@@ -361,6 +389,7 @@ impl Decorator202203 {
 
         let decorators = self.preserve_side_effect_of_decorators(class.decorators.take());
         self.state.class_decorators.extend(decorators);
+        self.handle_super_class(class);
 
         {
             let call_stmt = CallExpr {
@@ -417,6 +446,7 @@ impl Decorator202203 {
             self.state.class_lhs.push(Some(init_class.clone().into()));
 
             self.state.class_decorators.extend(decorators);
+            self.handle_super_class(&mut c.class);
 
             let mut body = c.class.body.take();
 
diff --git a/packages/helpers/esm/_apply_decs_2203_r.js b/packages/helpers/esm/_apply_decs_2203_r.js
index a3c4396df4..6ac65fd3b0 100644
--- a/packages/helpers/esm/_apply_decs_2203_r.js
+++ b/packages/helpers/esm/_apply_decs_2203_r.js
@@ -18,7 +18,7 @@
   CLASS = 10; // only used in assertValidReturnValue
 */
 
-export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
+export function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
     function createAddInitializerMethod(initializers, decoratorFinishedRef) {
         return function addInitializer(initializer) {
             assertNotFinished(decoratorFinishedRef, "addInitializer");
@@ -27,7 +27,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         };
     }
 
-    function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, value) {
+    function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
         var kindStr;
 
         switch (kind) {
@@ -136,7 +136,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         }
     }
 
-    function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers) {
+    function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
         var decs = decInfo[0];
 
         var desc, init, value;
@@ -168,7 +168,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         var newValue, get, set;
 
         if (typeof decs === "function") {
-            newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, value);
+            newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
 
             if (newValue !== void 0) {
                 assertValidReturnValue(kind, newValue);
@@ -189,7 +189,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
             for (var i = decs.length - 1; i >= 0; i--) {
                 var dec = decs[i];
 
-                newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, value);
+                newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
 
                 if (newValue !== void 0) {
                     assertValidReturnValue(kind, newValue);
@@ -280,7 +280,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         }
     }
 
-    function applyMemberDecs(Class, decInfos) {
+    function applyMemberDecs(Class, decInfos, metadata) {
         var ret = [];
         var protoInitializers;
         var staticInitializers;
@@ -336,7 +336,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
                 }
             }
 
-            applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers);
+            applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
         }
 
         pushInitializers(ret, protoInitializers);
@@ -353,7 +353,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         }
     }
 
-    function applyClassDecs(targetClass, classDecs) {
+    function applyClassDecs(targetClass, classDecs, metadata) {
         if (classDecs.length > 0) {
             var initializers = [];
             var newClass = targetClass;
@@ -363,7 +363,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
                 var decoratorFinishedRef = { v: false };
 
                 try {
-                    var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef) });
+                    var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), metadata });
                 } finally {
                     decoratorFinishedRef.v = true;
                 }
@@ -374,7 +374,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
                 }
             }
 
-            return [newClass, function() {
+            return [defineMetadata(newClass, metadata), function() {
                 for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass);
             }];
         }
@@ -382,6 +382,10 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
         // so we don't have to return an empty array here.
     }
 
+    function defineMetadata(Class, metadata) {
+        return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: true, enumerable: true, value: metadata });
+    }
+
     /**
     Basic usage:
 
@@ -528,17 +532,23 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) {
     initializeClass(Class);
    */
 
-    _apply_decs_2203_r = function(targetClass, memberDecs, classDecs) {
+    _apply_decs_2203_r = function(targetClass, memberDecs, classDecs, parentClass) {
+        if (parentClass !== void 0) {
+            var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
+        }
+        var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata);
+        var e = applyMemberDecs(targetClass, memberDecs, metadata);
+        if (!classDecs.length) defineMetadata(targetClass, metadata);
         return {
-            e: applyMemberDecs(targetClass, memberDecs),
+            e: e,
             // Lazily apply class decorations so that member init locals can be properly bound.
             get c() {
-                return applyClassDecs(targetClass, classDecs);
+                return applyClassDecs(targetClass, classDecs, metadata);
             }
         };
     };
 
-    return _apply_decs_2203_r(targetClass, memberDecs, classDecs);
+    return _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass);
 }
 
 export { _apply_decs_2203_r as _ };


Test patch:
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js
index 2cf2118bd7..9ec0bb7ff7 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js
@@ -1,5 +1,5 @@
 var _A, __, __1, __2, _C, __3, __11, __21, _class, __4, __12, __22, _class1, __5, __13, __23, _G, __6, __14, __24, _class2, __7, __15, __25, _class3, __8, __16, __26, _K, __9, __17, __27;
-var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1;
+var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L;
 const dec = ()=>{};
 const A = ((_A = class A {
 }, __ = {
@@ -81,12 +81,12 @@ const F = [
         value: _initClass5()
     }, _class2), _class6)
 ];
-const H = ((_class3 = class extends I {
+const H = ((_class3 = class extends (_I = I) {
 }, __8 = {
     writable: true,
     value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [
         dec
-    ])
+    ], _I)
 }, __16 = {
     writable: true,
     value: (()=>{})()
@@ -94,12 +94,12 @@ const H = ((_class3 = class extends I {
     writable: true,
     value: _initClass6()
 }, _class3), _class7);
-const J = ((_K = class K extends L {
+const J = ((_K = class K extends (_L = L) {
 }, __9 = {
     writable: true,
     value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [
         dec
-    ])
+    ], _L)
 }, __17 = {
     writable: true,
     value: (()=>{})()
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js
index ecfa44ae22..25fb680ba4 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js
@@ -1,5 +1,5 @@
 var _A, __, __1, _C, __2, __11, _class, __3, __12, _class1, __4, __13, _G, __5, __14, _class2, __6, __15, _class3, __7, __16, _K, __8, __17;
-var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1;
+var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L;
 const dec = ()=>{};
 const A = ((_A = class A {
 }, __ = {
@@ -63,22 +63,22 @@ const F = [
         value: _initClass5()
     }, _class2), _class6)
 ];
-const H = ((_class3 = class extends I {
+const H = ((_class3 = class extends (_I = I) {
 }, __7 = {
     writable: true,
     value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [
         dec
-    ])
+    ], _I)
 }, __16 = {
     writable: true,
     value: _initClass6()
 }, _class3), _class7);
-const J = ((_K = class K extends L {
+const J = ((_K = class K extends (_L = L) {
 }, __8 = {
     writable: true,
     value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [
         dec
-    ])
+    ], _L)
 }, __17 = {
     writable: true,
     value: _initClass7()
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js
index 1f50e12bf5..b4f3e46de2 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js
@@ -1,12 +1,12 @@
-var _initClass, _initClass1;
+var _initClass, _initClass1, _Bar;
 const dec1 = ()=>{};
 const dec2 = ()=>{};
-let _Bar;
+let _Bar1;
 class Bar {
 }
 var __ = {
     writable: true,
-    value: { c: [_Bar, _initClass] } = _apply_decs_2203_r(Bar, [], [
+    value: { c: [_Bar1, _initClass] } = _apply_decs_2203_r(Bar, [], [
         dec1
     ])
 };
@@ -15,13 +15,13 @@ var __1 = {
     value: _initClass()
 };
 let _Foo;
-class Foo extends _Bar {
+class Foo extends (_Bar = _Bar1) {
 }
 var __2 = {
     writable: true,
     value: { c: [_Foo, _initClass1] } = _apply_decs_2203_r(Foo, [], [
         dec2
-    ])
+    ], _Bar)
 };
 var __11 = {
     writable: true,
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js
index a24a9c6505..d543f75ae6 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js
@@ -1,10 +1,10 @@
 var _class, __, _class1, __1;
-var _initClass, _initClass1;
+var _initClass, _initClass1, _Foo;
 const dec = ()=>{};
-let _Foo;
+let _Foo1;
 new (_class = class extends _identity {
     constructor(){
-        super(_Foo), _initClass();
+        super(_Foo1), _initClass();
     }
 }, __ = {
     writable: true,
@@ -13,7 +13,7 @@ new (_class = class extends _identity {
         }
         var __ = {
             writable: true,
-            value: { c: [_Foo, _initClass] } = _apply_decs_2203_r(Foo, [], [
+            value: { c: [_Foo1, _initClass] } = _apply_decs_2203_r(Foo, [], [
                 dec
             ])
         };
@@ -28,13 +28,14 @@ new (_class1 = class extends _identity {
 }, __1 = {
     writable: true,
     value: (()=>{
-        class Bar extends _Foo {
+        var _ref;
+        class Bar extends (_ref = _Foo = _Foo1) {
         }
         var __ = {
             writable: true,
             value: { c: [_Bar, _initClass1] } = _apply_decs_2203_r(Bar, [], [
                 dec
-            ])
+            ], _Foo)
         };
         _define_property(Bar, "field", ((()=>{
             Bar.otherField = 456;
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js
index bf851aa857..1e5b39d651 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js
@@ -1,8 +1,8 @@
-var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _initClass7, _K;
+var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _I, _initClass7, _K, _L;
 const dec = ()=>{};
 const A = (class A {
     static{
-        ({ c: [_A, _initClass]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -13,7 +13,7 @@ const A = (class A {
 }, _A);
 const B = (class C {
     static{
-        ({ c: [_C, _initClass1]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -24,7 +24,7 @@ const B = (class C {
 }, _C);
 const D = (class {
     static{
-        ({ c: [_class, _initClass2]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -35,7 +35,7 @@ const D = (class {
 }, _class);
 const E = ((class {
     static{
-        ({ c: [_class1, _initClass3]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -47,7 +47,7 @@ const E = ((class {
 const F = [
     (class G {
         static{
-            ({ c: [_G, _initClass4]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
@@ -58,7 +58,7 @@ const F = [
     }, _G),
     (class {
         static{
-            ({ c: [_class2, _initClass5]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
@@ -68,22 +68,22 @@ const F = [
         }
     }, _class2)
 ];
-const H = (class extends I {
+const H = (class extends (_I = I) {
     static{
         ({ c: [_class3, _initClass6]  } = _apply_decs_2203_r(this, [], [
             dec
-        ]));
+        ], _I));
     }
     static{}
     static{
         _initClass6();
     }
 }, _class3);
-const J = (class K extends L {
+const J = (class K extends (_L = L) {
     static{
         ({ c: [_K, _initClass7]  } = _apply_decs_2203_r(this, [], [
             dec
-        ]));
+        ], _L));
     }
     static{}
     static{
@@ -94,7 +94,7 @@ function classFactory() {
     var _initClass, _class;
     return class {
         static{
-            ({ c: [_class, _initClass]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js
index 52fcbe5007..7e7ad38890 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js
@@ -1,8 +1,8 @@
-var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _initClass7, _K;
+var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _I, _initClass7, _K, _L;
 const dec = ()=>{};
 const A = (class A {
     static{
-        ({ c: [_A, _initClass]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -12,7 +12,7 @@ const A = (class A {
 }, _A);
 const B = (class C {
     static{
-        ({ c: [_C, _initClass1]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -22,7 +22,7 @@ const B = (class C {
 }, _C);
 const D = (class {
     static{
-        ({ c: [_class, _initClass2]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -32,7 +32,7 @@ const D = (class {
 }, _class);
 const E = ((class {
     static{
-        ({ c: [_class1, _initClass3]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [
             dec
         ]));
     }
@@ -43,7 +43,7 @@ const E = ((class {
 const F = [
     (class G {
         static{
-            ({ c: [_G, _initClass4]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
@@ -53,7 +53,7 @@ const F = [
     }, _G),
     (class {
         static{
-            ({ c: [_class2, _initClass5]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
@@ -62,21 +62,21 @@ const F = [
         }
     }, _class2)
 ];
-const H = (class extends I {
+const H = (class extends (_I = I) {
     static{
-        ({ c: [_class3, _initClass6]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [
             dec
-        ]));
+        ], _I));
     }
     static{
         _initClass6();
     }
 }, _class3);
-const J = (class K extends L {
+const J = (class K extends (_L = L) {
     static{
         ({ c: [_K, _initClass7]  } = _apply_decs_2203_r(this, [], [
             dec
-        ]));
+        ], _L));
     }
     static{
         _initClass7();
@@ -86,7 +86,7 @@ function classFactory() {
     var _initClass, _class;
     return class {
         static{
-            ({ c: [_class, _initClass]  } = _apply_decs_2203_r(this, [], [
+            ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [
                 dec
             ]));
         }
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js
index 14ad93309f..4cc40167c6 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js
@@ -1,9 +1,9 @@
-var _initClass, _initClass1;
+var _initClass, _initClass1, _Bar;
 const dec = ()=>{};
-let _Bar;
+let _Bar1;
 class Bar {
     static{
-        ({ c: [_Bar, _initClass]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_Bar1, _initClass] } = _apply_decs_2203_r(this, [], [
             dec1
         ]));
     }
@@ -12,11 +12,11 @@ class Bar {
     }
 }
 let _Foo;
-class Foo extends _Bar {
+class Foo extends (_Bar = _Bar1) {
     static{
-        ({ c: [_Foo, _initClass1]  } = _apply_decs_2203_r(this, [], [
+        ({ c: [_Foo, _initClass1] } = _apply_decs_2203_r(this, [], [
             dec2
-        ]));
+        ], _Bar));
     }
     static{
         _initClass1();
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js
index 031046371e..772fbce846 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js
@@ -1,14 +1,14 @@
-var _initClass, _initClass1;
+var _initClass, _initClass1, _Foo;
 const dec = ()=>{};
-let _Foo;
+let _Foo1;
 new class extends _identity {
     constructor(){
-        super(_Foo), _initClass();
+        super(_Foo1), _initClass();
     }
     static{
         class Foo {
             static{
-                ({ c: [_Foo, _initClass]  } = _apply_decs_2203_r(this, [], [
+                ({ c: [_Foo1, _initClass] } = _apply_decs_2203_r(this, [], [
                     dec
                 ]));
             }
@@ -22,11 +22,11 @@ new class extends _identity {
         super(_Bar), _initClass1();
     }
     static{
-        class Bar extends _Foo {
+        class Bar extends (_Foo = _Foo1) {
             static{
-                ({ c: [_Bar, _initClass1]  } = _apply_decs_2203_r(this, [], [
+                ({ c: [_Bar, _initClass1] } = _apply_decs_2203_r(this, [], [
                     dec
-                ]));
+                ], _Foo));
             }
             static field = ((()=>{
                 this.otherField = 456;
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js
new file mode 100644
index 0000000000..267e022185
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js
@@ -0,0 +1,11 @@
+function dec(_, ctx) {
+  ctx.metadata.foo = 3;
+}
+
+Symbol.metadata = Symbol();
+
+@dec
+class A {}
+
+expect(A[Symbol.metadata]).toEqual({ foo: 3 });
+expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js
new file mode 100644
index 0000000000..c70d840c5f
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js
@@ -0,0 +1,14 @@
+function dec(_, ctx) {
+  console.error(ctx);
+  ctx.metadata.foo = 3;
+}
+
+Symbol.metadata = Symbol();
+
+class A {
+  @dec
+  foo;
+}
+
+expect(A[Symbol.metadata]).toEqual({ foo: 3 });
+expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js
new file mode 100644
index 0000000000..9f2d6b450b
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js
@@ -0,0 +1,5 @@
+Symbol.metadata = Symbol();
+
+class A {}
+
+expect(A.hasOwnProperty(Symbol.metadata)).toBe(false);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json
new file mode 100644
index 0000000000..4e9da044d2
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json
@@ -0,0 +1,8 @@
+{
+    "plugins": [
+        ["proposal-decorators", { "version": "2022-03" }],
+        "proposal-class-properties",
+        "proposal-private-methods",
+        "proposal-class-static-block"
+    ]
+}
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js
new file mode 100644
index 0000000000..3949427e77
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js
@@ -0,0 +1,15 @@
+function dec(v) {
+  return (_, ctx) => {
+    ctx.metadata.foo = v;
+  };
+}
+
+Symbol.metadata = Symbol();
+
+class B {}
+
+@dec(3)
+class A extends B {}
+
+expect(A[Symbol.metadata]).toEqual({ foo: 3 });
+expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js
new file mode 100644
index 0000000000..c77dbb2dbe
--- /dev/null
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js
@@ -0,0 +1,18 @@
+function dec(v) {
+  return (_, ctx) => {
+    ctx.metadata.foo = v;
+  };
+}
+
+Symbol.metadata = Symbol();
+
+@dec(2)
+class B {}
+
+@dec(3)
+class A extends B {}
+
+expect(A[Symbol.metadata]).toEqual({ foo: 3 });
+expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(B[Symbol.metadata]);
+expect(B[Symbol.metadata]).toEqual({ foo: 2 });
+expect(Object.getPrototypeOf(B[Symbol.metadata])).toBe(null);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js
index 3594e7f254..1266b57cb0 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js
@@ -1,11 +1,11 @@
-var _initClass;
+var _initClass, _Bar;
 const dec = ()=>{};
 let _Foo;
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
     static{
         ({ c: [_Foo, _initClass]  } = _apply_decs_2203_r(this, [], [
             dec
-        ]));
+        ], _Bar));
     }
     constructor(){
         let foo = super();