Correctly transform spreads to use proper concat method (#9108)

* Correctly transform spreads to use proper concat method

* Add tests to ensure array spread clones elements
This commit is contained in:
Daniel Tschinder 2018-12-13 23:24:43 -08:00 committed by GitHub
parent 72471aff63
commit 47da5cf75a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 5 deletions

View File

@ -21,7 +21,7 @@ var _ref4 = [a[1], a[0]];
a[0] = _ref4[0];
a[1] = _ref4[1];
var _ref5 = babelHelpers.toConsumableArray(foo).concat([bar]),
var _ref5 = [].concat(babelHelpers.toConsumableArray(foo), [bar]),
a = _ref5[0],
b = _ref5[1];

View File

@ -57,13 +57,29 @@ export default declare((api, options) => {
if (!hasSpread(elements)) return;
const nodes = build(elements, scope);
const first = nodes.shift();
let first = nodes[0];
if (nodes.length === 0 && first !== elements[0].argument) {
// If there is only one element in the ArrayExpression and
// the element was transformed (Array.prototype.slice.call or toConsumableArray)
// we know that the transformed code already takes care of cloning the array.
// So we can simply return that element.
if (nodes.length === 1 && first !== elements[0].argument) {
path.replaceWith(first);
return;
}
// If the first element is a ArrayExpression we can directly call
// concat on it.
// `[..].concat(..)`
// If not then we have to use `[].concat(arr)` and not `arr.concat`
// because `arr` could be extended/modified (e.g. Immutable) and we do not know exactly
// what concat would produce.
if (!t.isArrayExpression(first)) {
first = t.arrayExpression([]);
} else {
nodes.shift();
}
path.replaceWith(
t.callExpression(
t.memberExpression(first, t.identifier("concat")),

View File

@ -0,0 +1,11 @@
const arr = [];
arr.concat = () => {
throw new Error('Should not be called');
};
let x;
expect(() => {
x = [...arr];
}).not.toThrow();
expect(x).not.toBe(arr);

View File

@ -0,0 +1,7 @@
const arr = [];
arr.concat = () => {
throw new Error('Should not be called');
};
const x = [...arr];

View File

@ -0,0 +1,7 @@
const arr = [];
arr.concat = () => {
throw new Error('Should not be called');
};
const x = [].concat(arr);

View File

@ -0,0 +1,9 @@
// test that toConsumableArray clones the array.
function foo() {
const x = [...arguments];
expect(x).not.toBe(arguments);
}
foo(1,2);

View File

@ -1 +1 @@
var lyrics = babelHelpers.toConsumableArray(parts).concat(["head", "and", "toes"]);
var lyrics = [].concat(babelHelpers.toConsumableArray(parts), ["head", "and", "toes"]);

View File

@ -3,5 +3,5 @@ function foo() {
bar[_key] = arguments[_key];
}
return bar.concat();
return [].concat(bar);
}

View File

@ -0,0 +1,7 @@
// test that toConsumableArray clones the array.
const arr = [];
const foo = () => arr;
const x = [...foo()];
expect(x).not.toBe(arr);