Skip to content

Commit

Permalink
fix: support delete obj?.#x.a
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Jun 3, 2020
1 parent 71972b5 commit fd7795f
Show file tree
Hide file tree
Showing 16 changed files with 986 additions and 4 deletions.
28 changes: 24 additions & 4 deletions packages/babel-helper-member-expression-to-functions/src/index.js
Expand Up @@ -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
Expand Down Expand Up @@ -211,7 +222,13 @@ const handle = {
}
}

endPath.replaceWith(
let replacementPath = endPath;
if (isDeleteOperation) {
replacementPath = endParentPath;
regular = endParentPath.node;
}

replacementPath.replaceWith(
t.conditionalExpression(
t.logicalExpression(
"||",
Expand All @@ -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(
Expand Down
@@ -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();
@@ -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();
@@ -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();
@@ -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();

0 comments on commit fd7795f

Please sign in to comment.