'use strict'; /* eslint global-require: 0 */ // the code is structured this way so that bundlers can // alias out `has-symbols` to `() => true` or `() => false` if your target // environments' Symbol capabilities are known, and then use // dead code elimination on the rest of this module. // // Similarly, `isarray` can be aliased to `Array.isArray` if // available in all target environments. var isArguments = require('is-arguments'); if (require('has-symbols')() || require('has-symbols/shams')()) { var $iterator = Symbol.iterator; // Symbol is available natively or shammed // natively: // - Chrome >= 38 // - Edge 12-14?, Edge >= 15 for sure // - FF >= 36 // - Safari >= 9 // - node >= 0.12 module.exports = function getIterator(iterable) { // alternatively, `iterable[$iterator]?.()` if (iterable != null && typeof iterable[$iterator] !== 'undefined') { return iterable[$iterator](); } if (isArguments(iterable)) { // arguments objects lack Symbol.iterator // - node 0.12 return Array.prototype[$iterator].call(iterable); } }; } else { // Symbol is not available, native or shammed var isArray = require('isarray'); var isString = require('is-string'); var GetIntrinsic = require('es-abstract/GetIntrinsic'); var $Map = GetIntrinsic('%Map%', true); var $Set = GetIntrinsic('%Set%', true); var callBound = require('es-abstract/helpers/callBound'); var $arrayPush = callBound('Array.prototype.push'); var $charCodeAt = callBound('String.prototype.charCodeAt'); var $stringSlice = callBound('String.prototype.slice'); var advanceStringIndex = function advanceStringIndex(S, index) { var length = S.length; if ((index + 1) >= length) { return index + 1; } var first = $charCodeAt(S, index); if (first < 0xD800 || first > 0xDBFF) { return index + 1; } var second = $charCodeAt(S, index + 1); if (second < 0xDC00 || second > 0xDFFF) { return index + 1; } return index + 2; }; var getArrayIterator = function getArrayIterator(arraylike) { var i = 0; return { next: function next() { var done = i >= arraylike.length; var value; if (!done) { value = arraylike[i]; i += 1; } return { done: done, value: value }; } }; }; var getNonCollectionIterator = function getNonCollectionIterator(iterable) { if (isArray(iterable) || isArguments(iterable)) { return getArrayIterator(iterable); } if (isString(iterable)) { var i = 0; return { next: function next() { var nextIndex = advanceStringIndex(iterable, i); var value = $stringSlice(iterable, i, nextIndex); i = nextIndex; return { done: nextIndex > iterable.length, value: value }; } }; } }; if (!$Map && !$Set) { // the only language iterables are Array, String, arguments // - Safari <= 6.0 // - Chrome < 38 // - node < 0.12 // - FF < 13 // - IE < 11 // - Edge < 11 module.exports = getNonCollectionIterator; } else { // either Map or Set are available, but Symbol is not // - es6-shim on an ES5 browser // - Safari 6.2 (maybe 6.1?) // - FF v[13, 36) // - IE 11 // - Edge 11 // - Safari v[6, 9) var isMap = require('is-map'); var isSet = require('is-set'); // Firefox >= 27, IE 11, Safari 6.2 - 9, Edge 11, es6-shim in older envs, all have forEach var $mapForEach = callBound('Map.prototype.forEach', true); var $setForEach = callBound('Set.prototype.forEach', true); if (typeof process === 'undefined' || !process.versions || !process.versions.node) { // "if is not node" // Firefox 17 - 26 has `.iterator()`, whose iterator `.next()` either // returns a value, or throws a StopIteration object. These browsers // do not have any other mechanism for iteration. var $mapIterator = callBound('Map.prototype.iterator', true); var $setIterator = callBound('Set.prototype.iterator', true); var getStopIterationIterator = function (iterator) { var done = false; return { next: function next() { try { return { done: done, value: done ? undefined : iterator.next() }; } catch (e) { done = true; return { done: true, value: undefined }; } } }; }; } // Firefox 27-35, and some older es6-shim versions, use a string "@@iterator" property // this returns a proper iterator object, so we should use it instead of forEach. // newer es6-shim versions use a string "_es6-shim iterator_" property. var $mapAtAtIterator = callBound('Map.prototype.@@iterator', true) || callBound('Map.prototype._es6-shim iterator_', true); var $setAtAtIterator = callBound('Set.prototype.@@iterator', true) || callBound('Set.prototype._es6-shim iterator_', true); var getCollectionIterator = function getCollectionIterator(iterable) { if (isMap(iterable)) { if ($mapIterator) { return getStopIterationIterator($mapIterator(iterable)); } if ($mapAtAtIterator) { return $mapAtAtIterator(iterable); } if ($mapForEach) { var entries = []; $mapForEach(iterable, function (v, k) { $arrayPush(entries, [k, v]); }); return getArrayIterator(entries); } } if (isSet(iterable)) { if ($setIterator) { return getStopIterationIterator($setIterator(iterable)); } if ($setAtAtIterator) { return $setAtAtIterator(iterable); } if ($setForEach) { var values = []; $setForEach(iterable, function (v) { $arrayPush(values, v); }); return getArrayIterator(values); } } }; module.exports = function getIterator(iterable) { return getCollectionIterator(iterable) || getNonCollectionIterator(iterable); }; } }