fix object rest in array pattern (#10275)

* fix object rest in array pattern

* update test fixtures

* early return

* use path.stop() at the right path
This commit is contained in:
Tan Li Hau 2019-09-10 21:18:45 +08:00 committed by Nicolò Ribaudo
parent 81831032c3
commit 8027dca501
9 changed files with 179 additions and 30 deletions

View File

@ -30,9 +30,20 @@ export default declare((api, opts) => {
function hasRestElement(path) { function hasRestElement(path) {
let foundRestElement = false; let foundRestElement = false;
visitRestElements(path, () => { visitRestElements(path, restElement => {
foundRestElement = true; foundRestElement = true;
path.stop(); restElement.stop();
});
return foundRestElement;
}
function hasObjectPatternRestElement(path) {
let foundRestElement = false;
visitRestElements(path, restElement => {
if (restElement.parentPath.isObjectPattern()) {
foundRestElement = true;
restElement.stop();
}
}); });
return foundRestElement; return foundRestElement;
} }
@ -163,9 +174,9 @@ export default declare((api, opts) => {
]; ];
} }
function replaceRestElement(parentPath, paramPath, i, numParams) { function replaceRestElement(parentPath, paramPath) {
if (paramPath.isAssignmentPattern()) { if (paramPath.isAssignmentPattern()) {
replaceRestElement(parentPath, paramPath.get("left"), i, numParams); replaceRestElement(parentPath, paramPath.get("left"));
return; return;
} }
@ -173,7 +184,7 @@ export default declare((api, opts) => {
const elements = paramPath.get("elements"); const elements = paramPath.get("elements");
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
replaceRestElement(parentPath, elements[i], i, elements.length); replaceRestElement(parentPath, elements[i]);
} }
} }
@ -200,7 +211,7 @@ export default declare((api, opts) => {
Function(path) { Function(path) {
const params = path.get("params"); const params = path.get("params");
for (let i = params.length - 1; i >= 0; i--) { for (let i = params.length - 1; i >= 0; i--) {
replaceRestElement(params[i].parentPath, params[i], i, params.length); replaceRestElement(params[i].parentPath, params[i]);
} }
}, },
// adapted from transform-destructuring/src/index.js#pushObjectRest // adapted from transform-destructuring/src/index.js#pushObjectRest
@ -380,8 +391,12 @@ export default declare((api, opts) => {
const leftPath = path.get("left"); const leftPath = path.get("left");
const left = node.left; const left = node.left;
if (!hasObjectPatternRestElement(leftPath)) {
return;
}
if (!t.isVariableDeclaration(left)) {
// for ({a, ...b} of []) {} // for ({a, ...b} of []) {}
if (t.isObjectPattern(left) && hasRestElement(leftPath)) {
const temp = scope.generateUidIdentifier("ref"); const temp = scope.generateUidIdentifier("ref");
node.left = t.variableDeclaration("var", [ node.left = t.variableDeclaration("var", [
@ -401,14 +416,9 @@ export default declare((api, opts) => {
t.assignmentExpression("=", left, t.cloneNode(temp)), t.assignmentExpression("=", left, t.cloneNode(temp)),
), ),
); );
} else {
return; // for (var {a, ...b} of []) {}
}
if (!t.isVariableDeclaration(left)) return;
const pattern = left.declarations[0].id; const pattern = left.declarations[0].id;
if (!t.isObjectPattern(pattern)) return;
const key = scope.generateUidIdentifier("ref"); const key = scope.generateUidIdentifier("ref");
node.left = t.variableDeclaration(left.kind, [ node.left = t.variableDeclaration(left.kind, [
@ -422,6 +432,38 @@ export default declare((api, opts) => {
t.variableDeclarator(pattern, t.cloneNode(key)), t.variableDeclarator(pattern, t.cloneNode(key)),
]), ]),
); );
}
},
// [{a, ...b}] = c;
ArrayPattern(path) {
const objectPatterns = [];
visitRestElements(path, path => {
if (!path.parentPath.isObjectPattern()) {
// Return early if the parent is not an ObjectPattern, but
// (for example) an ArrayPattern or Function, because that
// means this RestElement is an not an object property.
return;
}
const objectPattern = path.parentPath;
const uid = path.scope.generateUidIdentifier("ref");
objectPatterns.push(t.variableDeclarator(objectPattern.node, uid));
objectPattern.replaceWith(t.cloneNode(uid));
path.skip();
});
if (objectPatterns.length > 0) {
const statementPath = path.getStatementParent();
statementPath.insertAfter(
t.variableDeclaration(
statementPath.node.kind || "var",
objectPatterns,
),
);
}
}, },
// var a = { ...b, ...c } // var a = { ...b, ...c }
ObjectExpression(path, file) { ObjectExpression(path, file) {

View File

@ -0,0 +1,19 @@
// ForXStatement
for (const [{a, ...b}] of []) {}
for ([{a, ...b}] of []) {}
async function a() {
for await ([{a, ...b}] of []) {}
}
// skip
for ([{a}] in {}) {}
for ([{a}] of []) {}
async function a() {
for await ([{a}] of []) {}
}
for ([a, ...b] in {}) {}
for ([a, ...b] of []) {}
async function a() {
for await ([a, ...b] of []) {}
}

View File

@ -0,0 +1,49 @@
// ForXStatement
for (const _ref of []) {
const [_ref2] = _ref;
const {
a
} = _ref2,
b = babelHelpers.objectWithoutProperties(_ref2, ["a"]);
}
for (var _ref3 of []) {
[_ref4] = _ref3;
var {
a
} = _ref4,
b = babelHelpers.objectWithoutProperties(_ref4, ["a"]);
}
async function a() {
for await (var _ref5 of []) {
[_ref6] = _ref5;
var {
a
} = _ref6,
b = babelHelpers.objectWithoutProperties(_ref6, ["a"]);
}
} // skip
for ([{
a
}] in {}) {}
for ([{
a
}] of []) {}
async function a() {
for await ([{
a
}] of []) {}
}
for ([a, ...b] in {}) {}
for ([a, ...b] of []) {}
async function a() {
for await ([a, ...b] of []) {}
}

View File

@ -0,0 +1 @@
const [a, [{b, ...c}], {d, ...e}, [{ f, ...g}, {h: [i, {j, ...k}] }]] = x;

View File

@ -0,0 +1,19 @@
const [a, [_ref], _ref2, [_ref3, {
h: [i, _ref4]
}]] = x;
const {
b
} = _ref,
c = babelHelpers.objectWithoutProperties(_ref, ["b"]),
{
d
} = _ref2,
e = babelHelpers.objectWithoutProperties(_ref2, ["d"]),
{
f
} = _ref3,
g = babelHelpers.objectWithoutProperties(_ref3, ["f"]),
{
j
} = _ref4,
k = babelHelpers.objectWithoutProperties(_ref4, ["j"]);

View File

@ -0,0 +1,6 @@
const [a, {b, ...c}] = x;
let [d, {e, ...f}] = x;
[g, {h, ...i}] = x;

View File

@ -0,0 +1,15 @@
const [a, _ref] = x;
const {
b
} = _ref,
c = babelHelpers.objectWithoutProperties(_ref, ["b"]);
let [d, _ref2] = x;
let {
e
} = _ref2,
f = babelHelpers.objectWithoutProperties(_ref2, ["e"]);
[g, _ref3] = x;
var {
h
} = _ref3,
i = babelHelpers.objectWithoutProperties(_ref3, ["h"]);

View File

@ -1,9 +1,8 @@
import "core-js/modules/es7.string.pad-end"; import "core-js/modules/es7.string.pad-end";
import "core-js/modules/es7.string.pad-start"; import "core-js/modules/es7.string.pad-start";
for (const _ref of foo) { for (const {
const {
padStart padStart
} = _ref; } of foo) {
console.log('b'.padEnd(5)); console.log('b'.padEnd(5));
} }

View File

@ -2,9 +2,8 @@ import "core-js/modules/es.array.iterator";
import "core-js/modules/es.string.pad-end"; import "core-js/modules/es.string.pad-end";
import "core-js/modules/es.string.pad-start"; import "core-js/modules/es.string.pad-start";
for (const _ref of foo) { for (const {
const {
padStart padStart
} = _ref; } of foo) {
console.log('b'.padEnd(5)); console.log('b'.padEnd(5));
} }