Destructuring: Fix handling of impure computed keys with object rest (#9416)

This commit is contained in:
Moti Zilberman 2019-03-27 02:11:44 +00:00 committed by Daniel Tschinder
parent f7bfc774ba
commit 1f5444e96a
5 changed files with 90 additions and 0 deletions

View File

@ -19,3 +19,16 @@ key = 2;
expect(y).toBe("two");
expect(x).toEqual({});
expect(z).toBe("zee");
// rhs evaluated before lhs
var order = [];
function left() {
order.push("left");
return 0;
}
function right() {
order.push("right");
return {};
}
var { [left()]: y, ...x} = right();
expect(order).toEqual(["right", "left"]);

View File

@ -44,6 +44,19 @@ export default declare((api, options) => {
return false;
}
/**
* Test if an ObjectPattern's elements contain any RestElements.
*/
function hasObjectRest(pattern) {
for (const elem of (pattern.properties: Array)) {
if (t.isRestElement(elem)) {
return true;
}
}
return false;
}
const STOP_TRAVERSAL = {};
// NOTE: This visitor is meant to be used via t.traverse
@ -263,6 +276,31 @@ export default declare((api, options) => {
objRef = temp;
}
// Replace impure computed key expressions if we have a rest parameter
if (hasObjectRest(pattern)) {
let copiedPattern;
for (let i = 0; i < pattern.properties.length; i++) {
const prop = pattern.properties[i];
if (t.isRestElement(prop)) {
break;
}
const key = prop.key;
if (prop.computed && !this.scope.isPure(key)) {
const name = this.scope.generateUidIdentifierBasedOnNode(key);
this.nodes.push(this.buildVariableDeclaration(name, key));
if (!copiedPattern) {
copiedPattern = pattern = {
...pattern,
properties: pattern.properties.slice(),
};
}
copiedPattern.properties[i] = {
...copiedPattern.properties[i],
key: name,
};
}
}
}
//
for (let i = 0; i < pattern.properties.length; i++) {

View File

@ -0,0 +1,34 @@
var key, x, y, z;
// impure
key = 1;
var { [key++]: y, ...x } = { 1: 1, a: 1 };
expect(x).toEqual({ a: 1 });
expect(key).toBe(2);
expect(1).toBe(y);
// takes care of the order
key = 1;
var { [++key]: y, [++key]: z, ...rest} = {2: 2, 3: 3};
expect(y).toBe(2);
expect(z).toBe(3);
// pure, computed property should remain as-is
key = 2;
({ [key]: y, z, ...x } = {2: "two", z: "zee"});
expect(y).toBe("two");
expect(x).toEqual({});
expect(z).toBe("zee");
// rhs evaluated before lhs
var order = [];
function left() {
order.push("left");
return 0;
}
function right() {
order.push("right");
return {};
}
var { [left()]: y, ...x} = right();
expect(order).toEqual(["right", "left"]);

View File

@ -0,0 +1 @@
var { [fn()]: x, ...y } = z;

View File

@ -0,0 +1,4 @@
var _z = z,
_fn = fn(),
x = _z[_fn],
y = babelHelpers.objectWithoutProperties(_z, [_fn].map(babelHelpers.toPropertyKey));