Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "allowArrayLike" option to the destructuring and spread transforms #11265

Merged
merged 1 commit into from May 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/babel-helpers/src/helpers.js
Expand Up @@ -977,6 +977,18 @@ helpers.arrayWithHoles = helper("7.0.0-beta.0")`
}
`;

helpers.maybeArrayLike = helper("7.9.0")`
import arrayLikeToArray from "arrayLikeToArray";

export default function _maybeArrayLike(next, arr, i) {
if (arr && !Array.isArray(arr) && typeof arr.length === "number") {
var len = arr.length;
return arrayLikeToArray(arr, i !== void 0 && i < len ? i : len);
}
return next(arr, i);
}
`;

helpers.iterableToArray = helper("7.0.0-beta.0")`
export default function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
Expand Down
13 changes: 11 additions & 2 deletions packages/babel-plugin-transform-destructuring/src/index.js
Expand Up @@ -4,7 +4,11 @@ import { types as t } from "@babel/core";
export default declare((api, options) => {
api.assertVersion(7);

const { loose = false, useBuiltIns = false } = options;
const {
loose = false,
useBuiltIns = false,
allowArrayLike = false,
} = options;

if (typeof loose !== "boolean") {
throw new Error(`.loose must be a boolean or undefined`);
Expand Down Expand Up @@ -85,6 +89,7 @@ export default declare((api, options) => {
this.scope = opts.scope;
this.kind = opts.kind;
this.arrayOnlySpread = opts.arrayOnlySpread;
this.allowArrayLike = opts.allowArrayLike;
this.addHelper = opts.addHelper;
}

Expand Down Expand Up @@ -141,7 +146,7 @@ export default declare((api, options) => {
) {
return node;
} else {
return this.scope.toArray(node, count);
return this.scope.toArray(node, count, this.allowArrayLike);
}
}

Expand Down Expand Up @@ -523,6 +528,7 @@ export default declare((api, options) => {
scope: scope,
nodes: nodes,
arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name),
});

Expand All @@ -548,6 +554,7 @@ export default declare((api, options) => {
scope: scope,
nodes: nodes,
arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name),
});
destructuring.init(pattern, ref);
Expand All @@ -566,6 +573,7 @@ export default declare((api, options) => {
scope: scope,
nodes: nodes,
arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name),
});

Expand Down Expand Up @@ -624,6 +632,7 @@ export default declare((api, options) => {
scope: scope,
kind: node.kind,
arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name),
});

Expand Down
@@ -0,0 +1,6 @@
var o = { 0: "a", 2: "c", length: 3 };

var [...rest] = o;

expect(rest).toEqual(["a", undefined, "c"]);
expect(1 in rest).toBe(true); // Not holey
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,6 @@
var o = { 0: "a", 1: "b", 2: "c", length: 2 };

var [first, ...rest] = o;

expect(first).toBe("a");
expect(rest).toEqual(["b"]);
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,6 @@
var o = { 0: "a", 1: "b", 2: "c", length: 3 };

var [first, ...rest] = o;

expect(first).toBe("a");
expect(rest).toEqual(["b", "c"]);
@@ -0,0 +1 @@
var [first, ...rest] = o;
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,4 @@
var _o = o,
_o2 = babelHelpers.maybeArrayLike(babelHelpers.toArray, _o),
first = _o2[0],
rest = _o2.slice(1);
4 changes: 2 additions & 2 deletions packages/babel-plugin-transform-spread/src/index.js
Expand Up @@ -4,13 +4,13 @@ import { types as t } from "@babel/core";
export default declare((api, options) => {
api.assertVersion(7);

const { loose } = options;
const { loose, allowArrayLike } = options;

function getSpreadLiteral(spread, scope) {
if (loose && !t.isIdentifier(spread.argument, { name: "arguments" })) {
return spread.argument;
} else {
return scope.toArray(spread.argument, true);
return scope.toArray(spread.argument, true, allowArrayLike);
}
}

Expand Down
@@ -0,0 +1,6 @@
var p2 = { 0: "a", 2: "c", length: 3 };

var arr = [...p2, "d"];

expect(arr).toEqual(["a", undefined, "c", "d"]);
expect(1 in arr).toBe(true); // Not holey
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,5 @@
var p2 = { 0: "b", 1: "c", 2: "d", length: 2 };

var arr = ["a", ...p2, "e"];

expect(arr).toEqual(["a", "b", "c", "e"]);
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,5 @@
var p2 = { 0: "b", 1: "c", 2: "d", length: 3 };

var arr = ["a", ...p2, "e"];

expect(arr).toEqual(["a", "b", "c", "d", "e"]);
@@ -0,0 +1 @@
var arr = ["a", ...p2, "e"];
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}
@@ -0,0 +1 @@
var arr = ["a"].concat(babelHelpers.maybeArrayLike(babelHelpers.toConsumableArray, p2), ["e"]);
9 changes: 8 additions & 1 deletion packages/babel-traverse/src/scope/index.js
Expand Up @@ -493,7 +493,8 @@ export default class Scope {
console.log(sep);
}

toArray(node: Object, i?: number) {
// TODO: (Babel 8) Split i in two parameters, and use an object of flags
toArray(node: Object, i?: number | boolean, allowArrayLike?: boolean) {
if (t.isIdentifier(node)) {
const binding = this.getBinding(node.name);
if (binding && binding.constant && binding.path.isGenericType("Array")) {
Expand Down Expand Up @@ -536,6 +537,12 @@ export default class Scope {
// Used in array-rest to create an array
helperName = "toArray";
}

if (allowArrayLike) {
args.unshift(this.hub.addHelper(helperName));
helperName = "maybeArrayLike";
}

return t.callExpression(this.hub.addHelper(helperName), args);
}

Expand Down