├── # └── chain.js ├── .circleci └── config.yml ├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── CHANGES ├── LICENSE ├── README.md ├── appveyor.yml ├── array.js ├── for-of.js ├── get.js ├── index.js ├── is-iterable.js ├── package.json ├── string.js ├── test ├── # │ └── chain.js ├── .eslintrc.json ├── array.js ├── for-of.js ├── get.js ├── index.js ├── is-iterable.js ├── string.js └── valid-iterable.js └── valid-iterable.js /#/chain.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var setPrototypeOf = require("es5-ext/object/set-prototype-of") 4 | , d = require("d") 5 | , Iterator = require("../") 6 | , validIterable = require("../valid-iterable") 7 | 8 | , push = Array.prototype.push 9 | , defineProperties = Object.defineProperties 10 | , IteratorChain; 11 | 12 | IteratorChain = function (iterators) { 13 | defineProperties(this, { 14 | __iterators__: d("", iterators), 15 | __current__: d("w", iterators.shift()) 16 | }); 17 | }; 18 | if (setPrototypeOf) setPrototypeOf(IteratorChain, Iterator); 19 | 20 | IteratorChain.prototype = Object.create(Iterator.prototype, { 21 | constructor: d(IteratorChain), 22 | next: d(function () { 23 | var result; 24 | if (!this.__current__) return { done: true, value: undefined }; 25 | result = this.__current__.next(); 26 | while (result.done) { 27 | this.__current__ = this.__iterators__.shift(); 28 | if (!this.__current__) return { done: true, value: undefined }; 29 | result = this.__current__.next(); 30 | } 31 | return result; 32 | }) 33 | }); 34 | 35 | module.exports = function () { 36 | var iterators = [this]; 37 | push.apply(iterators, arguments); 38 | iterators.forEach(validIterable); 39 | return new IteratorChain(iterators); 40 | }; 41 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | 4 | lint: 5 | docker: 6 | - image: circleci/node:8 7 | steps: 8 | - checkout 9 | - restore_cache: 10 | keys: 11 | - dependencies-v8-{{ checksum "package.json" }} 12 | - dependencies-v8 13 | - run: npm install 14 | - save_cache: 15 | paths: 16 | - node_modules 17 | key: dependencies-v8-{{ checksum "package.json" }} 18 | - run: npm run lint 19 | 20 | node8: 21 | docker: 22 | - image: circleci/node:8 23 | steps: 24 | - checkout 25 | - restore_cache: 26 | keys: 27 | - dependencies-v8-{{ checksum "package.json" }} 28 | - dependencies-v8 29 | - run: npm install 30 | - save_cache: 31 | paths: 32 | - node_modules 33 | key: dependencies-v8-{{ checksum "package.json" }} 34 | - run: npm test 35 | 36 | node6: 37 | docker: 38 | - image: circleci/node:6 39 | steps: 40 | - checkout 41 | - restore_cache: 42 | keys: 43 | - dependencies-v6-{{ checksum "package.json" }} 44 | - dependencies-v6 45 | - run: npm install 46 | - save_cache: 47 | paths: 48 | - node_modules 49 | key: dependencies-v6-{{ checksum "package.json" }} 50 | - run: npm test 51 | 52 | node4: 53 | docker: 54 | - image: circleci/node:4 55 | steps: 56 | - checkout 57 | - restore_cache: 58 | keys: 59 | - dependencies-v4-{{ checksum "package.json" }} 60 | - dependencies-v4 61 | - run: npm install 62 | - save_cache: 63 | paths: 64 | - node_modules 65 | key: dependencies-v4-{{ checksum "package.json" }} 66 | - run: npm test 67 | 68 | workflows: 69 | version: 2 70 | test_and_lint: 71 | jobs: 72 | - lint 73 | - node8 74 | - node6 75 | - node4 76 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | indent_style = tab 11 | 12 | [{*.json,*.yml,*.md}] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: medikoo 2 | tidelift: "npm/es6-iterator" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | npm-debug.log 3 | /package-lock.json 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [2.0.3](https://github.com/medikoo/es6-iterator/compare/v2.0.2...v2.0.3) (2017-10-17) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * configurability of toStringTag ([b99f692](https://github.com/medikoo/es6-iterator/commit/b99f692)) 12 | 13 | 14 | 15 | 16 | ## [2.0.2](https://github.com/medikoo/es6-iterator/compare/v2.0.1...v2.0.2) (2017-10-17) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * constructor exposure ([dbc0c51](https://github.com/medikoo/es6-iterator/commit/dbc0c51)) 22 | * do not allow non constructor calls ([1f2f800](https://github.com/medikoo/es6-iterator/commit/1f2f800)) 23 | * toString and toStringTag symbol definitions. ([2d17786](https://github.com/medikoo/es6-iterator/commit/2d17786)), closes [#6](https://github.com/medikoo/es6-iterator/issues/6) 24 | 25 | ## Changelog for previous versions 26 | 27 | See `CHANGES` file 28 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | For recent changelog see CHANGELOG.md 2 | 3 | ----- 4 | 5 | v2.0.1 -- 2017.03.15 6 | * Update dependencies 7 | 8 | v2.0.0 -- 2015.10.02 9 | * Use es6-symbol at v3 10 | 11 | v1.0.0 -- 2015.06.23 12 | * Implement support for arguments object 13 | * Drop support for v0.8 node ('^' in package.json dependencies) 14 | 15 | v0.1.3 -- 2015.02.02 16 | * Update dependencies 17 | * Fix spelling of LICENSE 18 | 19 | v0.1.2 -- 2014.11.19 20 | * Optimise internal `_next` to not verify internal's list length at all times 21 | (#2 thanks @RReverser) 22 | * Fix documentation examples 23 | * Configure lint scripts 24 | 25 | v0.1.1 -- 2014.04.29 26 | * Fix es6-symbol dependency version 27 | 28 | v0.1.0 -- 2014.04.29 29 | * Assure strictly npm hosted dependencies 30 | * Remove sparse arrays dedicated handling (as per spec) 31 | * Add: isIterable, validIterable and chain (method) 32 | * Remove toArray, it's addressed by Array.from (polyfil can be found in es5-ext/array/from) 33 | * Add break possiblity to 'forOf' via 'doBreak' function argument 34 | * Provide dedicated iterator for array-likes (ArrayIterator) and for strings (StringIterator) 35 | * Provide @@toStringTag symbol 36 | * When available rely on @@iterator symbol 37 | * Remove 32bit integer maximum list length restriction 38 | * Improve Iterator internals 39 | * Update to use latest version of dependencies 40 | 41 | v0.0.0 -- 2013.10.12 42 | Initial (dev version) 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (C) 2013-2017 Mariusz Nowak (www.medikoo.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # es6-iterator 2 | ## ECMAScript 6 Iterator interface 3 | 4 | ### Installation 5 | 6 | $ npm install es6-iterator 7 | 8 | To port it to Browser or any other (non CJS) environment, use your favorite CJS bundler. No favorite yet? Try: [Browserify](http://browserify.org/), [Webmake](https://github.com/medikoo/modules-webmake) or [Webpack](http://webpack.github.io/) 9 | 10 | ## API 11 | 12 | ### Constructors 13 | 14 | #### Iterator(list) _(es6-iterator)_ 15 | 16 | Abstract Iterator interface. Meant for extensions and not to be used on its own. 17 | 18 | Accepts any _list_ object (technically object with numeric _length_ property). 19 | 20 | _Mind it doesn't iterate strings properly, for that use dedicated [StringIterator](#string-iterator)_ 21 | 22 | ```javascript 23 | var Iterator = require('es6-iterator') 24 | var iterator = new Iterator([1, 2, 3]); 25 | 26 | iterator.next(); // { value: 1, done: false } 27 | iterator.next(); // { value: 2, done: false } 28 | iterator.next(); // { value: 3, done: false } 29 | iterator.next(); // { value: undefined, done: true } 30 | ``` 31 | 32 | 33 | #### ArrayIterator(arrayLike[, kind]) _(es6-iterator/array)_ 34 | 35 | Dedicated for arrays and array-likes. Supports three iteration kinds: 36 | * __value__ _(default)_ - Iterates values 37 | * __key__ - Iterates indexes 38 | * __key+value__ - Iterates keys and indexes, each iteration value is in _[key, value]_ form. 39 | 40 | 41 | ```javascript 42 | var ArrayIterator = require('es6-iterator/array') 43 | var iterator = new ArrayIterator([1, 2, 3], 'key+value'); 44 | 45 | iterator.next(); // { value: [0, 1], done: false } 46 | iterator.next(); // { value: [1, 2], done: false } 47 | iterator.next(); // { value: [2, 3], done: false } 48 | iterator.next(); // { value: undefined, done: true } 49 | ``` 50 | 51 | May also be used for _arguments_ objects: 52 | 53 | ```javascript 54 | (function () { 55 | var iterator = new ArrayIterator(arguments); 56 | 57 | iterator.next(); // { value: 1, done: false } 58 | iterator.next(); // { value: 2, done: false } 59 | iterator.next(); // { value: 3, done: false } 60 | iterator.next(); // { value: undefined, done: true } 61 | }(1, 2, 3)); 62 | ``` 63 | 64 | #### StringIterator(str) _(es6-iterator/string)_ 65 | 66 | Assures proper iteration over unicode symbols. 67 | See: http://mathiasbynens.be/notes/javascript-unicode 68 | 69 | ```javascript 70 | var StringIterator = require('es6-iterator/string'); 71 | var iterator = new StringIterator('f🙈o🙉o🙊'); 72 | 73 | iterator.next(); // { value: 'f', done: false } 74 | iterator.next(); // { value: '🙈', done: false } 75 | iterator.next(); // { value: 'o', done: false } 76 | iterator.next(); // { value: '🙉', done: false } 77 | iterator.next(); // { value: 'o', done: false } 78 | iterator.next(); // { value: '🙊', done: false } 79 | iterator.next(); // { value: undefined, done: true } 80 | ``` 81 | 82 | ### Function utilities 83 | 84 | #### forOf(iterable, callback[, thisArg]) _(es6-iterator/for-of)_ 85 | 86 | Polyfill for ECMAScript 6 [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) statement. 87 | 88 | ``` 89 | var forOf = require('es6-iterator/for-of'); 90 | var result = []; 91 | 92 | forOf('🙈🙉🙊', function (monkey) { result.push(monkey); }); 93 | console.log(result); // ['🙈', '🙉', '🙊']; 94 | ``` 95 | 96 | Optionally you can break iteration at any point: 97 | 98 | ```javascript 99 | var result = []; 100 | 101 | forOf([1,2,3,4]', function (val, doBreak) { 102 | result.push(monkey); 103 | if (val >= 3) doBreak(); 104 | }); 105 | console.log(result); // [1, 2, 3]; 106 | ``` 107 | 108 | #### get(obj) _(es6-iterator/get)_ 109 | 110 | Return iterator for any iterable object. 111 | 112 | ```javascript 113 | var getIterator = require('es6-iterator/get'); 114 | var iterator = get([1,2,3]); 115 | 116 | iterator.next(); // { value: 1, done: false } 117 | iterator.next(); // { value: 2, done: false } 118 | iterator.next(); // { value: 3, done: false } 119 | iterator.next(); // { value: undefined, done: true } 120 | ``` 121 | 122 | #### isIterable(obj) _(es6-iterator/is-iterable)_ 123 | 124 | Whether _obj_ is iterable 125 | 126 | ```javascript 127 | var isIterable = require('es6-iterator/is-iterable'); 128 | 129 | isIterable(null); // false 130 | isIterable(true); // false 131 | isIterable('str'); // true 132 | isIterable(['a', 'r', 'r']); // true 133 | isIterable(new ArrayIterator([])); // true 134 | ``` 135 | 136 | #### validIterable(obj) _(es6-iterator/valid-iterable)_ 137 | 138 | If _obj_ is an iterable it is returned. Otherwise _TypeError_ is thrown. 139 | 140 | ### Method extensions 141 | 142 | #### iterator.chain(iterator1[, …iteratorn]) _(es6-iterator/#/chain)_ 143 | 144 | Chain multiple iterators into one. 145 | 146 | ### Tests [![Build Status](https://travis-ci.org/medikoo/es6-iterator.png)](https://travis-ci.org/medikoo/es6-iterator) 147 | 148 | $ npm test 149 | 150 | ## Security contact information 151 | 152 | To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. 153 | 154 | --- 155 | 156 |
157 | 158 | Get professional support for d with a Tidelift subscription 159 | 160 |
161 | 162 | Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. 163 |
164 |
165 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against the latest version of this Node.js version 2 | environment: 3 | matrix: 4 | # node.js 5 | - nodejs_version: "0.12" 6 | - nodejs_version: "4" 7 | - nodejs_version: "6" 8 | - nodejs_version: "8" 9 | 10 | # Install scripts. (runs after repo cloning) 11 | install: 12 | # Get the latest stable version of Node.js or io.js 13 | - ps: Install-Product node $env:nodejs_version 14 | # install modules 15 | - npm install 16 | 17 | # Post-install test scripts. 18 | test_script: 19 | # Output useful info for debugging. 20 | - node --version 21 | - npm --version 22 | # run tests 23 | - npm test 24 | 25 | # Don't actually build. 26 | build: off 27 | -------------------------------------------------------------------------------- /array.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var setPrototypeOf = require("es5-ext/object/set-prototype-of") 4 | , contains = require("es5-ext/string/#/contains") 5 | , d = require("d") 6 | , Symbol = require("es6-symbol") 7 | , Iterator = require("./"); 8 | 9 | var defineProperty = Object.defineProperty, ArrayIterator; 10 | 11 | ArrayIterator = module.exports = function (arr, kind) { 12 | if (!(this instanceof ArrayIterator)) throw new TypeError("Constructor requires 'new'"); 13 | Iterator.call(this, arr); 14 | if (!kind) kind = "value"; 15 | else if (contains.call(kind, "key+value")) kind = "key+value"; 16 | else if (contains.call(kind, "key")) kind = "key"; 17 | else kind = "value"; 18 | defineProperty(this, "__kind__", d("", kind)); 19 | }; 20 | if (setPrototypeOf) setPrototypeOf(ArrayIterator, Iterator); 21 | 22 | // Internal %ArrayIteratorPrototype% doesn't expose its constructor 23 | delete ArrayIterator.prototype.constructor; 24 | 25 | ArrayIterator.prototype = Object.create(Iterator.prototype, { 26 | _resolve: d(function (i) { 27 | if (this.__kind__ === "value") return this.__list__[i]; 28 | if (this.__kind__ === "key+value") return [i, this.__list__[i]]; 29 | return i; 30 | }) 31 | }); 32 | defineProperty(ArrayIterator.prototype, Symbol.toStringTag, d("c", "Array Iterator")); 33 | -------------------------------------------------------------------------------- /for-of.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var isArguments = require("es5-ext/function/is-arguments") 4 | , callable = require("es5-ext/object/valid-callable") 5 | , isString = require("es5-ext/string/is-string") 6 | , get = require("./get"); 7 | 8 | var isArray = Array.isArray, call = Function.prototype.call, some = Array.prototype.some; 9 | 10 | module.exports = function (iterable, cb /*, thisArg*/) { 11 | var mode, thisArg = arguments[2], result, doBreak, broken, i, length, char, code; 12 | if (isArray(iterable) || isArguments(iterable)) mode = "array"; 13 | else if (isString(iterable)) mode = "string"; 14 | else iterable = get(iterable); 15 | 16 | callable(cb); 17 | doBreak = function () { 18 | broken = true; 19 | }; 20 | if (mode === "array") { 21 | some.call(iterable, function (value) { 22 | call.call(cb, thisArg, value, doBreak); 23 | return broken; 24 | }); 25 | return; 26 | } 27 | if (mode === "string") { 28 | length = iterable.length; 29 | for (i = 0; i < length; ++i) { 30 | char = iterable[i]; 31 | if (i + 1 < length) { 32 | code = char.charCodeAt(0); 33 | if (code >= 0xd800 && code <= 0xdbff) char += iterable[++i]; 34 | } 35 | call.call(cb, thisArg, char, doBreak); 36 | if (broken) break; 37 | } 38 | return; 39 | } 40 | result = iterable.next(); 41 | 42 | while (!result.done) { 43 | call.call(cb, thisArg, result.value, doBreak); 44 | if (broken) return; 45 | result = iterable.next(); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /get.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var isArguments = require("es5-ext/function/is-arguments") 4 | , isString = require("es5-ext/string/is-string") 5 | , ArrayIterator = require("./array") 6 | , StringIterator = require("./string") 7 | , iterable = require("./valid-iterable") 8 | , iteratorSymbol = require("es6-symbol").iterator; 9 | 10 | module.exports = function (obj) { 11 | if (typeof iterable(obj)[iteratorSymbol] === "function") return obj[iteratorSymbol](); 12 | if (isArguments(obj)) return new ArrayIterator(obj); 13 | if (isString(obj)) return new StringIterator(obj); 14 | return new ArrayIterator(obj); 15 | }; 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var clear = require("es5-ext/array/#/clear") 4 | , assign = require("es5-ext/object/assign") 5 | , callable = require("es5-ext/object/valid-callable") 6 | , value = require("es5-ext/object/valid-value") 7 | , d = require("d") 8 | , autoBind = require("d/auto-bind") 9 | , Symbol = require("es6-symbol"); 10 | 11 | var defineProperty = Object.defineProperty, defineProperties = Object.defineProperties, Iterator; 12 | 13 | module.exports = Iterator = function (list, context) { 14 | if (!(this instanceof Iterator)) throw new TypeError("Constructor requires 'new'"); 15 | defineProperties(this, { 16 | __list__: d("w", value(list)), 17 | __context__: d("w", context), 18 | __nextIndex__: d("w", 0) 19 | }); 20 | if (!context) return; 21 | callable(context.on); 22 | context.on("_add", this._onAdd); 23 | context.on("_delete", this._onDelete); 24 | context.on("_clear", this._onClear); 25 | }; 26 | 27 | // Internal %IteratorPrototype% doesn't expose its constructor 28 | delete Iterator.prototype.constructor; 29 | 30 | defineProperties( 31 | Iterator.prototype, 32 | assign( 33 | { 34 | _next: d(function () { 35 | var i; 36 | if (!this.__list__) return undefined; 37 | if (this.__redo__) { 38 | i = this.__redo__.shift(); 39 | if (i !== undefined) return i; 40 | } 41 | if (this.__nextIndex__ < this.__list__.length) return this.__nextIndex__++; 42 | this._unBind(); 43 | return undefined; 44 | }), 45 | next: d(function () { 46 | return this._createResult(this._next()); 47 | }), 48 | _createResult: d(function (i) { 49 | if (i === undefined) return { done: true, value: undefined }; 50 | return { done: false, value: this._resolve(i) }; 51 | }), 52 | _resolve: d(function (i) { 53 | return this.__list__[i]; 54 | }), 55 | _unBind: d(function () { 56 | this.__list__ = null; 57 | delete this.__redo__; 58 | if (!this.__context__) return; 59 | this.__context__.off("_add", this._onAdd); 60 | this.__context__.off("_delete", this._onDelete); 61 | this.__context__.off("_clear", this._onClear); 62 | this.__context__ = null; 63 | }), 64 | toString: d(function () { 65 | return "[object " + (this[Symbol.toStringTag] || "Object") + "]"; 66 | }) 67 | }, 68 | autoBind({ 69 | _onAdd: d(function (index) { 70 | if (index >= this.__nextIndex__) return; 71 | ++this.__nextIndex__; 72 | if (!this.__redo__) { 73 | defineProperty(this, "__redo__", d("c", [index])); 74 | return; 75 | } 76 | this.__redo__.forEach(function (redo, i) { 77 | if (redo >= index) this.__redo__[i] = ++redo; 78 | }, this); 79 | this.__redo__.push(index); 80 | }), 81 | _onDelete: d(function (index) { 82 | var i; 83 | if (index >= this.__nextIndex__) return; 84 | --this.__nextIndex__; 85 | if (!this.__redo__) return; 86 | i = this.__redo__.indexOf(index); 87 | if (i !== -1) this.__redo__.splice(i, 1); 88 | this.__redo__.forEach(function (redo, j) { 89 | if (redo > index) this.__redo__[j] = --redo; 90 | }, this); 91 | }), 92 | _onClear: d(function () { 93 | if (this.__redo__) clear.call(this.__redo__); 94 | this.__nextIndex__ = 0; 95 | }) 96 | }) 97 | ) 98 | ); 99 | 100 | defineProperty( 101 | Iterator.prototype, 102 | Symbol.iterator, 103 | d(function () { 104 | return this; 105 | }) 106 | ); 107 | -------------------------------------------------------------------------------- /is-iterable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var isArguments = require("es5-ext/function/is-arguments") 4 | , isValue = require("es5-ext/object/is-value") 5 | , isString = require("es5-ext/string/is-string"); 6 | 7 | var iteratorSymbol = require("es6-symbol").iterator 8 | , isArray = Array.isArray; 9 | 10 | module.exports = function (value) { 11 | if (!isValue(value)) return false; 12 | if (isArray(value)) return true; 13 | if (isString(value)) return true; 14 | if (isArguments(value)) return true; 15 | return typeof value[iteratorSymbol] === "function"; 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-iterator", 3 | "version": "2.0.3", 4 | "description": "Iterator abstraction based on ES6 specification", 5 | "author": "Mariusz Nowak (http://www.medikoo.com/)", 6 | "keywords": [ 7 | "iterator", 8 | "array", 9 | "list", 10 | "set", 11 | "map", 12 | "generator" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/medikoo/es6-iterator.git" 17 | }, 18 | "dependencies": { 19 | "d": "^1.0.1", 20 | "es5-ext": "^0.10.50", 21 | "es6-symbol": "^3.1.1" 22 | }, 23 | "devDependencies": { 24 | "eslint": "^5.16.0", 25 | "eslint-config-medikoo-es5": "^1.7.3", 26 | "event-emitter": "^0.3.5", 27 | "tad": "^0.2.8" 28 | }, 29 | "eslintConfig": { 30 | "extends": "medikoo-es5", 31 | "root": true, 32 | "rules": { 33 | "no-extend-native": "off" 34 | } 35 | }, 36 | "scripts": { 37 | "lint": "eslint --ignore-path=.gitignore .", 38 | "test": "node ./node_modules/tad/bin/tad" 39 | }, 40 | "license": "MIT" 41 | } 42 | -------------------------------------------------------------------------------- /string.js: -------------------------------------------------------------------------------- 1 | // Thanks @mathiasbynens 2 | // http://mathiasbynens.be/notes/javascript-unicode#iterating-over-symbols 3 | 4 | "use strict"; 5 | 6 | var setPrototypeOf = require("es5-ext/object/set-prototype-of") 7 | , d = require("d") 8 | , Symbol = require("es6-symbol") 9 | , Iterator = require("./"); 10 | 11 | var defineProperty = Object.defineProperty, StringIterator; 12 | 13 | StringIterator = module.exports = function (str) { 14 | if (!(this instanceof StringIterator)) throw new TypeError("Constructor requires 'new'"); 15 | str = String(str); 16 | Iterator.call(this, str); 17 | defineProperty(this, "__length__", d("", str.length)); 18 | }; 19 | if (setPrototypeOf) setPrototypeOf(StringIterator, Iterator); 20 | 21 | // Internal %ArrayIteratorPrototype% doesn't expose its constructor 22 | delete StringIterator.prototype.constructor; 23 | 24 | StringIterator.prototype = Object.create(Iterator.prototype, { 25 | _next: d(function () { 26 | if (!this.__list__) return undefined; 27 | if (this.__nextIndex__ < this.__length__) return this.__nextIndex__++; 28 | this._unBind(); 29 | return undefined; 30 | }), 31 | _resolve: d(function (i) { 32 | var char = this.__list__[i], code; 33 | if (this.__nextIndex__ === this.__length__) return char; 34 | code = char.charCodeAt(0); 35 | if (code >= 0xd800 && code <= 0xdbff) return char + this.__list__[this.__nextIndex__++]; 36 | return char; 37 | }) 38 | }); 39 | defineProperty(StringIterator.prototype, Symbol.toStringTag, d("c", "String Iterator")); 40 | -------------------------------------------------------------------------------- /test/#/chain.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Iterator = require("../../"); 4 | 5 | module.exports = function (t, a) { 6 | var i1 = new Iterator(["raz", "dwa", "trzy"]) 7 | , i2 = new Iterator(["cztery", "pięć", "sześć"]) 8 | , i3 = new Iterator(["siedem", "osiem", "dziewięć"]) 9 | 10 | , iterator = t.call(i1, i2, i3); 11 | 12 | a.deep(iterator.next(), { done: false, value: "raz" }, "#1"); 13 | a.deep(iterator.next(), { done: false, value: "dwa" }, "#2"); 14 | a.deep(iterator.next(), { done: false, value: "trzy" }, "#3"); 15 | a.deep(iterator.next(), { done: false, value: "cztery" }, "#4"); 16 | a.deep(iterator.next(), { done: false, value: "pięć" }, "#5"); 17 | a.deep(iterator.next(), { done: false, value: "sześć" }, "#6"); 18 | a.deep(iterator.next(), { done: false, value: "siedem" }, "#7"); 19 | a.deep(iterator.next(), { done: false, value: "osiem" }, "#8"); 20 | a.deep(iterator.next(), { done: false, value: "dziewięć" }, "#9"); 21 | a.deep(iterator.next(), { done: true, value: undefined }, "Done #1"); 22 | a.deep(iterator.next(), { done: true, value: undefined }, "Done #2"); 23 | }; 24 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "id-length": "off" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/array.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var iteratorSymbol = require("es6-symbol").iterator; 4 | 5 | module.exports = function (T) { 6 | return { 7 | "Values": function (a) { 8 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], it; 9 | 10 | it = new T(x); 11 | a(it[iteratorSymbol](), it, "@@iterator"); 12 | a.deep(it.next(), { done: false, value: "raz" }, "#1"); 13 | a.deep(it.next(), { done: false, value: "dwa" }, "#2"); 14 | x.splice(1, 0, "elo"); 15 | a.deep(it.next(), { done: false, value: "dwa" }, "Insert"); 16 | a.deep(it.next(), { done: false, value: "trzy" }, "#3"); 17 | a.deep(it.next(), { done: false, value: "cztery" }, "#4"); 18 | x.pop(); 19 | a.deep(it.next(), { done: false, value: "pięć" }, "#5"); 20 | a.deep(it.next(), { done: true, value: undefined }, "End"); 21 | }, 22 | "Keys & Values": function (a) { 23 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], it; 24 | 25 | it = new T(x, "key+value"); 26 | a(it[iteratorSymbol](), it, "@@iterator"); 27 | a.deep(it.next(), { done: false, value: [0, "raz"] }, "#1"); 28 | a.deep(it.next(), { done: false, value: [1, "dwa"] }, "#2"); 29 | x.splice(1, 0, "elo"); 30 | a.deep(it.next(), { done: false, value: [2, "dwa"] }, "Insert"); 31 | a.deep(it.next(), { done: false, value: [3, "trzy"] }, "#3"); 32 | a.deep(it.next(), { done: false, value: [4, "cztery"] }, "#4"); 33 | x.pop(); 34 | a.deep(it.next(), { done: false, value: [5, "pięć"] }, "#5"); 35 | a.deep(it.next(), { done: true, value: undefined }, "End"); 36 | }, 37 | "Keys": function (a) { 38 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], it; 39 | 40 | it = new T(x, "key"); 41 | a(it[iteratorSymbol](), it, "@@iterator"); 42 | a.deep(it.next(), { done: false, value: 0 }, "#1"); 43 | a.deep(it.next(), { done: false, value: 1 }, "#2"); 44 | x.splice(1, 0, "elo"); 45 | a.deep(it.next(), { done: false, value: 2 }, "Insert"); 46 | a.deep(it.next(), { done: false, value: 3 }, "#3"); 47 | a.deep(it.next(), { done: false, value: 4 }, "#4"); 48 | x.pop(); 49 | a.deep(it.next(), { done: false, value: 5 }, "#5"); 50 | a.deep(it.next(), { done: true, value: undefined }, "End"); 51 | }, 52 | "Sparse": function (a) { 53 | var x = new Array(6), it; 54 | 55 | x[2] = "raz"; 56 | x[4] = "dwa"; 57 | it = new T(x); 58 | a.deep(it.next(), { done: false, value: undefined }, "#1"); 59 | a.deep(it.next(), { done: false, value: undefined }, "#2"); 60 | a.deep(it.next(), { done: false, value: "raz" }, "#3"); 61 | a.deep(it.next(), { done: false, value: undefined }, "#4"); 62 | a.deep(it.next(), { done: false, value: "dwa" }, "#5"); 63 | a.deep(it.next(), { done: false, value: undefined }, "#6"); 64 | a.deep(it.next(), { done: true, value: undefined }, "End"); 65 | } 66 | }; 67 | }; 68 | -------------------------------------------------------------------------------- /test/for-of.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var ArrayIterator = require("../array") 4 | 5 | , slice = Array.prototype.slice; 6 | 7 | module.exports = function (t, a) { 8 | var i = 0, x = ["raz", "dwa", "trzy"], y = {}, called = 0; 9 | t(x, function () { 10 | a.deep(slice.call(arguments, 0, 1), [x[i]], "Array " + i + "#"); 11 | a(this, y, "Array: context: " + i++ + "#"); 12 | }, y); 13 | i = 0; 14 | t((function () { 15 | return arguments; 16 | }("raz", "dwa", "trzy")), function () { 17 | a.deep(slice.call(arguments, 0, 1), [x[i]], "Arguments" + i + "#"); 18 | a(this, y, "Arguments: context: " + i++ + "#"); 19 | }, y); 20 | i = 0; 21 | t(x = "foo", function () { 22 | a.deep(slice.call(arguments, 0, 1), [x[i]], "String " + i + "#"); 23 | a(this, y, "Regular String: context: " + i++ + "#"); 24 | }, y); 25 | i = 0; 26 | x = ["r", "💩", "z"]; 27 | t("r💩z", function () { 28 | a.deep(slice.call(arguments, 0, 1), [x[i]], "String " + i + "#"); 29 | a(this, y, "Unicode String: context: " + i++ + "#"); 30 | }, y); 31 | i = 0; 32 | t(new ArrayIterator(x), function () { 33 | a.deep(slice.call(arguments, 0, 1), [x[i]], "Iterator " + i + "#"); 34 | a(this, y, "Iterator: context: " + i++ + "#"); 35 | }, y); 36 | 37 | t(x = ["raz", "dwa", "trzy"], function (value, doBreak) { 38 | ++called; 39 | return doBreak(); 40 | }); 41 | a(called, 1, "Break"); 42 | }; 43 | -------------------------------------------------------------------------------- /test/get.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var iteratorSymbol = require("es6-symbol").iterator 4 | , Iterator = require("../"); 5 | 6 | module.exports = function (t, a) { 7 | var iterator; 8 | a.throws(function () { 9 | t(); 10 | }, TypeError, "Null"); 11 | a.throws(function () { 12 | t({}); 13 | }, TypeError, "Plain object"); 14 | a.throws(function () { 15 | t({ length: 0 }); 16 | }, TypeError, "Array-like"); 17 | iterator = {}; 18 | iterator[iteratorSymbol] = function () { 19 | return new Iterator([]); 20 | }; 21 | a(t(iterator) instanceof Iterator, true, "Iterator"); 22 | a(String(t([])), "[object Array Iterator]", " Array"); 23 | a(String(t(function () { 24 | return arguments; 25 | }())), "[object Array Iterator]", " Arguments"); 26 | a(String(t("foo")), "[object String Iterator]", "String"); 27 | }; 28 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var ee = require("event-emitter") 4 | , iteratorSymbol = require("es6-symbol").iterator; 5 | 6 | module.exports = function (T) { 7 | return { 8 | "": function (a) { 9 | var x = ["raz", "dwa", "trzy", "cztery", "pięć"], it, y, z; 10 | 11 | it = new T(x); 12 | a(it[iteratorSymbol](), it, "@@iterator"); 13 | y = it.next(); 14 | a.deep(y, { done: false, value: "raz" }, "#1"); 15 | z = it.next(); 16 | a.not(y, z, "Recreate result"); 17 | a.deep(z, { done: false, value: "dwa" }, "#2"); 18 | a.deep(it.next(), { done: false, value: "trzy" }, "#3"); 19 | a.deep(it.next(), { done: false, value: "cztery" }, "#4"); 20 | a.deep(it.next(), { done: false, value: "pięć" }, "#5"); 21 | a.deep(y = it.next(), { done: true, value: undefined }, "End"); 22 | a.not(y, it.next(), "Recreate result on dead"); 23 | }, 24 | "Emited": function (a) { 25 | var x = ["raz", "dwa", "trzy", "cztery", "pięć"], y, it; 26 | 27 | y = ee(); 28 | it = new T(x, y); 29 | a.deep(it.next(), { done: false, value: "raz" }, "#1"); 30 | a.deep(it.next(), { done: false, value: "dwa" }, "#2"); 31 | y.emit("_add", x.push("sześć") - 1); 32 | a.deep(it.next(), { done: false, value: "trzy" }, "#3"); 33 | x.splice(1, 0, "półtora"); 34 | y.emit("_add", 1); 35 | a.deep(it.next(), { done: false, value: "półtora" }, "Insert"); 36 | x.splice(5, 1); 37 | y.emit("_delete", 5); 38 | a.deep(it.next(), { done: false, value: "cztery" }, "#4"); 39 | a.deep(it.next(), { done: false, value: "sześć" }, "#5"); 40 | a.deep(it.next(), { done: true, value: undefined }, "End"); 41 | }, 42 | "Emited #2": function (a) { 43 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], y, it; 44 | 45 | y = ee(); 46 | it = new T(x, y); 47 | a.deep(it.next(), { done: false, value: "raz" }, "#1"); 48 | a.deep(it.next(), { done: false, value: "dwa" }, "#2"); 49 | x.splice(1, 0, "półtora"); 50 | y.emit("_add", 1); 51 | x.splice(1, 0, "1.25"); 52 | y.emit("_add", 1); 53 | x.splice(0, 1); 54 | y.emit("_delete", 0); 55 | a.deep(it.next(), { done: false, value: "półtora" }, "Insert"); 56 | a.deep(it.next(), { done: false, value: "1.25" }, "Insert #2"); 57 | a.deep(it.next(), { done: false, value: "trzy" }, "#3"); 58 | a.deep(it.next(), { done: false, value: "cztery" }, "#4"); 59 | x.splice(5, 1); 60 | y.emit("_delete", 5); 61 | a.deep(it.next(), { done: false, value: "sześć" }, "#5"); 62 | a.deep(it.next(), { done: true, value: undefined }, "End"); 63 | }, 64 | "Emited: Clear #1": function (a) { 65 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], y, it; 66 | 67 | y = ee(); 68 | it = new T(x, y); 69 | a.deep(it.next(), { done: false, value: "raz" }, "#1"); 70 | a.deep(it.next(), { done: false, value: "dwa" }, "#2"); 71 | x.length = 0; 72 | y.emit("_clear"); 73 | a.deep(it.next(), { done: true, value: undefined }, "End"); 74 | }, 75 | "Emited: Clear #2": function (a) { 76 | var x = ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"], y, it; 77 | 78 | y = ee(); 79 | it = new T(x, y); 80 | a.deep(it.next(), { done: false, value: "raz" }, "#1"); 81 | a.deep(it.next(), { done: false, value: "dwa" }, "#2"); 82 | x.length = 0; 83 | y.emit("_clear"); 84 | x.push("foo"); 85 | x.push("bar"); 86 | a.deep(it.next(), { done: false, value: "foo" }, "#3"); 87 | a.deep(it.next(), { done: false, value: "bar" }, "#4"); 88 | x.splice(1, 0, "półtora"); 89 | y.emit("_add", 1); 90 | x.splice(1, 0, "1.25"); 91 | y.emit("_add", 1); 92 | x.splice(0, 1); 93 | y.emit("_delete", 0); 94 | a.deep(it.next(), { done: false, value: "półtora" }, "Insert"); 95 | a.deep(it.next(), { done: false, value: "1.25" }, "Insert #2"); 96 | a.deep(it.next(), { done: true, value: undefined }, "End"); 97 | } 98 | }; 99 | }; 100 | -------------------------------------------------------------------------------- /test/is-iterable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var iteratorSymbol = require("es6-symbol").iterator 4 | , Iterator = require("../"); 5 | 6 | module.exports = function (t, a) { 7 | var iterator; 8 | a(t(), false, "Undefined"); 9 | a(t(123), false, "Number"); 10 | a(t({}), false, "Plain object"); 11 | a(t({ length: 0 }), false, "Array-like"); 12 | iterator = {}; 13 | iterator[iteratorSymbol] = function () { 14 | return new Iterator([]); 15 | }; 16 | a(t(iterator), true, "Iterator"); 17 | a(t([]), true, "Array"); 18 | a(t("foo"), true, "String"); 19 | a(t(""), true, "Empty string"); 20 | a(t(function () { 21 | return arguments; 22 | }()), true, "Arguments"); 23 | }; 24 | -------------------------------------------------------------------------------- /test/string.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var iteratorSymbol = require("es6-symbol").iterator; 4 | 5 | module.exports = function (T, a) { 6 | var it = new T("foobar"); 7 | 8 | a(it[iteratorSymbol](), it, "@@iterator"); 9 | a.deep(it.next(), { done: false, value: "f" }, "#1"); 10 | a.deep(it.next(), { done: false, value: "o" }, "#2"); 11 | a.deep(it.next(), { done: false, value: "o" }, "#3"); 12 | a.deep(it.next(), { done: false, value: "b" }, "#4"); 13 | a.deep(it.next(), { done: false, value: "a" }, "#5"); 14 | a.deep(it.next(), { done: false, value: "r" }, "#6"); 15 | a.deep(it.next(), { done: true, value: undefined }, "End"); 16 | 17 | a.h1("Outside of BMP"); 18 | it = new T("r💩z"); 19 | a.deep(it.next(), { done: false, value: "r" }, "#1"); 20 | a.deep(it.next(), { done: false, value: "💩" }, "#2"); 21 | a.deep(it.next(), { done: false, value: "z" }, "#3"); 22 | a.deep(it.next(), { done: true, value: undefined }, "End"); 23 | }; 24 | -------------------------------------------------------------------------------- /test/valid-iterable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var iteratorSymbol = require("es6-symbol").iterator 4 | , Iterator = require("../"); 5 | 6 | module.exports = function (t, a) { 7 | var obj; 8 | a.throws(function () { 9 | t(); 10 | }, TypeError, "Undefined"); 11 | a.throws(function () { 12 | t({}); 13 | }, TypeError, "Plain object"); 14 | a.throws(function () { 15 | t({ length: 0 }); 16 | }, TypeError, "Array-like"); 17 | obj = {}; 18 | obj[iteratorSymbol] = function () { 19 | return new Iterator([]); 20 | }; 21 | a(t(obj), obj, "Iterator"); 22 | obj = []; 23 | a(t(obj), obj, "Array"); 24 | obj = (function () { 25 | return arguments; 26 | }()); 27 | a(t(obj), obj, "Arguments"); 28 | }; 29 | -------------------------------------------------------------------------------- /valid-iterable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var isIterable = require("./is-iterable"); 4 | 5 | module.exports = function (value) { 6 | if (!isIterable(value)) throw new TypeError(value + " is not iterable"); 7 | return value; 8 | }; 9 | --------------------------------------------------------------------------------