diff --git a/packages/babel-helper-member-expression-to-functions/src/index.js b/packages/babel-helper-member-expression-to-functions/src/index.js index 7724406d2b46..ee965b67e684 100644 --- a/packages/babel-helper-member-expression-to-functions/src/index.js +++ b/packages/babel-helper-member-expression-to-functions/src/index.js @@ -125,8 +125,19 @@ const handle = { ) { throw member.buildCodeFrameError(`can't handle assignment`); } - if (rootParentPath.isUnaryExpression({ operator: "delete" })) { - throw member.buildCodeFrameError(`can't handle delete`); + const isDeleteOperation = rootParentPath.isUnaryExpression({ + operator: "delete", + }); + if ( + isDeleteOperation && + endPath.isOptionalMemberExpression() && + endPath.get("property").isPrivateName() + ) { + // @babel/parser will throw error on `delete obj?.#x`. + // This error serves as fallback when `delete obj?.#x` is constructed from babel types + throw member.buildCodeFrameError( + `can't delete a private class element`, + ); } // Now, we're looking for the start of this optional chain, which is @@ -211,7 +222,13 @@ const handle = { } } - endPath.replaceWith( + let replacementPath = endPath; + if (isDeleteOperation) { + replacementPath = endParentPath; + regular = endParentPath.node; + } + + replacementPath.replaceWith( t.conditionalExpression( t.logicalExpression( "||", @@ -228,11 +245,14 @@ const handle = { scope.buildUndefinedNode(), ), ), - scope.buildUndefinedNode(), + isDeleteOperation + ? t.booleanLiteral(true) + : scope.buildUndefinedNode(), regular, ), ); + // context and isDeleteOperation can not be both truthy if (context) { const endParent = endParentPath.node; endParentPath.replaceWith( diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/exec.js new file mode 100644 index 000000000000..d38a87624dea --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/exec.js @@ -0,0 +1,102 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + expect(() => delete Foo?.#self.unicorn).toThrow(TypeError); + expect(() => delete deep?.very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fnDeep?.().very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + + } + + static testNull() { + const o = null; + const deep = { very: { o } }; + const fn = null; + function fnDeep() { + return deep; + } + + expect(delete deep?.very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fnDeep?.().very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + } +} + +Object.defineProperty(Foo, "unicorn", { configurable: false }); +Foo.test(); +Foo.testNull(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/input.js new file mode 100644 index 000000000000..cd39a04ec063 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/input.js @@ -0,0 +1,56 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + delete Foo?.#self.unicorn; + delete deep?.very.o?.Foo.#self.unicorn; + + delete o?.Foo.#self.unicorn; + delete o?.Foo.#self.self.unicorn; + delete o?.Foo.#self?.self.unicorn; + delete o?.Foo.#self.self?.self.unicorn; + delete o?.Foo.#self?.self?.self.unicorn; + + delete o?.Foo.#self.getSelf().unicorn; + delete o?.Foo.#self.getSelf?.().unicorn; + delete o?.Foo.#self?.getSelf().unicorn; + delete o?.Foo.#self?.getSelf?.().unicorn; + delete o?.Foo.#self.getSelf()?.self.unicorn; + delete o?.Foo.#self.getSelf?.()?.self.unicorn; + delete o?.Foo.#self?.getSelf()?.self.unicorn; + delete o?.Foo.#self?.getSelf?.()?.self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fnDeep?.().very.o?.Foo.#self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fn?.().Foo.#self.self.unicorn; + delete fn?.().Foo.#self?.self.unicorn; + delete fn?.().Foo.#self.self?.self.unicorn; + delete fn?.().Foo.#self?.self?.self.unicorn; + + delete fn?.().Foo.#self.getSelf().unicorn; + delete fn?.().Foo.#self.getSelf?.().unicorn; + delete fn?.().Foo.#self?.getSelf().unicorn; + delete fn?.().Foo.#self?.getSelf?.().unicorn; + delete fn?.().Foo.#self.getSelf()?.self.unicorn; + delete fn?.().Foo.#self.getSelf?.()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn; + + } +} + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/output.js new file mode 100644 index 000000000000..31dcdd093503 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property-with-transform/output.js @@ -0,0 +1,83 @@ +var _x = babelHelpers.classPrivateFieldLooseKey("x"); + +var _self = babelHelpers.classPrivateFieldLooseKey("self"); + +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + babelHelpers.createClass(Foo, null, [{ + key: "getSelf", + value: function getSelf() { + return this; + } + }, { + key: "test", + value: function test() { + var _deep$very$o, _babelHelpers$classPr, _babelHelpers$classPr2, _fnDeep$very$o, _babelHelpers$classPr3, _babelHelpers$classPr4; + + var o = { + Foo: Foo + }; + var deep = { + very: { + o + } + }; + + function fn() { + return o; + } + + function fnDeep() { + return deep; + } + + Foo === null || Foo === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(Foo, _self)[_self].unicorn; + (_deep$very$o = deep?.very.o) === null || _deep$very$o === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(_deep$very$o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self].self.unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self].self)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.self?.self.unicorn; + o === null || o === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : (_babelHelpers$classPr = babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf)?.call(_babelHelpers$classPr).unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf?.().unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf())?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : (_babelHelpers$classPr2 = babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf)?.call(_babelHelpers$classPr2)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf()?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf?.()?.self.unicorn; + fn === null || fn === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + (_fnDeep$very$o = fnDeep?.().very.o) === null || _fnDeep$very$o === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(_fnDeep$very$o.Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].self)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.self?.self.unicorn; + fn === null || fn === void 0 ? true : delete babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_babelHelpers$classPr3 = babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf)?.call(_babelHelpers$classPr3).unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf?.().unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf())?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_babelHelpers$classPr4 = babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf)?.call(_babelHelpers$classPr4)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf()?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : babelHelpers.classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf?.()?.self.unicorn; + } + }]); + return Foo; +}(); + +Object.defineProperty(Foo, _x, { + writable: true, + value: 1 +}); +Object.defineProperty(Foo, _self, { + writable: true, + value: Foo +}); +Foo.self = Foo; +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/exec.js new file mode 100644 index 000000000000..d38a87624dea --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/exec.js @@ -0,0 +1,102 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + expect(() => delete Foo?.#self.unicorn).toThrow(TypeError); + expect(() => delete deep?.very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fnDeep?.().very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + + } + + static testNull() { + const o = null; + const deep = { very: { o } }; + const fn = null; + function fnDeep() { + return deep; + } + + expect(delete deep?.very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fnDeep?.().very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + } +} + +Object.defineProperty(Foo, "unicorn", { configurable: false }); +Foo.test(); +Foo.testNull(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/input.js new file mode 100644 index 000000000000..cd39a04ec063 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/input.js @@ -0,0 +1,56 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + delete Foo?.#self.unicorn; + delete deep?.very.o?.Foo.#self.unicorn; + + delete o?.Foo.#self.unicorn; + delete o?.Foo.#self.self.unicorn; + delete o?.Foo.#self?.self.unicorn; + delete o?.Foo.#self.self?.self.unicorn; + delete o?.Foo.#self?.self?.self.unicorn; + + delete o?.Foo.#self.getSelf().unicorn; + delete o?.Foo.#self.getSelf?.().unicorn; + delete o?.Foo.#self?.getSelf().unicorn; + delete o?.Foo.#self?.getSelf?.().unicorn; + delete o?.Foo.#self.getSelf()?.self.unicorn; + delete o?.Foo.#self.getSelf?.()?.self.unicorn; + delete o?.Foo.#self?.getSelf()?.self.unicorn; + delete o?.Foo.#self?.getSelf?.()?.self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fnDeep?.().very.o?.Foo.#self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fn?.().Foo.#self.self.unicorn; + delete fn?.().Foo.#self?.self.unicorn; + delete fn?.().Foo.#self.self?.self.unicorn; + delete fn?.().Foo.#self?.self?.self.unicorn; + + delete fn?.().Foo.#self.getSelf().unicorn; + delete fn?.().Foo.#self.getSelf?.().unicorn; + delete fn?.().Foo.#self?.getSelf().unicorn; + delete fn?.().Foo.#self?.getSelf?.().unicorn; + delete fn?.().Foo.#self.getSelf()?.self.unicorn; + delete fn?.().Foo.#self.getSelf?.()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn; + + } +} + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/options.json new file mode 100644 index 000000000000..2d5cfe8e8095 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["proposal-class-properties", { "loose": true }]], + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/output.js new file mode 100644 index 000000000000..62d562129d70 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/optional-chain-delete-property/output.js @@ -0,0 +1,79 @@ +function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } + +var id = 0; + +function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } + +var _x = _classPrivateFieldLooseKey("x"); + +var _self = _classPrivateFieldLooseKey("self"); + +class Foo { + static getSelf() { + return this; + } + + static test() { + var _deep$very$o, _classPrivateFieldLoo, _classPrivateFieldLoo2, _fnDeep$very$o, _classPrivateFieldLoo3, _classPrivateFieldLoo4; + + const o = { + Foo: Foo + }; + const deep = { + very: { + o + } + }; + + function fn() { + return o; + } + + function fnDeep() { + return deep; + } + + Foo === null || Foo === void 0 ? true : delete _classPrivateFieldLooseBase(Foo, _self)[_self].unicorn; + (_deep$very$o = deep?.very.o) === null || _deep$very$o === void 0 ? true : delete _classPrivateFieldLooseBase(_deep$very$o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self].self)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.self?.self.unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : (_classPrivateFieldLoo = _classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf)?.call(_classPrivateFieldLoo).unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf?.().unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf())?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : (_classPrivateFieldLoo2 = _classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf)?.call(_classPrivateFieldLoo2)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf()?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self])?.getSelf?.()?.self.unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + (_fnDeep$very$o = fnDeep?.().very.o) === null || _fnDeep$very$o === void 0 ? true : delete _classPrivateFieldLooseBase(_fnDeep$very$o.Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self].self)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.self?.self.unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_classPrivateFieldLoo3 = _classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf)?.call(_classPrivateFieldLoo3).unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf?.().unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf())?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_classPrivateFieldLoo4 = _classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf)?.call(_classPrivateFieldLoo4)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf()?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self])?.getSelf?.()?.self.unicorn; + } + +} + +Object.defineProperty(Foo, _x, { + writable: true, + value: 1 +}); +Object.defineProperty(Foo, _self, { + writable: true, + value: Foo +}); +Foo.self = Foo; +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/exec.js new file mode 100644 index 000000000000..d38a87624dea --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/exec.js @@ -0,0 +1,102 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + expect(() => delete Foo?.#self.unicorn).toThrow(TypeError); + expect(() => delete deep?.very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fnDeep?.().very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + + } + + static testNull() { + const o = null; + const deep = { very: { o } }; + const fn = null; + function fnDeep() { + return deep; + } + + expect(delete deep?.very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fnDeep?.().very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + } +} + +Object.defineProperty(Foo, "unicorn", { configurable: false }); +Foo.test(); +Foo.testNull(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/input.js new file mode 100644 index 000000000000..cd39a04ec063 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/input.js @@ -0,0 +1,56 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + delete Foo?.#self.unicorn; + delete deep?.very.o?.Foo.#self.unicorn; + + delete o?.Foo.#self.unicorn; + delete o?.Foo.#self.self.unicorn; + delete o?.Foo.#self?.self.unicorn; + delete o?.Foo.#self.self?.self.unicorn; + delete o?.Foo.#self?.self?.self.unicorn; + + delete o?.Foo.#self.getSelf().unicorn; + delete o?.Foo.#self.getSelf?.().unicorn; + delete o?.Foo.#self?.getSelf().unicorn; + delete o?.Foo.#self?.getSelf?.().unicorn; + delete o?.Foo.#self.getSelf()?.self.unicorn; + delete o?.Foo.#self.getSelf?.()?.self.unicorn; + delete o?.Foo.#self?.getSelf()?.self.unicorn; + delete o?.Foo.#self?.getSelf?.()?.self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fnDeep?.().very.o?.Foo.#self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fn?.().Foo.#self.self.unicorn; + delete fn?.().Foo.#self?.self.unicorn; + delete fn?.().Foo.#self.self?.self.unicorn; + delete fn?.().Foo.#self?.self?.self.unicorn; + + delete fn?.().Foo.#self.getSelf().unicorn; + delete fn?.().Foo.#self.getSelf?.().unicorn; + delete fn?.().Foo.#self?.getSelf().unicorn; + delete fn?.().Foo.#self?.getSelf?.().unicorn; + delete fn?.().Foo.#self.getSelf()?.self.unicorn; + delete fn?.().Foo.#self.getSelf?.()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn; + + } +} + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/options.json new file mode 100644 index 000000000000..124133b5af2b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + ["proposal-optional-chaining", { "loose": true }], + ["proposal-class-properties", { "loose": true }] + ] +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/output.js new file mode 100644 index 000000000000..9770ba43cfcf --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property-with-transform/output.js @@ -0,0 +1,79 @@ +function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } + +var id = 0; + +function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } + +var _x = _classPrivateFieldLooseKey("x"); + +var _self = _classPrivateFieldLooseKey("self"); + +class Foo { + static getSelf() { + return this; + } + + static test() { + var _deep$very$o, _classPrivateFieldLoo, _classPrivateFieldLoo2, _fnDeep$very$o, _classPrivateFieldLoo3, _classPrivateFieldLoo4, _ref, _ref2, _ref3, _ref3$self, _ref4, _ref5, _ref6, _ref7, _ref8, _ref8$call, _ref9, _ref9$getSelf, _ref10, _ref10$getSelf, _ref11, _ref12, _ref13, _ref13$self, _ref14, _ref15, _ref16, _ref17, _ref18, _ref18$call, _ref19, _ref19$getSelf, _ref20, _ref20$getSelf; + + const o = { + Foo: Foo + }; + const deep = { + very: { + o + } + }; + + function fn() { + return o; + } + + function fnDeep() { + return deep; + } + + Foo === null || Foo === void 0 ? true : delete _classPrivateFieldLooseBase(Foo, _self)[_self].unicorn; + (_deep$very$o = deep == null ? void 0 : deep.very.o) === null || _deep$very$o === void 0 ? true : delete _classPrivateFieldLooseBase(_deep$very$o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].self.unicorn; + (_ref = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : delete _ref.self.unicorn; + (_ref2 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self].self) == null ? true : delete _ref2.self.unicorn; + (_ref3 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : (_ref3$self = _ref3.self) == null ? true : delete _ref3$self.self.unicorn; + o === null || o === void 0 ? true : delete _classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf().unicorn; + (_ref4 = o === null || o === void 0 ? void 0 : (_classPrivateFieldLoo = _classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf) == null ? true : delete _ref4.call(_classPrivateFieldLoo).unicorn; + (_ref5 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : delete _ref5.getSelf().unicorn; + (_ref6 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : _ref6.getSelf == null ? true : delete _ref6.getSelf().unicorn; + (_ref7 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self].getSelf()) == null ? true : delete _ref7.self.unicorn; + (_ref8 = o === null || o === void 0 ? void 0 : (_classPrivateFieldLoo2 = _classPrivateFieldLooseBase(o.Foo, _self)[_self]).getSelf) == null ? true : (_ref8$call = _ref8.call(_classPrivateFieldLoo2)) == null ? true : delete _ref8$call.self.unicorn; + (_ref9 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : (_ref9$getSelf = _ref9.getSelf()) == null ? true : delete _ref9$getSelf.self.unicorn; + (_ref10 = o === null || o === void 0 ? void 0 : _classPrivateFieldLooseBase(o.Foo, _self)[_self]) == null ? true : _ref10.getSelf == null ? true : (_ref10$getSelf = _ref10.getSelf()) == null ? true : delete _ref10$getSelf.self.unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + (_fnDeep$very$o = fnDeep == null ? void 0 : fnDeep().very.o) === null || _fnDeep$very$o === void 0 ? true : delete _classPrivateFieldLooseBase(_fnDeep$very$o.Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].self.unicorn; + (_ref11 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : delete _ref11.self.unicorn; + (_ref12 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self].self) == null ? true : delete _ref12.self.unicorn; + (_ref13 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : (_ref13$self = _ref13.self) == null ? true : delete _ref13$self.self.unicorn; + fn === null || fn === void 0 ? true : delete _classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf().unicorn; + (_ref14 = fn === null || fn === void 0 ? void 0 : (_classPrivateFieldLoo3 = _classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf) == null ? true : delete _ref14.call(_classPrivateFieldLoo3).unicorn; + (_ref15 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : delete _ref15.getSelf().unicorn; + (_ref16 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : _ref16.getSelf == null ? true : delete _ref16.getSelf().unicorn; + (_ref17 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self].getSelf()) == null ? true : delete _ref17.self.unicorn; + (_ref18 = fn === null || fn === void 0 ? void 0 : (_classPrivateFieldLoo4 = _classPrivateFieldLooseBase(fn().Foo, _self)[_self]).getSelf) == null ? true : (_ref18$call = _ref18.call(_classPrivateFieldLoo4)) == null ? true : delete _ref18$call.self.unicorn; + (_ref19 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : (_ref19$getSelf = _ref19.getSelf()) == null ? true : delete _ref19$getSelf.self.unicorn; + (_ref20 = fn === null || fn === void 0 ? void 0 : _classPrivateFieldLooseBase(fn().Foo, _self)[_self]) == null ? true : _ref20.getSelf == null ? true : (_ref20$getSelf = _ref20.getSelf()) == null ? true : delete _ref20$getSelf.self.unicorn; + } + +} + +Object.defineProperty(Foo, _x, { + writable: true, + value: 1 +}); +Object.defineProperty(Foo, _self, { + writable: true, + value: Foo +}); +Foo.self = Foo; +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/exec.js new file mode 100644 index 000000000000..d38a87624dea --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/exec.js @@ -0,0 +1,102 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + expect(() => delete Foo?.#self.unicorn).toThrow(TypeError); + expect(() => delete deep?.very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete o?.Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fnDeep?.().very.o?.Foo.#self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.self?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.self?.self.unicorn).toThrow(TypeError); + + expect(() => delete fn?.().Foo.#self.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.().unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toThrow(TypeError); + expect(() => delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toThrow(TypeError); + + + } + + static testNull() { + const o = null; + const deep = { very: { o } }; + const fn = null; + function fnDeep() { + return deep; + } + + expect(delete deep?.very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.self?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete o?.Foo.#self.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete o?.Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fnDeep?.().very.o?.Foo.#self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.self?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.self?.self.unicorn).toBe(true); + + expect(delete fn?.().Foo.#self.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf().unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.().unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self.getSelf?.()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf()?.self.unicorn).toBe(true); + expect(delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn).toBe(true); + } +} + +Object.defineProperty(Foo, "unicorn", { configurable: false }); +Foo.test(); +Foo.testNull(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/input.js new file mode 100644 index 000000000000..cd39a04ec063 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/input.js @@ -0,0 +1,56 @@ +class Foo { + static #x = 1; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + delete Foo?.#self.unicorn; + delete deep?.very.o?.Foo.#self.unicorn; + + delete o?.Foo.#self.unicorn; + delete o?.Foo.#self.self.unicorn; + delete o?.Foo.#self?.self.unicorn; + delete o?.Foo.#self.self?.self.unicorn; + delete o?.Foo.#self?.self?.self.unicorn; + + delete o?.Foo.#self.getSelf().unicorn; + delete o?.Foo.#self.getSelf?.().unicorn; + delete o?.Foo.#self?.getSelf().unicorn; + delete o?.Foo.#self?.getSelf?.().unicorn; + delete o?.Foo.#self.getSelf()?.self.unicorn; + delete o?.Foo.#self.getSelf?.()?.self.unicorn; + delete o?.Foo.#self?.getSelf()?.self.unicorn; + delete o?.Foo.#self?.getSelf?.()?.self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fnDeep?.().very.o?.Foo.#self.unicorn; + + delete fn?.().Foo.#self.unicorn; + delete fn?.().Foo.#self.self.unicorn; + delete fn?.().Foo.#self?.self.unicorn; + delete fn?.().Foo.#self.self?.self.unicorn; + delete fn?.().Foo.#self?.self?.self.unicorn; + + delete fn?.().Foo.#self.getSelf().unicorn; + delete fn?.().Foo.#self.getSelf?.().unicorn; + delete fn?.().Foo.#self?.getSelf().unicorn; + delete fn?.().Foo.#self?.getSelf?.().unicorn; + delete fn?.().Foo.#self.getSelf()?.self.unicorn; + delete fn?.().Foo.#self.getSelf?.()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf()?.self.unicorn; + delete fn?.().Foo.#self?.getSelf?.()?.self.unicorn; + + } +} + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/options.json new file mode 100644 index 000000000000..3b59e1bbfcc8 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["proposal-class-properties"], + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/output.js new file mode 100644 index 000000000000..f7a3fc21af1d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/optional-chain-delete-property/output.js @@ -0,0 +1,75 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +class Foo { + static getSelf() { + return this; + } + + static test() { + var _deep$very$o, _classStaticPrivateFi, _classStaticPrivateFi2, _fnDeep$very$o, _classStaticPrivateFi3, _classStaticPrivateFi4; + + const o = { + Foo: Foo + }; + const deep = { + very: { + o + } + }; + + function fn() { + return o; + } + + function fnDeep() { + return deep; + } + + Foo === null || Foo === void 0 ? true : delete _classStaticPrivateFieldSpecGet(Foo, Foo, _self).unicorn; + (_deep$very$o = deep?.very.o) === null || _deep$very$o === void 0 ? true : delete _classStaticPrivateFieldSpecGet(_deep$very$o.Foo, Foo, _self).unicorn; + o === null || o === void 0 ? true : delete _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).unicorn; + o === null || o === void 0 ? true : delete _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).self)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.self?.self.unicorn; + o === null || o === void 0 ? true : delete _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : (_classStaticPrivateFi = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi).unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf().unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf?.().unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).getSelf())?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : (_classStaticPrivateFi2 = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi2)?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf()?.self.unicorn; + delete (o === null || o === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf?.()?.self.unicorn; + fn === null || fn === void 0 ? true : delete _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).unicorn; + (_fnDeep$very$o = fnDeep?.().very.o) === null || _fnDeep$very$o === void 0 ? true : delete _classStaticPrivateFieldSpecGet(_fnDeep$very$o.Foo, Foo, _self).unicorn; + fn === null || fn === void 0 ? true : delete _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).unicorn; + fn === null || fn === void 0 ? true : delete _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).self)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.self?.self.unicorn; + fn === null || fn === void 0 ? true : delete _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_classStaticPrivateFi3 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi3).unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf().unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf?.().unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).getSelf())?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : (_classStaticPrivateFi4 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi4)?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf()?.self.unicorn; + delete (fn === null || fn === void 0 ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf?.()?.self.unicorn; + } + +} + +var _x = { + writable: true, + value: 1 +}; +var _self = { + writable: true, + value: Foo +}; + +_defineProperty(Foo, "self", Foo); + +Foo.test();