Skip to content

Commit

Permalink
Support iterating generators in browsers without Symbol (#13129)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Apr 15, 2021
1 parent 5d55055 commit 808d437
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 53 deletions.
79 changes: 36 additions & 43 deletions packages/babel-helpers/src/helpers.js
Expand Up @@ -83,18 +83,15 @@ helpers.jsx = helper("7.0.0-beta.0")`

helpers.asyncIterator = helper("7.0.0-beta.0")`
export default function _asyncIterator(iterable) {
var method
var method;
if (typeof Symbol !== "undefined") {
if (Symbol.asyncIterator) {
method = iterable[Symbol.asyncIterator]
if (method != null) return method.call(iterable);
}
if (Symbol.iterator) {
method = iterable[Symbol.iterator]
if (method != null) return method.call(iterable);
}
if (Symbol.asyncIterator) method = iterable[Symbol.asyncIterator];
if (method == null && Symbol.iterator) method = iterable[Symbol.iterator];
}
throw new TypeError("Object is not async iterable");
if (method == null) method = iterable["@@asyncIterator"];
if (method == null) method = iterable["@@iterator"]
if (method == null) throw new TypeError("Object is not async iterable");
return method.call(iterable);
}
`;

Expand Down Expand Up @@ -179,9 +176,7 @@ helpers.AsyncGenerator = helper("7.0.0-beta.0")`
}
}
if (typeof Symbol === "function" && Symbol.asyncIterator) {
AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; };
}
AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () { return this; };
AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); };
AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); };
Expand Down Expand Up @@ -216,9 +211,7 @@ helpers.asyncGeneratorDelegate = helper("7.0.0-beta.0")`
return { done: false, value: awaitWrap(value) };
};
if (typeof Symbol === "function" && Symbol.iterator) {
iter[Symbol.iterator] = function () { return this; };
}
iter[typeof Symbol !== "undefined" && Symbol.iterator || "@@iterator"] = function () { return this; };
iter.next = function (value) {
if (waiting) {
Expand Down Expand Up @@ -1003,7 +996,7 @@ helpers.maybeArrayLike = helper("7.9.0")`

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);
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
`;

Expand All @@ -1019,14 +1012,15 @@ helpers.iterableToArrayLimit = helper("7.0.0-beta.0")`
// _i = _iterator
// _s = _step
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]);
if (_i == null) return;
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
for (_i = _i.call(arr), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
Expand All @@ -1046,10 +1040,11 @@ helpers.iterableToArrayLimit = helper("7.0.0-beta.0")`

helpers.iterableToArrayLimitLoose = helper("7.0.0-beta.0")`
export default function _iterableToArrayLimitLoose(arr, i) {
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]);
if (_i == null) return;
var _arr = [];
for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
for (_i = _i.call(arr), _step; !(_step = _i.next()).done;) {
_arr.push(_step.value);
if (i && _arr.length === i) break;
}
Expand Down Expand Up @@ -1104,8 +1099,9 @@ helpers.createForOfIteratorHelper = helper("7.9.0")`
// f: finish (always called at the end)
export default function _createForOfIteratorHelper(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
// Fallback for engines without symbol support
if (
Array.isArray(o) ||
Expand Down Expand Up @@ -1133,7 +1129,7 @@ helpers.createForOfIteratorHelper = helper("7.9.0")`
return {
s: function() {
it = o[Symbol.iterator]();
it = it.call(o);
},
n: function() {
var step = it.next();
Expand All @@ -1159,28 +1155,25 @@ helpers.createForOfIteratorHelperLoose = helper("7.9.0")`
import unsupportedIterableToArray from "unsupportedIterableToArray";
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) ||
(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++] };
}
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
// Fallback for engines without symbol support
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.");
}
it = o[Symbol.iterator]();
return it.next.bind(it);
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
`;

Expand Down
Expand Up @@ -12,7 +12,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }

function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (_i = _i.call(arr), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

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

Expand Down
@@ -0,0 +1,25 @@
let iterable = function* fn() {
yield 0;
yield 1;
yield 2;
}();

let iteratorMethod = iterable[Symbol.iterator];
iterable[Symbol.iterator] = undefined;

expect(() => {
let [_, ...res] = iterable;
}).toThrow(/non-iterable/);

// In older envs, regenerator uses @@iterator.
// In those browser Babel must delegate to Array.from, which
// needs to be polyfilled by the user and support @@iterator.
iterable["@@iterator"] = iteratorMethod;
Array.from = (it) => {
var i = it["@@iterator"](), arr = [], r;
while (!(r = it.next()).done) arr.push(r.value);
return arr;
};

let [_, ...res] = iterable;
expect(res).toEqual([1, 2]);
@@ -0,0 +1,3 @@
{
"plugins": ["transform-regenerator", "transform-destructuring"]
}
@@ -0,0 +1,25 @@
let iterable = function* fn() {
yield 1;
yield 2;
}();

let iteratorMethod = iterable[Symbol.iterator];
iterable[Symbol.iterator] = undefined;

expect(() => {
[...iterable];
}).toThrow(/non-iterable/);

// In older envs, regenerator uses @@iterator.
// In those browser Babel must delegate to Array.from, which
// needs to be polyfilled by the user and support @@iterator.
iterable["@@iterator"] = iteratorMethod;
Array.from = (it) => {
var i = it["@@iterator"](), arr = [], r;
while (!(r = it.next()).done) arr.push(r.value);
return arr;
};

let res = [...iterable];

expect(res).toEqual([1, 2]);
@@ -0,0 +1,3 @@
{
"plugins": ["transform-regenerator", "transform-spread"]
}
@@ -0,0 +1,19 @@
let iterable = function* fn() {
yield 1;
yield 2;
}();

let iteratorMethod = iterable[Symbol.iterator];
iterable[Symbol.iterator] = undefined;

expect(() => {
for (let x of iterable);
}).toThrow(/non-iterable/);

// In older envs, regenerator uses @@iterator.
iterable["@@iterator"] = iteratorMethod;

let res = [];
for (let x of iterable) res.push(x);

expect(res).toEqual([1, 2]);
@@ -0,0 +1,3 @@
{
"plugins": ["transform-regenerator", "transform-for-of"]
}
@@ -1,6 +1,6 @@
var o = {};

expect(() => [...undefined]).toThrow(/spread non-iterable/);
expect(() => [...undefined]).toThrow(/undefined is not iterable|property 'Symbol\(Symbol\.iterator\)' of undefined/);

expect(() => [...o]).toThrow(/spread non-iterable/);

Expand Down
Expand Up @@ -42,7 +42,7 @@ function _wrapAsyncGenerator(fn) { return function () { return new _AsyncGenerat

function _AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; var wrappedAwait = value instanceof _AwaitValue; Promise.resolve(wrappedAwait ? value.wrapped : value).then(function (arg) { if (wrappedAwait) { resume(key === "return" ? "return" : "next", arg); return; } settle(result.done ? "return" : "normal", arg); }, function (err) { resume("throw", err); }); } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen["return"] !== "function") { this["return"] = undefined; } }

if (typeof Symbol === "function" && Symbol.asyncIterator) { _AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; }
_AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () { return this; };

_AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); };

