From 78a877e2b7f088542a8fcd18f741523b0e3de5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 7 Feb 2024 00:38:23 +0100 Subject: [PATCH] Do not define `ctx.access.set` for setter decorators --- .../babel-helpers/src/helpers-generated.ts | 4 +- .../src/helpers/applyDecs2311.ts | 51 ++++++++++++------- .../private/exec.js | 2 + .../2023-11-getters--to-es2015/public/exec.js | 3 ++ .../static-private/exec.js | 2 + .../static-public/exec.js | 3 ++ .../private/exec.js | 5 ++ .../2023-11-methods--to-es2015/public/exec.js | 5 ++ .../static-private/exec.js | 5 ++ .../static-public/exec.js | 5 ++ .../private/exec.js | 2 + .../2023-11-setters--to-es2015/public/exec.js | 3 ++ .../static-private/exec.js | 2 + .../static-public/exec.js | 3 ++ 14 files changed, 74 insertions(+), 21 deletions(-) diff --git a/packages/babel-helpers/src/helpers-generated.ts b/packages/babel-helpers/src/helpers-generated.ts index 6ff7344dfaf3..d693bd8ed240 100644 --- a/packages/babel-helpers/src/helpers-generated.ts +++ b/packages/babel-helpers/src/helpers-generated.ts @@ -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=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;f3,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: 2882, gzip size: 1463 + // size: 2911, gzip size: 1497 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 c,a,u=Symbol.metadata||Symbol.for("Symbol.metadata"),s=Object.defineProperty,l={},f=n.length;function p(e,t,n,r){for(var o=0;o=0;H-=n?2:1){var K=b[H],R=n?b[H-1]:void 0,T={},A={kind:["field","accessor","method","getter","setter","class"][o],name:r,metadata:c,addInitializer:function(e,t){if(e.v)throw new Error("attempted to call addInitializer after decoration was finished");d(t,"An initializer","be",!0),i.push(t)}.bind(null,T)};if(D)a=K.call(R,z,A),T.v=1,d(a,"class decorators","return")&&(z=a);else if(A.static=f,A.private=m,a=A.access={has:m?v.bind():function(e){return r in e}},E||(P(),a.get=m?I?function(e){return g(e),F.value}:k("get",g):function(e){return e[r]}),j||(P(1),a.set=m?k("set",g):function(e,t){e[r]=t}),z=K.call(R,y?{get:F.get,set:F.set}:F[O],A),T.v=1,y){if("object"==typeof z&&z)(a=d(z.get,"accessor.get"))&&(F.get=a),(a=d(z.set,"accessor.set"))&&(F.set=a),(a=d(z.init,"accessor.init"))&&N.unshift(a);else if(void 0!==z)throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined")}else d(z,(h?"field":"method")+" decorators","return")&&(h?N.unshift(z):F[O]=z)}return o<2&&u.push(p.bind(null,N,1),p.bind(null,i,0)),h||D||(m?y?u.splice(-1,0,k("get"),k("set")):u.push(I?F[O]:p.call.bind(F[O])):s(e,r,F)),z}function m(e){return s(e,u,{configurable:!0,enumerable:!0,value:c})}return void 0!==i&&(c=i[u]),c=Object.create(null==c?null:c),a=function(){var n,r,i=[];function c(e){e&&i.push(p.bind(null,e,0))}for(var a=0;a=0;O-=n?2:1){var _=b[O],z=n?b[O-1]:void 0,H={},K={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");d(t,"An initializer","be",!0),i.push(t)}.bind(null,H)};if(D)c=_.call(z,N,K),H.v=1,d(c,"class decorators","return")&&(N=c);else{if(K.static=f,K.private=m,c=K.access={has:m?y.bind():function(e){return r in e}},!O&&!h&&!m){var R=l[S];if(R){if(7!=(R^o))throw new Error("Decorating two elements with the same name ("+r+") is not supported yet");l[S]=1}else l[S]=o>2?o:1}if(j||(c.get=m?E?function(e){return g(e),P.value}:I("get",g):function(e){return e[r]}),(o<2||j)&&(c.set=m?I("set",g):function(e,t){e[r]=t}),N=_.call(z,v?{get:P.get,set:P.set}:P[F],K),H.v=1,v){if("object"==typeof N&&N)(c=d(N.get,"accessor.get"))&&(P.get=c),(c=d(N.set,"accessor.set"))&&(P.set=c),(c=d(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 d(N,(h?"field":"method")+" decorators","return")&&(h?k.unshift(N):P[F]=N)}}return o<2&&u.push(p.bind(null,k,1),p.bind(null,i,0)),h||D||(m?v?u.splice(-1,0,I("get"),I("set")):u.push(E?P[F]:p.call.bind(P[F])):s(e,r,P)),N}function m(e){return s(e,u,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[u]),a=Object.create(null==a?null:a),c=function(){var n,r,i=[];function a(e){e&&i.push(p.bind(null,e,0))}for(var c=0;c = {}; + // Use both as and satisfies to ensure that we only use non-zero values + var existingNonFields = { __proto__: null } as Record< + string, + 1 | 3 | 4 + > satisfies Record< + string, + PROP_KIND.ACCESSOR | PROP_KIND.GETTER | PROP_KIND.SETTER + >; var hasClassDecs = classDecs.length; // This is a temporary variable for smaller helper size var _: any; @@ -269,21 +276,6 @@ export default /* @no-mangle */ function applyDecs2311( var isSetter = kind === PROP_KIND.SETTER; var isMethod = kind === PROP_KIND.METHOD; - function markExistingNonField(hasSetter?: 1) { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (!i && !isField && !isPrivate) { - if (existingNonFields[mapKey + hasSetter]) { - throw new Error( - "Decorating two elements with the same name (" + - name + - ") is not supported yet", - ); - } - - existingNonFields[mapKey + hasSetter] = 1; - } - } - function _bindPropCall(name: keyof PropertyDescriptor, before?: Function) { return function (_this: any, value?: any) { if (before) { @@ -377,8 +369,30 @@ export default /* @no-mangle */ function applyDecs2311( }, }; + if (!i && !isField && !isPrivate) { + var flag = existingNonFields[mapKey]; + if (flag) { + if ((flag ^ kind) === 7) { + // 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. + existingNonFields[mapKey] = PROP_KIND.ACCESSOR; + } else { + throw new Error( + "Decorating two elements with the same name (" + + name + + ") is not supported yet", + ); + } + } else { + // We use PROP_KIND.ACCESSOR to mark a name as "fully used": + // either a get/set pair, or a non-getter/setter. + existingNonFields[mapKey] = + kind > PROP_KIND.METHOD + ? (kind as PROP_KIND.GETTER | PROP_KIND.SETTER) + : PROP_KIND.ACCESSOR; + } + } if (!isSetter) { - markExistingNonField(); _.get = isPrivate ? isMethod ? function (_this: any) { @@ -390,8 +404,7 @@ export default /* @no-mangle */ function applyDecs2311( return target[name]; }; } - if (!isGetter) { - markExistingNonField(1); + if (kind < PROP_KIND.METHOD || isSetter) { _.set = isPrivate ? _bindPropCall("set", assertInstanceIfPrivate) : function (target: any, v: any) { diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/private/exec.js index 604bd55ecdcf..0936aba0b50e 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/private/exec.js @@ -26,6 +26,8 @@ let foo = new Foo(); const aContext = foo['#aContext']; +expect(aContext.access).not.toHaveProperty("set"); + expect(aContext.access.has(foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(foo))).toBe(false); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/public/exec.js index 8ad618ae7afa..c4592966d8df 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/public/exec.js @@ -28,6 +28,9 @@ let foo = new Foo(); const aContext = foo['aContext']; const bContext = foo['bContext']; +expect(aContext.access).not.toHaveProperty("set"); +expect(bContext.access).not.toHaveProperty("set"); + expect(aContext.access.has(foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(foo))).toBe(true); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-private/exec.js index dcade7dd8781..1e25bdfad497 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-private/exec.js @@ -24,6 +24,8 @@ class Foo { const aContext = Foo['#aContext']; +expect(aContext.access).not.toHaveProperty("set"); + expect(aContext.access.has(Foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(Foo))).toBe(false); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-public/exec.js index 65024716d1ae..f7c9745ecbae 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-getters--to-es2015/static-public/exec.js @@ -26,6 +26,9 @@ class Foo { const aContext = Foo['aContext']; const bContext = Foo['bContext']; +expect(aContext.access).not.toHaveProperty("set"); +expect(bContext.access).not.toHaveProperty("set"); + expect(aContext.access.has(Foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(Foo))).toBe(true); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private/exec.js index 5a13a15503fb..d766ded54c1e 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private/exec.js @@ -1,5 +1,8 @@ +let aContext; + function dec(fn, context) { expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; return function () { return fn.call(this) + 1; } @@ -20,6 +23,8 @@ class Foo { let foo = new Foo(); +expect(aContext.access).not.toHaveProperty("set"); + expect(foo.callA()).toBe(2); foo.value = 123; expect(foo.callA()).toBe(124); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/public/exec.js index 8512a6fc55ea..d8f733ec0e96 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/public/exec.js @@ -1,5 +1,8 @@ +let aContext; + function dec(fn, context) { expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; return function () { return fn.call(this) + 1; } @@ -21,6 +24,8 @@ class Foo { let foo = new Foo(); +expect(aContext.access).not.toHaveProperty("set"); + expect(foo.a()).toBe(2); expect(foo.b()).toBe(2); foo.value = 123; diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-private/exec.js index f416caa6d4af..76ee192448b6 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-private/exec.js @@ -1,5 +1,8 @@ +let aContext; + function dec(fn, context) { expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; return function () { return fn.call(this) + 1; } @@ -18,6 +21,8 @@ class Foo { } } +expect(aContext.access).not.toHaveProperty("set"); + expect(Foo.callA()).toBe(2); Foo.value = 123; expect(Foo.callA()).toBe(124); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-public/exec.js index 47d2e2e02cdc..26e7ff852c81 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/static-public/exec.js @@ -1,5 +1,8 @@ +let aContext; + function dec(fn, context) { expect(fn.name).toEqual(context.name); + if (!aContext) aContext = context; return function () { return fn.call(this) + 1; } @@ -19,6 +22,8 @@ class Foo { } } +expect(aContext.access).not.toHaveProperty("set"); + expect(Foo.a()).toBe(2); expect(Foo.b()).toBe(2); Foo.value = 123; diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/private/exec.js index 212817ee56e4..f28fec2051f8 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/private/exec.js @@ -26,6 +26,8 @@ let foo = new Foo(); const aContext = foo['#aContext']; +expect(aContext.access).not.toHaveProperty("get"); + expect(aContext.access.has(foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(foo))).toBe(false); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/public/exec.js index fcf76c5edbc6..84576bc0e91f 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/public/exec.js @@ -28,6 +28,9 @@ let foo = new Foo(); const aContext = foo['aContext']; const bContext = foo['bContext']; +expect(aContext.access).not.toHaveProperty("get"); +expect(bContext.access).not.toHaveProperty("get"); + expect(aContext.access.has(foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(foo))).toBe(true); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-private/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-private/exec.js index 796f5bb9dca6..5d6141f742cb 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-private/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-private/exec.js @@ -24,6 +24,8 @@ class Foo { const aContext = Foo['#aContext']; +expect(aContext.access).not.toHaveProperty("get"); + expect(aContext.access.has(Foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(Foo))).toBe(false); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-public/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-public/exec.js index 7946a5418f25..79a9fccf013a 100644 --- a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-public/exec.js +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-setters--to-es2015/static-public/exec.js @@ -26,6 +26,9 @@ class Foo { const aContext = Foo['aContext']; const bContext = Foo['bContext']; +expect(aContext.access).not.toHaveProperty("get"); +expect(bContext.access).not.toHaveProperty("get"); + expect(aContext.access.has(Foo)).toBe(true); expect(aContext.access.has({})).toBe(false); expect(aContext.access.has(Object.create(Foo))).toBe(true);