Skip to content

Commit

Permalink
Add "allowArrayLike" support to the for-of transform
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Mar 20, 2020
1 parent 2e6f958 commit 2811336
Show file tree
Hide file tree
Showing 19 changed files with 125 additions and 12 deletions.
29 changes: 21 additions & 8 deletions packages/babel-helpers/src/helpers.js
Expand Up @@ -1079,10 +1079,16 @@ helpers.createForOfIteratorHelper = helper("7.9.0")`
// e: error (called whenever something throws)
// f: finish (always called at the end)
export default function _createForOfIteratorHelper(o) {
export default function _createForOfIteratorHelper(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
// Fallback for engines without symbol support
if (Array.isArray(o) || (o = unsupportedIterableToArray(o))) {
if (
Array.isArray(o) ||
(it = unsupportedIterableToArray(o)) ||
(allowArrayLike && o && typeof o.length === "number")
) {
if (it) o = it;
var i = 0;
var F = function(){};
return {
Expand All @@ -1099,7 +1105,7 @@ helpers.createForOfIteratorHelper = helper("7.9.0")`
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var it, normalCompletion = true, didErr = false, err;
var normalCompletion = true, didErr = false, err;
return {
s() {
Expand Down Expand Up @@ -1128,22 +1134,29 @@ helpers.createForOfIteratorHelper = helper("7.9.0")`
helpers.createForOfIteratorHelperLoose = helper("7.9.0")`
import unsupportedIterableToArray from "unsupportedIterableToArray";
export default function _createForOfIteratorHelperLoose(o) {
var i = 0;
export default function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
// Fallback for engines without symbol support
if (Array.isArray(o) || (o = unsupportedIterableToArray(o)))
if (
Array.isArray(o) ||
(it = unsupportedIterableToArray(o)) ||
(allowArrayLike && o && typeof o.length === "number")
) {
if (it) o = it;
var i = 0;
return function() {
if (i >= o.length) return { done: true };
return { done: false, value: o[i++] };
}
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
i = o[Symbol.iterator]();
return i.next.bind(i);
it = o[Symbol.iterator]();
return it.next.bind(it);
}
`;

Expand Down
13 changes: 10 additions & 3 deletions packages/babel-plugin-transform-for-of/src/index.js
Expand Up @@ -6,14 +6,20 @@ import transformWithoutHelper from "./no-helper-implementation";
export default declare((api, options) => {
api.assertVersion(7);

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

if (loose === true && assumeArray === true) {
throw new Error(
`The loose and assumeArray options cannot be used together in @babel/plugin-transform-for-of`,
);
}

if (assumeArray === true && allowArrayLike === true) {
throw new Error(
`The assumeArray and allowArrayLike options cannot be used together in @babel/plugin-transform-for-of`,
);
}

if (assumeArray) {
return {
name: "transform-for-of",
Expand Down Expand Up @@ -86,12 +92,12 @@ export default declare((api, options) => {
`);

const buildForOfLoose = template.statements(`
for (var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT), STEP_KEY;
for (var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ALLOW_ARRAY_LIKE), STEP_KEY;
!(STEP_KEY = ITERATOR_HELPER()).done;) BODY;
`);

const buildForOf = template.statements(`
var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT), STEP_KEY;
var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ALLOW_ARRAY_LIKE), STEP_KEY;
try {
for (ITERATOR_HELPER.s(); !(STEP_KEY = ITERATOR_HELPER.n()).done;) BODY;
} catch (err) {
Expand Down Expand Up @@ -200,6 +206,7 @@ export default declare((api, options) => {
const nodes = builder.build({
CREATE_ITERATOR_HELPER: state.addHelper(builder.helper),
ITERATOR_HELPER: scope.generateUidIdentifier("iterator"),
ALLOW_ARRAY_LIKE: allowArrayLike ? t.booleanLiteral(true) : null,
STEP_KEY: t.identifier(stepKey),
OBJECT: node.right,
BODY: node.body,
Expand Down
@@ -0,0 +1,7 @@
var p2 = { 0: "a", 2: "c", length: 3 };

var arr = [];
for (var x of p2) arr.push(x);

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

var arr = [];
for (var x of p2) arr.push(x);

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

var arr = [];
for (var x of p2) arr.push(x);

expect(arr).toEqual(["b", "c", "d"]);
@@ -0,0 +1 @@
for (var x of p2) arr.push(x);
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-for-of", { "loose": true, "allowArrayLike": true }]
]
}
@@ -0,0 +1,4 @@
for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(p2, true), _step; !(_step = _iterator()).done;) {
var x = _step.value;
arr.push(x);
}
@@ -0,0 +1,7 @@
var p2 = { 0: "a", 2: "c", length: 3 };

var arr = [];
for (var x of p2) arr.push(x);

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

var arr = [];
for (var x of p2) arr.push(x);

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

var arr = [];
for (var x of p2) arr.push(x);

expect(arr).toEqual(["b", "c", "d"]);
@@ -0,0 +1 @@
for (var x of p2) arr.push(x);
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.100.0" }],
["transform-for-of", { "allowArrayLike": true }]
]
}
@@ -0,0 +1,13 @@
var _iterator = babelHelpers.createForOfIteratorHelper(p2, true),
_step;

try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var x = _step.value;
arr.push(x);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
Expand Up @@ -6,7 +6,7 @@ function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

Expand Down

0 comments on commit 2811336

Please sign in to comment.