From ab2e4d7793226b10585c26e732b0e2aa2f64d300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 2 Feb 2024 09:11:19 -0500 Subject: [PATCH] fix: handle decorated async private method and generator (#16258) --- .../src/decorators.ts | 38 ++++++++++--------- .../private-async-and-generator/exec.js | 23 +++++++++++ .../private-async-and-generator/input.js | 10 +++++ .../private-async-and-generator/options.json | 3 ++ .../private-async-and-generator/output.js | 26 +++++++++++++ .../private-async-and-generator/exec.js | 23 +++++++++++ .../private-async-and-generator/input.js | 10 +++++ .../private-async-and-generator/options.json | 3 ++ .../private-async-and-generator/output.js | 15 ++++++++ 9 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/exec.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/input.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/options.json create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/output.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/exec.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/input.js create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/options.json create mode 100644 packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/decorators.ts b/packages/babel-helper-create-class-features-plugin/src/decorators.ts index aff492d103f2..7be7ea5568b4 100644 --- a/packages/babel-helper-create-class-features-plugin/src/decorators.ts +++ b/packages/babel-helper-create-class-features-plugin/src/decorators.ts @@ -634,12 +634,6 @@ function addCallAccessorsFor( ); } -function isNotTsParameter( - node: t.Identifier | t.Pattern | t.RestElement | t.TSParameterProperty, -): node is t.Identifier | t.Pattern | t.RestElement { - return node.type !== "TSParameterProperty"; -} - function movePrivateAccessor( element: NodePath, key: t.PrivateName, @@ -702,6 +696,25 @@ function maybeSequenceExpression(exprs: t.Expression[]) { return t.sequenceExpression(exprs); } +/** + * Create FunctionExpression from a ClassPrivateMethod. + * The returned FunctionExpression node takes ownership of the private method's body and params. + * + * @param {t.ClassPrivateMethod} node + * @returns + */ +function createFunctionExpressionFromPrivateMethod(node: t.ClassPrivateMethod) { + const { params, body, generator: isGenerator, async: isAsync } = node; + return t.functionExpression( + undefined, + // @ts-expect-error todo: Improve typings: TSParameterProperty is only allowed in constructor + params, + body, + isGenerator, + isAsync, + ); +} + function createSetFunctionNameCall( state: PluginPass, className: t.Identifier | t.StringLiteral, @@ -1122,18 +1135,9 @@ function transformClass( replaceSupers.replace(); - const { - params, - body, - async: isAsync, - } = element.node as t.ClassPrivateMethod; - privateMethods = [ - t.functionExpression( - undefined, - params.filter(isNotTsParameter), - body, - isAsync, + createFunctionExpressionFromPrivateMethod( + element.node as t.ClassPrivateMethod, ), ]; diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/exec.js new file mode 100644 index 000000000000..8e4f3c2207bf --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/exec.js @@ -0,0 +1,23 @@ +let counter = 0; + +class Foo { + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncFunction"); + }) + async #a() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("GeneratorFunction"); + }) + *#g() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncGeneratorFunction"); + }) + async *#ag() {} +} + +expect(counter).toBe(3); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/input.js new file mode 100644 index 000000000000..4a680503322e --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/input.js @@ -0,0 +1,10 @@ +class Foo { + @dec + async #a() {} + + @dec + *#g() {} + + @dec + async *#ag() {} +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/options.json b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/options.json new file mode 100644 index 000000000000..9df229613eaf --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "10.0.0" +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/output.js new file mode 100644 index 000000000000..1c689c3a2048 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods--to-es2015/private-async-and-generator/output.js @@ -0,0 +1,26 @@ +var _initProto, _dec, _call_a, _dec2, _call_g, _dec3, _call_ag, _Foo; +_dec = dec; +_dec2 = dec; +_dec3 = dec; +var _ag = /*#__PURE__*/new WeakMap(); +var _g = /*#__PURE__*/new WeakMap(); +var _a = /*#__PURE__*/new WeakMap(); +class Foo { + constructor() { + babelHelpers.classPrivateFieldInitSpec(this, _ag, { + writable: true, + value: _call_ag + }); + babelHelpers.classPrivateFieldInitSpec(this, _g, { + writable: true, + value: _call_g + }); + babelHelpers.classPrivateFieldInitSpec(this, _a, { + writable: true, + value: _call_a + }); + _initProto(this); + } +} +_Foo = Foo; +[_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(_Foo, [[_dec, 2, "a", async function () {}], [_dec2, 2, "g", function* () {}], [_dec3, 2, "ag", async function* () {}]], [], 0, _ => _a.has(babelHelpers.checkInRHS(_))).e; diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/exec.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/exec.js new file mode 100644 index 000000000000..8e4f3c2207bf --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/exec.js @@ -0,0 +1,23 @@ +let counter = 0; + +class Foo { + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncFunction"); + }) + async #a() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("GeneratorFunction"); + }) + *#g() {} + + @(function (fn) { + counter++; + expect(fn.constructor.name).toBe("AsyncGeneratorFunction"); + }) + async *#ag() {} +} + +expect(counter).toBe(3); diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/input.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/input.js new file mode 100644 index 000000000000..4a680503322e --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/input.js @@ -0,0 +1,10 @@ +class Foo { + @dec + async #a() {} + + @dec + *#g() {} + + @dec + async *#ag() {} +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/options.json b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/options.json new file mode 100644 index 000000000000..f97653393918 --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/options.json @@ -0,0 +1,3 @@ +{ + "minNodeVersion": "16.11.0" +} diff --git a/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/output.js b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/output.js new file mode 100644 index 000000000000..bb12903fc68b --- /dev/null +++ b/packages/babel-plugin-proposal-decorators/test/fixtures/2023-11-methods/private-async-and-generator/output.js @@ -0,0 +1,15 @@ +var _initProto, _dec, _call_a, _dec2, _call_g, _dec3, _call_ag; +_dec = dec; +_dec2 = dec; +_dec3 = dec; +class Foo { + static { + [_call_a, _call_g, _call_ag, _initProto] = babelHelpers.applyDecs2311(this, [[_dec, 2, "a", async function () {}], [_dec2, 2, "g", function* () {}], [_dec3, 2, "ag", async function* () {}]], [], 0, _ => #a in _).e; + } + constructor() { + _initProto(this); + } + #ag = _call_ag; + #g = _call_g; + #a = _call_a; +}