add support for logical assignments with private properties (#11702)
* add support for logical assignments with private properties Patches the logic for handling assignment operators and adds support for handling the logical assignment operators appropriately. Fixes: https://github.com/babel/babel/issues/11646 * replace hardcoded logical assignment operators with constant Replace a hardcoded check for logical assignment operators with the LOGICAL_OPERATORS constant in plugin-proposal-logical-assignment-operators. Refs: https://github.com/babel/babel/pull/11702#discussion_r438554423
This commit is contained in:
parent
aa82ab6358
commit
2ac49ba7c4
@ -315,29 +315,42 @@ const handle = {
|
||||
|
||||
// MEMBER = VALUE -> _set(MEMBER, VALUE)
|
||||
// MEMBER += VALUE -> _set(MEMBER, _get(MEMBER) + VALUE)
|
||||
// MEMBER ??= VALUE -> _get(MEMBER) ?? _set(MEMBER, VALUE)
|
||||
if (parentPath.isAssignmentExpression({ left: node })) {
|
||||
if (this.simpleSet) {
|
||||
member.replaceWith(this.simpleSet(member));
|
||||
return;
|
||||
}
|
||||
|
||||
const { operator, right } = parent;
|
||||
let value = right;
|
||||
const { operator, right: value } = parent;
|
||||
|
||||
if (operator !== "=") {
|
||||
if (operator === "=") {
|
||||
parentPath.replaceWith(this.set(member, value));
|
||||
} else {
|
||||
const operatorTrunc = operator.slice(0, -1);
|
||||
if (t.LOGICAL_OPERATORS.includes(operatorTrunc)) {
|
||||
// Give the state handler a chance to memoise the member, since we'll
|
||||
// reference it twice. The second access (the set) should do the memo
|
||||
// reference it twice. The first access (the get) should do the memo
|
||||
// assignment.
|
||||
this.memoise(member, 2);
|
||||
|
||||
value = t.binaryExpression(
|
||||
operator.slice(0, -1),
|
||||
this.memoise(member, 1);
|
||||
parentPath.replaceWith(
|
||||
t.logicalExpression(
|
||||
operatorTrunc,
|
||||
this.get(member),
|
||||
value,
|
||||
this.set(member, value),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Here, the second access (the set) is evaluated first.
|
||||
this.memoise(member, 2);
|
||||
parentPath.replaceWith(
|
||||
this.set(
|
||||
member,
|
||||
t.binaryExpression(operatorTrunc, this.get(member), value),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
parentPath.replaceWith(this.set(member, value));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
class Foo {
|
||||
#nullish = 0;
|
||||
#and = 0;
|
||||
#or = 0;
|
||||
|
||||
self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
test() {
|
||||
this.#nullish ??= 42;
|
||||
this.#and &&= 0;
|
||||
this.#or ||= 0;
|
||||
|
||||
this.self().#nullish ??= 42;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-logical-assignment-operators", { "loose": true }],
|
||||
["proposal-class-properties", { "loose": true }]
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
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 _nullish = _classPrivateFieldLooseKey("nullish");
|
||||
|
||||
var _and = _classPrivateFieldLooseKey("and");
|
||||
|
||||
var _or = _classPrivateFieldLooseKey("or");
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
Object.defineProperty(this, _nullish, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, _and, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, _or, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
|
||||
self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
test() {
|
||||
var _classPrivateFieldLoo, _classPrivateFieldLoo2, _classPrivateFieldLoo3, _classPrivateFieldLoo4;
|
||||
|
||||
(_classPrivateFieldLoo = _classPrivateFieldLooseBase(this, _nullish))[_nullish] ?? (_classPrivateFieldLoo[_nullish] = 42);
|
||||
(_classPrivateFieldLoo2 = _classPrivateFieldLooseBase(this, _and))[_and] && (_classPrivateFieldLoo2[_and] = 0);
|
||||
(_classPrivateFieldLoo3 = _classPrivateFieldLooseBase(this, _or))[_or] || (_classPrivateFieldLoo3[_or] = 0);
|
||||
(_classPrivateFieldLoo4 = _classPrivateFieldLooseBase(this.self(), _nullish))[_nullish] ?? (_classPrivateFieldLoo4[_nullish] = 42);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
class Foo {
|
||||
#nullish = 0;
|
||||
#and = 0;
|
||||
#or = 0;
|
||||
|
||||
self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
test() {
|
||||
this.#nullish ??= 42;
|
||||
this.#and &&= 0;
|
||||
this.#or ||= 0;
|
||||
|
||||
this.self().#nullish ??= 42;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
"proposal-logical-assignment-operators",
|
||||
"proposal-class-properties"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
|
||||
|
||||
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
|
||||
|
||||
var _nullish = new WeakMap();
|
||||
|
||||
var _and = new WeakMap();
|
||||
|
||||
var _or = new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
_nullish.set(this, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
|
||||
_and.set(this, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
|
||||
_or.set(this, {
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
|
||||
self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
test() {
|
||||
var _this$self;
|
||||
|
||||
_classPrivateFieldGet(this, _nullish) ?? _classPrivateFieldSet(this, _nullish, 42);
|
||||
_classPrivateFieldGet(this, _and) && _classPrivateFieldSet(this, _and, 0);
|
||||
_classPrivateFieldGet(this, _or) || _classPrivateFieldSet(this, _or, 0);
|
||||
_classPrivateFieldGet(_this$self = this.self(), _nullish) ?? _classPrivateFieldSet(_this$self, _nullish, 42);
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,7 +13,8 @@ export default declare(api => {
|
||||
AssignmentExpression(path) {
|
||||
const { node, scope } = path;
|
||||
const { operator, left, right } = node;
|
||||
if (operator !== "||=" && operator !== "&&=" && operator !== "??=") {
|
||||
const operatorTrunc = operator.slice(0, -1);
|
||||
if (!t.LOGICAL_OPERATORS.includes(operatorTrunc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ export default declare(api => {
|
||||
|
||||
path.replaceWith(
|
||||
t.logicalExpression(
|
||||
operator.slice(0, -1),
|
||||
operatorTrunc,
|
||||
lhs,
|
||||
t.assignmentExpression("=", left, right),
|
||||
),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user