Add "allowArrayLike" opt to destructuring and spread transforms (#11265)

This commit is contained in:
Nicolò Ribaudo 2020-05-24 23:00:06 +02:00 committed by GitHub
parent 28231e1be6
commit 93978267ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 110 additions and 5 deletions

View File

@ -980,6 +980,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")` helpers.iterableToArray = helper("7.0.0-beta.0")`
export default function _iterableToArray(iter) { export default function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);

View File

@ -4,7 +4,11 @@ import { types as t } from "@babel/core";
export default declare((api, options) => { export default declare((api, options) => {
api.assertVersion(7); api.assertVersion(7);
const { loose = false, useBuiltIns = false } = options; const {
loose = false,
useBuiltIns = false,
allowArrayLike = false,
} = options;
if (typeof loose !== "boolean") { if (typeof loose !== "boolean") {
throw new Error(`.loose must be a boolean or undefined`); throw new Error(`.loose must be a boolean or undefined`);
@ -85,6 +89,7 @@ export default declare((api, options) => {
this.scope = opts.scope; this.scope = opts.scope;
this.kind = opts.kind; this.kind = opts.kind;
this.arrayOnlySpread = opts.arrayOnlySpread; this.arrayOnlySpread = opts.arrayOnlySpread;
this.allowArrayLike = opts.allowArrayLike;
this.addHelper = opts.addHelper; this.addHelper = opts.addHelper;
} }
@ -141,7 +146,7 @@ export default declare((api, options) => {
) { ) {
return node; return node;
} else { } else {
return this.scope.toArray(node, count); return this.scope.toArray(node, count, this.allowArrayLike);
} }
} }
@ -523,6 +528,7 @@ export default declare((api, options) => {
scope: scope, scope: scope,
nodes: nodes, nodes: nodes,
arrayOnlySpread, arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name), addHelper: name => this.addHelper(name),
}); });
@ -548,6 +554,7 @@ export default declare((api, options) => {
scope: scope, scope: scope,
nodes: nodes, nodes: nodes,
arrayOnlySpread, arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name), addHelper: name => this.addHelper(name),
}); });
destructuring.init(pattern, ref); destructuring.init(pattern, ref);
@ -566,6 +573,7 @@ export default declare((api, options) => {
scope: scope, scope: scope,
nodes: nodes, nodes: nodes,
arrayOnlySpread, arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name), addHelper: name => this.addHelper(name),
}); });
@ -624,6 +632,7 @@ export default declare((api, options) => {
scope: scope, scope: scope,
kind: node.kind, kind: node.kind,
arrayOnlySpread, arrayOnlySpread,
allowArrayLike,
addHelper: name => this.addHelper(name), addHelper: name => this.addHelper(name),
}); });

View File

@ -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

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}

View File

@ -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"]);

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}

View File

@ -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"]);

View File

@ -0,0 +1 @@
var [first, ...rest] = o;

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-destructuring", { "allowArrayLike": true }]
]
}

View File

@ -0,0 +1,4 @@
var _o = o,
_o2 = babelHelpers.maybeArrayLike(babelHelpers.toArray, _o),
first = _o2[0],
rest = _o2.slice(1);

View File

@ -4,13 +4,13 @@ import { types as t } from "@babel/core";
export default declare((api, options) => { export default declare((api, options) => {
api.assertVersion(7); api.assertVersion(7);
const { loose } = options; const { loose, allowArrayLike } = options;
function getSpreadLiteral(spread, scope) { function getSpreadLiteral(spread, scope) {
if (loose && !t.isIdentifier(spread.argument, { name: "arguments" })) { if (loose && !t.isIdentifier(spread.argument, { name: "arguments" })) {
return spread.argument; return spread.argument;
} else { } else {
return scope.toArray(spread.argument, true); return scope.toArray(spread.argument, true, allowArrayLike);
} }
} }

View File

@ -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

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}

View File

@ -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"]);

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}

View File

@ -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"]);

View File

@ -0,0 +1 @@
var arr = ["a", ...p2, "e"];

View File

@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-spread", { "allowArrayLike": true }]
]
}

View File

@ -0,0 +1 @@
var arr = ["a"].concat(babelHelpers.maybeArrayLike(babelHelpers.toConsumableArray, p2), ["e"]);

View File

@ -520,7 +520,8 @@ export default class Scope {
console.log(sep); 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)) { if (t.isIdentifier(node)) {
const binding = this.getBinding(node.name); const binding = this.getBinding(node.name);
if (binding?.constant && binding.path.isGenericType("Array")) { if (binding?.constant && binding.path.isGenericType("Array")) {
@ -563,6 +564,12 @@ export default class Scope {
// Used in array-rest to create an array // Used in array-rest to create an array
helperName = "toArray"; helperName = "toArray";
} }
if (allowArrayLike) {
args.unshift(this.hub.addHelper(helperName));
helperName = "maybeArrayLike";
}
return t.callExpression(this.hub.addHelper(helperName), args); return t.callExpression(this.hub.addHelper(helperName), args);
} }