Expand Down
Expand Up @@ -42,7 +42,7 @@ function _wrapAsyncGenerator(fn) { return function () { return new _AsyncGenerat

function _AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; var wrappedAwait = value instanceof _AwaitValue; Promise.resolve(wrappedAwait ? value.wrapped : value).then(function (arg) { if (wrappedAwait) { resume(key === "return" ? "return" : "next", arg); return; } settle(result.done ? "return" : "normal", arg); }, function (err) { resume("throw", err); }); } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen["return"] !== "function") { this["return"] = undefined; } }

if (typeof Symbol === "function" && Symbol.asyncIterator) { _AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; }
_AsyncGenerator.prototype[typeof Symbol === "function" && Symbol.asyncIterator || "@@asyncIterator"] = function () { return this; };

_AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); };

Expand Down
4 changes: 2 additions & 2 deletions packages/babel-runtime-corejs2/helpers/esm/iterableToArray.js
@@ -1,6 +1,6 @@
import _Symbol from "@babel/runtime-corejs2/core-js/symbol";
import _isIterable from "@babel/runtime-corejs2/core-js/is-iterable";
import _Symbol$iterator from "@babel/runtime-corejs2/core-js/symbol/iterator";
import _Array$from from "@babel/runtime-corejs2/core-js/array/from";
export default function _iterableToArray(iter) {
if (typeof _Symbol !== "undefined" && _isIterable(Object(iter))) return _Array$from(iter);
if (typeof _Symbol !== "undefined" && iter[_Symbol$iterator] != null || iter["@@iterator"] != null) return _Array$from(iter);
}
4 changes: 2 additions & 2 deletions packages/babel-runtime-corejs2/helpers/iterableToArray.js
@@ -1,11 +1,11 @@
var _Symbol = require("@babel/runtime-corejs2/core-js/symbol");

var _isIterable = require("@babel/runtime-corejs2/core-js/is-iterable");
var _Symbol$iterator = require("@babel/runtime-corejs2/core-js/symbol/iterator");

var _Array$from = require("@babel/runtime-corejs2/core-js/array/from");

function _iterableToArray(iter) {
if (typeof _Symbol !== "undefined" && _isIterable(Object(iter))) return _Array$from(iter);
if (typeof _Symbol !== "undefined" && iter[_Symbol$iterator] != null || iter["@@iterator"] != null) return _Array$from(iter);
}

module.exports = _iterableToArray;
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-runtime/helpers/esm/iterableToArray.js
@@ -1,3 +1,3 @@
export default function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
2 changes: 1 addition & 1 deletion packages/babel-runtime/helpers/iterableToArray.js
@@ -1,5 +1,5 @@
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}

module.exports = _iterableToArray;
Expand Down

0 comments on commit 808d437

Please sign in to comment.