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

Handle symbol key class elements decoration #16270

Merged
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
4 changes: 2 additions & 2 deletions packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -48,10 +48,10 @@ export default Object.freeze({
"7.21.0",
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2305(e,t,r,n,o,a){function i(e,t,r){return function(n,o){return r&&r(n),e[t].call(n,o)}}function c(e,t){for(var r=0;r<e.length;r++)e[r].call(t);return t}function s(e,t,r,n){if("function"!=typeof e&&(n||void 0!==e))throw new TypeError(t+" must "+(r||"be")+" a function"+(n?"":" or undefined"));return e}function applyDec(e,t,r,n,o,a,c,u,l,f,p,d,h){function m(e){if(!h(e))throw new TypeError("Attempted to access private element on non-instance")}var y,v=t[0],g=t[3],b=!u;if(!b){r||Array.isArray(v)||(v=[v]);var w={},S=[],A=3===o?"get":4===o||d?"set":"value";f?(p||d?w={get:setFunctionName((function(){return g(this)}),n,"get"),set:function(e){t[4](this,e)}}:w[A]=g,p||setFunctionName(w[A],n,2===o?"":A)):p||(w=Object.getOwnPropertyDescriptor(e,n))}for(var P=e,j=v.length-1;j>=0;j-=r?2:1){var D=v[j],E=r?v[j-1]:void 0,I={},O={kind:["field","accessor","method","getter","setter","class"][o],name:n,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");s(t,"An initializer","be",!0),c.push(t)}.bind(null,I)};try{if(b)(y=s(D.call(E,P,O),"class decorators","return"))&&(P=y);else{var k,F;O.static=l,O.private=f,f?2===o?k=function(e){return m(e),w.value}:(o<4&&(k=i(w,"get",m)),3!==o&&(F=i(w,"set",m))):(k=function(e){return e[n]},(o<2||4===o)&&(F=function(e,t){e[n]=t}));var N=O.access={has:f?h.bind():function(e){return n in e}};if(k&&(N.get=k),F&&(N.set=F),P=D.call(E,d?{get:w.get,set:w.set}:w[A],O),d){if("object"==typeof P&&P)(y=s(P.get,"accessor.get"))&&(w.get=y),(y=s(P.set,"accessor.set"))&&(w.set=y),(y=s(P.init,"accessor.init"))&&S.push(y);else if(void 0!==P)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0")}else s(P,(p?"field":"method")+" decorators","return")&&(p?S.push(P):w[A]=P)}}finally{I.v=!0}}return(p||d)&&u.push((function(e,t){for(var r=S.length-1;r>=0;r--)t=S[r].call(e,t);return t})),p||b||(f?d?u.push(i(w,"get"),i(w,"set")):u.push(2===o?w[A]:i.call.bind(w[A])):Object.defineProperty(e,n,w)),P}function u(e,t){return Object.defineProperty(e,Symbol.metadata||Symbol.for("Symbol.metadata"),{configurable:!0,enumerable:!0,value:t})}if(arguments.length>=6)var l=a[Symbol.metadata||Symbol.for("Symbol.metadata")];var f=Object.create(null==l?null:l),p=function(e,t,r,n){var o,a,i=[],s=function(t){return checkInRHS(t)===e},u=new Map;function l(e){e&&i.push(c.bind(null,e))}for(var f=0;f<t.length;f++){var p=t[f];if(Array.isArray(p)){var d=p[1],h=p[2],m=p.length>3,y=16&d,v=!!(8&d),g=0==(d&=7),b=h+"/"+v;if(!g&&!m){var w=u.get(b);if(!0===w||3===w&&4!==d||4===w&&3!==d)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);u.set(b,!(d>2)||d)}applyDec(v?e:e.prototype,p,y,m?"#"+h:toPropertyKey(h),d,n,v?a=a||[]:o=o||[],i,v,m,g,1===d,v&&m?s:r)}}return l(o),l(a),i}(e,t,o,f);return r.length||u(e,f),{e:p,get c(){var t=[];return r.length&&[u(applyDec(e,[r],n,e.name,5,f,t),f),c.bind(null,t,e)]}}}',
),
// size: 2883, gzip size: 1472
// size: 2899, gzip size: 1475
applyDecs2311: helper(
"7.23.0",
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2311(e,t,n,r,o,i){var a,c,u=Symbol.metadata||Symbol.for("Symbol.metadata"),s=Object.defineProperty,l=Object.create,f=l(null),p=n.length;function d(e,t,n,r){for(var o=0;o<e.length;o++)r=e[o].apply(n,t?[r]:[]);return t?r:n}function m(e,t,n,r){if("function"!=typeof e&&(r||void 0!==e))throw new TypeError(t+" must "+(n||"be")+" a function"+(r?"":" or undefined"));return e}function applyDec(e,t,n,r,o,i,u,l,p,h,y,v){function g(e){if(!v(e))throw new TypeError("Attempted to access private element on non-instance")}var b=[].concat(t[0]),w=t[3],D=!u,S=r+"/"+l,j=3===o,E=4===o,I=2===o;function P(e,t){return function(n,r){return t&&t(n),k[e].call(n,r)}}if(!D){var k={},F=[],N=j?"get":E||y?"set":"value";if(p?(h||y?k={get:setFunctionName((function(){return w(this)}),r,"get"),set:function(e){t[4](this,e)}}:k[N]=w,h||setFunctionName(k[N],r,I?"":N)):h||(k=Object.getOwnPropertyDescriptor(e,r)),!h&&!p){if((c=f[S])&&7!=(c^o))throw new Error("Decorating two elements with the same name ("+r+") is not supported yet");f[S]=o<3?1:o}}for(var O=e,z=b.length-1;z>=0;z-=n?2:1){var H=b[z],K=n?b[z-1]:void 0,R={},T={kind:["field","accessor","method","getter","setter","class"][o],name:r,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");m(t,"An initializer","be",!0),i.push(t)}.bind(null,R)};if(D)c=H.call(K,O,T),R.v=1,m(c,"class decorators","return")&&(O=c);else if(T.static=l,T.private=p,c=T.access={has:p?v.bind():function(e){return r in e}},E||(c.get=p?I?function(e){return g(e),k.value}:P("get",g):function(e){return e[r]}),I||j||(c.set=p?P("set",g):function(e,t){e[r]=t}),O=H.call(K,y?{get:k.get,set:k.set}:k[N],T),R.v=1,y){if("object"==typeof O&&O)(c=m(O.get,"accessor.get"))&&(k.get=c),(c=m(O.set,"accessor.set"))&&(k.set=c),(c=m(O.init,"accessor.init"))&&F.unshift(c);else if(void 0!==O)throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined")}else m(O,(h?"field":"method")+" decorators","return")&&(h?F.unshift(O):k[N]=O)}return o<2&&u.push(d.bind(null,F,1),d.bind(null,i,0)),h||D||(p?y?u.splice(-1,0,P("get"),P("set")):u.push(I?k[N]:d.call.bind(k[N])):s(e,r,k)),O}function h(e){return s(e,u,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[u]),a=l(null==a?null:a),c=function(){var n,r,i=[];function a(e){e&&i.push(d.bind(null,e,0))}for(var c=0;c<t.length;c++){var u=t[c],s=u[1],l=u[2],f=!!u[3],p=16&s,m=!!(8&s),h=0==(s&=7),y=1===s;applyDec(m?e:e.prototype,u,p,f?"#"+l:toPropertyKey(l),s,h||y?[]:m?r=r||[]:n=n||[],i,m,f,h,y,m&&f?function(t){return checkInRHS(t)===e}:o)}return a(n),a(r),i}(),p||h(e),{e:c,get c(){var t=[];return p&&[h(applyDec(e,[n],r,e.name,5,t)),d.bind(null,t,0,e)]}}}',
'import checkInRHS from"checkInRHS";import setFunctionName from"setFunctionName";import toPropertyKey from"toPropertyKey";export default function applyDecs2311(e,t,n,r,o,i){var a,c,u=Symbol.metadata||Symbol.for("Symbol.metadata"),s=Object.defineProperty,l=Object.create,f=[l(null),l(null)],p=n.length;function d(e,t,n,r){for(var o=0;o<e.length;o++)r=e[o].apply(n,t?[r]:[]);return t?r:n}function m(e,t,n,r){if("function"!=typeof e&&(r||void 0!==e))throw new TypeError(t+" must "+(n||"be")+" a function"+(r?"":" or undefined"));return e}function applyDec(e,t,n,r,o,i,u,l,p,h,y,v){function g(e){if(!v(e))throw new TypeError("Attempted to access private element on non-instance")}var b=[].concat(t[0]),w=t[3],D=!u,S=3===o,j=4===o,E=2===o;function I(e,t){return function(n,r){return t&&t(n),P[e].call(n,r)}}if(!D){var P={},k=[],F=S?"get":j||y?"set":"value";if(p?(h||y?P={get:setFunctionName((function(){return w(this)}),r,"get"),set:function(e){t[4](this,e)}}:P[F]=w,h||setFunctionName(P[F],r,E?"":F)):h||(P=Object.getOwnPropertyDescriptor(e,r)),!h&&!p){if((c=f[+l][r])&&7!=(c^o))throw new Error("Decorating two elements with the same name ("+P[F].name+") is not supported yet");f[+l][r]=o<3?1:o}}for(var N=e,O=b.length-1;O>=0;O-=n?2:1){var z=b[O],H=n?b[O-1]:void 0,K={},R={kind:["field","accessor","method","getter","setter","class"][o],name:r,metadata:a,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");m(t,"An initializer","be",!0),i.push(t)}.bind(null,K)};if(D)c=z.call(H,N,R),K.v=1,m(c,"class decorators","return")&&(N=c);else if(R.static=l,R.private=p,c=R.access={has:p?v.bind():function(e){return r in e}},j||(c.get=p?E?function(e){return g(e),P.value}:I("get",g):function(e){return e[r]}),E||S||(c.set=p?I("set",g):function(e,t){e[r]=t}),N=z.call(H,y?{get:P.get,set:P.set}:P[F],R),K.v=1,y){if("object"==typeof N&&N)(c=m(N.get,"accessor.get"))&&(P.get=c),(c=m(N.set,"accessor.set"))&&(P.set=c),(c=m(N.init,"accessor.init"))&&k.unshift(c);else if(void 0!==N)throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined")}else m(N,(h?"field":"method")+" decorators","return")&&(h?k.unshift(N):P[F]=N)}return o<2&&u.push(d.bind(null,k,1),d.bind(null,i,0)),h||D||(p?y?u.splice(-1,0,I("get"),I("set")):u.push(E?P[F]:d.call.bind(P[F])):s(e,r,P)),N}function h(e){return s(e,u,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[u]),a=l(null==a?null:a),c=function(){var n,r,i=[];function a(e){e&&i.push(d.bind(null,e,0))}for(var c=0;c<t.length;c++){var u=t[c],s=u[1],l=u[2],f=!!u[3],p=16&s,m=!!(8&s),h=0==(s&=7),y=1===s;applyDec(m?e:e.prototype,u,p,f?"#"+l:toPropertyKey(l),s,h||y?[]:m?r=r||[]:n=n||[],i,m,f,h,y,m&&f?function(t){return checkInRHS(t)===e}:o)}return a(n),a(r),i}(),p||h(e),{e:c,get c(){var t=[];return p&&[h(applyDec(e,[n],r,e.name,5,t)),d.bind(null,t,0,e)]}}}',
),
// size: 187, gzip size: 167
assertClassBrand: helper(
Expand Down
29 changes: 14 additions & 15 deletions packages/babel-helpers/src/helpers/applyDecs2311.ts
Expand Up @@ -26,7 +26,7 @@ type DecoratorContextAccess = {
};
type DecoratorContext = {
kind: "accessor" | "method" | "getter" | "setter" | "field" | "class";
name: string;
name: string | symbol;
static?: boolean;
private?: boolean;
access?: DecoratorContextAccess;
Expand All @@ -42,7 +42,10 @@ type DecoratorInfo =
privateSetter?: Function,
]
| [classDecs: Function[]];

type DecoratorNonFieldCheckStorage = Record<
string | symbol,
PROP_KIND.ACCESSOR | PROP_KIND.GETTER | PROP_KIND.SETTER
>;
/**
Basic usage:

Expand Down Expand Up @@ -202,13 +205,10 @@ export default /* @no-mangle */ function applyDecs2311(
var create = Object.create;
var metadata: any;
// Use both as and satisfies to ensure that we only use non-zero values
var existingNonFields = create(null) as Record<
string,
1 | 3 | 4
> satisfies Record<
string,
PROP_KIND.ACCESSOR | PROP_KIND.GETTER | PROP_KIND.SETTER
>;
var existingNonFields = [create(null), create(null)] as [
DecoratorNonFieldCheckStorage,
DecoratorNonFieldCheckStorage,
];
var hasClassDecs = classDecs.length;
// This is a temporary variable for smaller helper size
var _: any;
Expand Down Expand Up @@ -250,7 +250,7 @@ export default /* @no-mangle */ function applyDecs2311(
Class: any,
decInfo: DecoratorInfo,
decoratorsHaveThis: number,
name: string,
name: string | symbol,
kind: PROP_KIND,
initializers: Function[],
ret?: Function[],
Expand All @@ -270,8 +270,7 @@ export default /* @no-mangle */ function applyDecs2311(

var decs = [].concat(decInfo[0]),
decVal = decInfo[3],
isClass = !ret,
mapKey = name + "/" + isStatic;
isClass = !ret;

var isGetter = kind === PROP_KIND.GETTER;
var isSetter = kind === PROP_KIND.SETTER;
Expand Down Expand Up @@ -322,19 +321,19 @@ export default /* @no-mangle */ function applyDecs2311(
}

if (!isField && !isPrivate) {
_ = existingNonFields[mapKey];
_ = existingNonFields[+isStatic][name];
// flag is 1, 3, or 4; kind is 0, 1, 2, 3, or 4
// flag ^ kind is 7 if and only if one of them is 3 and the other one is 4.
if (_ && (_ ^ kind) !== 7) {
throw new Error(
"Decorating two elements with the same name (" +
name +
desc[key].name +
") is not supported yet",
);
}
// We use PROP_KIND.ACCESSOR to mark a name as "fully used":
// either a get/set pair, or a non-getter/setter.
existingNonFields[mapKey] =
existingNonFields[+isStatic][name] =
kind < PROP_KIND.GETTER
? PROP_KIND.ACCESSOR
: (kind as PROP_KIND.GETTER | PROP_KIND.SETTER);
Expand Down
Expand Up @@ -49,3 +49,30 @@ expect(() => {
}
}
}).toThrow("Decorating two elements with the same name");

expect(() => {
class Foo {
@dec
*[Symbol.iterator]() {
return 1;
}

@dec
get [Symbol.iterator]() {
return function *() {};
}
}
}).toThrow("Decorating two elements with the same name (get [Symbol.iterator]) is not supported yet");

expect(() => {
class Foo {
@dec
*[Symbol.iterator]() {}

@dec
*[Symbol("Symbol.iterator")]() {}

@dec
*"[Symbol.iterator]"() {}
}
}).not.toThrow();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test will throw if we use symbol.description as a key in existingNonFields.