index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. 'use strict';
  2. /* eslint global-require: 0 */
  3. // the code is structured this way so that bundlers can
  4. // alias out `has-symbols` to `() => true` or `() => false` if your target
  5. // environments' Symbol capabilities are known, and then use
  6. // dead code elimination on the rest of this module.
  7. //
  8. // Similarly, `isarray` can be aliased to `Array.isArray` if
  9. // available in all target environments.
  10. var isArguments = require('is-arguments');
  11. var getStopIterationIterator = require('stop-iteration-iterator');
  12. if (require('has-symbols')() || require('has-symbols/shams')()) {
  13. var $iterator = Symbol.iterator;
  14. // Symbol is available natively or shammed
  15. // natively:
  16. // - Chrome >= 38
  17. // - Edge 12-14?, Edge >= 15 for sure
  18. // - FF >= 36
  19. // - Safari >= 9
  20. // - node >= 0.12
  21. module.exports = function getIterator(iterable) {
  22. // alternatively, `iterable[$iterator]?.()`
  23. if (iterable != null && typeof iterable[$iterator] !== 'undefined') {
  24. return iterable[$iterator]();
  25. }
  26. if (isArguments(iterable)) {
  27. // arguments objects lack Symbol.iterator
  28. // - node 0.12
  29. return Array.prototype[$iterator].call(iterable);
  30. }
  31. };
  32. } else {
  33. // Symbol is not available, native or shammed
  34. var isArray = require('isarray');
  35. var isString = require('is-string');
  36. var GetIntrinsic = require('get-intrinsic');
  37. var $Map = GetIntrinsic('%Map%', true);
  38. var $Set = GetIntrinsic('%Set%', true);
  39. var callBound = require('call-bind/callBound');
  40. var $arrayPush = callBound('Array.prototype.push');
  41. var $charCodeAt = callBound('String.prototype.charCodeAt');
  42. var $stringSlice = callBound('String.prototype.slice');
  43. var advanceStringIndex = function advanceStringIndex(S, index) {
  44. var length = S.length;
  45. if ((index + 1) >= length) {
  46. return index + 1;
  47. }
  48. var first = $charCodeAt(S, index);
  49. if (first < 0xD800 || first > 0xDBFF) {
  50. return index + 1;
  51. }
  52. var second = $charCodeAt(S, index + 1);
  53. if (second < 0xDC00 || second > 0xDFFF) {
  54. return index + 1;
  55. }
  56. return index + 2;
  57. };
  58. var getArrayIterator = function getArrayIterator(arraylike) {
  59. var i = 0;
  60. return {
  61. next: function next() {
  62. var done = i >= arraylike.length;
  63. var value;
  64. if (!done) {
  65. value = arraylike[i];
  66. i += 1;
  67. }
  68. return {
  69. done: done,
  70. value: value
  71. };
  72. }
  73. };
  74. };
  75. var getNonCollectionIterator = function getNonCollectionIterator(iterable, noPrimordialCollections) {
  76. if (isArray(iterable) || isArguments(iterable)) {
  77. return getArrayIterator(iterable);
  78. }
  79. if (isString(iterable)) {
  80. var i = 0;
  81. return {
  82. next: function next() {
  83. var nextIndex = advanceStringIndex(iterable, i);
  84. var value = $stringSlice(iterable, i, nextIndex);
  85. i = nextIndex;
  86. return {
  87. done: nextIndex > iterable.length,
  88. value: value
  89. };
  90. }
  91. };
  92. }
  93. // es6-shim and es-shims' es-map use a string "_es6-shim iterator_" property on different iterables, such as MapIterator.
  94. if (noPrimordialCollections && typeof iterable['_es6-shim iterator_'] !== 'undefined') {
  95. return iterable['_es6-shim iterator_']();
  96. }
  97. };
  98. if (!$Map && !$Set) {
  99. // the only language iterables are Array, String, arguments
  100. // - Safari <= 6.0
  101. // - Chrome < 38
  102. // - node < 0.12
  103. // - FF < 13
  104. // - IE < 11
  105. // - Edge < 11
  106. module.exports = function getIterator(iterable) {
  107. if (iterable != null) {
  108. return getNonCollectionIterator(iterable, true);
  109. }
  110. };
  111. } else {
  112. // either Map or Set are available, but Symbol is not
  113. // - es6-shim on an ES5 browser
  114. // - Safari 6.2 (maybe 6.1?)
  115. // - FF v[13, 36)
  116. // - IE 11
  117. // - Edge 11
  118. // - Safari v[6, 9)
  119. var isMap = require('is-map');
  120. var isSet = require('is-set');
  121. // Firefox >= 27, IE 11, Safari 6.2 - 9, Edge 11, es6-shim in older envs, all have forEach
  122. var $mapForEach = callBound('Map.prototype.forEach', true);
  123. var $setForEach = callBound('Set.prototype.forEach', true);
  124. if (typeof process === 'undefined' || !process.versions || !process.versions.node) { // "if is not node"
  125. // Firefox 17 - 26 has `.iterator()`, whose iterator `.next()` either
  126. // returns a value, or throws a StopIteration object. These browsers
  127. // do not have any other mechanism for iteration.
  128. var $mapIterator = callBound('Map.prototype.iterator', true);
  129. var $setIterator = callBound('Set.prototype.iterator', true);
  130. }
  131. // Firefox 27-35, and some older es6-shim versions, use a string "@@iterator" property
  132. // this returns a proper iterator object, so we should use it instead of forEach.
  133. // newer es6-shim versions use a string "_es6-shim iterator_" property.
  134. var $mapAtAtIterator = callBound('Map.prototype.@@iterator', true) || callBound('Map.prototype._es6-shim iterator_', true);
  135. var $setAtAtIterator = callBound('Set.prototype.@@iterator', true) || callBound('Set.prototype._es6-shim iterator_', true);
  136. var getCollectionIterator = function getCollectionIterator(iterable) {
  137. if (isMap(iterable)) {
  138. if ($mapIterator) {
  139. return getStopIterationIterator($mapIterator(iterable));
  140. }
  141. if ($mapAtAtIterator) {
  142. return $mapAtAtIterator(iterable);
  143. }
  144. if ($mapForEach) {
  145. var entries = [];
  146. $mapForEach(iterable, function (v, k) {
  147. $arrayPush(entries, [k, v]);
  148. });
  149. return getArrayIterator(entries);
  150. }
  151. }
  152. if (isSet(iterable)) {
  153. if ($setIterator) {
  154. return getStopIterationIterator($setIterator(iterable));
  155. }
  156. if ($setAtAtIterator) {
  157. return $setAtAtIterator(iterable);
  158. }
  159. if ($setForEach) {
  160. var values = [];
  161. $setForEach(iterable, function (v) {
  162. $arrayPush(values, v);
  163. });
  164. return getArrayIterator(values);
  165. }
  166. }
  167. };
  168. module.exports = function getIterator(iterable) {
  169. return getCollectionIterator(iterable) || getNonCollectionIterator(iterable);
  170. };
  171. }
  172. }