Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the "decorator metadata" proposal #15895

Merged
merged 5 commits into from Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -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",
Expand Down
49 changes: 39 additions & 10 deletions packages/babel-helpers/src/helpers/applyDecs2305.js
Expand Up @@ -45,7 +45,8 @@ function memberDec(
isStatic,
isPrivate,
value,
hasPrivateBrand
hasPrivateBrand,
metadata
) {
var kindStr;

Expand All @@ -71,6 +72,7 @@ function memberDec(
name: isPrivate ? "#" + name : name,
static: isStatic,
private: isPrivate,
metadata: metadata,
};

var decoratorFinishedRef = { v: false };
Expand Down Expand Up @@ -211,7 +213,8 @@ function applyMemberDec(
isStatic,
isPrivate,
initializers,
hasPrivateBrand
hasPrivateBrand,
metadata
) {
var decs = decInfo[0];

Expand Down Expand Up @@ -276,7 +279,8 @@ function applyMemberDec(
isStatic,
isPrivate,
value,
hasPrivateBrand
hasPrivateBrand,
metadata
);

if (newValue !== void 0) {
Expand Down Expand Up @@ -369,7 +373,7 @@ function applyMemberDec(
}
}

function applyMemberDecs(Class, decInfos, instanceBrand) {
function applyMemberDecs(Class, decInfos, instanceBrand, metadata) {
var ret = [];
var protoInitializers;
var staticInitializers;
Expand Down Expand Up @@ -451,7 +455,8 @@ function applyMemberDecs(Class, decInfos, instanceBrand) {
isStatic,
isPrivate,
initializers,
hasPrivateBrand
hasPrivateBrand,
metadata
);
}

Expand All @@ -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;
Expand All @@ -493,6 +498,7 @@ function applyClassDecs(targetClass, classDecs, decoratorsHaveThis) {
initializers,
decoratorFinishedRef
),
metadata,
}
);
} finally {
Expand All @@ -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);
Expand All @@ -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:

Expand Down Expand Up @@ -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
);
},
};
}
Expand Up @@ -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(
[
Expand All @@ -1080,6 +1089,7 @@ function transformClass(
t.arrayExpression(classDecorations),
t.numericLiteral(classDecorationsFlag),
needsInstancePrivateBrandCheck ? lastInstancePrivateName : null,
t.cloneNode(superClass),
state,
version,
),
Expand Down Expand Up @@ -1111,6 +1121,7 @@ function createLocalsAssignment(
classDecorations: t.ArrayExpression,
classDecorationsFlag: t.NumericLiteral,
maybePrivateBranName: t.PrivateName | null,
superClass: null | t.Expression,
state: PluginPass,
version: DecoratorVersionKind,
) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
@@ -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();
Expand Down
@@ -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);
Expand Down
@@ -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);
Expand Down
@@ -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() {
Expand Down Expand Up @@ -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;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -1,4 +1,4 @@
var _initClass, _class, _initClass2, _class2;
var _initClass, _class, _initClass2, _Bar2, _class2;
const dec1 = () => {};
const dec2 = () => {};
let _Bar;
Expand All @@ -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();