enumerate.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. 'use strict';
  2. var _assign = require('object-assign');
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. /**
  5. * Copyright (c) 2013-present, Facebook, Inc.
  6. *
  7. * This source code is licensed under the MIT license found in the
  8. * LICENSE file in the root directory of this source tree.
  9. *
  10. *
  11. */
  12. var KIND_KEYS = 'keys';
  13. var KIND_VALUES = 'values';
  14. var KIND_ENTRIES = 'entries';
  15. /**
  16. * Specific Array iterators.
  17. */
  18. var ArrayIterators = function () {
  19. var hasNative = hasNativeIterator(Array);
  20. var ArrayIterator = void 0;
  21. if (!hasNative) {
  22. ArrayIterator = function () {
  23. // 22.1.5.1 CreateArrayIterator Abstract Operation
  24. function ArrayIterator(array, kind) {
  25. _classCallCheck(this, ArrayIterator);
  26. this._iteratedObject = array;
  27. this._kind = kind;
  28. this._nextIndex = 0;
  29. }
  30. // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
  31. ArrayIterator.prototype.next = function next() {
  32. if (this._iteratedObject == null) {
  33. return { value: undefined, done: true };
  34. }
  35. var array = this._iteratedObject;
  36. var len = this._iteratedObject.length;
  37. var index = this._nextIndex;
  38. var kind = this._kind;
  39. if (index >= len) {
  40. this._iteratedObject = undefined;
  41. return { value: undefined, done: true };
  42. }
  43. this._nextIndex = index + 1;
  44. if (kind === KIND_KEYS) {
  45. return { value: index, done: false };
  46. } else if (kind === KIND_VALUES) {
  47. return { value: array[index], done: false };
  48. } else if (kind === KIND_ENTRIES) {
  49. return { value: [index, array[index]], done: false };
  50. }
  51. };
  52. // 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]()
  53. ArrayIterator.prototype[Symbol.iterator] = function () {
  54. return this;
  55. };
  56. return ArrayIterator;
  57. }();
  58. }
  59. return {
  60. keys: hasNative ? function (array) {
  61. return array.keys();
  62. } : function (array) {
  63. return new ArrayIterator(array, KIND_KEYS);
  64. },
  65. values: hasNative ? function (array) {
  66. return array.values();
  67. } : function (array) {
  68. return new ArrayIterator(array, KIND_VALUES);
  69. },
  70. entries: hasNative ? function (array) {
  71. return array.entries();
  72. } : function (array) {
  73. return new ArrayIterator(array, KIND_ENTRIES);
  74. }
  75. };
  76. }();
  77. // -----------------------------------------------------------------
  78. /**
  79. * Specific String iterators.
  80. */
  81. var StringIterators = function () {
  82. var hasNative = hasNativeIterator(String);
  83. var StringIterator = void 0;
  84. if (!hasNative) {
  85. StringIterator = function () {
  86. // 21.1.5.1 CreateStringIterator Abstract Operation
  87. function StringIterator(string) {
  88. _classCallCheck(this, StringIterator);
  89. this._iteratedString = string;
  90. this._nextIndex = 0;
  91. }
  92. // 21.1.5.2.1 %StringIteratorPrototype%.next()
  93. StringIterator.prototype.next = function next() {
  94. if (this._iteratedString == null) {
  95. return { value: undefined, done: true };
  96. }
  97. var index = this._nextIndex;
  98. var s = this._iteratedString;
  99. var len = s.length;
  100. if (index >= len) {
  101. this._iteratedString = undefined;
  102. return { value: undefined, done: true };
  103. }
  104. var ret = void 0;
  105. var first = s.charCodeAt(index);
  106. if (first < 0xD800 || first > 0xDBFF || index + 1 === len) {
  107. ret = s[index];
  108. } else {
  109. var second = s.charCodeAt(index + 1);
  110. if (second < 0xDC00 || second > 0xDFFF) {
  111. ret = s[index];
  112. } else {
  113. ret = s[index] + s[index + 1];
  114. }
  115. }
  116. this._nextIndex = index + ret.length;
  117. return { value: ret, done: false };
  118. };
  119. // 21.1.5.2.2 %StringIteratorPrototype%[@@iterator]()
  120. StringIterator.prototype[Symbol.iterator] = function () {
  121. return this;
  122. };
  123. return StringIterator;
  124. }();
  125. }
  126. return {
  127. keys: function keys() {
  128. throw TypeError('Strings default iterator doesn\'t implement keys.');
  129. },
  130. values: hasNative ? function (string) {
  131. return string[Symbol.iterator]();
  132. } : function (string) {
  133. return new StringIterator(string);
  134. },
  135. entries: function entries() {
  136. throw TypeError('Strings default iterator doesn\'t implement entries.');
  137. }
  138. };
  139. }();
  140. function hasNativeIterator(classObject) {
  141. return typeof classObject.prototype[Symbol.iterator] === 'function' && typeof classObject.prototype.values === 'function' && typeof classObject.prototype.keys === 'function' && typeof classObject.prototype.entries === 'function';
  142. }
  143. // -----------------------------------------------------------------
  144. /**
  145. * Generic object iterator.
  146. */
  147. var ObjectIterator = function () {
  148. function ObjectIterator(object, kind) {
  149. _classCallCheck(this, ObjectIterator);
  150. this._iteratedObject = object;
  151. this._kind = kind;
  152. this._keys = Object.keys(object);
  153. this._nextIndex = 0;
  154. }
  155. ObjectIterator.prototype.next = function next() {
  156. var len = this._keys.length;
  157. var index = this._nextIndex;
  158. var kind = this._kind;
  159. var key = this._keys[index];
  160. if (index >= len) {
  161. this._iteratedObject = undefined;
  162. return { value: undefined, done: true };
  163. }
  164. this._nextIndex = index + 1;
  165. if (kind === KIND_KEYS) {
  166. return { value: key, done: false };
  167. } else if (kind === KIND_VALUES) {
  168. return { value: this._iteratedObject[key], done: false };
  169. } else if (kind === KIND_ENTRIES) {
  170. return { value: [key, this._iteratedObject[key]], done: false };
  171. }
  172. };
  173. ObjectIterator.prototype[Symbol.iterator] = function () {
  174. return this;
  175. };
  176. return ObjectIterator;
  177. }();
  178. /**
  179. * Generic object iterator, iterates over all own enumerable
  180. * properties. Used only if if no specific iterator is available,
  181. * and object don't implement iterator protocol.
  182. */
  183. var GenericIterators = {
  184. keys: function keys(object) {
  185. return new ObjectIterator(object, KIND_KEYS);
  186. },
  187. values: function values(object) {
  188. return new ObjectIterator(object, KIND_VALUES);
  189. },
  190. entries: function entries(object) {
  191. return new ObjectIterator(object, KIND_ENTRIES);
  192. }
  193. };
  194. // -----------------------------------------------------------------
  195. /**
  196. * Main iterator function. Returns default iterator based
  197. * on the class of an instance.
  198. */
  199. function enumerate(object, kind) {
  200. // First check specific iterators.
  201. if (typeof object === 'string') {
  202. return StringIterators[kind || KIND_VALUES](object);
  203. } else if (Array.isArray(object)) {
  204. return ArrayIterators[kind || KIND_VALUES](object);
  205. // Then see if an object implements own.
  206. } else if (object[Symbol.iterator]) {
  207. return object[Symbol.iterator]();
  208. // And fallback to generic with entries.
  209. } else {
  210. return GenericIterators[kind || KIND_ENTRIES](object);
  211. }
  212. }
  213. _assign(enumerate, {
  214. /**
  215. * Export constants
  216. */
  217. KIND_KEYS: KIND_KEYS,
  218. KIND_VALUES: KIND_VALUES,
  219. KIND_ENTRIES: KIND_ENTRIES,
  220. /**
  221. * Convenient explicit iterators for special kinds.
  222. */
  223. keys: function keys(object) {
  224. return enumerate(object, KIND_KEYS);
  225. },
  226. values: function values(object) {
  227. return enumerate(object, KIND_VALUES);
  228. },
  229. entries: function entries(object) {
  230. return enumerate(object, KIND_ENTRIES);
  231. },
  232. generic: GenericIterators.entries
  233. });
  234. module.exports = enumerate;