From 458406879e8afc17f03f06a3d6e664d9bd123cc9 Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Sat, 25 May 2019 17:12:08 -0400 Subject: [PATCH 1/8] Remove error for static private accessors --- .../src/features.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/features.js b/packages/babel-helper-create-class-features-plugin/src/features.js index fffc0d0014e0..4fc528bff185 100644 --- a/packages/babel-helper-create-class-features-plugin/src/features.js +++ b/packages/babel-helper-create-class-features-plugin/src/features.js @@ -66,12 +66,6 @@ export function verifyUsedFeatures(path, file) { if (!hasFeature(file, FEATURES.privateMethods)) { throw path.buildCodeFrameError("Class private methods are not enabled."); } - - if (path.node.static && path.node.kind !== "method") { - throw path.buildCodeFrameError( - "@babel/plugin-class-features doesn't support class static private accessors yet.", - ); - } } if ( From d0e94da3601523cda338a7d69293adcfbe3211a1 Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Sun, 16 Jun 2019 17:06:45 +0100 Subject: [PATCH 2/8] Private static accessors strict --- .../src/fields.js | 61 ++++++++++++++++--- packages/babel-helpers/src/helpers.js | 20 ++++-- .../private-static-method/this/output.js | 8 +-- .../fixtures/static-accessors/basic/exec.js | 23 +++++++ .../fixtures/static-accessors/basic/input.js | 19 ++++++ .../fixtures/static-accessors/basic/output.js | 27 ++++++++ .../static-accessors/get-only-setter/exec.js | 13 ++++ .../static-accessors/get-only-setter/input.js | 11 ++++ .../get-only-setter/output.js | 18 ++++++ .../fixtures/static-accessors/options.json | 14 +++++ .../static-accessors/set-only-getter/exec.js | 13 ++++ .../static-accessors/set-only-getter/input.js | 11 ++++ .../set-only-getter/output.js | 18 ++++++ .../fixtures/static-accessors/updates/exec.js | 46 ++++++++++++++ .../static-accessors/updates/input.js | 44 +++++++++++++ .../static-accessors/updates/output.js | 51 ++++++++++++++++ 16 files changed, 379 insertions(+), 18 deletions(-) create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/options.json create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index c6fb3da40ded..1c5d2c46158a 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -142,9 +142,10 @@ const privateNameHandlerSpec = { } = privateNamesMap.get(name); if (isStatic) { - const helperName = isMethod - ? "classStaticPrivateMethodGet" - : "classStaticPrivateFieldSpecGet"; + const helperName = + isMethod && !(getId || setId) + ? "classStaticPrivateMethodGet" + : "classStaticPrivateFieldSpecGet"; return t.callExpression(file.addHelper(helperName), [ this.receiver(member), @@ -180,12 +181,14 @@ const privateNameHandlerSpec = { static: isStatic, method: isMethod, setId, + getId, } = privateNamesMap.get(name); if (isStatic) { - const helperName = isMethod - ? "classStaticPrivateMethodSet" - : "classStaticPrivateFieldSpecSet"; + const helperName = + isMethod && !(getId || setId) + ? "classStaticPrivateMethodSet" + : "classStaticPrivateFieldSpecSet"; return t.callExpression(file.addHelper(helperName), [ this.receiver(member), @@ -300,8 +303,47 @@ function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) { } function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { - const { id } = privateNamesMap.get(prop.node.key.id.name); + const privateName = privateNamesMap.get(prop.node.key.id.name); + const { id, getId, setId, initAdded } = privateName; const value = prop.node.value || prop.scope.buildUndefinedNode(); + if (!prop.isProperty() && (initAdded || !(getId || setId))) return; + + if (getId || setId) { + privateNamesMap.set(prop.node.key.id.name, { + ...privateName, + initAdded: true, + }); + + if (getId && setId) { + return template.statement.ast` + var ${id.name} = { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId.name}, + set: ${setId.name} + } + `; + } else if (getId && !setId) { + return template.statement.ast` + var ${id.name} = { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId.name} + } + `; + } else if (!getId && setId) { + return template.statement.ast` + var ${id.name} = { + // configurable is false by default + // enumerable is false by default + // writable is false by default + set: ${setId.name} + } + `; + } + } return template.statement.ast` var ${id} = { @@ -615,6 +657,9 @@ export function buildFieldsInitNodes( case isStatic && isPrivate && isMethod && !loose: needsClassRef = true; staticNodes.push( + buildPrivateStaticFieldInitSpec(prop, privateNamesMap), + ); + staticNodes.unshift( buildPrivateMethodDeclaration(prop, privateNamesMap, loose), ); break; @@ -646,7 +691,7 @@ export function buildFieldsInitNodes( } return { - staticNodes, + staticNodes: staticNodes.filter(Boolean), instanceNodes: instanceNodes.filter(Boolean), wrapClass(path) { for (const prop of props) { diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index ef9231df6ff4..29ed9d82264d 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -1177,6 +1177,9 @@ helpers.classStaticPrivateFieldSpecGet = helper("7.0.2")` if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } + if (descriptor.get) { + return descriptor.get.call(receiver); + } return descriptor.value; } `; @@ -1186,13 +1189,18 @@ helpers.classStaticPrivateFieldSpecSet = helper("7.0.2")` if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } - if (!descriptor.writable) { - // This should only throw in strict mode, but class bodies are - // always strict and private fields can only be used inside - // class bodies. - throw new TypeError("attempted to set read only private field"); + if (descriptor.set) { + descriptor.set.call(receiver, value); + } else { + if (!descriptor.writable) { + // This should only throw in strict mode, but class bodies are + // always strict and private fields can only be used inside + // class bodies. + throw new TypeError("attempted to set read only private field"); + } + descriptor.value = value; } - descriptor.value = value; + return value; } `; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/output.js index e440955ecc99..49a4f4a7c600 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/output.js @@ -16,12 +16,12 @@ class B extends A { } -var _getA = function _getA() { - return babelHelpers.get(babelHelpers.getPrototypeOf(B), "a", this); -}; - var _getB = function _getB() { return this.b; }; +var _getA = function _getA() { + return babelHelpers.get(babelHelpers.getPrototypeOf(B), "a", this); +}; + var [getA, getB] = B.extract(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/exec.js new file mode 100644 index 000000000000..791a59034af9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/exec.js @@ -0,0 +1,23 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} + +expect(Cl.getValue()).toEqual("top secret string"); +Cl.setValue(); +expect(Cl.getValue()).toEqual("Updated: dank"); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/input.js new file mode 100644 index 000000000000..c79cdbe5ff0e --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/input.js @@ -0,0 +1,19 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/output.js new file mode 100644 index 000000000000..7dc0b26977eb --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/basic/output.js @@ -0,0 +1,27 @@ +class Cl { + static getValue() { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateStaticFieldValue); + } + + static setValue() { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateStaticFieldValue, "dank"); + } + +} + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _PRIVATE_STATIC_FIELD, `Updated: ${newValue}`); +}; + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _PRIVATE_STATIC_FIELD); +}; + +var _PRIVATE_STATIC_FIELD = { + writable: true, + value: "top secret string" +}; +var _privateStaticFieldValue = { + get: _get_privateStaticFieldValue, + set: _set_privateStaticFieldValue +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/exec.js new file mode 100644 index 000000000000..0c14f25c0938 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} + +expect(Cl.getPrivateStaticFieldValue()).toBeUndefined(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/input.js new file mode 100644 index 000000000000..ab8771074ec7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js new file mode 100644 index 000000000000..36075fd22e62 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js @@ -0,0 +1,18 @@ +class Cl { + static getPrivateStaticFieldValue() { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateStaticFieldValue); + } + +} + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _PRIVATE_STATIC_FIELD, newValue); +}; + +var _PRIVATE_STATIC_FIELD = { + writable: true, + value: 0 +}; +var _privateStaticFieldValue = { + set: _set_privateStaticFieldValue +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/options.json new file mode 100644 index 000000000000..c5e6649e4ea8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/options.json @@ -0,0 +1,14 @@ +{ + "plugins": [ + [ + "external-helpers", + { + "helperVersion": "7.1000.0" + } + ], + "proposal-private-methods", + "proposal-class-properties", + "transform-block-scoping", + "syntax-class-properties" + ] +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/exec.js new file mode 100644 index 000000000000..7069abfadc9d --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} + +expect(() => Cl.setPrivateStaticFieldValue()).toThrow(TypeError); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/input.js new file mode 100644 index 000000000000..d54ce4e2c2d0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js new file mode 100644 index 000000000000..7160682ebe44 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js @@ -0,0 +1,18 @@ +class Cl { + static setPrivateStaticFieldValue() { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateStaticFieldValue, 1); + } + +} + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _PRIVATE_STATIC_FIELD); +}; + +var _PRIVATE_STATIC_FIELD = { + writable: true, + value: 0 +}; +var _privateStaticFieldValue = { + get: _get_privateStaticFieldValue +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/exec.js new file mode 100644 index 000000000000..05f70aecceec --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/exec.js @@ -0,0 +1,46 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + expect(Cl.#privateField).toEqual(Cl.publicField); + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + expect(Cl.#privateField).toEqual(Cl.publicField); + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + expect(Cl.#privateField).toEqual(Cl.publicField); + } +} + +Cl.testUpdates(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/input.js new file mode 100644 index 000000000000..33c7b39d9cb4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/input.js @@ -0,0 +1,44 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + + Cl.#privateFieldValue = -(Cl.#privateFieldValue ** Cl.#privateFieldValue); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/output.js new file mode 100644 index 000000000000..1869c5b6ead8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/updates/output.js @@ -0,0 +1,51 @@ +class Cl { + static publicGetPrivateField() { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue); + } + + static publicSetPrivateField(newValue) { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, newValue); + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + var _Cl$privateFieldValue, _Cl$privateFieldValue2; + + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateField, 0); + Cl.publicField = 0; + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, (babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, (_Cl$privateFieldValue2 = +babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue)) + 1), _Cl$privateFieldValue2)); + Cl.publicFieldValue = Cl.publicFieldValue++; + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, +babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue) + 1); + ++Cl.publicFieldValue; + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue) + 1); + Cl.publicFieldValue += 1; + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateFieldValue, -(babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue) ** babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateFieldValue))); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } + +} + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classStaticPrivateFieldSpecSet(Cl, Cl, _privateField, newValue); +}; + +var _get_privateFieldValue = function () { + return babelHelpers.classStaticPrivateFieldSpecGet(Cl, Cl, _privateField); +}; + +var _privateField = { + writable: true, + value: "top secret string" +}; +babelHelpers.defineProperty(Cl, "publicField", "not secret string"); +var _privateFieldValue = { + get: _get_privateFieldValue, + set: _set_privateFieldValue +}; From 231861b4b245f1ed0627ec5908b4b1d3d13ab16d Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Sun, 14 Jul 2019 11:50:49 -0400 Subject: [PATCH 3/8] Add loose mode support --- .../src/fields.js | 48 +++++++++++++++-- .../this/output.js | 9 ++-- .../static-accessors-loose/basic/exec.js | 23 ++++++++ .../static-accessors-loose/basic/input.js | 19 +++++++ .../static-accessors-loose/basic/output.js | 31 +++++++++++ .../get-only-setter/exec.js | 13 +++++ .../get-only-setter/input.js | 11 ++++ .../get-only-setter/output.js | 22 ++++++++ .../static-accessors-loose/options.json | 14 +++++ .../set-only-getter/exec.js | 13 +++++ .../set-only-getter/input.js | 11 ++++ .../set-only-getter/output.js | 22 ++++++++ .../static-accessors-loose/updates/exec.js | 46 ++++++++++++++++ .../static-accessors-loose/updates/input.js | 44 +++++++++++++++ .../static-accessors-loose/updates/output.js | 53 +++++++++++++++++++ 15 files changed, 370 insertions(+), 9 deletions(-) create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/options.json create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/exec.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/input.js create mode 100644 packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/output.js diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 1c5d2c46158a..0d629c72c044 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -471,7 +471,47 @@ function buildPublicFieldInitSpec(ref, prop, state) { } function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) { - const { id, methodId } = privateNamesMap.get(prop.node.key.id.name); + const privateName = privateNamesMap.get(prop.node.key.id.name); + const { id, methodId, getId, setId, initAdded } = privateName; + if (initAdded) return; + + if (getId || setId) { + privateNamesMap.set(prop.node.key.id.name, { + ...privateName, + initAdded: true, + }); + + if (getId && setId) { + return template.statement.ast` + Object.defineProperty(${ref}, ${id}, { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId.name}, + set: ${setId.name} + }) + `; + } else if (getId && !setId) { + return template.statement.ast` + Object.defineProperty(${ref}, ${id}, { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId.name}, + }) + `; + } else if (!getId && setId) { + return template.statement.ast` + Object.defineProperty(${ref}, ${id}, { + // configurable is false by default + // enumerable is false by default + // writable is false by default + set: ${setId.name}, + }) + `; + } + } + return template.statement.ast` Object.defineProperty(${ref}, ${id}, { // configurable is false by default @@ -665,9 +705,6 @@ export function buildFieldsInitNodes( break; case isStatic && isPrivate && isMethod && loose: needsClassRef = true; - staticNodes.push( - buildPrivateMethodDeclaration(prop, privateNamesMap, loose), - ); staticNodes.push( buildPrivateStaticMethodInitLoose( t.cloneNode(ref), @@ -676,6 +713,9 @@ export function buildFieldsInitNodes( privateNamesMap, ), ); + staticNodes.unshift( + buildPrivateMethodDeclaration(prop, privateNamesMap, loose), + ); break; case isInstance && isPublic && isField && loose: instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop)); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-loose/this/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-loose/this/output.js index 4a5cddf8618c..0bccfda42bec 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-loose/this/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-loose/this/output.js @@ -20,6 +20,10 @@ var _getA = babelHelpers.classPrivateFieldLooseKey("getA"); var _getB = babelHelpers.classPrivateFieldLooseKey("getB"); +var _getB2 = function _getB2() { + return this.b; +}; + var _getA2 = function _getA2() { return A.a; }; @@ -27,11 +31,6 @@ var _getA2 = function _getA2() { Object.defineProperty(B, _getA, { value: _getA2 }); - -var _getB2 = function _getB2() { - return this.b; -}; - Object.defineProperty(B, _getB, { value: _getB2 }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/exec.js new file mode 100644 index 000000000000..791a59034af9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/exec.js @@ -0,0 +1,23 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} + +expect(Cl.getValue()).toEqual("top secret string"); +Cl.setValue(); +expect(Cl.getValue()).toEqual("Updated: dank"); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/input.js new file mode 100644 index 000000000000..c79cdbe5ff0e --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/input.js @@ -0,0 +1,19 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/output.js new file mode 100644 index 000000000000..83619d5323e6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/basic/output.js @@ -0,0 +1,31 @@ +class Cl { + static getValue() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue]; + } + + static setValue() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue] = "dank"; + } + +} + +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD] = `Updated: ${newValue}`; +}; + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD]; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: "top secret string" +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + get: _get_privateStaticFieldValue, + set: _set_privateStaticFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/exec.js new file mode 100644 index 000000000000..0c14f25c0938 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} + +expect(Cl.getPrivateStaticFieldValue()).toBeUndefined(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/input.js new file mode 100644 index 000000000000..ab8771074ec7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js new file mode 100644 index 000000000000..7e2b40385762 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js @@ -0,0 +1,22 @@ +class Cl { + static getPrivateStaticFieldValue() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue]; + } + +} + +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD] = newValue; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: 0 +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + set: _set_privateStaticFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/options.json new file mode 100644 index 000000000000..50c7612f8387 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/options.json @@ -0,0 +1,14 @@ +{ + "plugins": [ + [ + "external-helpers", + { + "helperVersion": "7.1000.0" + } + ], + ["proposal-private-methods", { "loose": true }], + ["proposal-class-properties", { "loose": true }], + "transform-block-scoping", + "syntax-class-properties" + ] +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/exec.js new file mode 100644 index 000000000000..7069abfadc9d --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} + +expect(() => Cl.setPrivateStaticFieldValue()).toThrow(TypeError); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/input.js new file mode 100644 index 000000000000..d54ce4e2c2d0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js new file mode 100644 index 000000000000..740f56053161 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js @@ -0,0 +1,22 @@ +class Cl { + static setPrivateStaticFieldValue() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue] = 1; + } + +} + +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD]; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: 0 +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + get: _get_privateStaticFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/exec.js new file mode 100644 index 000000000000..05f70aecceec --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/exec.js @@ -0,0 +1,46 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + expect(Cl.#privateField).toEqual(Cl.publicField); + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + expect(Cl.#privateField).toEqual(Cl.publicField); + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + expect(Cl.#privateField).toEqual(Cl.publicField); + } +} + +Cl.testUpdates(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/input.js new file mode 100644 index 000000000000..33c7b39d9cb4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/input.js @@ -0,0 +1,44 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + + Cl.#privateFieldValue = -(Cl.#privateFieldValue ** Cl.#privateFieldValue); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/output.js new file mode 100644 index 000000000000..b75fa4a4d18c --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/updates/output.js @@ -0,0 +1,53 @@ +class Cl { + static publicGetPrivateField() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]; + } + + static publicSetPrivateField(newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField] = 0; + Cl.publicField = 0; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]++; + Cl.publicFieldValue = Cl.publicFieldValue++; + ++babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]; + ++Cl.publicFieldValue; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] += 1; + Cl.publicFieldValue += 1; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = -(babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] ** babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } + +} + +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField] = newValue; +}; + +var _get_privateFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField]; +}; + +Object.defineProperty(Cl, _privateField, { + writable: true, + value: "top secret string" +}); +Cl.publicField = "not secret string"; +Object.defineProperty(Cl, _privateFieldValue, { + get: _get_privateFieldValue, + set: _set_privateFieldValue +}); From 15ad1b5c9e2cf2066914d2f9fd17968c9c425eda Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Mon, 22 Jul 2019 09:20:19 -0400 Subject: [PATCH 4/8] Move `value` decl for early return --- .../babel-helper-create-class-features-plugin/src/fields.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 0d629c72c044..d52213a92189 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -305,7 +305,7 @@ function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) { function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { const privateName = privateNamesMap.get(prop.node.key.id.name); const { id, getId, setId, initAdded } = privateName; - const value = prop.node.value || prop.scope.buildUndefinedNode(); + if (!prop.isProperty() && (initAdded || !(getId || setId))) return; if (getId || setId) { @@ -345,6 +345,7 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { } } + const value = prop.node.value || prop.scope.buildUndefinedNode(); return template.statement.ast` var ${id} = { // configurable is false by default From 6f7ed38e98d686a22b55eb0f04b6552f440adb70 Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Mon, 22 Jul 2019 09:20:57 -0400 Subject: [PATCH 5/8] Reuse getter/setter template --- .../src/fields.js | 38 +++++-------------- .../get-only-setter/output.js | 1 + .../set-only-getter/output.js | 3 +- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index d52213a92189..0dff4304cd9b 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -314,35 +314,15 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { initAdded: true, }); - if (getId && setId) { - return template.statement.ast` - var ${id.name} = { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name}, - set: ${setId.name} - } - `; - } else if (getId && !setId) { - return template.statement.ast` - var ${id.name} = { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name} - } - `; - } else if (!getId && setId) { - return template.statement.ast` - var ${id.name} = { - // configurable is false by default - // enumerable is false by default - // writable is false by default - set: ${setId.name} - } - `; - } + return template.statement.ast` + var ${id.name} = { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId ? getId.name : "null"}, + set: ${setId ? setId.name : "null"} + } + `; } const value = prop.node.value || prop.scope.buildUndefinedNode(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js index 36075fd22e62..aff5135c8ed5 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js @@ -14,5 +14,6 @@ var _PRIVATE_STATIC_FIELD = { value: 0 }; var _privateStaticFieldValue = { + get: null, set: _set_privateStaticFieldValue }; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js index 7160682ebe44..b58651007e0d 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js @@ -14,5 +14,6 @@ var _PRIVATE_STATIC_FIELD = { value: 0 }; var _privateStaticFieldValue = { - get: _get_privateStaticFieldValue + get: _get_privateStaticFieldValue, + set: null }; From 3f8d0218c91a832bedd3701ee106e4bca76fca4d Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Mon, 22 Jul 2019 18:18:20 -0400 Subject: [PATCH 6/8] Reuse getter/setter templates --- .../src/fields.js | 102 +++++------------- .../accessors-loose/get-only-setter/output.js | 1 + .../accessors-loose/set-only-getter/output.js | 3 +- .../accessors/get-only-setter/output.js | 1 + .../accessors/set-only-getter/output.js | 3 +- .../get-only-setter/output.js | 1 + .../set-only-getter/output.js | 3 +- 7 files changed, 33 insertions(+), 81 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 0dff4304cd9b..e14b7b1a5ac5 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -358,35 +358,15 @@ function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) { initAdded: true, }); - if (getId && setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name}, - set: ${setId.name} - }); - `; - } else if (getId && !setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name} - }); - `; - } else if (!getId && setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - set: ${setId.name} - }); - `; - } + return template.statement.ast` + Object.defineProperty(${ref}, ${id}, { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId ? getId.name : "undefined"}, + set: ${setId ? setId.name : "undefined"} + }); + `; } } @@ -401,26 +381,12 @@ function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) { initAdded: true, }); - if (getId && setId) { - return template.statement.ast` - ${id}.set(${ref}, { - get: ${getId.name}, - set: ${setId.name} - }); - `; - } else if (getId && !setId) { - return template.statement.ast` - ${id}.set(${ref}, { - get: ${getId.name} - }); - `; - } else if (!getId && setId) { - return template.statement.ast` - ${id}.set(${ref}, { - set: ${setId.name} - }); - `; - } + return template.statement.ast` + ${id}.set(${ref}, { + get: ${getId ? getId.name : "undefined"}, + set: ${setId ? setId.name : "undefined"} + }); + `; } return template.statement.ast`${id}.add(${ref})`; } @@ -462,35 +428,15 @@ function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) { initAdded: true, }); - if (getId && setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name}, - set: ${setId.name} - }) - `; - } else if (getId && !setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - get: ${getId.name}, - }) - `; - } else if (!getId && setId) { - return template.statement.ast` - Object.defineProperty(${ref}, ${id}, { - // configurable is false by default - // enumerable is false by default - // writable is false by default - set: ${setId.name}, - }) - `; - } + return template.statement.ast` + Object.defineProperty(${ref}, ${id}, { + // configurable is false by default + // enumerable is false by default + // writable is false by default + get: ${getId ? getId.name : "undefined"}, + set: ${setId ? setId.name : "undefined"} + }) + `; } return template.statement.ast` diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js index 05866e2142fb..cdd5951ff669 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js @@ -1,6 +1,7 @@ class Cl { constructor() { Object.defineProperty(this, _privateFieldValue, { + get: undefined, set: _set_privateFieldValue }); Object.defineProperty(this, _privateField, { diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js index 57a8789016fa..dd0746627f39 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js @@ -1,7 +1,8 @@ class Cl { constructor() { Object.defineProperty(this, _privateFieldValue, { - get: _get_privateFieldValue + get: _get_privateFieldValue, + set: undefined }); Object.defineProperty(this, _privateField, { writable: true, diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js index 0906668c51fe..cee46af765f3 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js @@ -1,6 +1,7 @@ class Cl { constructor() { _privateFieldValue.set(this, { + get: undefined, set: _set_privateFieldValue }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js index 4ea497e71a17..f332457f800e 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js @@ -1,7 +1,8 @@ class Cl { constructor() { _privateFieldValue.set(this, { - get: _get_privateFieldValue + get: _get_privateFieldValue, + set: undefined }); _privateField.set(this, { diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js index 7e2b40385762..16d8f5442ddc 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js @@ -18,5 +18,6 @@ Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { value: 0 }); Object.defineProperty(Cl, _privateStaticFieldValue, { + get: undefined, set: _set_privateStaticFieldValue }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js index 740f56053161..5d570a8fafb9 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js @@ -18,5 +18,6 @@ Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { value: 0 }); Object.defineProperty(Cl, _privateStaticFieldValue, { - get: _get_privateStaticFieldValue + get: _get_privateStaticFieldValue, + set: undefined }); From 3e6c95525f603aa4e9c75d9c59405ec130142777 Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Wed, 24 Jul 2019 09:15:33 -0400 Subject: [PATCH 7/8] Use `buildUndefinedNode` in accessor templates --- .../src/fields.js | 16 ++++++++-------- .../accessors-loose/get-only-setter/output.js | 2 +- .../accessors-loose/set-only-getter/output.js | 2 +- .../fixtures/accessors/get-only-setter/output.js | 2 +- .../fixtures/accessors/set-only-getter/output.js | 2 +- .../get-only-setter/output.js | 2 +- .../set-only-getter/output.js | 2 +- .../static-accessors/get-only-setter/output.js | 2 +- .../static-accessors/set-only-getter/output.js | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index e14b7b1a5ac5..519dfeba7227 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -319,8 +319,8 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { // configurable is false by default // enumerable is false by default // writable is false by default - get: ${getId ? getId.name : "null"}, - set: ${setId ? setId.name : "null"} + get: ${getId ? getId.name : prop.scope.buildUndefinedNode()}, + set: ${setId ? setId.name : prop.scope.buildUndefinedNode()} } `; } @@ -363,8 +363,8 @@ function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) { // configurable is false by default // enumerable is false by default // writable is false by default - get: ${getId ? getId.name : "undefined"}, - set: ${setId ? setId.name : "undefined"} + get: ${getId ? getId.name : prop.scope.buildUndefinedNode()}, + set: ${setId ? setId.name : prop.scope.buildUndefinedNode()} }); `; } @@ -383,8 +383,8 @@ function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) { return template.statement.ast` ${id}.set(${ref}, { - get: ${getId ? getId.name : "undefined"}, - set: ${setId ? setId.name : "undefined"} + get: ${getId ? getId.name : prop.scope.buildUndefinedNode()}, + set: ${setId ? setId.name : prop.scope.buildUndefinedNode()} }); `; } @@ -433,8 +433,8 @@ function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) { // configurable is false by default // enumerable is false by default // writable is false by default - get: ${getId ? getId.name : "undefined"}, - set: ${setId ? setId.name : "undefined"} + get: ${getId ? getId.name : prop.scope.buildUndefinedNode()}, + set: ${setId ? setId.name : prop.scope.buildUndefinedNode()} }) `; } diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js index cdd5951ff669..9d7d52b847b8 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/get-only-setter/output.js @@ -1,7 +1,7 @@ class Cl { constructor() { Object.defineProperty(this, _privateFieldValue, { - get: undefined, + get: void 0, set: _set_privateFieldValue }); Object.defineProperty(this, _privateField, { diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js index dd0746627f39..eb046676cf54 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-loose/set-only-getter/output.js @@ -2,7 +2,7 @@ class Cl { constructor() { Object.defineProperty(this, _privateFieldValue, { get: _get_privateFieldValue, - set: undefined + set: void 0 }); Object.defineProperty(this, _privateField, { writable: true, diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js index cee46af765f3..15691ee34a50 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/get-only-setter/output.js @@ -1,7 +1,7 @@ class Cl { constructor() { _privateFieldValue.set(this, { - get: undefined, + get: void 0, set: _set_privateFieldValue }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js index f332457f800e..e301c07805de 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors/set-only-getter/output.js @@ -2,7 +2,7 @@ class Cl { constructor() { _privateFieldValue.set(this, { get: _get_privateFieldValue, - set: undefined + set: void 0 }); _privateField.set(this, { diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js index 16d8f5442ddc..adb85a9ead8c 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/get-only-setter/output.js @@ -18,6 +18,6 @@ Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { value: 0 }); Object.defineProperty(Cl, _privateStaticFieldValue, { - get: undefined, + get: void 0, set: _set_privateStaticFieldValue }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js index 5d570a8fafb9..73e658037394 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-loose/set-only-getter/output.js @@ -19,5 +19,5 @@ Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { }); Object.defineProperty(Cl, _privateStaticFieldValue, { get: _get_privateStaticFieldValue, - set: undefined + set: void 0 }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js index aff5135c8ed5..31c1bf46873e 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/get-only-setter/output.js @@ -14,6 +14,6 @@ var _PRIVATE_STATIC_FIELD = { value: 0 }; var _privateStaticFieldValue = { - get: null, + get: void 0, set: _set_privateStaticFieldValue }; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js index b58651007e0d..fa3aebd45bfc 100644 --- a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors/set-only-getter/output.js @@ -15,5 +15,5 @@ var _PRIVATE_STATIC_FIELD = { }; var _privateStaticFieldValue = { get: _get_privateStaticFieldValue, - set: null + set: void 0 }; From fc24d84a1cff0040418e2972565317a1f148dcc6 Mon Sep 17 00:00:00 2001 From: Timothy McClure Date: Sun, 28 Jul 2019 17:19:08 -0400 Subject: [PATCH 8/8] Extract `isAccessor` variable --- .../src/fields.js | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 519dfeba7227..4cdaccd1bbb5 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -44,6 +44,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) { // because static fields are directly assigned to a variable in the // buildPrivateStaticFieldInitSpec function. const { id, static: isStatic, method: isMethod, getId, setId } = value; + const isAccessor = getId || setId; if (loose) { initNodes.push( template.statement.ast` @@ -51,7 +52,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) { `, ); } else if (isMethod && !isStatic) { - if (getId || setId) { + if (isAccessor) { initNodes.push(template.statement.ast`var ${id} = new WeakMap();`); } else { initNodes.push(template.statement.ast`var ${id} = new WeakSet();`); @@ -140,10 +141,11 @@ const privateNameHandlerSpec = { getId, setId, } = privateNamesMap.get(name); + const isAccessor = getId || setId; if (isStatic) { const helperName = - isMethod && !(getId || setId) + isMethod && !isAccessor ? "classStaticPrivateMethodGet" : "classStaticPrivateFieldSpecGet"; @@ -155,7 +157,7 @@ const privateNameHandlerSpec = { } if (isMethod) { - if (getId || setId) { + if (isAccessor) { return t.callExpression(file.addHelper("classPrivateFieldGet"), [ this.receiver(member), t.cloneNode(id), @@ -183,10 +185,11 @@ const privateNameHandlerSpec = { setId, getId, } = privateNamesMap.get(name); + const isAccessor = getId || setId; if (isStatic) { const helperName = - isMethod && !(getId || setId) + isMethod && !isAccessor ? "classStaticPrivateMethodSet" : "classStaticPrivateFieldSpecSet"; @@ -305,10 +308,11 @@ function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) { function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) { const privateName = privateNamesMap.get(prop.node.key.id.name); const { id, getId, setId, initAdded } = privateName; + const isAccessor = getId || setId; - if (!prop.isProperty() && (initAdded || !(getId || setId))) return; + if (!prop.isProperty() && (initAdded || !isAccessor)) return; - if (getId || setId) { + if (isAccessor) { privateNamesMap.set(prop.node.key.id.name, { ...privateName, initAdded: true, @@ -351,8 +355,8 @@ function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) { }); `; } - - if (getId || setId) { + const isAccessor = getId || setId; + if (isAccessor) { privateNamesMap.set(prop.node.key.id.name, { ...privateName, initAdded: true, @@ -373,9 +377,11 @@ function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) { function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) { const privateName = privateNamesMap.get(prop.node.key.id.name); const { id, getId, setId, initAdded } = privateName; + if (initAdded) return; - if (getId || setId) { + const isAccessor = getId || setId; + if (isAccessor) { privateNamesMap.set(prop.node.key.id.name, { ...privateName, initAdded: true, @@ -420,9 +426,11 @@ function buildPublicFieldInitSpec(ref, prop, state) { function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) { const privateName = privateNamesMap.get(prop.node.key.id.name); const { id, methodId, getId, setId, initAdded } = privateName; + if (initAdded) return; - if (getId || setId) { + const isAccessor = getId || setId; + if (isAccessor) { privateNamesMap.set(prop.node.key.id.name, { ...privateName, initAdded: true,