From efcc01cbe65325386dc9f5ae27260f517ee229aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 28 Mar 2024 19:21:45 -0400 Subject: [PATCH] Ensure decorators are callable (#16388) --- .../babel-helpers/src/helpers-generated.ts | 4 +- .../src/helpers/applyDecs2311.ts | 2 +- .../invalid-non-callable-decorators/exec.js | 43 +++++++++++++++++++ .../invalid-non-callable-decorators/exec.js | 43 +++++++++++++++++++ .../helpers/esm/applyDecs2311.js | 16 +++---- 5 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc/invalid-non-callable-decorators/exec.js diff --git a/packages/babel-helpers/src/helpers-generated.ts b/packages/babel-helpers/src/helpers-generated.ts index ea4edb8f44f9..384d3d2b915c 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 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 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: 2943, gzip size: 1502 + // size: 2968, gzip size: 1508 applyDecs2311: helper( "7.24.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,s,f,l,p,d=Symbol.metadata||Symbol.for("Symbol.metadata"),m=Object.defineProperty,h=Object.create,y=[h(null),h(null)],v=t.length;function g(t,n,r){return function(o,i){n&&(i=o,o=e);for(var a=0;a=0;O-=n?2:1){var z=h[O],H=n?h[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 Error("attempted to call addInitializer after decoration was finished");b(t,"An initializer","be",!0),i.push(t)}.bind(null,K)};if(w)c=z.call(H,N,R),K.v=1,b(c,"class decorators","return")&&(N=c);else if(R.static=s,R.private=f,c=R.access={has:f?p.bind():function(e){return r in e}},j||(c.get=f?E?function(e){return d(e),P.value}:I("get",0,d):function(e){return e[r]}),E||S||(c.set=f?I("set",0,d):function(e,t){e[r]=t}),N=z.call(H,D?{get:P.get,set:P.set}:P[F],R),K.v=1,D){if("object"==typeof N&&N)(c=b(N.get,"accessor.get"))&&(P.get=c),(c=b(N.set,"accessor.set"))&&(P.set=c),(c=b(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 b(N,(l?"field":"method")+" decorators","return")&&(l?k.unshift(N):P[F]=N)}return o<2&&u.push(g(k,s,1),g(i,s,0)),l||w||(f?D?u.splice(-1,0,I("get",s),I("set",s)):u.push(E?P[F]:b.call.bind(P[F])):m(e,r,P)),N}function w(e){return m(e,d,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[d]),a=h(null==a?null:a),f=[],l=function(e){e&&f.push(g(e))},p=function(t,r){for(var i=0;i=0;O-=n?2:1){var z=b(h[O],"A decorator","be",!0),A=n?h[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 Error("attempted to call addInitializer after decoration was finished");b(t,"An initializer","be",!0),i.push(t)}.bind(null,H)};if(w)c=z.call(A,N,K),H.v=1,b(c,"class decorators","return")&&(N=c);else if(K.static=s,K.private=f,c=K.access={has:f?p.bind():function(e){return r in e}},j||(c.get=f?E?function(e){return d(e),P.value}:I("get",0,d):function(e){return e[r]}),E||S||(c.set=f?I("set",0,d):function(e,t){e[r]=t}),N=z.call(A,D?{get:P.get,set:P.set}:P[F],K),H.v=1,D){if("object"==typeof N&&N)(c=b(N.get,"accessor.get"))&&(P.get=c),(c=b(N.set,"accessor.set"))&&(P.set=c),(c=b(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 b(N,(l?"field":"method")+" decorators","return")&&(l?k.unshift(N):P[F]=N)}return o<2&&u.push(g(k,s,1),g(i,s,0)),l||w||(f?D?u.splice(-1,0,I("get",s),I("set",s)):u.push(E?P[F]:b.call.bind(P[F])):m(e,r,P)),N}function w(e){return m(e,d,{configurable:!0,enumerable:!0,value:a})}return void 0!==i&&(a=i[d]),a=h(null==a?null:a),f=[],l=function(e){e&&f.push(g(e))},p=function(t,r){for(var i=0;i= 0; i -= decoratorsHaveThis ? 2 : 1) { - var dec = (decs as Function[])[i], + var dec = assertCallable(decs[i], "A decorator", "be", true) as Function, decThis = decoratorsHaveThis ? decs[i - 1] : void 0; var decoratorFinishedRef: DecoratorFinishedRef = {}; diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js new file mode 100644 index 000000000000..9249424de280 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc--to-es2015/invalid-non-callable-decorators/exec.js @@ -0,0 +1,43 @@ +{ + "invalid non-callable class decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => @nonCallable class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable field decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable field }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable accessor decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable method decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable method() {} }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined class decorators"; + expect(() => @(void 0) class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined field decorators"; + expect(() => class { @(void 0) field }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined accessor decorators"; + expect(() => class { @(void 0) accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined method decorators"; + expect(() => class { @(void 0) method() {} }).toThrow("A decorator must be a function"); +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc/invalid-non-callable-decorators/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc/invalid-non-callable-decorators/exec.js new file mode 100644 index 000000000000..9249424de280 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-misc/invalid-non-callable-decorators/exec.js @@ -0,0 +1,43 @@ +{ + "invalid non-callable class decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => @nonCallable class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable field decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable field }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable accessor decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid non-callable method decorators"; + const nonCallable = { call() {}, bind() {}, apply() {} } + expect(() => class { @nonCallable method() {} }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined class decorators"; + expect(() => @(void 0) class {}).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined field decorators"; + expect(() => class { @(void 0) field }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined accessor decorators"; + expect(() => class { @(void 0) accessor accessor; }).toThrow("A decorator must be a function"); +} + +{ + "invalid undefined method decorators"; + expect(() => class { @(void 0) method() {} }).toThrow("A decorator must be a function"); +} diff --git a/packages/babel-runtime-corejs3/helpers/esm/applyDecs2311.js b/packages/babel-runtime-corejs3/helpers/esm/applyDecs2311.js index 3bc2e0130c67..69f8ccb98fff 100644 --- a/packages/babel-runtime-corejs3/helpers/esm/applyDecs2311.js +++ b/packages/babel-runtime-corejs3/helpers/esm/applyDecs2311.js @@ -71,19 +71,19 @@ export default function applyDecs2311(e, t, n, r, o, i) { } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var _context2; - var z = h[O], - H = n ? h[O - 1] : void 0, - K = {}, - R = { + var z = b(h[O], "A decorator", "be", !0), + A = n ? h[O - 1] : void 0, + H = {}, + K = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: _bindInstanceProperty(_context2 = function _context2(e, t) { if (e.v) throw Error("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), _pushInstanceProperty(i).call(i, t); - }).call(_context2, null, K) + }).call(_context2, null, H) }; - if (w) c = z.call(H, N, R), K.v = 1, b(c, "class decorators", "return") && (N = c);else if (R["static"] = s, R["private"] = f, c = R.access = { + if (w) c = z.call(A, N, K), H.v = 1, b(c, "class decorators", "return") && (N = c);else if (K["static"] = s, K["private"] = f, c = K.access = { has: f ? _bindInstanceProperty(p).call(p) : function (e) { return r in e; } @@ -93,10 +93,10 @@ export default function applyDecs2311(e, t, n, r, o, i) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; - }), N = z.call(H, D ? { + }), N = z.call(A, D ? { get: P.get, set: P.set - } : P[F], R), K.v = 1, D) { + } : P[F], K), H.v = 1, D) { if ("object" == _typeof(N) && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && _unshiftInstanceProperty(k).call(k, c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? _unshiftInstanceProperty(k).call(k, N) : P[F] = N); }