Skip to content

Commit

Permalink
Throw better errors for non-iterables when Symbol doesn't exist (#11264)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Mar 16, 2020
1 parent 1005890 commit 1ba41f2
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 25 deletions.
27 changes: 18 additions & 9 deletions packages/babel-helpers/src/helpers.js
Expand Up @@ -936,7 +936,7 @@ helpers.iterableToArray = helper("7.0.0-beta.0")`
if (
typeof iter === 'string'
|| Object.prototype.toString.call(iter) === "[object Arguments]"
|| Symbol.iterator in Object(iter)
|| (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter))
) return Array.from(iter);
}
`;
Expand All @@ -952,9 +952,12 @@ helpers.iterableToArrayLimit = helper("7.0.0-beta.0")`
// _e = _iteratorError
// _i = _iterator
// _s = _step
if (!(
Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]"
)) { return }
if (
(typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) &&
Object.prototype.toString.call(arr) !== "[object Arguments]"
) return;
var _arr = [];
var _n = true;
var _d = false;
Expand All @@ -980,9 +983,11 @@ helpers.iterableToArrayLimit = helper("7.0.0-beta.0")`

helpers.iterableToArrayLimitLoose = helper("7.0.0-beta.0")`
export default function _iterableToArrayLimitLoose(arr, i) {
if (!(
Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]"
)) { return }
if (
(typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) &&
Object.prototype.toString.call(arr) !== "[object Arguments]"
) return;
var _arr = [];
for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) {
_arr.push(_step.value);
Expand All @@ -994,13 +999,17 @@ helpers.iterableToArrayLimitLoose = helper("7.0.0-beta.0")`

helpers.nonIterableSpread = helper("7.0.0-beta.0")`
export default function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
throw new TypeError(
"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
);
}
`;

helpers.nonIterableRest = helper("7.0.0-beta.0")`
export default function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
throw new TypeError(
"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
);
}
`;

Expand Down
@@ -0,0 +1,13 @@
var a = (() => [1, 2, 3])();

// Simulate old environment
let _Symbol = Symbol;
Symbol = void 0;
try {
var [first, ...rest] = a;

expect(first).toBe(1);
expect(rest).toEqual([2, 3]);
} finally {
Symbol = _Symbol;
}
@@ -0,0 +1,6 @@
var a = (() => [1, 2, 3])();

// !!! In order to run this test, this shouldn't be optimized using type inference
// If it's optimized and doesn't call toArray, please modify this test
// and exec.js
var [first, ...rest] = a;
@@ -0,0 +1,8 @@
var a = (() => [1, 2, 3])(); // !!! In order to run this test, this shouldn't be optimized using type inference
// If it's optimized and doesn't call toArray, please modify this test
// and exec.js


var _a = babelHelpers.toArray(a),
first = _a[0],
rest = _a.slice(1);
@@ -1,9 +1,22 @@
var foo, bar;

expect(
() => {
var [foo, bar] = undefined;
}).toThrow("Invalid attempt to destructure non-iterable instance");
() => [foo, bar] = undefined
).toThrow(/destructure non-iterable/);

expect(
() => {
var foo = [ ...undefined ];
}).toThrow("Invalid attempt to spread non-iterable instance");
() => [foo, bar] = {}
).toThrow(/destructure non-iterable/);

// Simulate old browser
let _Symbol = Symbol;
Symbol = void 0;
try {

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

} finally {
Symbol = _Symbol;
}
@@ -0,0 +1,5 @@
{
"plugins": [
"transform-destructuring"
]
}
Expand Up @@ -6,9 +6,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "d

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 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) { if ((typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) && Object.prototype.toString.call(arr) !== "[object Arguments]") 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 _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

Expand Down
@@ -0,0 +1,10 @@
var a = (() => [2, 3])();

// Simulate old environment
let _Symbol = Symbol;
Symbol = void 0;
try {
expect([1, ...a]).toEqual([1, 2, 3]);
} finally {
Symbol = _Symbol;
}
@@ -0,0 +1,6 @@
var a = (() => [2, 3])();

// !!! In order to run this test, this shouldn't be optimized using type inference
// If it's optimized and doesn't call toConsumableArray, please modify this test
// and exec.js
[1, ...a];
@@ -0,0 +1,6 @@
var a = (() => [2, 3])(); // !!! In order to run this test, this shouldn't be optimized using type inference
// If it's optimized and doesn't call toConsumableArray, please modify this test
// and exec.js


[1].concat(babelHelpers.toConsumableArray(a));
@@ -0,0 +1,10 @@
var o = {};

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

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

// Simulate old browser
Symbol = void 0;

expect(() => [...o]).toThrow(/spread non-iterable/);
Expand Up @@ -2,9 +2,9 @@

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 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) { if ((typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) && Object.prototype.toString.call(arr) !== "[object Arguments]") 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 _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

Expand Down
@@ -1,8 +1,8 @@
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { 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) { if ((typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) && Object.prototype.toString.call(arr) !== "[object Arguments]") 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 _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

Expand Down
@@ -1,5 +1,6 @@
import _Array$from from "../../core-js/array/from";
import _isIterable from "../../core-js/is-iterable";
import _Symbol from "../../core-js/symbol";
export default function _iterableToArray(iter) {
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || _isIterable(Object(iter))) return _Array$from(iter);
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || typeof _Symbol !== "undefined" && _isIterable(Object(iter))) return _Array$from(iter);
}
4 changes: 3 additions & 1 deletion packages/babel-runtime-corejs2/helpers/iterableToArray.js
Expand Up @@ -2,8 +2,10 @@ var _Array$from = require("../core-js/array/from");

var _isIterable = require("../core-js/is-iterable");

var _Symbol = require("../core-js/symbol");

function _iterableToArray(iter) {
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || _isIterable(Object(iter))) return _Array$from(iter);
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || typeof _Symbol !== "undefined" && _isIterable(Object(iter))) return _Array$from(iter);
}

module.exports = _iterableToArray;
2 changes: 1 addition & 1 deletion packages/babel-runtime/helpers/esm/iterableToArray.js
@@ -1,3 +1,3 @@
export default function _iterableToArray(iter) {
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || Symbol.iterator in Object(iter)) return Array.from(iter);
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) 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 iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || Symbol.iterator in Object(iter)) return Array.from(iter);
if (typeof iter === 'string' || Object.prototype.toString.call(iter) === "[object Arguments]" || typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}

module.exports = _iterableToArray;

0 comments on commit 1ba41f2

Please sign in to comment.