From b8bc4b2605dad6258da97cf77058b6f098220320 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Wed, 28 Feb 2024 02:27:12 +0800 Subject: [PATCH] Fix the support of `arguments` in private `get/set` method (#16307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix arguments * Update packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/exec.js Co-authored-by: Nicolò Ribaudo * review * fix types --------- Co-authored-by: Nicolò Ribaudo --- .../src/fields.ts | 28 +++++++++++++--- .../test/fixtures/accessors/arguments/exec.js | 33 +++++++++++++++++++ .../fixtures/accessors/arguments/input.js | 25 ++++++++++++++ .../fixtures/accessors/arguments/output.js | 25 ++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/exec.js create mode 100644 packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/input.js create mode 100644 packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index 7f42040194a1..9650ef14bb39 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -1312,11 +1312,25 @@ function buildPrivateMethodDeclaration( (isGetter || isSetter) && !privateFieldsAsProperties ) { - const thisArg = prop.get("body").scope.generateUidIdentifier("this"); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - prop.traverse(thisContextVisitor, { + const scope = prop.get("body").scope; + const thisArg = scope.generateUidIdentifier("this"); + const state: ReplaceThisState = { thisRef: thisArg, - }); + argumentsPath: [], + }; + // eslint-disable-next-line @typescript-eslint/no-use-before-define + prop.traverse(thisContextVisitor, state); + if (state.argumentsPath.length) { + const argumentsId = scope.generateUidIdentifier("arguments"); + scope.push({ + id: argumentsId, + init: template.expression.ast`[].slice.call(arguments, 1)`, + }); + for (const path of state.argumentsPath) { + path.replaceWith(t.cloneNode(argumentsId)); + } + } + params.unshift(t.cloneNode(thisArg)); } @@ -1357,12 +1371,18 @@ type ReplaceThisState = { thisRef: t.Identifier; needsClassRef?: boolean; innerBinding?: t.Identifier | null; + argumentsPath?: NodePath[]; }; type ReplaceInnerBindingReferenceState = ReplaceThisState; const thisContextVisitor = traverse.visitors.merge([ { + Identifier(path, state) { + if (state.argumentsPath && path.node.name === "arguments") { + state.argumentsPath.push(path); + } + }, UnaryExpression(path) { // Replace `delete this` with `true` const { node } = path; diff --git a/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/exec.js b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/exec.js new file mode 100644 index 000000000000..4a672aac3a4f --- /dev/null +++ b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/exec.js @@ -0,0 +1,33 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + expect(arguments.length).toBe(0); + return this.#privateField; + } + + set #privateFieldValue(newValue) { + expect(arguments.length).toBe(1); + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } +} + +const cl = new Cl(); + +expect(cl.publicGetPrivateField()).toEqual("top secret string"); + +cl.publicSetPrivateField("new secret string"); +expect(cl.publicGetPrivateField()).toEqual("new secret string"); + diff --git a/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/input.js b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/input.js new file mode 100644 index 000000000000..7d708a558d61 --- /dev/null +++ b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/input.js @@ -0,0 +1,25 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + expect(arguments.length).toBe(0); + return this.#privateField; + } + + set #privateFieldValue(newValue) { + expect(arguments.length).toBe(1); + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } +} diff --git a/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/output.js b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/output.js new file mode 100644 index 000000000000..7c4d26072401 --- /dev/null +++ b/packages/babel-plugin-transform-private-methods/test/fixtures/accessors/arguments/output.js @@ -0,0 +1,25 @@ +var _privateField = /*#__PURE__*/new WeakMap(); +var _Cl_brand = /*#__PURE__*/new WeakSet(); +class Cl { + constructor() { + babelHelpers.classPrivateMethodInitSpec(this, _Cl_brand); + babelHelpers.classPrivateFieldInitSpec(this, _privateField, "top secret string"); + this.publicField = "not secret string"; + } + publicGetPrivateField() { + return babelHelpers.classPrivateGetter(_Cl_brand, this, _get_privateFieldValue); + } + publicSetPrivateField(newValue) { + babelHelpers.classPrivateSetter(_Cl_brand, _set_privateFieldValue, this, newValue); + } +} +function _get_privateFieldValue(_this) { + var _arguments = [].slice.call(arguments, 1); + expect(_arguments.length).toBe(0); + return babelHelpers.classPrivateFieldGet2(_privateField, _this); +} +function _set_privateFieldValue(_this2, newValue) { + var _arguments2 = [].slice.call(arguments, 1); + expect(_arguments2.length).toBe(1); + babelHelpers.classPrivateFieldSet2(_privateField, _this2, newValue); +}