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 4, 2020
1 parent c9da3bc commit f226bc8
Show file tree
Hide file tree
Showing 17 changed files with 988 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,6 @@
{
"plugins": [
["proposal-optional-chaining", { "loose": true }],
["proposal-class-properties", { "loose": true }]
]
}
@@ -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();

0 comments on commit f226bc8

Please sign in to comment.