Repository: babel/babel (TypeScript)

Issue:
[Bug]: Decorator metadata is not implemented
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

@babel/cli

### Input code

```js
function test(target, context) {
  console.log(context.metadata); // undefined
}

class A {
  @test foo;
}
```

I am not able to make a reproduction with the REPL due to: https://github.com/babel/website/issues/1292 since the decorator plugin has a required option that can't be set.

### Configuration file name

.babelrc

### Configuration

```json
{
  "plugins":[
    "@babel/plugin-transform-class-static-block",
    ["@babel/plugin-proposal-decorators", {"version": "2023-05", "decoratorsBeforeExport": true}],
    ["@babel/plugin-proposal-class-properties"]
  ]
}
```

### Current and expected behavior

`context.metadata` should be an object per https://github.com/tc39/proposal-decorator-metadata

### Environment

    "@babel/cli": "^7.22.10",
    "@babel/core": "^7.22.11",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/plugin-proposal-decorators": "^7.22.10",
    "@babel/plugin-transform-class-static-block": "^7.22.11",


### Possible solution

_No response_

### Additional context

TypeScript 5.2 (due to be released the week of 8/22) implements decorator metadata.


Hints:
Hey @justinfagnani! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.
Given that TS is shipping this, I think we should wait releasing 7.23 to also include this proposal (I can work on this Monday)

