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 +});