Patch:
diff --git a/packages/babel-helpers/src/helpers-generated.ts b/packages/babel-helpers/src/helpers-generated.ts
--- a/packages/babel-helpers/src/helpers-generated.ts
+++ b/packages/babel-helpers/src/helpers-generated.ts
@@ -39,7 +39,7 @@ export default Object.freeze({
   ),
   applyDecs2305: helper(
     "7.21.0",
-    'import checkInRHS from"checkInRHS";function createAddInitializerMethod(e,t){return function(r){assertNotFinished(t,"addInitializer"),assertCallable(r,"An initializer"),e.push(r)}}function assertInstanceIfPrivate(e,t){if(!e(t))throw new TypeError("Attempted to access private element on non-instance")}function memberDec(e,t,r,n,a,i,s,o,c,l){var u;switch(i){case 1:u="accessor";break;case 2:u="method";break;case 3:u="getter";break;case 4:u="setter";break;default:u="field"}var f,d,p={kind:u,name:o?"#"+r:r,static:s,private:o},h={v:!1};if(0!==i&&(p.addInitializer=createAddInitializerMethod(a,h)),o||0!==i&&2!==i)if(2===i)f=function(e){return assertInstanceIfPrivate(l,e),n.value};else{var v=0===i||1===i;(v||3===i)&&(f=o?function(e){return assertInstanceIfPrivate(l,e),n.get.call(e)}:function(e){return n.get.call(e)}),(v||4===i)&&(d=o?function(e,t){assertInstanceIfPrivate(l,e),n.set.call(e,t)}:function(e,t){n.set.call(e,t)})}else f=function(e){return e[r]},0===i&&(d=function(e,t){e[r]=t});var y=o?l.bind():function(e){return r in e};p.access=f&&d?{get:f,set:d,has:y}:f?{get:f,has:y}:{set:d,has:y};try{return e.call(t,c,p)}finally{h.v=!0}}function assertNotFinished(e,t){if(e.v)throw new Error("attempted to call "+t+" after decoration was finished")}function assertCallable(e,t){if("function"!=typeof e)throw new TypeError(t+" must be a function")}function assertValidReturnValue(e,t){var r=typeof t;if(1===e){if("object"!==r||null===t)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==t.get&&assertCallable(t.get,"accessor.get"),void 0!==t.set&&assertCallable(t.set,"accessor.set"),void 0!==t.init&&assertCallable(t.init,"accessor.init")}else if("function"!==r){var n;throw n=0===e?"field":5===e?"class":"method",new TypeError(n+" decorators must return a function or void 0")}}function curryThis1(e){return function(){return e(this)}}function curryThis2(e){return function(t){e(this,t)}}function applyMemberDec(e,t,r,n,a,i,s,o,c,l){var u,f,d,p,h,v,y=r[0];n||Array.isArray(y)||(y=[y]),o?u=0===i||1===i?{get:curryThis1(r[3]),set:curryThis2(r[4])}:3===i?{get:r[3]}:4===i?{set:r[3]}:{value:r[3]}:0!==i&&(u=Object.getOwnPropertyDescriptor(t,a)),1===i?d={get:u.get,set:u.set}:2===i?d=u.value:3===i?d=u.get:4===i&&(d=u.set);for(var g=n?2:1,m=y.length-1;m>=0;m-=g){var b;if(void 0!==(p=memberDec(y[m],n?y[m-1]:void 0,a,u,c,i,s,o,d,l)))assertValidReturnValue(i,p),0===i?b=p:1===i?(b=p.init,h=p.get||d.get,v=p.set||d.set,d={get:h,set:v}):d=p,void 0!==b&&(void 0===f?f=b:"function"==typeof f?f=[f,b]:f.push(b))}if(0===i||1===i){if(void 0===f)f=function(e,t){return t};else if("function"!=typeof f){var I=f;f=function(e,t){for(var r=t,n=I.length-1;n>=0;n--)r=I[n].call(e,r);return r}}else{var w=f;f=function(e,t){return w.call(e,t)}}e.push(f)}0!==i&&(1===i?(u.get=d.get,u.set=d.set):2===i?u.value=d:3===i?u.get=d:4===i&&(u.set=d),o?1===i?(e.push((function(e,t){return d.get.call(e,t)})),e.push((function(e,t){return d.set.call(e,t)}))):2===i?e.push(d):e.push((function(e,t){return d.call(e,t)})):Object.defineProperty(t,a,u))}function applyMemberDecs(e,t,r){for(var n,a,i,s=[],o=new Map,c=new Map,l=0;l<t.length;l++){var u=t[l];if(Array.isArray(u)){var f,d,p=u[1],h=u[2],v=u.length>3,y=16&p,g=!!(8&p),m=r;if(p&=7,g?(f=e,0!==p&&(d=a=a||[]),v&&!i&&(i=function(t){return checkInRHS(t)===e}),m=i):(f=e.prototype,0!==p&&(d=n=n||[])),0!==p&&!v){var b=g?c:o,I=b.get(h)||0;if(!0===I||3===I&&4!==p||4===I&&3!==p)throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: "+h);b.set(h,!(!I&&p>2)||p)}applyMemberDec(s,f,u,y,h,p,g,v,d,m)}}return pushInitializers(s,n),pushInitializers(s,a),s}function pushInitializers(e,t){t&&e.push((function(e){for(var r=0;r<t.length;r++)t[r].call(e);return e}))}function applyClassDecs(e,t,r){if(t.length){for(var n=[],a=e,i=e.name,s=r?2:1,o=t.length-1;o>=0;o-=s){var c={v:!1};try{var l=t[o].call(r?t[o-1]:void 0,a,{kind:"class",name:i,addInitializer:createAddInitializerMethod(n,c)})}finally{c.v=!0}void 0!==l&&(assertValidReturnValue(5,l),a=l)}return[a,function(){for(var e=0;e<n.length;e++)n[e].call(a)}]}}export default function applyDecs2305(e,t,r,n,a){return{e:applyMemberDecs(e,t,a),get c(){return applyClassDecs(e,r,n)}}}',
+    'import checkInRHS from"checkInRHS";function createAddInitializerMethod(e,t){return function(r){assertNotFinished(t,"addInitializer"),assertCallable(r,"An initializer"),e.push(r)}}function assertInstanceIfPrivate(e,t){if(!e(t))throw new TypeError("Attempted to access private element on non-instance")}function memberDec(e,t,r,a,n,i,s,o,c,l,u){var f;switch(i){case 1:f="accessor";break;case 2:f="method";break;case 3:f="getter";break;case 4:f="setter";break;default:f="field"}var d,p,h={kind:f,name:o?"#"+r:r,static:s,private:o,metadata:u},v={v:!1};if(0!==i&&(h.addInitializer=createAddInitializerMethod(n,v)),o||0!==i&&2!==i)if(2===i)d=function(e){return assertInstanceIfPrivate(l,e),a.value};else{var y=0===i||1===i;(y||3===i)&&(d=o?function(e){return assertInstanceIfPrivate(l,e),a.get.call(e)}:function(e){return a.get.call(e)}),(y||4===i)&&(p=o?function(e,t){assertInstanceIfPrivate(l,e),a.set.call(e,t)}:function(e,t){a.set.call(e,t)})}else d=function(e){return e[r]},0===i&&(p=function(e,t){e[r]=t});var m=o?l.bind():function(e){return r in e};h.access=d&&p?{get:d,set:p,has:m}:d?{get:d,has:m}:{set:p,has:m};try{return e.call(t,c,h)}finally{v.v=!0}}function assertNotFinished(e,t){if(e.v)throw new Error("attempted to call "+t+" after decoration was finished")}function assertCallable(e,t){if("function"!=typeof e)throw new TypeError(t+" must be a function")}function assertValidReturnValue(e,t){var r=typeof t;if(1===e){if("object"!==r||null===t)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==t.get&&assertCallable(t.get,"accessor.get"),void 0!==t.set&&assertCallable(t.set,"accessor.set"),void 0!==t.init&&assertCallable(t.init,"accessor.init")}else if("function"!==r){var a;throw a=0===e?"field":5===e?"class":"method",new TypeError(a+" decorators must return a function or void 0")}}function curryThis1(e){return function(){return e(this)}}function curryThis2(e){return function(t){e(this,t)}}function applyMemberDec(e,t,r,a,n,i,s,o,c,l,u){var f,d,p,h,v,y,m=r[0];a||Array.isArray(m)||(m=[m]),o?f=0===i||1===i?{get:curryThis1(r[3]),set:curryThis2(r[4])}:3===i?{get:r[3]}:4===i?{set:r[3]}:{value:r[3]}:0!==i&&(f=Object.getOwnPropertyDescriptor(t,n)),1===i?p={get:f.get,set:f.set}:2===i?p=f.value:3===i?p=f.get:4===i&&(p=f.set);for(var g=a?2:1,b=m.length-1;b>=0;b-=g){var I;if(void 0!==(h=memberDec(m[b],a?m[b-1]:void 0,n,f,c,i,s,o,p,l,u)))assertValidReturnValue(i,h),0===i?I=h:1===i?(I=h.init,v=h.get||p.get,y=h.set||p.set,p={get:v,set:y}):p=h,void 0!==I&&(void 0===d?d=I:"function"==typeof d?d=[d,I]:d.push(I))}if(0===i||1===i){if(void 0===d)d=function(e,t){return t};else if("function"!=typeof d){var w=d;d=function(e,t){for(var r=t,a=w.length-1;a>=0;a--)r=w[a].call(e,r);return r}}else{var M=d;d=function(e,t){return M.call(e,t)}}e.push(d)}0!==i&&(1===i?(f.get=p.get,f.set=p.set):2===i?f.value=p:3===i?f.get=p:4===i&&(f.set=p),o?1===i?(e.push((function(e,t){return p.get.call(e,t)})),e.push((function(e,t){return p.set.call(e,t)}))):2===i?e.push(p):e.push((function(e,t){return p.call(e,t)})):Object.defineProperty(t,n,f))}function applyMemberDecs(e,t,r,a){for(var n,i,s,o=[],c=new Map,l=new Map,u=0;u<t.length;u++){var f=t[u];if(Array.isArray(f)){var d,p,h=f[1],v=f[2],y=f.length>3,m=16&h,g=!!(8&h),b=r;if(h&=7,g?(d=e,0!==h&&(p=i=i||[]),y&&!s&&(s=function(t){return checkInRHS(t)===e}),b=s):(d=e.prototype,0!==h&&(p=n=n||[])),0!==h&&!y){var I=g?l:c,w=I.get(v)||0;if(!0===w||3===w&&4!==h||4===w&&3!==h)throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: "+v);I.set(v,!(!w&&h>2)||h)}applyMemberDec(o,d,f,m,v,h,g,y,p,b,a)}}return pushInitializers(o,n),pushInitializers(o,i),o}function pushInitializers(e,t){t&&e.push((function(e){for(var r=0;r<t.length;r++)t[r].call(e);return e}))}function applyClassDecs(e,t,r,a){if(t.length){for(var n=[],i=e,s=e.name,o=r?2:1,c=t.length-1;c>=0;c-=o){var l={v:!1};try{var u=t[c].call(r?t[c-1]:void 0,i,{kind:"class",name:s,addInitializer:createAddInitializerMethod(n,l),metadata:a})}finally{l.v=!0}void 0!==u&&(assertValidReturnValue(5,u),i=u)}return[defineMetadata(i,a),function(){for(var e=0;e<n.length;e++)n[e].call(i)}]}}function defineMetadata(e,t){return Object.defineProperty(e,Symbol.metadata||Symbol.for("Symbol.metadata"),{configurable:!0,enumerable:!0,value:t})}export default function applyDecs2305(e,t,r,a,n,i){if(arguments.length>=6)var s=i[Symbol.metadata||Symbol.for("Symbol.metadata")];var o=Object.create(void 0===s?null:s),c=applyMemberDecs(e,t,n,o);return r.length||defineMetadata(e,o),{e:c,get c(){return applyClassDecs(e,r,a,o)}}}',
   ),
   asyncGeneratorDelegate: helper(
     "7.0.0-beta.0",
diff --git a/packages/babel-helpers/src/helpers/applyDecs2305.js b/packages/babel-helpers/src/helpers/applyDecs2305.js
--- a/packages/babel-helpers/src/helpers/applyDecs2305.js
+++ b/packages/babel-helpers/src/helpers/applyDecs2305.js
@@ -45,7 +45,8 @@ function memberDec(
   isStatic,
   isPrivate,
   value,
-  hasPrivateBrand
+  hasPrivateBrand,
+  metadata
 ) {
   var kindStr;
 
@@ -71,6 +72,7 @@ function memberDec(
     name: isPrivate ? "#" + name : name,
     static: isStatic,
     private: isPrivate,
+    metadata: metadata,
   };
 
   var decoratorFinishedRef = { v: false };
@@ -211,7 +213,8 @@ function applyMemberDec(
   isStatic,
   isPrivate,
   initializers,
-  hasPrivateBrand
+  hasPrivateBrand,
+  metadata
 ) {
   var decs = decInfo[0];
 
@@ -276,7 +279,8 @@ function applyMemberDec(
       isStatic,
       isPrivate,
       value,
-      hasPrivateBrand
+      hasPrivateBrand,
+      metadata
     );
 
     if (newValue !== void 0) {
@@ -369,7 +373,7 @@ function applyMemberDec(
   }
 }
 
-function applyMemberDecs(Class, decInfos, instanceBrand) {
+function applyMemberDecs(Class, decInfos, instanceBrand, metadata) {
   var ret = [];
   var protoInitializers;
   var staticInitializers;
@@ -451,7 +455,8 @@ function applyMemberDecs(Class, decInfos, instanceBrand) {
       isStatic,
       isPrivate,
       initializers,
-      hasPrivateBrand
+      hasPrivateBrand,
+      metadata
     );
   }
 
@@ -471,7 +476,7 @@ function pushInitializers(ret, initializers) {
   }
 }
 
-function applyClassDecs(targetClass, classDecs, decoratorsHaveThis) {
+function applyClassDecs(targetClass, classDecs, decoratorsHaveThis, metadata) {
   if (classDecs.length) {
     var initializers = [];
     var newClass = targetClass;
@@ -493,6 +498,7 @@ function applyClassDecs(targetClass, classDecs, decoratorsHaveThis) {
               initializers,
               decoratorFinishedRef
             ),
+            metadata,
           }
         );
       } finally {
@@ -506,7 +512,7 @@ function applyClassDecs(targetClass, classDecs, decoratorsHaveThis) {
     }
 
     return [
-      newClass,
+      defineMetadata(newClass, metadata),
       function () {
         for (var i = 0; i < initializers.length; i++) {
           initializers[i].call(newClass);
@@ -518,6 +524,14 @@ function applyClassDecs(targetClass, classDecs, decoratorsHaveThis) {
   // 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:
 
@@ -669,13 +683,28 @@ export default function applyDecs2305(
   memberDecs,
   classDecs,
   classDecsHaveThis,
-  instanceBrand
+  instanceBrand,
+  parentClass
 ) {
+  if (arguments.length >= 6) {
+    var parentMetadata =
+      parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
+  }
+  var metadata = Object.create(
+    parentMetadata === void 0 ? null : parentMetadata
+  );
+  var e = applyMemberDecs(targetClass, memberDecs, instanceBrand, metadata);
+  if (!classDecs.length) defineMetadata(targetClass, metadata);
   return {
-    e: applyMemberDecs(targetClass, memberDecs, instanceBrand),
+    e: e,
     // Lazily apply class decorations so that member init locals can be properly bound.
     get c() {
-      return applyClassDecs(targetClass, classDecs, classDecsHaveThis);
+      return applyClassDecs(
+        targetClass,
+        classDecs,
+        classDecsHaveThis,
+        metadata
+      );
     },
   };
 }
diff --git a/packages/babel-plugin-proposal-decorators/src/transformer-2023-05.ts b/packages/babel-plugin-proposal-decorators/src/transformer-2023-05.ts
--- a/packages/babel-plugin-proposal-decorators/src/transformer-2023-05.ts
+++ b/packages/babel-plugin-proposal-decorators/src/transformer-2023-05.ts
@@ -1069,6 +1069,15 @@ function transformClass(
     );
   }
 
+  let { superClass } = originalClass;
+  if (superClass && (process.env.BABEL_8_BREAKING || version === "2023-05")) {
+    const id = path.scope.maybeGenerateMemoised(superClass);
+    if (id) {
+      originalClass.superClass = t.assignmentExpression("=", id, superClass);
+      superClass = id;
+    }
+  }
+
   originalClass.body.body.unshift(
     t.staticBlock(
       [
@@ -1080,6 +1089,7 @@ function transformClass(
             t.arrayExpression(classDecorations),
             t.numericLiteral(classDecorationsFlag),
             needsInstancePrivateBrandCheck ? lastInstancePrivateName : null,
+            t.cloneNode(superClass),
             state,
             version,
           ),
@@ -1111,6 +1121,7 @@ function createLocalsAssignment(
   classDecorations: t.ArrayExpression,
   classDecorationsFlag: t.NumericLiteral,
   maybePrivateBranName: t.PrivateName | null,
+  superClass: null | t.Expression,
   state: PluginPass,
   version: DecoratorVersionKind,
 ) {
@@ -1136,7 +1147,11 @@ function createLocalsAssignment(
   }
 
   if (process.env.BABEL_8_BREAKING || version === "2023-05") {
-    if (maybePrivateBranName || classDecorationsFlag.value !== 0) {
+    if (
+      maybePrivateBranName ||
+      superClass ||
+      classDecorationsFlag.value !== 0
+    ) {
       args.push(classDecorationsFlag);
     }
     if (maybePrivateBranName) {
@@ -1145,7 +1160,10 @@ function createLocalsAssignment(
             _ => ${t.cloneNode(maybePrivateBranName)} in _
           ` as t.ArrowFunctionExpression,
       );
+    } else if (superClass) {
+      args.push(t.unaryExpression("void", t.numericLiteral(0)));
     }
+    if (superClass) args.push(superClass);
     rhs = t.callExpression(state.addHelper("applyDecs2305"), args);
   } else if (version === "2023-01") {
     if (maybePrivateBranName) {


Test patch:
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-nested-constructor-expression/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-nested-constructor-expression/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-nested-constructor-expression/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-nested-constructor-expression/output.js
@@ -1,9 +1,9 @@
-var _initClass;
+var _initClass, _Bar;
 const dec = () => {};
 let _Foo;
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
-    [_Foo, _initClass] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+    [_Foo, _initClass] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _Bar).c;
   }
   constructor() {
     let foo = super();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-accessor/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-accessor/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-accessor/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-accessor/output.js
@@ -1,10 +1,10 @@
-var _call_x, _initProto;
+var _call_x, _initProto, _Bar;
 const dec = () => {};
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
     [_call_x, _initProto] = babelHelpers.applyDecs2305(this, [[dec, 3, "x", function () {
       return Bar.prototype.foo.call(this);
-    }]], [], 0, _ => #x in _).e;
+    }]], [], 0, _ => #x in _, _Bar).e;
   }
   constructor(...args) {
     super(...args);
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-method/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-method/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-method/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-assumption-constantSuper/super-in-private-method/output.js
@@ -1,10 +1,10 @@
-var _call_x, _initProto;
+var _call_x, _initProto, _Bar;
 const dec = () => {};
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
     [_call_x, _initProto] = babelHelpers.applyDecs2305(this, [[dec, 2, "x", function () {
       return Bar.prototype.foo.call(this);
-    }]], [], 0, _ => #x in _).e;
+    }]], [], 0, _ => #x in _, _Bar).e;
   }
   constructor(...args) {
     super(...args);
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions-static-blocks/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions-static-blocks/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions-static-blocks/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions-static-blocks/output.js
@@ -1,4 +1,4 @@
-var _initClass, _A, _temp, _initClass2, _C, _temp2, _initClass3, _D, _temp3, _initClass4, _decorated_class, _temp4, _class5, _initClass5, _G, _temp5, _initClass6, _decorated_class2, _temp6, _class7, _initClass7, _H, _temp7, _initClass8, _K, _temp8;
+var _initClass, _A, _temp, _initClass2, _C, _temp2, _initClass3, _D, _temp3, _initClass4, _decorated_class, _temp4, _class5, _initClass5, _G, _temp5, _initClass6, _decorated_class2, _temp6, _class7, _initClass7, _H, _I, _temp7, _initClass8, _K, _L, _temp8;
 const dec = () => {};
 const A = (new (_temp = class extends babelHelpers.identity {
   constructor() {
@@ -50,18 +50,18 @@ const H = (new (_temp7 = class extends babelHelpers.identity {
     super(_H), (() => {})(), _initClass7();
   }
 }, (_class8 => {
-  class H extends I {}
+  class H extends (_I = I) {}
   _class8 = H;
-  [_H, _initClass7] = babelHelpers.applyDecs2305(_class8, [], [dec]).c;
+  [_H, _initClass7] = babelHelpers.applyDecs2305(_class8, [], [dec], 0, void 0, _I).c;
 })(), _temp7)(), _H);
 const J = (new (_temp8 = class extends babelHelpers.identity {
   constructor() {
     super(_K), (() => {})(), _initClass8();
   }
 }, (_class9 => {
-  class K extends L {}
+  class K extends (_L = L) {}
   _class9 = K;
-  [_K, _initClass8] = babelHelpers.applyDecs2305(_class9, [], [dec]).c;
+  [_K, _initClass8] = babelHelpers.applyDecs2305(_class9, [], [dec], 0, void 0, _L).c;
 })(), _temp8)(), _K);
 function classFactory() {
   var _initClass9, _decorated_class3, _temp9, _class11;
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/expressions/output.js
@@ -1,12 +1,12 @@
-var _initClass, _A, _class, _initClass2, _C, _class2, _initClass3, _D, _class3, _initClass4, _decorated_class, _class4, _initClass5, _G, _class5, _initClass6, _decorated_class2, _class6, _initClass7, _H, _class7, _initClass8, _K, _class8;
+var _initClass, _A, _class, _initClass2, _C, _class2, _initClass3, _D, _class3, _initClass4, _decorated_class, _class4, _initClass5, _G, _class5, _initClass6, _decorated_class2, _class6, _initClass7, _H, _I, _class7, _initClass8, _K, _L, _class8;
 const dec = () => {};
 const A = ((_class = class A {}, [_A, _initClass] = babelHelpers.applyDecs2305(_class, [], [dec]).c, _initClass()), _A);
 const B = ((_class2 = class C {}, [_C, _initClass2] = babelHelpers.applyDecs2305(_class2, [], [dec]).c, _initClass2()), _C);
 const D = ((_class3 = class D {}, [_D, _initClass3] = babelHelpers.applyDecs2305(_class3, [], [dec]).c, _initClass3()), _D);
 const E = (((_class4 = class {}, [_decorated_class, _initClass4] = babelHelpers.applyDecs2305(_class4, [], [dec]).c, _initClass4()), _decorated_class), 123);
 const F = [((_class5 = class G {}, [_G, _initClass5] = babelHelpers.applyDecs2305(_class5, [], [dec]).c, _initClass5()), _G), ((_class6 = class {}, [_decorated_class2, _initClass6] = babelHelpers.applyDecs2305(_class6, [], [dec]).c, _initClass6()), _decorated_class2)];
-const H = ((_class7 = class H extends I {}, [_H, _initClass7] = babelHelpers.applyDecs2305(_class7, [], [dec]).c, _initClass7()), _H);
-const J = ((_class8 = class K extends L {}, [_K, _initClass8] = babelHelpers.applyDecs2305(_class8, [], [dec]).c, _initClass8()), _K);
+const H = ((_class7 = class H extends (_I = I) {}, [_H, _initClass7] = babelHelpers.applyDecs2305(_class7, [], [dec], 0, void 0, _I).c, _initClass7()), _H);
+const J = ((_class8 = class K extends (_L = L) {}, [_K, _initClass8] = babelHelpers.applyDecs2305(_class8, [], [dec], 0, void 0, _L).c, _initClass8()), _K);
 function classFactory() {
   var _initClass9, _decorated_class3, _class9;
   return (_class9 = class {}, [_decorated_class3, _initClass9] = babelHelpers.applyDecs2305(_class9, [], [dec]).c, _initClass9()), _decorated_class3;
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/inheritance/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/inheritance/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/inheritance/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/inheritance/output.js
@@ -1,4 +1,4 @@
-var _initClass, _class, _initClass2, _class2;
+var _initClass, _class, _initClass2, _Bar2, _class2;
 const dec1 = () => {};
 const dec2 = () => {};
 let _Bar;
@@ -7,7 +7,7 @@ _class = Bar;
 [_Bar, _initClass] = babelHelpers.applyDecs2305(_class, [], [dec1]).c;
 _initClass();
 let _Foo;
-class Foo extends _Bar {}
+class Foo extends (_Bar2 = _Bar) {}
 _class2 = Foo;
-[_Foo, _initClass2] = babelHelpers.applyDecs2305(_class2, [], [dec2]).c;
+[_Foo, _initClass2] = babelHelpers.applyDecs2305(_class2, [], [dec2], 0, void 0, _Bar2).c;
 _initClass2();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/initializers/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/initializers/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/initializers/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes--to-es2015/initializers/output.js
@@ -1,4 +1,4 @@
-var _initClass, _temp, _initClass2, _temp2;
+var _initClass, _temp, _initClass2, _Foo2, _temp2;
 const dec = () => {};
 let _Foo;
 new (_temp = class extends babelHelpers.identity {
@@ -18,7 +18,7 @@ new (_temp2 = class extends babelHelpers.identity {
     })(), 123))), _initClass2();
   }
 }, (_class3 => {
-  class Bar extends _Foo {}
+  class Bar extends (_Foo2 = _Foo) {}
   _class3 = Bar;
-  [_Bar, _initClass2] = babelHelpers.applyDecs2305(_class3, [], [dec]).c;
+  [_Bar, _initClass2] = babelHelpers.applyDecs2305(_class3, [], [dec], 0, void 0, _Foo2).c;
 })(), _temp2)();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions-static-blocks/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions-static-blocks/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions-static-blocks/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions-static-blocks/output.js
@@ -1,4 +1,4 @@
-var _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _initClass8, _K;
+var _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _I, _initClass8, _K, _L;
 const dec = () => {};
 const A = (new class extends babelHelpers.identity {
   static {
@@ -73,9 +73,9 @@ const F = [(new class extends babelHelpers.identity {
 }(), _decorated_class2)];
 const H = (new class extends babelHelpers.identity {
   static {
-    class H extends I {
+    class H extends (_I = I) {
       static {
-        [_H, _initClass7] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+        [_H, _initClass7] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _I).c;
       }
     }
   }
@@ -85,9 +85,9 @@ const H = (new class extends babelHelpers.identity {
 }(), _H);
 const J = (new class extends babelHelpers.identity {
   static {
-    class K extends L {
+    class K extends (_L = L) {
       static {
-        [_K, _initClass8] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+        [_K, _initClass8] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _L).c;
       }
     }
   }
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/expressions/output.js
@@ -1,4 +1,4 @@
-var _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _initClass8, _K;
+var _initClass, _A, _initClass2, _C, _initClass3, _D, _initClass4, _decorated_class, _initClass5, _G, _initClass6, _decorated_class2, _initClass7, _H, _I, _initClass8, _K, _L;
 const dec = () => {};
 const A = (class A {
   static {
@@ -47,17 +47,17 @@ const F = [(class G {
     _initClass6();
   }
 }, _decorated_class2)];
-const H = (class H extends I {
+const H = (class H extends (_I = I) {
   static {
-    [_H, _initClass7] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+    [_H, _initClass7] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _I).c;
   }
   static {
     _initClass7();
   }
 }, _H);
-const J = (class K extends L {
+const J = (class K extends (_L = L) {
   static {
-    [_K, _initClass8] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+    [_K, _initClass8] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _L).c;
   }
   static {
     _initClass8();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/inheritance/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/inheritance/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/inheritance/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/inheritance/output.js
@@ -1,4 +1,4 @@
-var _initClass, _dec, _initClass2, _dec2;
+var _initClass, _dec, _initClass2, _dec2, _Bar2;
 const dec = () => {};
 let _Bar;
 _dec = dec1;
@@ -12,9 +12,9 @@ class Bar {
 }
 let _Foo;
 _dec2 = dec2;
-class Foo extends _Bar {
+class Foo extends (_Bar2 = _Bar) {
   static {
-    [_Foo, _initClass2] = babelHelpers.applyDecs2305(this, [], [_dec2]).c;
+    [_Foo, _initClass2] = babelHelpers.applyDecs2305(this, [], [_dec2], 0, void 0, _Bar2).c;
   }
   static {
     _initClass2();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/initializers/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/initializers/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/initializers/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-classes/initializers/output.js
@@ -1,4 +1,4 @@
-var _initClass, _initClass2;
+var _initClass, _initClass2, _Foo2;
 const dec = () => {};
 let _Foo;
 new class extends babelHelpers.identity {
@@ -17,9 +17,9 @@ new class extends babelHelpers.identity {
 let _Bar;
 new class extends babelHelpers.identity {
   static {
-    class Bar extends _Foo {
+    class Bar extends (_Foo2 = _Foo) {
       static {
-        [_Bar, _initClass2] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+        [_Bar, _initClass2] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _Foo2).c;
       }
     }
   }
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc--to-es2015/initProto-existing-derived-constructor/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc--to-es2015/initProto-existing-derived-constructor/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc--to-es2015/initProto-existing-derived-constructor/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc--to-es2015/initProto-existing-derived-constructor/output.js
@@ -1,7 +1,7 @@
-var _dec, _initProto, _class;
+var _dec, _initProto, _B, _class;
 const dec = () => {};
 _dec = deco;
-class A extends B {
+class A extends (_B = B) {
   constructor() {
     let a = 2;
     _initProto(super(a));
@@ -10,4 +10,4 @@ class A extends B {
   method() {}
 }
 _class = A;
-[_initProto] = babelHelpers.applyDecs2305(_class, [[_dec, 2, "method"]], []).e;
+[_initProto] = babelHelpers.applyDecs2305(_class, [[_dec, 2, "method"]], [], 0, void 0, _B).e;
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor-multiple-super/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor-multiple-super/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor-multiple-super/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor-multiple-super/output.js
@@ -1,9 +1,9 @@
-var _dec, _initProto, _dec2, _initProto2;
+var _dec, _initProto, _B, _dec2, _initProto2, _B2;
 const dec = () => {};
 _dec = deco;
-class A extends B {
+class A extends (_B = B) {
   static {
-    [_initProto] = babelHelpers.applyDecs2305(this, [[_dec, 2, "method"]], []).e;
+    [_initProto] = babelHelpers.applyDecs2305(this, [[_dec, 2, "method"]], [], 0, void 0, _B).e;
   }
   constructor() {
     if (Math.random() > 0.5) {
@@ -15,9 +15,9 @@ class A extends B {
   method() {}
 }
 _dec2 = deco;
-class C extends B {
+class C extends (_B2 = B) {
   static {
-    [_initProto2] = babelHelpers.applyDecs2305(this, [[_dec2, 2, "method"]], []).e;
+    [_initProto2] = babelHelpers.applyDecs2305(this, [[_dec2, 2, "method"]], [], 0, void 0, _B2).e;
   }
   constructor() {
     try {
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/initProto-existing-derived-constructor/output.js
@@ -1,8 +1,8 @@
-var _initProto;
+var _initProto, _B;
 const dec = () => {};
-class A extends B {
+class A extends (_B = B) {
   static {
-    [_initProto] = babelHelpers.applyDecs2305(this, [[dec, 2, "method"]], []).e;
+    [_initProto] = babelHelpers.applyDecs2305(this, [[dec, 2, "method"]], [], 0, void 0, _B).e;
   }
   constructor() {
     let a = 2;
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-nested-constructor-expression/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-nested-constructor-expression/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-nested-constructor-expression/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-nested-constructor-expression/output.js
@@ -1,9 +1,9 @@
-var _initClass;
+var _initClass, _Bar;
 const dec = () => {};
 let _Foo;
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
-    [_Foo, _initClass] = babelHelpers.applyDecs2305(this, [], [dec]).c;
+    [_Foo, _initClass] = babelHelpers.applyDecs2305(this, [], [dec], 0, void 0, _Bar).c;
   }
   constructor() {
     let foo = super();
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-accessor/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-accessor/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-accessor/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-accessor/output.js
@@ -1,10 +1,10 @@
-var _call_x, _initProto;
+var _call_x, _initProto, _Bar;
 const dec = () => {};
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
     [_call_x, _initProto] = babelHelpers.applyDecs2305(this, [[dec, 3, "x", function () {
       return babelHelpers.get(babelHelpers.getPrototypeOf(Foo), "foo", this).call(this);
-    }]], [], 0, _ => #x in _).e;
+    }]], [], 0, _ => #x in _, _Bar).e;
   }
   constructor(...args) {
     super(...args);
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-method/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-method/output.js
--- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-method/output.js
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-05-misc/super-in-private-method/output.js
@@ -1,10 +1,10 @@
-var _call_x, _initProto;
+var _call_x, _initProto, _Bar;
 const dec = () => {};
-class Foo extends Bar {
+class Foo extends (_Bar = Bar) {
   static {
     [_call_x, _initProto] = babelHelpers.applyDecs2305(this, [[dec, 2, "x", function () {
       return babelHelpers.get(babelHelpers.getPrototypeOf(Foo), "foo", this).call(this);
-    }]], [], 0, _ => #x in _).e;
+    }]], [], 0, _ => #x in _, _Bar).e;
   }
   constructor(...args) {
     super(...args);
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/class/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/class/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/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/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/element/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/element/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/element/exec.js
@@ -0,0 +1,13 @@
+function dec(_, 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/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/no-decorators/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/no-decorators/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/no-decorators/exec.js
@@ -0,0 +1,5 @@
+Symbol.metadata = Symbol();
+
+class A {}
+
+expect(A.hasOwnProperty(Symbol.metadata)).toBe(false);
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/options.json b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/options.json
@@ -0,0 +1,8 @@
+{
+  "plugins": [
+    ["proposal-decorators", { "version": "2023-05" }],
+    "transform-class-properties",
+    "transform-private-methods",
+    "transform-class-static-block"
+  ]
+}
diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/subclass-no-super-decorators/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/subclass-no-super-decorators/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/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/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/subclass-super-decorators/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/metadata/subclass-super-decorators/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-proposal-decorators/test/fixtures/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);