├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── LazyIterator.js └── index.js └── test └── index.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parserOptions": { 4 | "ecmaVersion": 6 5 | }, 6 | "env": { 7 | "es6": true, 8 | "node": true 9 | }, 10 | "rules": { 11 | "no-await-in-loop": "warn", 12 | "no-extra-parens": ["warn", "all", { 13 | "nestedBinaryExpressions": false 14 | }], 15 | "no-template-curly-in-string": "error", 16 | "no-unsafe-negation": "error", 17 | "valid-jsdoc": ["error", { 18 | "requireReturn": true, 19 | "requireReturnDescription": false, 20 | "prefer": { 21 | "return": "returns", 22 | "arg": "param" 23 | }, 24 | "preferType": { 25 | "String": "string", 26 | "Number": "number", 27 | "Boolean": "boolean", 28 | "object": "Object", 29 | "function": "Function", 30 | "array": "Array", 31 | "date": "Date", 32 | "error": "Error", 33 | "null": "void" 34 | } 35 | }], 36 | 37 | "accessor-pairs": "warn", 38 | "array-callback-return": "error", 39 | "complexity": ["warn", 25], 40 | "consistent-return": "error", 41 | "curly": ["error", "multi-line", "consistent"], 42 | "dot-location": ["error", "property"], 43 | "dot-notation": "error", 44 | "eqeqeq": ["error", "smart"], 45 | "no-console": "warn", 46 | "no-empty-function": "error", 47 | "no-floating-decimal": "error", 48 | "no-implied-eval": "error", 49 | "no-invalid-this": "error", 50 | "no-lone-blocks": "error", 51 | "no-multi-spaces": "error", 52 | "no-new-func": "error", 53 | "no-new-wrappers": "error", 54 | "no-new": "error", 55 | "no-octal-escape": "error", 56 | "no-return-assign": "error", 57 | "no-return-await": "error", 58 | "no-self-compare": "error", 59 | "no-sequences": "error", 60 | "no-throw-literal": "error", 61 | "no-unmodified-loop-condition": "error", 62 | "no-unused-expressions": "error", 63 | "no-useless-call": "error", 64 | "no-useless-concat": "error", 65 | "no-useless-escape": "error", 66 | "no-useless-return": "error", 67 | "no-void": "error", 68 | "no-warning-comments": "warn", 69 | "require-await": "warn", 70 | "wrap-iife": "error", 71 | "yoda": "error", 72 | 73 | "no-label-var": "error", 74 | "no-shadow": "error", 75 | "no-undef-init": "error", 76 | 77 | "callback-return": "error", 78 | "handle-callback-err": "error", 79 | "no-mixed-requires": "error", 80 | "no-new-require": "error", 81 | "no-path-concat": "error", 82 | 83 | "array-bracket-spacing": "error", 84 | "block-spacing": "error", 85 | "brace-style": ["error", "1tbs", { "allowSingleLine": true }], 86 | "capitalized-comments": ["error", "always", { "ignoreConsecutiveComments": true }], 87 | "comma-dangle": ["error", "never"], 88 | "comma-spacing": "error", 89 | "comma-style": "error", 90 | "computed-property-spacing": "error", 91 | "consistent-this": ["error", "$this"], 92 | "eol-last": "error", 93 | "func-names": "error", 94 | "func-name-matching": "error", 95 | "func-style": ["error", "declaration", { "allowArrowFunctions": true }], 96 | "indent": ["error", 4, { "MemberExpression": 1 }], 97 | "key-spacing": "error", 98 | "keyword-spacing": "error", 99 | "max-depth": ["error", 7], 100 | "max-nested-callbacks": ["error", { "max": 4 }], 101 | "max-statements-per-line": ["error", { "max": 2 }], 102 | "new-cap": "error", 103 | "no-array-constructor": "error", 104 | "no-inline-comments": "error", 105 | "no-lonely-if": "error", 106 | "no-mixed-operators": "error", 107 | "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], 108 | "no-new-object": "error", 109 | "no-spaced-func": "error", 110 | "no-trailing-spaces": "error", 111 | "no-unneeded-ternary": "error", 112 | "no-whitespace-before-property": "error", 113 | "object-curly-spacing": ["error", "always"], 114 | "operator-assignment": "error", 115 | "operator-linebreak": ["error", "before"], 116 | "padded-blocks": ["error", "never"], 117 | "quote-props": ["error", "as-needed"], 118 | "quotes": ["error", "single"], 119 | "semi-spacing": "error", 120 | "semi": "error", 121 | "space-before-blocks": "error", 122 | "space-before-function-paren": ["error", { "anonymous": "always", "named": "never", "asyncArrow": "always" }], 123 | "space-in-parens": "error", 124 | "space-infix-ops": "error", 125 | "space-unary-ops": "error", 126 | "spaced-comment": "error", 127 | "unicode-bom": "error", 128 | 129 | "arrow-parens": ["error", "as-needed"], 130 | "arrow-spacing": "error", 131 | "no-duplicate-imports": "error", 132 | "no-useless-computed-key": "error", 133 | "no-useless-constructor": "error", 134 | "prefer-const": "error", 135 | "prefer-arrow-callback": "error", 136 | "prefer-numeric-literals": "error", 137 | "prefer-rest-params": "error", 138 | "prefer-spread": "error", 139 | "prefer-template": "error", 140 | "rest-spread-spacing": "error", 141 | "template-curly-spacing": "error", 142 | "yield-star-spacing": "error" 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | .vscode 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "8" 5 | - "10" 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 1Computer1 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lazyer 2 | 3 | Lazy iteration in JavaScript. 4 | Based heavily on the [Rust iterator trait](https://doc.rust-lang.org/std/iter/trait.Iterator.html). 5 | 6 | ### Overview 7 | 8 | Lazyer allows for lazy iteration. 9 | It can be used for working with finite sequences: 10 | 11 | ```js 12 | const lazy = require('lazyer'); 13 | lazy.from(people) 14 | .filter(person => person.age >= 65) 15 | .map(person => `${person.firstName} ${person.lastName}`) 16 | .map(name => name.toUpperCase()) 17 | .forEach(name => console.log(name)); 18 | ``` 19 | 20 | And infinite sequences: 21 | 22 | ```js 23 | const lazy = require('lazyer'); 24 | 25 | lazy.range() 26 | .scan(([a, b]) => [b, a + b], [0, 1]) 27 | .map(([a]) => a) 28 | .take(10) 29 | .collect(); 30 | → [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 31 | ``` 32 | 33 | Works with anything iterable: 34 | 35 | ```js 36 | const lazy = require('lazyer'); 37 | const string = 'Hello World!'; 38 | const set = new Set(string); 39 | 40 | lazy.range(0) 41 | .zip(set) 42 | .collectMap() 43 | → Map { 44 | 0 => 'H', 45 | 1 => 'e', 46 | 2 => 'l', 47 | 3 => 'o', 48 | 4 => ' ', 49 | 5 => 'W', 50 | 6 => 'r', 51 | 7 => 'd', 52 | 8 => '!' 53 | } 54 | ``` 55 | 56 | And does a bunch of useful things: 57 | 58 | ```js 59 | const lazy = require('lazyer'); 60 | const longest = lazy.from(listOfListOfNodes) 61 | .flat() 62 | .flatMap(node => node.children) 63 | .max(node => node.data.length); 64 | ``` 65 | 66 | ### Functions 67 | 68 | Functions that create a lazy iterator. 69 | 70 | - `from` 71 | - `of` 72 | - `range` 73 | - `repeat` 74 | - `repeatWith` 75 | - `iterate` 76 | 77 | ### Adaptors 78 | 79 | Methods that adapt the iterator. 80 | A consumer needs to be called before any of these will be executed. 81 | 82 | - `stepBy` 83 | - `skip` 84 | - `take` 85 | - `skipWhile` 86 | - `takeWhile` 87 | - `chunk` 88 | - `enumerate` 89 | - `concat` 90 | - `cycle` 91 | - `map` 92 | - `filter` 93 | - `scan` 94 | - `zip` 95 | - `flat` 96 | - `flatMap` 97 | - `join` 98 | - `joinWith` 99 | - `each` 100 | 101 | ### Consumers 102 | 103 | Methods that consume the iterator. 104 | These methods start the iteration. 105 | 106 | - `next` 107 | - `peek` 108 | - `at` 109 | - `count` 110 | - `last` 111 | - `forEach` 112 | - `reduce` 113 | - `sum` 114 | - `product` 115 | - `find` 116 | - `findIndex` 117 | - `includes` 118 | - `every` 119 | - `some` 120 | - `max` 121 | - `min` 122 | - `maxBy` 123 | - `minBy` 124 | - `collect` 125 | - `partition` 126 | - `unzip` 127 | - `group` 128 | - `categorize` 129 | - `clone` 130 | - `cloneMany` 131 | 132 | ### Docs 133 | 134 | See the [documented source code](./src/LazyIterator.js). 135 | And for examples, see the [test file](./test/index.js). 136 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazyer", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "acorn": { 8 | "version": "5.7.1", 9 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", 10 | "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", 11 | "dev": true 12 | }, 13 | "acorn-jsx": { 14 | "version": "4.1.1", 15 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", 16 | "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", 17 | "dev": true, 18 | "requires": { 19 | "acorn": "^5.0.3" 20 | } 21 | }, 22 | "ajv": { 23 | "version": "6.5.2", 24 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", 25 | "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", 26 | "dev": true, 27 | "requires": { 28 | "fast-deep-equal": "^2.0.1", 29 | "fast-json-stable-stringify": "^2.0.0", 30 | "json-schema-traverse": "^0.4.1", 31 | "uri-js": "^4.2.1" 32 | } 33 | }, 34 | "ajv-keywords": { 35 | "version": "3.2.0", 36 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", 37 | "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", 38 | "dev": true 39 | }, 40 | "ansi-escapes": { 41 | "version": "3.1.0", 42 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", 43 | "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", 44 | "dev": true 45 | }, 46 | "ansi-regex": { 47 | "version": "2.1.1", 48 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 49 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 50 | "dev": true 51 | }, 52 | "ansi-styles": { 53 | "version": "2.2.1", 54 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 55 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 56 | "dev": true 57 | }, 58 | "argparse": { 59 | "version": "1.0.10", 60 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 61 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 62 | "dev": true, 63 | "requires": { 64 | "sprintf-js": "~1.0.2" 65 | } 66 | }, 67 | "array-union": { 68 | "version": "1.0.2", 69 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 70 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 71 | "dev": true, 72 | "requires": { 73 | "array-uniq": "^1.0.1" 74 | } 75 | }, 76 | "array-uniq": { 77 | "version": "1.0.3", 78 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 79 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 80 | "dev": true 81 | }, 82 | "arrify": { 83 | "version": "1.0.1", 84 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 85 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 86 | "dev": true 87 | }, 88 | "babel-code-frame": { 89 | "version": "6.26.0", 90 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 91 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 92 | "dev": true, 93 | "requires": { 94 | "chalk": "^1.1.3", 95 | "esutils": "^2.0.2", 96 | "js-tokens": "^3.0.2" 97 | }, 98 | "dependencies": { 99 | "chalk": { 100 | "version": "1.1.3", 101 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 102 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 103 | "dev": true, 104 | "requires": { 105 | "ansi-styles": "^2.2.1", 106 | "escape-string-regexp": "^1.0.2", 107 | "has-ansi": "^2.0.0", 108 | "strip-ansi": "^3.0.0", 109 | "supports-color": "^2.0.0" 110 | } 111 | }, 112 | "strip-ansi": { 113 | "version": "3.0.1", 114 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 115 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 116 | "dev": true, 117 | "requires": { 118 | "ansi-regex": "^2.0.0" 119 | } 120 | } 121 | } 122 | }, 123 | "balanced-match": { 124 | "version": "1.0.0", 125 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 126 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 127 | "dev": true 128 | }, 129 | "brace-expansion": { 130 | "version": "1.1.11", 131 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 132 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 133 | "dev": true, 134 | "requires": { 135 | "balanced-match": "^1.0.0", 136 | "concat-map": "0.0.1" 137 | } 138 | }, 139 | "caller-path": { 140 | "version": "0.1.0", 141 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", 142 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", 143 | "dev": true, 144 | "requires": { 145 | "callsites": "^0.2.0" 146 | } 147 | }, 148 | "callsites": { 149 | "version": "0.2.0", 150 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", 151 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", 152 | "dev": true 153 | }, 154 | "chalk": { 155 | "version": "2.4.1", 156 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 157 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 158 | "dev": true, 159 | "requires": { 160 | "ansi-styles": "^3.2.1", 161 | "escape-string-regexp": "^1.0.5", 162 | "supports-color": "^5.3.0" 163 | }, 164 | "dependencies": { 165 | "ansi-styles": { 166 | "version": "3.2.1", 167 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 168 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 169 | "dev": true, 170 | "requires": { 171 | "color-convert": "^1.9.0" 172 | } 173 | }, 174 | "supports-color": { 175 | "version": "5.4.0", 176 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 177 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 178 | "dev": true, 179 | "requires": { 180 | "has-flag": "^3.0.0" 181 | } 182 | } 183 | } 184 | }, 185 | "chardet": { 186 | "version": "0.4.2", 187 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", 188 | "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", 189 | "dev": true 190 | }, 191 | "circular-json": { 192 | "version": "0.3.3", 193 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", 194 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", 195 | "dev": true 196 | }, 197 | "cli-cursor": { 198 | "version": "2.1.0", 199 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 200 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 201 | "dev": true, 202 | "requires": { 203 | "restore-cursor": "^2.0.0" 204 | } 205 | }, 206 | "cli-width": { 207 | "version": "2.2.0", 208 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 209 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 210 | "dev": true 211 | }, 212 | "color-convert": { 213 | "version": "1.9.2", 214 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", 215 | "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", 216 | "dev": true, 217 | "requires": { 218 | "color-name": "1.1.1" 219 | } 220 | }, 221 | "color-name": { 222 | "version": "1.1.1", 223 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", 224 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", 225 | "dev": true 226 | }, 227 | "concat-map": { 228 | "version": "0.0.1", 229 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 230 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 231 | "dev": true 232 | }, 233 | "cross-spawn": { 234 | "version": "6.0.5", 235 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 236 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 237 | "dev": true, 238 | "requires": { 239 | "nice-try": "^1.0.4", 240 | "path-key": "^2.0.1", 241 | "semver": "^5.5.0", 242 | "shebang-command": "^1.2.0", 243 | "which": "^1.2.9" 244 | } 245 | }, 246 | "debug": { 247 | "version": "3.1.0", 248 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 249 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 250 | "dev": true, 251 | "requires": { 252 | "ms": "2.0.0" 253 | } 254 | }, 255 | "deep-is": { 256 | "version": "0.1.3", 257 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 258 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 259 | "dev": true 260 | }, 261 | "define-properties": { 262 | "version": "1.1.2", 263 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", 264 | "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", 265 | "dev": true, 266 | "requires": { 267 | "foreach": "^2.0.5", 268 | "object-keys": "^1.0.8" 269 | } 270 | }, 271 | "del": { 272 | "version": "2.2.2", 273 | "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", 274 | "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", 275 | "dev": true, 276 | "requires": { 277 | "globby": "^5.0.0", 278 | "is-path-cwd": "^1.0.0", 279 | "is-path-in-cwd": "^1.0.0", 280 | "object-assign": "^4.0.1", 281 | "pify": "^2.0.0", 282 | "pinkie-promise": "^2.0.0", 283 | "rimraf": "^2.2.8" 284 | } 285 | }, 286 | "doctrine": { 287 | "version": "2.1.0", 288 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", 289 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", 290 | "dev": true, 291 | "requires": { 292 | "esutils": "^2.0.2" 293 | } 294 | }, 295 | "es-abstract": { 296 | "version": "1.12.0", 297 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", 298 | "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", 299 | "dev": true, 300 | "requires": { 301 | "es-to-primitive": "^1.1.1", 302 | "function-bind": "^1.1.1", 303 | "has": "^1.0.1", 304 | "is-callable": "^1.1.3", 305 | "is-regex": "^1.0.4" 306 | } 307 | }, 308 | "es-to-primitive": { 309 | "version": "1.1.1", 310 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", 311 | "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", 312 | "dev": true, 313 | "requires": { 314 | "is-callable": "^1.1.1", 315 | "is-date-object": "^1.0.1", 316 | "is-symbol": "^1.0.1" 317 | } 318 | }, 319 | "escape-string-regexp": { 320 | "version": "1.0.5", 321 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 322 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 323 | "dev": true 324 | }, 325 | "eslint": { 326 | "version": "5.1.0", 327 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.1.0.tgz", 328 | "integrity": "sha512-DyH6JsoA1KzA5+OSWFjg56DFJT+sDLO0yokaPZ9qY0UEmYrPA1gEX/G1MnVkmRDsksG4H1foIVz2ZXXM3hHYvw==", 329 | "dev": true, 330 | "requires": { 331 | "ajv": "^6.5.0", 332 | "babel-code-frame": "^6.26.0", 333 | "chalk": "^2.1.0", 334 | "cross-spawn": "^6.0.5", 335 | "debug": "^3.1.0", 336 | "doctrine": "^2.1.0", 337 | "eslint-scope": "^4.0.0", 338 | "eslint-utils": "^1.3.1", 339 | "eslint-visitor-keys": "^1.0.0", 340 | "espree": "^4.0.0", 341 | "esquery": "^1.0.1", 342 | "esutils": "^2.0.2", 343 | "file-entry-cache": "^2.0.0", 344 | "functional-red-black-tree": "^1.0.1", 345 | "glob": "^7.1.2", 346 | "globals": "^11.7.0", 347 | "ignore": "^3.3.3", 348 | "imurmurhash": "^0.1.4", 349 | "inquirer": "^5.2.0", 350 | "is-resolvable": "^1.1.0", 351 | "js-yaml": "^3.11.0", 352 | "json-stable-stringify-without-jsonify": "^1.0.1", 353 | "levn": "^0.3.0", 354 | "lodash": "^4.17.5", 355 | "minimatch": "^3.0.4", 356 | "mkdirp": "^0.5.1", 357 | "natural-compare": "^1.4.0", 358 | "optionator": "^0.8.2", 359 | "path-is-inside": "^1.0.2", 360 | "pluralize": "^7.0.0", 361 | "progress": "^2.0.0", 362 | "regexpp": "^1.1.0", 363 | "require-uncached": "^1.0.3", 364 | "semver": "^5.5.0", 365 | "string.prototype.matchall": "^2.0.0", 366 | "strip-ansi": "^4.0.0", 367 | "strip-json-comments": "^2.0.1", 368 | "table": "^4.0.3", 369 | "text-table": "^0.2.0" 370 | } 371 | }, 372 | "eslint-scope": { 373 | "version": "4.0.0", 374 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", 375 | "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", 376 | "dev": true, 377 | "requires": { 378 | "esrecurse": "^4.1.0", 379 | "estraverse": "^4.1.1" 380 | } 381 | }, 382 | "eslint-utils": { 383 | "version": "1.3.1", 384 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", 385 | "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", 386 | "dev": true 387 | }, 388 | "eslint-visitor-keys": { 389 | "version": "1.0.0", 390 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 391 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 392 | "dev": true 393 | }, 394 | "espree": { 395 | "version": "4.0.0", 396 | "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", 397 | "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", 398 | "dev": true, 399 | "requires": { 400 | "acorn": "^5.6.0", 401 | "acorn-jsx": "^4.1.1" 402 | } 403 | }, 404 | "esprima": { 405 | "version": "4.0.0", 406 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", 407 | "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", 408 | "dev": true 409 | }, 410 | "esquery": { 411 | "version": "1.0.1", 412 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 413 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 414 | "dev": true, 415 | "requires": { 416 | "estraverse": "^4.0.0" 417 | } 418 | }, 419 | "esrecurse": { 420 | "version": "4.2.1", 421 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 422 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 423 | "dev": true, 424 | "requires": { 425 | "estraverse": "^4.1.0" 426 | } 427 | }, 428 | "estraverse": { 429 | "version": "4.2.0", 430 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 431 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 432 | "dev": true 433 | }, 434 | "esutils": { 435 | "version": "2.0.2", 436 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 437 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 438 | "dev": true 439 | }, 440 | "external-editor": { 441 | "version": "2.2.0", 442 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", 443 | "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", 444 | "dev": true, 445 | "requires": { 446 | "chardet": "^0.4.0", 447 | "iconv-lite": "^0.4.17", 448 | "tmp": "^0.0.33" 449 | } 450 | }, 451 | "fast-deep-equal": { 452 | "version": "2.0.1", 453 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 454 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", 455 | "dev": true 456 | }, 457 | "fast-json-stable-stringify": { 458 | "version": "2.0.0", 459 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 460 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 461 | "dev": true 462 | }, 463 | "fast-levenshtein": { 464 | "version": "2.0.6", 465 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 466 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 467 | "dev": true 468 | }, 469 | "figures": { 470 | "version": "2.0.0", 471 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 472 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 473 | "dev": true, 474 | "requires": { 475 | "escape-string-regexp": "^1.0.5" 476 | } 477 | }, 478 | "file-entry-cache": { 479 | "version": "2.0.0", 480 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", 481 | "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", 482 | "dev": true, 483 | "requires": { 484 | "flat-cache": "^1.2.1", 485 | "object-assign": "^4.0.1" 486 | } 487 | }, 488 | "flat-cache": { 489 | "version": "1.3.0", 490 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", 491 | "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", 492 | "dev": true, 493 | "requires": { 494 | "circular-json": "^0.3.1", 495 | "del": "^2.0.2", 496 | "graceful-fs": "^4.1.2", 497 | "write": "^0.2.1" 498 | } 499 | }, 500 | "foreach": { 501 | "version": "2.0.5", 502 | "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", 503 | "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", 504 | "dev": true 505 | }, 506 | "fs.realpath": { 507 | "version": "1.0.0", 508 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 509 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 510 | "dev": true 511 | }, 512 | "function-bind": { 513 | "version": "1.1.1", 514 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 515 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 516 | "dev": true 517 | }, 518 | "functional-red-black-tree": { 519 | "version": "1.0.1", 520 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 521 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 522 | "dev": true 523 | }, 524 | "glob": { 525 | "version": "7.1.2", 526 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 527 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 528 | "dev": true, 529 | "requires": { 530 | "fs.realpath": "^1.0.0", 531 | "inflight": "^1.0.4", 532 | "inherits": "2", 533 | "minimatch": "^3.0.4", 534 | "once": "^1.3.0", 535 | "path-is-absolute": "^1.0.0" 536 | } 537 | }, 538 | "globals": { 539 | "version": "11.7.0", 540 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", 541 | "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", 542 | "dev": true 543 | }, 544 | "globby": { 545 | "version": "5.0.0", 546 | "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", 547 | "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", 548 | "dev": true, 549 | "requires": { 550 | "array-union": "^1.0.1", 551 | "arrify": "^1.0.0", 552 | "glob": "^7.0.3", 553 | "object-assign": "^4.0.1", 554 | "pify": "^2.0.0", 555 | "pinkie-promise": "^2.0.0" 556 | } 557 | }, 558 | "graceful-fs": { 559 | "version": "4.1.11", 560 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 561 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 562 | "dev": true 563 | }, 564 | "has": { 565 | "version": "1.0.3", 566 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 567 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 568 | "dev": true, 569 | "requires": { 570 | "function-bind": "^1.1.1" 571 | } 572 | }, 573 | "has-ansi": { 574 | "version": "2.0.0", 575 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 576 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 577 | "dev": true, 578 | "requires": { 579 | "ansi-regex": "^2.0.0" 580 | } 581 | }, 582 | "has-flag": { 583 | "version": "3.0.0", 584 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 585 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 586 | "dev": true 587 | }, 588 | "has-symbols": { 589 | "version": "1.0.0", 590 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 591 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 592 | "dev": true 593 | }, 594 | "iconv-lite": { 595 | "version": "0.4.23", 596 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 597 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 598 | "dev": true, 599 | "requires": { 600 | "safer-buffer": ">= 2.1.2 < 3" 601 | } 602 | }, 603 | "ignore": { 604 | "version": "3.3.10", 605 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", 606 | "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", 607 | "dev": true 608 | }, 609 | "imurmurhash": { 610 | "version": "0.1.4", 611 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 612 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 613 | "dev": true 614 | }, 615 | "inflight": { 616 | "version": "1.0.6", 617 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 618 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 619 | "dev": true, 620 | "requires": { 621 | "once": "^1.3.0", 622 | "wrappy": "1" 623 | } 624 | }, 625 | "inherits": { 626 | "version": "2.0.3", 627 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 628 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 629 | "dev": true 630 | }, 631 | "inquirer": { 632 | "version": "5.2.0", 633 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", 634 | "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", 635 | "dev": true, 636 | "requires": { 637 | "ansi-escapes": "^3.0.0", 638 | "chalk": "^2.0.0", 639 | "cli-cursor": "^2.1.0", 640 | "cli-width": "^2.0.0", 641 | "external-editor": "^2.1.0", 642 | "figures": "^2.0.0", 643 | "lodash": "^4.3.0", 644 | "mute-stream": "0.0.7", 645 | "run-async": "^2.2.0", 646 | "rxjs": "^5.5.2", 647 | "string-width": "^2.1.0", 648 | "strip-ansi": "^4.0.0", 649 | "through": "^2.3.6" 650 | } 651 | }, 652 | "is-callable": { 653 | "version": "1.1.4", 654 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 655 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 656 | "dev": true 657 | }, 658 | "is-date-object": { 659 | "version": "1.0.1", 660 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 661 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 662 | "dev": true 663 | }, 664 | "is-fullwidth-code-point": { 665 | "version": "2.0.0", 666 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 667 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 668 | "dev": true 669 | }, 670 | "is-path-cwd": { 671 | "version": "1.0.0", 672 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", 673 | "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", 674 | "dev": true 675 | }, 676 | "is-path-in-cwd": { 677 | "version": "1.0.1", 678 | "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", 679 | "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", 680 | "dev": true, 681 | "requires": { 682 | "is-path-inside": "^1.0.0" 683 | } 684 | }, 685 | "is-path-inside": { 686 | "version": "1.0.1", 687 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 688 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 689 | "dev": true, 690 | "requires": { 691 | "path-is-inside": "^1.0.1" 692 | } 693 | }, 694 | "is-promise": { 695 | "version": "2.1.0", 696 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 697 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 698 | "dev": true 699 | }, 700 | "is-regex": { 701 | "version": "1.0.4", 702 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 703 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 704 | "dev": true, 705 | "requires": { 706 | "has": "^1.0.1" 707 | } 708 | }, 709 | "is-resolvable": { 710 | "version": "1.1.0", 711 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", 712 | "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", 713 | "dev": true 714 | }, 715 | "is-symbol": { 716 | "version": "1.0.1", 717 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", 718 | "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", 719 | "dev": true 720 | }, 721 | "isexe": { 722 | "version": "2.0.0", 723 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 724 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 725 | "dev": true 726 | }, 727 | "js-tokens": { 728 | "version": "3.0.2", 729 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 730 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 731 | "dev": true 732 | }, 733 | "js-yaml": { 734 | "version": "3.12.0", 735 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 736 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 737 | "dev": true, 738 | "requires": { 739 | "argparse": "^1.0.7", 740 | "esprima": "^4.0.0" 741 | } 742 | }, 743 | "json-schema-traverse": { 744 | "version": "0.4.1", 745 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 746 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 747 | "dev": true 748 | }, 749 | "json-stable-stringify-without-jsonify": { 750 | "version": "1.0.1", 751 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 752 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 753 | "dev": true 754 | }, 755 | "levn": { 756 | "version": "0.3.0", 757 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 758 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 759 | "dev": true, 760 | "requires": { 761 | "prelude-ls": "~1.1.2", 762 | "type-check": "~0.3.2" 763 | } 764 | }, 765 | "lodash": { 766 | "version": "4.17.10", 767 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 768 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", 769 | "dev": true 770 | }, 771 | "mimic-fn": { 772 | "version": "1.2.0", 773 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 774 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 775 | "dev": true 776 | }, 777 | "minimatch": { 778 | "version": "3.0.4", 779 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 780 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 781 | "dev": true, 782 | "requires": { 783 | "brace-expansion": "^1.1.7" 784 | } 785 | }, 786 | "minimist": { 787 | "version": "0.0.8", 788 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 789 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 790 | "dev": true 791 | }, 792 | "mkdirp": { 793 | "version": "0.5.1", 794 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 795 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 796 | "dev": true, 797 | "requires": { 798 | "minimist": "0.0.8" 799 | } 800 | }, 801 | "ms": { 802 | "version": "2.0.0", 803 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 804 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 805 | "dev": true 806 | }, 807 | "mute-stream": { 808 | "version": "0.0.7", 809 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 810 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 811 | "dev": true 812 | }, 813 | "natural-compare": { 814 | "version": "1.4.0", 815 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 816 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 817 | "dev": true 818 | }, 819 | "nice-try": { 820 | "version": "1.0.4", 821 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", 822 | "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", 823 | "dev": true 824 | }, 825 | "object-assign": { 826 | "version": "4.1.1", 827 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 828 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 829 | "dev": true 830 | }, 831 | "object-keys": { 832 | "version": "1.0.12", 833 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", 834 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", 835 | "dev": true 836 | }, 837 | "once": { 838 | "version": "1.4.0", 839 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 840 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 841 | "dev": true, 842 | "requires": { 843 | "wrappy": "1" 844 | } 845 | }, 846 | "onetime": { 847 | "version": "2.0.1", 848 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 849 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 850 | "dev": true, 851 | "requires": { 852 | "mimic-fn": "^1.0.0" 853 | } 854 | }, 855 | "optionator": { 856 | "version": "0.8.2", 857 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 858 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 859 | "dev": true, 860 | "requires": { 861 | "deep-is": "~0.1.3", 862 | "fast-levenshtein": "~2.0.4", 863 | "levn": "~0.3.0", 864 | "prelude-ls": "~1.1.2", 865 | "type-check": "~0.3.2", 866 | "wordwrap": "~1.0.0" 867 | } 868 | }, 869 | "os-tmpdir": { 870 | "version": "1.0.2", 871 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 872 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 873 | "dev": true 874 | }, 875 | "path-is-absolute": { 876 | "version": "1.0.1", 877 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 878 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 879 | "dev": true 880 | }, 881 | "path-is-inside": { 882 | "version": "1.0.2", 883 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 884 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 885 | "dev": true 886 | }, 887 | "path-key": { 888 | "version": "2.0.1", 889 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 890 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 891 | "dev": true 892 | }, 893 | "pify": { 894 | "version": "2.3.0", 895 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 896 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 897 | "dev": true 898 | }, 899 | "pinkie": { 900 | "version": "2.0.4", 901 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 902 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 903 | "dev": true 904 | }, 905 | "pinkie-promise": { 906 | "version": "2.0.1", 907 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 908 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 909 | "dev": true, 910 | "requires": { 911 | "pinkie": "^2.0.0" 912 | } 913 | }, 914 | "pluralize": { 915 | "version": "7.0.0", 916 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", 917 | "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", 918 | "dev": true 919 | }, 920 | "prelude-ls": { 921 | "version": "1.1.2", 922 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 923 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 924 | "dev": true 925 | }, 926 | "progress": { 927 | "version": "2.0.0", 928 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", 929 | "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", 930 | "dev": true 931 | }, 932 | "punycode": { 933 | "version": "2.1.1", 934 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 935 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 936 | "dev": true 937 | }, 938 | "regexp.prototype.flags": { 939 | "version": "1.2.0", 940 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", 941 | "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", 942 | "dev": true, 943 | "requires": { 944 | "define-properties": "^1.1.2" 945 | } 946 | }, 947 | "regexpp": { 948 | "version": "1.1.0", 949 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", 950 | "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", 951 | "dev": true 952 | }, 953 | "require-uncached": { 954 | "version": "1.0.3", 955 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", 956 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", 957 | "dev": true, 958 | "requires": { 959 | "caller-path": "^0.1.0", 960 | "resolve-from": "^1.0.0" 961 | } 962 | }, 963 | "resolve-from": { 964 | "version": "1.0.1", 965 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", 966 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", 967 | "dev": true 968 | }, 969 | "restore-cursor": { 970 | "version": "2.0.0", 971 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 972 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 973 | "dev": true, 974 | "requires": { 975 | "onetime": "^2.0.0", 976 | "signal-exit": "^3.0.2" 977 | } 978 | }, 979 | "rimraf": { 980 | "version": "2.6.2", 981 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 982 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 983 | "dev": true, 984 | "requires": { 985 | "glob": "^7.0.5" 986 | } 987 | }, 988 | "run-async": { 989 | "version": "2.3.0", 990 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 991 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 992 | "dev": true, 993 | "requires": { 994 | "is-promise": "^2.1.0" 995 | } 996 | }, 997 | "rxjs": { 998 | "version": "5.5.11", 999 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.11.tgz", 1000 | "integrity": "sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA==", 1001 | "dev": true, 1002 | "requires": { 1003 | "symbol-observable": "1.0.1" 1004 | } 1005 | }, 1006 | "safer-buffer": { 1007 | "version": "2.1.2", 1008 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1009 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1010 | "dev": true 1011 | }, 1012 | "semver": { 1013 | "version": "5.5.0", 1014 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 1015 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", 1016 | "dev": true 1017 | }, 1018 | "shebang-command": { 1019 | "version": "1.2.0", 1020 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1021 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1022 | "dev": true, 1023 | "requires": { 1024 | "shebang-regex": "^1.0.0" 1025 | } 1026 | }, 1027 | "shebang-regex": { 1028 | "version": "1.0.0", 1029 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1030 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1031 | "dev": true 1032 | }, 1033 | "signal-exit": { 1034 | "version": "3.0.2", 1035 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1036 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1037 | "dev": true 1038 | }, 1039 | "slice-ansi": { 1040 | "version": "1.0.0", 1041 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", 1042 | "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", 1043 | "dev": true, 1044 | "requires": { 1045 | "is-fullwidth-code-point": "^2.0.0" 1046 | } 1047 | }, 1048 | "sprintf-js": { 1049 | "version": "1.0.3", 1050 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1051 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1052 | "dev": true 1053 | }, 1054 | "string-width": { 1055 | "version": "2.1.1", 1056 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1057 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1058 | "dev": true, 1059 | "requires": { 1060 | "is-fullwidth-code-point": "^2.0.0", 1061 | "strip-ansi": "^4.0.0" 1062 | } 1063 | }, 1064 | "string.prototype.matchall": { 1065 | "version": "2.0.0", 1066 | "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz", 1067 | "integrity": "sha512-WoZ+B2ypng1dp4iFLF2kmZlwwlE19gmjgKuhL1FJfDgCREWb3ye3SDVHSzLH6bxfnvYmkCxbzkmWcQZHA4P//Q==", 1068 | "dev": true, 1069 | "requires": { 1070 | "define-properties": "^1.1.2", 1071 | "es-abstract": "^1.10.0", 1072 | "function-bind": "^1.1.1", 1073 | "has-symbols": "^1.0.0", 1074 | "regexp.prototype.flags": "^1.2.0" 1075 | } 1076 | }, 1077 | "strip-ansi": { 1078 | "version": "4.0.0", 1079 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1080 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1081 | "dev": true, 1082 | "requires": { 1083 | "ansi-regex": "^3.0.0" 1084 | }, 1085 | "dependencies": { 1086 | "ansi-regex": { 1087 | "version": "3.0.0", 1088 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1089 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1090 | "dev": true 1091 | } 1092 | } 1093 | }, 1094 | "strip-json-comments": { 1095 | "version": "2.0.1", 1096 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1097 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1098 | "dev": true 1099 | }, 1100 | "supports-color": { 1101 | "version": "2.0.0", 1102 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1103 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1104 | "dev": true 1105 | }, 1106 | "symbol-observable": { 1107 | "version": "1.0.1", 1108 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", 1109 | "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", 1110 | "dev": true 1111 | }, 1112 | "table": { 1113 | "version": "4.0.3", 1114 | "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", 1115 | "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", 1116 | "dev": true, 1117 | "requires": { 1118 | "ajv": "^6.0.1", 1119 | "ajv-keywords": "^3.0.0", 1120 | "chalk": "^2.1.0", 1121 | "lodash": "^4.17.4", 1122 | "slice-ansi": "1.0.0", 1123 | "string-width": "^2.1.1" 1124 | } 1125 | }, 1126 | "text-table": { 1127 | "version": "0.2.0", 1128 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1129 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1130 | "dev": true 1131 | }, 1132 | "through": { 1133 | "version": "2.3.8", 1134 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1135 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1136 | "dev": true 1137 | }, 1138 | "tmp": { 1139 | "version": "0.0.33", 1140 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1141 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1142 | "dev": true, 1143 | "requires": { 1144 | "os-tmpdir": "~1.0.2" 1145 | } 1146 | }, 1147 | "type-check": { 1148 | "version": "0.3.2", 1149 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1150 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1151 | "dev": true, 1152 | "requires": { 1153 | "prelude-ls": "~1.1.2" 1154 | } 1155 | }, 1156 | "uri-js": { 1157 | "version": "4.2.2", 1158 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1159 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1160 | "dev": true, 1161 | "requires": { 1162 | "punycode": "^2.1.0" 1163 | } 1164 | }, 1165 | "which": { 1166 | "version": "1.3.1", 1167 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1168 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1169 | "dev": true, 1170 | "requires": { 1171 | "isexe": "^2.0.0" 1172 | } 1173 | }, 1174 | "wordwrap": { 1175 | "version": "1.0.0", 1176 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1177 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1178 | "dev": true 1179 | }, 1180 | "wrappy": { 1181 | "version": "1.0.2", 1182 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1183 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1184 | "dev": true 1185 | }, 1186 | "write": { 1187 | "version": "0.2.1", 1188 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", 1189 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", 1190 | "dev": true, 1191 | "requires": { 1192 | "mkdirp": "^0.5.1" 1193 | } 1194 | } 1195 | } 1196 | } 1197 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazyer", 3 | "version": "0.2.1", 4 | "description": "Lazy iteration in JavaScript.", 5 | "main": "./src/index.js", 6 | "author": "1Computer", 7 | "license": "MIT", 8 | "keywords": [ 9 | "lazy", 10 | "iteration", 11 | "iter" 12 | ], 13 | "dependencies": {}, 14 | "devDependencies": { 15 | "eslint": "^5.1.0" 16 | }, 17 | "scripts": { 18 | "test": "npm run lint && npm run unit-tests", 19 | "lint": "eslint src && eslint test", 20 | "unit-tests": "node test" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/1Computer1/lazyer.git" 25 | }, 26 | "bugs": { 27 | "url": "https://github.com/1Computer1/lazyer/issues" 28 | }, 29 | "homepage": "https://github.com/1Computer1/lazyer" 30 | } 31 | -------------------------------------------------------------------------------- /src/LazyIterator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class for lazy iteration. 3 | * Wraps around an iterator. 4 | * @class 5 | */ 6 | class LazyIterator { 7 | /** 8 | * Wraps a lazy iterator around an iterator. 9 | * @param {Iterator} iterator Object that implements JavaScript's iterator protocol. 10 | */ 11 | constructor(iterator) { 12 | this.iterator = iterator; 13 | this.peeked = false; 14 | this.peekedAt = null; 15 | } 16 | 17 | [Symbol.iterator]() { 18 | return this; 19 | } 20 | 21 | /** 22 | * Returns the next item in the iterator. 23 | * @returns {IteratorResult} Iterator item. 24 | */ 25 | next() { 26 | if (this.peeked) { 27 | this.peeked = false; 28 | return this.peekedAt; 29 | } 30 | 31 | return this.iterator.next(); 32 | } 33 | 34 | /** 35 | * Peeks at the next item in the iterator. 36 | * @returns {IteratorResult} Iterator item. 37 | */ 38 | peek() { 39 | if (this.peeked) { 40 | return this.peekedAt; 41 | } 42 | 43 | this.peeked = true; 44 | this.peekedAt = this.iterator.next(); 45 | return this.peekedAt; 46 | } 47 | 48 | /** 49 | * Returns the value at a certain position. 50 | * This consumes the iterator until the given position. 51 | * @param {number} index Position of value. 52 | * @returns {any} The value at the given position. 53 | */ 54 | at(index) { 55 | let value; 56 | for (let i = 0; i <= index; i++) { 57 | const item = this.next(); 58 | if (item.done) { 59 | return undefined; 60 | } 61 | 62 | value = item.value; 63 | } 64 | 65 | return value; 66 | } 67 | 68 | /** 69 | * Returns the size of the iterator. 70 | * This consumes the iterator. 71 | * @returns {number} Size of the iterator. 72 | */ 73 | count() { 74 | let i = 0; 75 | // eslint-disable-next-line no-unused-vars 76 | for (const value of this) { 77 | i++; 78 | } 79 | 80 | return i; 81 | } 82 | 83 | /** 84 | * Returns the last item of the iterator. 85 | * This consumes the iterator. 86 | * @returns {any} Last item of the iterator. 87 | */ 88 | last() { 89 | let val; 90 | for (const value of this) { 91 | val = value; 92 | } 93 | 94 | return val; 95 | } 96 | 97 | /** 98 | * Returns an iterator that steps in an interval. 99 | * The iterator starts at the first element. 100 | * @param {number} stepSize Interval to step by. 101 | * @returns {StepIterator} The iterator. 102 | */ 103 | stepBy(stepSize) { 104 | return new StepIterator(this, stepSize); 105 | } 106 | 107 | /** 108 | * Returns an iterator that skips some amount of elements. 109 | * @param {number} skipAmount Amount of elements to skip. 110 | * @returns {SkipIterator} The iterator. 111 | */ 112 | skip(skipAmount) { 113 | return new SkipIterator(this, skipAmount); 114 | } 115 | 116 | /** 117 | * Returns an iterator that takes only some amount of elements. 118 | * @param {number} takeAmount Amount of elements to take. 119 | * @returns {TakeIterator} The iterator. 120 | */ 121 | take(takeAmount) { 122 | return new TakeIterator(this, takeAmount); 123 | } 124 | 125 | /** 126 | * Returns an iterator that skips while a condition is true. 127 | * The iterator will skip until the predicate returns false. 128 | * After that, all elements will be yielded as normal. 129 | * @param {Predicate} fn Predicate function. 130 | * @returns {SkipWhileIterator} The iterator. 131 | */ 132 | skipWhile(fn) { 133 | return new SkipWhileIterator(this, fn); 134 | } 135 | 136 | /** 137 | * Returns an iterator that takes while a condition is true. 138 | * The iterator will take until the predicate returns false. 139 | * After that, the iterator is considered done. 140 | * @param {Predicate} fn Predicate function. 141 | * @returns {TakeWhileIterator} The iterator. 142 | */ 143 | takeWhile(fn) { 144 | return new TakeWhileIterator(this, fn); 145 | } 146 | 147 | /** 148 | * Returns an iterator that puts multiple consecutive values into one value. 149 | * If the iterator does not divide evenly into the given size, there will be a shorter chunk at the end. 150 | * @param {number} chunkSize Size of a chunk. 151 | * @returns {ChunkIterator} The iterator. 152 | */ 153 | chunk(chunkSize) { 154 | return new ChunkIterator(this, chunkSize); 155 | } 156 | 157 | /** 158 | * Returns an iterator that includes the index. 159 | * The iterator will iterate through (index, value) pairs. 160 | * @returns {EnumerateIterator} The iterator. 161 | */ 162 | enumerate() { 163 | return new EnumerateIterator(this); 164 | } 165 | 166 | /** 167 | * Returns an iterator that is a chain of iterators. 168 | * Once one iterator is done, the next iterator starts. 169 | * @param {Array} iters Iterators or iterables. 170 | * @returns {ConcatIterator} The iterator. 171 | */ 172 | concat(...iters) { 173 | return new ConcatIterator(this, iters.map(iter => LazyIterator.from(iter))); 174 | } 175 | 176 | /** 177 | * Returns an iterator that repeats this iterator forever. 178 | * @returns {CycleIterator} The iterator. 179 | */ 180 | cycle() { 181 | return new CycleIterator(this); 182 | } 183 | 184 | /** 185 | * Returns an iterator that maps each element with a function. 186 | * @param {Mapping} fn Mapping function. 187 | * @returns {MapIterator} The iterator. 188 | */ 189 | map(fn) { 190 | return new MapIterator(this, fn); 191 | } 192 | 193 | /** 194 | * Returns an iterator that filters out certain elements. 195 | * @param {Predicate} fn Predicate function. 196 | * @returns {FilterIterator} The iterator. 197 | */ 198 | filter(fn) { 199 | return new FilterIterator(this, fn); 200 | } 201 | 202 | /** 203 | * Returns an iterator that holds internal state. 204 | * Each element of the iterator is the state at that iteration. 205 | * This can be thought of as a reduce. 206 | * @param {Reducer} fn Reducer function. 207 | * @param {any} [accum] Accumulator. 208 | * @returns {ScanIterator} The iterator. 209 | */ 210 | scan(fn, accum) { 211 | return new ScanIterator(this, fn, accum); 212 | } 213 | 214 | /** 215 | * Returns an iterator where each iterator is zipped with each other. 216 | * Each element is a tuple of zipped elements e.g. (a, b, c) if given two iterators. 217 | * @param {Array} iters Iterators or iterables. 218 | * @returns {ZipIterator} The iterator. 219 | */ 220 | zip(...iters) { 221 | return new ZipIterator(this, iters.map(iter => LazyIterator.from(iter))); 222 | } 223 | 224 | /** 225 | * Returns an iterator that flattens iterators and iterables inside this interator. 226 | * @param {number} [depth=1] The amount of depth to flatten. 227 | * @returns {FlatIterator} The iterator. 228 | */ 229 | flat(depth = 1) { 230 | return new FlatIterator(this, depth); 231 | } 232 | 233 | /** 234 | * Returns an iterator that flattens iterators and iterables from a mapping. 235 | * @param {Mapping} fn Mapping function. 236 | * @returns {FlatMapIterator} The iterator. 237 | */ 238 | flatMap(fn) { 239 | return new FlatMapIterator(this, fn); 240 | } 241 | 242 | /** 243 | * Returns an iterator where between every element is the given value. 244 | * @param {any} val Value to join with. 245 | * @returns {JoinIterator} The iterator. 246 | */ 247 | join(val) { 248 | return new JoinIterator(this, val); 249 | } 250 | 251 | /** 252 | * Returns an iterator where between every element are the values of the given iterator. 253 | * The joining iterator will be consumed and cycled through. 254 | * @param {Iterator|Iterable} iter Iterator to intercalate. 255 | * @returns {JoinWithIterator} The iterator. 256 | */ 257 | joinWith(iter) { 258 | return new JoinWithIterator(this, LazyIterator.from(iter)); 259 | } 260 | 261 | /** 262 | * Returns an iterator that calls a function on each element. 263 | * @param {Consumer} fn Consumer function. 264 | * @returns {EachIterator} The iterator. 265 | */ 266 | each(fn) { 267 | return new EachIterator(this, fn); 268 | } 269 | 270 | /** 271 | * Calls a function on each element. 272 | * This consumes the iterator. 273 | * @param {Consumer} fn Consumer function. 274 | * @returns {void} Nothing. 275 | */ 276 | forEach(fn) { 277 | for (const value of this) { 278 | fn(value); 279 | } 280 | } 281 | 282 | /** 283 | * Reduces each element into one single result. 284 | * Also known as fold, inject, etc. 285 | * This consumes the iterator. 286 | * @param {Reducer} fn Reducer function. 287 | * @param {any} [accum] The accumulator. 288 | * Defaults to the first element in the iterator. 289 | * @returns {any} The accumulator. 290 | */ 291 | reduce(fn, accum) { 292 | if (accum === undefined) { 293 | const first = this.next(); 294 | if (first.done) { 295 | throw new TypeError('Reduce of empty sequence with no initial value'); 296 | } 297 | 298 | accum = first.value; 299 | } 300 | 301 | for (const value of this) { 302 | accum = fn(accum, value); 303 | } 304 | 305 | return accum; 306 | } 307 | 308 | /** 309 | * Takes the conjunction (logical AND) of every element. 310 | * An empty iterator will return true. 311 | * This consumes the iterator. 312 | * @returns {any} 313 | */ 314 | and() { 315 | return this.reduce((a, b) => a && b, true); 316 | } 317 | 318 | /** 319 | * Takes the disjunction (logical OR) of every element. 320 | * An empty iterator will return false. 321 | * This consumes the iterator. 322 | * @returns {any} 323 | */ 324 | or() { 325 | return this.reduce((a, b) => a || b, false); 326 | } 327 | 328 | /** 329 | * Sums or concatenates the elements in the iterator. 330 | * This consumes the iterator. 331 | * @returns {number|string} The sum or string. 332 | */ 333 | sum() { 334 | return this.reduce((a, b) => a + b, 0); 335 | } 336 | 337 | /** 338 | * Takes the product of the elements in the iterator. 339 | * This consumes the iterator. 340 | * @returns {number} The product. 341 | */ 342 | product() { 343 | return this.reduce((a, b) => a * b, 1); 344 | } 345 | 346 | /** 347 | * Finds a value in the iterator that passes the predicate. 348 | * This consumes the iterator until the found value. 349 | * @param {Predicate} fn Predicate function. 350 | * @returns {any} The found value. 351 | */ 352 | find(fn) { 353 | for (const value of this) { 354 | if (fn(value)) { 355 | return value; 356 | } 357 | } 358 | 359 | return undefined; 360 | } 361 | 362 | /** 363 | * Finds the index of the value in the iterator that passes the predicate. 364 | * This consumes the iterator until the found value. 365 | * @param {Predicate} fn Predicate function. 366 | * @returns {number} The found index. 367 | */ 368 | findIndex(fn) { 369 | let i = 0; 370 | for (const value of this) { 371 | if (fn(value)) { 372 | return i; 373 | } 374 | 375 | i++; 376 | } 377 | 378 | return -1; 379 | } 380 | 381 | /** 382 | * Checks if a value is in the iterator. 383 | * This consumes the iterator until the found value. 384 | * @param {any} searchElement Value to look for inclusion. 385 | * @param {number} [from=0] Index to search from. 386 | * @returns {boolean} Whether the value was found. 387 | */ 388 | includes(searchElement, from = 0) { 389 | let i = 0; 390 | for (const value of this) { 391 | if (i < from) { 392 | i++; 393 | continue; 394 | } 395 | 396 | if (sameValueZero(searchElement, value)) { 397 | return true; 398 | } 399 | } 400 | 401 | return false; 402 | } 403 | 404 | /** 405 | * Checks that every element in the iterator passes the predicate. 406 | * This consumes the iterator until a value that does not pass the predicate. 407 | * @param {Predicate} fn Predicate function. 408 | * @returns {boolean} Whether all elements passed or not. 409 | */ 410 | every(fn) { 411 | for (const value of this) { 412 | if (!fn(value)) { 413 | return false; 414 | } 415 | } 416 | 417 | return true; 418 | } 419 | 420 | /** 421 | * Checks that one element in the iterator passes the predicate. 422 | * This consumes the iterator until a value passes the predicate. 423 | * @param {Predicate} fn Predicate function. 424 | * @returns {boolean} Whether one element passed or not. 425 | */ 426 | some(fn) { 427 | for (const value of this) { 428 | if (fn(value)) { 429 | return true; 430 | } 431 | } 432 | 433 | return false; 434 | } 435 | 436 | /** 437 | * Finds the element that is considered the maximum. 438 | * A mapping can be passed to compare by an associated value. 439 | * This consumes the iterator. 440 | * @param {Mapping} [fn] Mapping function. 441 | * @returns {any} The maximum. 442 | */ 443 | max(fn = x => x) { 444 | let max; 445 | const first = this.next(); 446 | if (first.done) { 447 | return undefined; 448 | } 449 | 450 | max = first.value; 451 | for (const value of this) { 452 | if (fn(value) > fn(max)) { 453 | max = value; 454 | } 455 | } 456 | 457 | return max; 458 | } 459 | 460 | /** 461 | * Finds the element that is considered the minimum. 462 | * A mapping can be passed to compare by an associated value. 463 | * This consumes the iterator. 464 | * @param {Mapping} [fn] Mapping function. 465 | * @returns {any} The minimum. 466 | */ 467 | min(fn = x => x) { 468 | let min; 469 | const first = this.next(); 470 | if (first.done) { 471 | return undefined; 472 | } 473 | 474 | min = first.value; 475 | for (const value of this) { 476 | if (fn(value) < fn(min)) { 477 | min = value; 478 | } 479 | } 480 | 481 | return min; 482 | } 483 | 484 | /** 485 | * Finds the element that is considered the maximum by some comparison. 486 | * This consumes the iterator. 487 | * @param {Comparator} fn Comparator function. 488 | * @returns {any} The maximum. 489 | */ 490 | maxBy(fn) { 491 | let max; 492 | const first = this.next(); 493 | if (first.done) { 494 | return undefined; 495 | } 496 | 497 | max = first.value; 498 | for (const value of this) { 499 | if (fn(value, max) > 0) { 500 | max = value; 501 | } 502 | } 503 | 504 | return max; 505 | } 506 | 507 | /** 508 | * Finds the element that is considered the minimum by some comparison. 509 | * This consumes the iterator. 510 | * @param {Comparator} fn Comparator function. 511 | * @returns {any} The minimum. 512 | */ 513 | minBy(fn) { 514 | let min; 515 | const first = this.next(); 516 | if (first.done) { 517 | return undefined; 518 | } 519 | 520 | min = first.value; 521 | for (const value of this) { 522 | if (fn(value, min) < 0) { 523 | min = value; 524 | } 525 | } 526 | 527 | return min; 528 | } 529 | 530 | /** 531 | * Collects the iterator into a collection. 532 | * Defaults to an array. 533 | * This consumes the iterator. 534 | * @param {CollectionConstructor} [cons] Constructs a collection. 535 | * @param {CollectionExtender} [extend] Extends a collection. 536 | * @returns {any} The collection. 537 | */ 538 | collect(cons = consFunctions.Array, extend = extendFunctions.Array) { 539 | let coll = cons(); 540 | for (const value of this) { 541 | coll = extend(coll, value); 542 | } 543 | 544 | return coll; 545 | } 546 | 547 | /** 548 | * Partitions the iterator into a collection based on a predicate. 549 | * Items passing the predicate goes in the first collection. 550 | * Items not passing goes into the second collection. 551 | * The kind of collection defaults to an array. 552 | * This consumes the iterator. 553 | * @param {Predicate} fn Predicate fuction. 554 | * @param {CollectionConstructor} [cons] Constructs a collection. 555 | * @param {CollectionExtender} [extend] Extends a collection. 556 | * @returns {[any, any]} The collections. 557 | */ 558 | partition(fn, cons = consFunctions.Array, extend = extendFunctions.Array) { 559 | let left = cons(); 560 | let right = cons(); 561 | for (const value of this) { 562 | if (fn(value)) { 563 | left = extend(left, value); 564 | } else { 565 | right = extend(right, value); 566 | } 567 | } 568 | 569 | return [left, right]; 570 | } 571 | 572 | /** 573 | * Unzips an iterator of tuples into collections. 574 | * Each element in a tuple is added to the collection corresponding to their position. 575 | * Can be thought of as the opposite of zip. 576 | * The kind of collection defaults to an array. 577 | * This consumes the iterator. 578 | * @param {number} [size] Size of the tuples. 579 | * Defaults to the length of the first element. 580 | * @param {CollectionConstructor} [cons] Constructs a collection. 581 | * @param {CollectionExtender} [extend] Extends a collection. 582 | * @returns {any[]} The collections. 583 | */ 584 | unzip(size, cons = consFunctions.Array, extend = extendFunctions.Array) { 585 | const first = this.next(); 586 | let length; 587 | if (first.done) { 588 | if (size === undefined) { 589 | throw new TypeError('Unzip of empty sequence with no given size'); 590 | } 591 | 592 | length = size; 593 | } else { 594 | length = size === undefined 595 | ? first.value.length 596 | : size; 597 | } 598 | 599 | const colls = Array.from({ length }, () => cons()); 600 | if (!first.done) { 601 | for (let i = 0; i < length; i++) { 602 | colls[i] = extend(colls[i], first.value[i]); 603 | } 604 | } 605 | 606 | for (const value of this) { 607 | for (let i = 0; i < length; i++) { 608 | colls[i] = extend(colls[i], value[i]); 609 | } 610 | } 611 | 612 | return colls; 613 | } 614 | 615 | /** 616 | * Groups consecutive elements that are equal into an array of collections. 617 | * The kind of collection defaults to an array. 618 | * This consumes the iterator. 619 | * @param {Equality} [eq] Equality function. 620 | * @param {CollectionConstructor} [cons] Constructs a collection. 621 | * @param {CollectionExtender} [extend] Extends a collection. 622 | * @returns {any[]} 623 | */ 624 | group(eq = (a, b) => sameValueZero(a, b), cons = consFunctions.Array, extend = extendFunctions.Array) { 625 | const arr = []; 626 | let accum = cons(); 627 | let prev = null; 628 | 629 | const first = this.next(); 630 | if (first.done) { 631 | return arr; 632 | } 633 | 634 | prev = first.value; 635 | accum = extend(accum, first.value); 636 | for (const value of this) { 637 | if (eq(prev, value)) { 638 | accum = extend(accum, value); 639 | prev = value; 640 | } else { 641 | arr.push(accum); 642 | accum = cons(); 643 | accum = extend(accum, value); 644 | prev = value; 645 | } 646 | } 647 | 648 | arr.push(accum); 649 | return arr; 650 | } 651 | 652 | /** 653 | * Categorizes elements by some property. 654 | * The resulting map associates categories with collections of values. 655 | * The kind of collection defaults to an array. 656 | * This consumes the iterator. 657 | * @param {Mapping} fn Mapping function. 658 | * @param {CollectionConstructor} [cons] Constructs a collection. 659 | * @param {CollectionExtender} [extend] Extends a collection. 660 | * @returns {Map} 661 | */ 662 | categorize(fn, cons = consFunctions.Array, extend = extendFunctions.Array) { 663 | const map = new Map(); 664 | for (const value of this) { 665 | const cat = fn(value); 666 | if (!map.has(cat)) { 667 | map.set(cat, cons()); 668 | } 669 | 670 | map.set(cat, extend(map.get(cat), value)); 671 | } 672 | 673 | return map; 674 | } 675 | 676 | /** 677 | * Clones the iterator. 678 | * This consumes the current iterator and recreates it. 679 | * @returns {LazyIterator} The cloned iterator. 680 | */ 681 | clone() { 682 | const cache = this.collectArray(); 683 | this.iterator = cache[Symbol.iterator](); 684 | return new LazyIterator(cache[Symbol.iterator]()); 685 | } 686 | 687 | /** 688 | * Clones the iterator multiples times. 689 | * This consumes the current iterator and recreates it. 690 | * @param {number} amount Amount of times to clone. 691 | * @returns {LazyIterator[]} The cloned iterators. 692 | */ 693 | cloneMany(amount) { 694 | const cache = this.collectArray(); 695 | this.iterator = cache[Symbol.iterator](); 696 | return Array.from({ length: amount }, () => new LazyIterator(cache[Symbol.iterator]())); 697 | } 698 | 699 | /** 700 | * Checks if a value is an iterator. 701 | * @param {any} val Value to check. 702 | * @returns {boolean} Whether the value is an iterator. 703 | */ 704 | static isIterator(val) { 705 | return typeof val.next === 'function'; 706 | } 707 | 708 | /** 709 | * Checks if a value is an iterable. 710 | * @param {any} val Value to check. 711 | * @returns {boolean} Whether the value is an iterable. 712 | */ 713 | static isIterable(val) { 714 | return val != null && val[Symbol.iterator] != null; 715 | } 716 | 717 | /** 718 | * Creates a lazy iterator from an iterator or iterable. 719 | * @param {Iterator|Iterable} iter Iterator or iterable. 720 | * @returns {LazyIterator} The iterator. 721 | */ 722 | static from(iter) { 723 | if (LazyIterator.isIterator(iter)) { 724 | return new LazyIterator(iter); 725 | } 726 | 727 | if (LazyIterator.isIterable(iter)) { 728 | return new LazyIterator(iter[Symbol.iterator]()); 729 | } 730 | 731 | throw new TypeError('Value given is not iterable or an iterator'); 732 | } 733 | 734 | // Alias for above. 735 | static for(iter) { 736 | return LazyIterator.from(iter); 737 | } 738 | 739 | /** 740 | * Creates a lazy iterator for a sequence of items. 741 | * @param {any[]} items Items to yield. 742 | * @returns {LazyIterator} The iterator. 743 | */ 744 | static of(...items) { 745 | return new LazyIterator(items[Symbol.iterator]()); 746 | } 747 | 748 | /** 749 | * Generates an iterator yielding a range of integers. 750 | * @param {number} [start=0] The start value. 751 | * @param {number} [end=Infinity] The end value. 752 | * @param {number} [step=1] The step value. 753 | * @param {boolean} [inclusive=false] Whether or not this is an inclusive range. 754 | * @returns {LazyIterator} The iterator. 755 | */ 756 | static range(start = 0, end = Infinity, step = 1, inclusive = false) { 757 | if (inclusive) { 758 | return new LazyIterator(function* range() { 759 | for (let i = start; i <= end; i += step) { 760 | yield i; 761 | } 762 | }()); 763 | } 764 | 765 | return new LazyIterator(function* range() { 766 | for (let i = start; i < end; i += step) { 767 | yield i; 768 | } 769 | }()); 770 | } 771 | 772 | /** 773 | * Creates an iterator that yields an item for a certain amount of times. 774 | * @param {any} item Item to yield. 775 | * @param {number} [amount=Infinity] Amount of times to repeat. 776 | * @returns {LazyIterator} The iterator. 777 | */ 778 | static repeat(item, amount = Infinity) { 779 | return new LazyIterator(function* repeat() { 780 | for (let i = 0; i < amount; i++) { 781 | yield item; 782 | } 783 | }()); 784 | } 785 | 786 | /** 787 | * Creates an iterator that repeatedly yields the result of a function. 788 | * @param {Generating} fn Generating function. 789 | * @param {number} [amount=Infinity] Amount of times to repeat. 790 | * @returns {LazyIterator} The iterator. 791 | */ 792 | static repeatWith(fn, amount = Infinity) { 793 | return new LazyIterator(function* repeatWith() { 794 | for (let i = 0; i < amount; i++) { 795 | yield fn(); 796 | } 797 | }()); 798 | } 799 | 800 | /** 801 | * Creates an iterator where each element is the previous element with the given function applied to it. 802 | * @param {Mapping} fn Mapping function. 803 | * @param {any} init Initial value. 804 | * @returns {LazyIterator} The iterator. 805 | */ 806 | static iterate(fn, init) { 807 | return new LazyIterator(function* iterate() { 808 | let val = init; 809 | while (true) { 810 | yield val; 811 | val = fn(val); 812 | } 813 | }()); 814 | } 815 | } 816 | 817 | const sameValueZero = (a, b) => { 818 | if (a === 0 && b === 0) { 819 | return 1 / a === 1 / b; 820 | } 821 | 822 | if (a === b) { 823 | return true; 824 | } 825 | 826 | return isNaN(a) && isNaN(b); 827 | }; 828 | 829 | const consFunctions = { 830 | Array: () => { 831 | return []; 832 | }, 833 | Set: () => { 834 | return new Set(); 835 | }, 836 | Map: () => { 837 | return new Map(); 838 | }, 839 | String: () => { 840 | return ''; 841 | } 842 | }; 843 | 844 | const extendFunctions = { 845 | Array: (c, i) => { 846 | c.push(i); 847 | return c; 848 | }, 849 | Set: (c, i) => { 850 | c.add(i); 851 | return c; 852 | }, 853 | Map: (c, i) => { 854 | c.set(i[0], i[1]); 855 | return c; 856 | }, 857 | String: (c, i) => { 858 | return c + i; 859 | } 860 | }; 861 | 862 | for (const type of ['Array', 'Set', 'Map', 'String']) { 863 | const fnName = `collect${type}`; 864 | Object.defineProperty(LazyIterator.prototype, fnName, { 865 | value: { 866 | // eslint-disable-next-line func-names 867 | [fnName]: function () { 868 | return this.collect(consFunctions[type], extendFunctions[type]); 869 | } 870 | }[fnName], 871 | writable: true, 872 | enumerable: false, 873 | configurable: true 874 | }); 875 | } 876 | 877 | for (const method of ['partition', 'unzip', 'group', 'categorize']) { 878 | for (const type of ['Array', 'Set', 'Map', 'String']) { 879 | const fnName = `${method}${type}`; 880 | Object.defineProperty(LazyIterator.prototype, fnName, { 881 | value: { 882 | // eslint-disable-next-line func-names 883 | [fnName]: function (a1) { 884 | return this[method](a1, consFunctions[type], extendFunctions[type]); 885 | } 886 | }[fnName], 887 | writable: true, 888 | enumerable: false, 889 | configurable: true 890 | }); 891 | } 892 | } 893 | 894 | class StepIterator extends LazyIterator { 895 | constructor(iterator, stepSize) { 896 | super(iterator); 897 | this.stepSize = stepSize; 898 | } 899 | 900 | next() { 901 | const item = this.iterator.next(); 902 | for (let i = 0; i < this.stepSize - 1; i++) { 903 | this.iterator.next(); 904 | } 905 | 906 | return item; 907 | } 908 | } 909 | 910 | class SkipIterator extends LazyIterator { 911 | constructor(iterator, skipAmount) { 912 | super(iterator); 913 | this.skipAmount = skipAmount; 914 | } 915 | 916 | next() { 917 | if (this.skipAmount !== 0) { 918 | this.skipAmount--; 919 | this.iterator.next(); 920 | return this.next(); 921 | } 922 | 923 | return this.iterator.next(); 924 | } 925 | } 926 | 927 | class TakeIterator extends LazyIterator { 928 | constructor(iterator, takeAmount) { 929 | super(iterator); 930 | this.takeAmount = takeAmount; 931 | } 932 | 933 | next() { 934 | if (this.takeAmount !== 0) { 935 | this.takeAmount--; 936 | return this.iterator.next(); 937 | } 938 | 939 | return { done: true }; 940 | } 941 | } 942 | 943 | class SkipWhileIterator extends LazyIterator { 944 | constructor(iterator, fn) { 945 | super(iterator); 946 | this.fn = fn; 947 | this.finishedSkipping = false; 948 | } 949 | 950 | next() { 951 | if (!this.finishedSkipping) { 952 | const item = this.iterator.next(); 953 | if (item.done) { 954 | return { done: true }; 955 | } 956 | 957 | if (!this.fn(item.value)) { 958 | this.finishedSkipping = true; 959 | return { done: false, value: item.value }; 960 | } 961 | 962 | return this.next(); 963 | } 964 | 965 | return this.iterator.next(); 966 | } 967 | } 968 | 969 | class TakeWhileIterator extends LazyIterator { 970 | constructor(iterator, fn) { 971 | super(iterator); 972 | this.fn = fn; 973 | this.finishedTaking = false; 974 | } 975 | 976 | next() { 977 | if (!this.finishedTaking) { 978 | const item = this.iterator.next(); 979 | if (item.done) { 980 | return { done: true }; 981 | } 982 | 983 | if (!this.fn(item.value)) { 984 | this.finishedTaking = true; 985 | return { done: true }; 986 | } 987 | 988 | return { done: false, value: item.value }; 989 | } 990 | 991 | return { done: true }; 992 | } 993 | } 994 | 995 | class ChunkIterator extends LazyIterator { 996 | constructor(iterator, chunkSize) { 997 | super(iterator); 998 | this.chunkSize = chunkSize; 999 | } 1000 | 1001 | next() { 1002 | const values = []; 1003 | for (let i = 0; i < this.chunkSize; i++) { 1004 | const item = this.iterator.next(); 1005 | if (!item.done) { 1006 | values.push(item.value); 1007 | } 1008 | } 1009 | 1010 | if (!values.length) { 1011 | return { done: true }; 1012 | } 1013 | 1014 | return { done: false, value: values }; 1015 | } 1016 | } 1017 | 1018 | class EnumerateIterator extends LazyIterator { 1019 | constructor(iterator) { 1020 | super(iterator); 1021 | this.index = 0; 1022 | } 1023 | 1024 | next() { 1025 | const item = this.iterator.next(); 1026 | if (item.done) { 1027 | return { done: true }; 1028 | } 1029 | 1030 | return { done: false, value: [this.index++, item.value] }; 1031 | } 1032 | } 1033 | 1034 | class ConcatIterator extends LazyIterator { 1035 | constructor(iterator, concatIterators) { 1036 | super(iterator); 1037 | this.concatIterators = concatIterators; 1038 | this.currentIterator = this.iterator; 1039 | } 1040 | 1041 | next() { 1042 | const item = this.currentIterator.next(); 1043 | if (item.done) { 1044 | if (!this.concatIterators.length) { 1045 | return { done: true }; 1046 | } 1047 | 1048 | this.currentIterator = this.concatIterators.shift(); 1049 | return this.next(); 1050 | } 1051 | 1052 | return item; 1053 | } 1054 | } 1055 | 1056 | class CycleIterator extends LazyIterator { 1057 | constructor(iterator) { 1058 | super(iterator); 1059 | this.cache = []; 1060 | this.cachedAll = false; 1061 | } 1062 | 1063 | next() { 1064 | const item = this.iterator.next(); 1065 | if (item.done) { 1066 | this.iterator = new LazyIterator(this.cache[Symbol.iterator]()); 1067 | this.cachedAll = true; 1068 | return this.next(); 1069 | } 1070 | 1071 | if (!this.cachedAll) { 1072 | this.cache.push(item.value); 1073 | } 1074 | 1075 | return item; 1076 | } 1077 | } 1078 | 1079 | class MapIterator extends LazyIterator { 1080 | constructor(iterator, fn) { 1081 | super(iterator); 1082 | this.fn = fn; 1083 | } 1084 | 1085 | next() { 1086 | const item = this.iterator.next(); 1087 | return item.done 1088 | ? { done: true } 1089 | : { done: false, value: this.fn(item.value) }; 1090 | } 1091 | } 1092 | 1093 | class FilterIterator extends LazyIterator { 1094 | constructor(iterator, fn) { 1095 | super(iterator); 1096 | this.fn = fn; 1097 | } 1098 | 1099 | next() { 1100 | const item = this.iterator.next(); 1101 | return item.done 1102 | ? { done: true } 1103 | : this.fn(item.value) 1104 | ? { done: false, value: item.value } 1105 | : this.next(); 1106 | } 1107 | } 1108 | 1109 | class ScanIterator extends LazyIterator { 1110 | constructor(iterator, fn, accum) { 1111 | super(iterator); 1112 | this.fn = fn; 1113 | this.accum = accum; 1114 | this.yieldedStart = false; 1115 | } 1116 | 1117 | next() { 1118 | if (!this.yieldedStart) { 1119 | if (this.accum !== undefined) { 1120 | this.yieldedStart = true; 1121 | return { done: false, value: this.accum }; 1122 | } 1123 | 1124 | const item = this.iterator.next(); 1125 | if (item.done) { 1126 | throw new TypeError('Scan of empty sequence with no initial value'); 1127 | } 1128 | 1129 | this.yieldedStart = true; 1130 | this.accum = item.value; 1131 | return item; 1132 | } 1133 | 1134 | const item = this.iterator.next(); 1135 | if (item.done) { 1136 | return { done: true }; 1137 | } 1138 | 1139 | this.accum = this.fn(this.accum, item.value); 1140 | return { done: false, value: this.accum }; 1141 | } 1142 | } 1143 | 1144 | class ZipIterator extends LazyIterator { 1145 | constructor(iterator, zipIterators) { 1146 | super(iterator); 1147 | this.zipIterators = zipIterators; 1148 | } 1149 | 1150 | next() { 1151 | const item = this.iterator.next(); 1152 | const zipItems = this.zipIterators.map(iter => iter.next()); 1153 | return item.done || zipItems.some(nz => nz.done) 1154 | ? { done: true } 1155 | : { done: false, value: [item.value, ...zipItems.map(zipItem => zipItem.value)] }; 1156 | } 1157 | } 1158 | 1159 | class FlatIterator extends LazyIterator { 1160 | constructor(iterator, depth) { 1161 | super(iterator); 1162 | this.depth = depth; 1163 | this.flatIterator = null; 1164 | } 1165 | 1166 | next() { 1167 | if (this.flatIterator) { 1168 | const item = this.flatIterator.next(); 1169 | if (item.done) { 1170 | this.flatIterator = null; 1171 | return this.next(); 1172 | } 1173 | 1174 | return item; 1175 | } 1176 | 1177 | const item = this.iterator.next(); 1178 | if (item.done) { 1179 | return { done: true }; 1180 | } 1181 | 1182 | if (this.depth > 0 && (LazyIterator.isIterable(item.value) || LazyIterator.isIterator(item.value))) { 1183 | this.flatIterator = new FlatIterator(LazyIterator.from(item.value), this.depth - 1); 1184 | return this.flatIterator.next(); 1185 | } 1186 | 1187 | return item; 1188 | } 1189 | } 1190 | 1191 | class FlatMapIterator extends LazyIterator { 1192 | constructor(iterator, fn) { 1193 | super(iterator); 1194 | this.fn = fn; 1195 | this.flatIterator = null; 1196 | } 1197 | 1198 | next() { 1199 | if (this.flatIterator) { 1200 | const item = this.flatIterator.next(); 1201 | if (item.done) { 1202 | this.flatIterator = null; 1203 | return this.next(); 1204 | } 1205 | 1206 | return item; 1207 | } 1208 | 1209 | const item = this.iterator.next(); 1210 | if (item.done) { 1211 | return { done: true }; 1212 | } 1213 | 1214 | const value = this.fn(item.value); 1215 | if (LazyIterator.isIterable(value) || LazyIterator.isIterator(value)) { 1216 | this.flatIterator = new FlatIterator(LazyIterator.from(value), 1); 1217 | return this.flatIterator.next(); 1218 | } 1219 | 1220 | return { done: false, value }; 1221 | } 1222 | } 1223 | 1224 | class JoinIterator extends LazyIterator { 1225 | constructor(iterator, joinValue) { 1226 | super(iterator); 1227 | this.joinValue = joinValue; 1228 | this.joinNext = false; 1229 | } 1230 | 1231 | next() { 1232 | if (this.joinNext) { 1233 | this.joinNext = false; 1234 | return { done: false, value: this.joinValue }; 1235 | } 1236 | 1237 | const item = this.iterator.next(); 1238 | if (item.done) { 1239 | return { done: true }; 1240 | } 1241 | 1242 | if (!this.iterator.peek().done) { 1243 | this.joinNext = true; 1244 | } 1245 | 1246 | return item; 1247 | } 1248 | } 1249 | 1250 | class JoinWithIterator extends LazyIterator { 1251 | constructor(iterator, joinWithIterator) { 1252 | super(iterator); 1253 | this.joinWithIterator = joinWithIterator; 1254 | this.joinNext = false; 1255 | this.cache = []; 1256 | this.cachedAll = false; 1257 | } 1258 | 1259 | next() { 1260 | if (this.joinNext) { 1261 | const item = this.joinWithIterator.next(); 1262 | if (item.done) { 1263 | this.joinWithIterator = new LazyIterator(this.cache[Symbol.iterator]()); 1264 | this.joinNext = false; 1265 | this.cachedAll = true; 1266 | return this.next(); 1267 | } 1268 | 1269 | if (!this.cachedAll) { 1270 | this.cache.push(item.value); 1271 | } 1272 | 1273 | return item; 1274 | } 1275 | 1276 | const item = this.iterator.next(); 1277 | if (item.done) { 1278 | return { done: true }; 1279 | } 1280 | 1281 | if (!this.iterator.peek().done) { 1282 | this.joinNext = true; 1283 | } 1284 | 1285 | return item; 1286 | } 1287 | } 1288 | 1289 | class EachIterator extends LazyIterator { 1290 | constructor(iterator, fn) { 1291 | super(iterator); 1292 | this.fn = fn; 1293 | } 1294 | 1295 | next() { 1296 | const item = this.iterator.next(); 1297 | if (!item.done) { 1298 | this.fn(item.value); 1299 | } 1300 | 1301 | return item; 1302 | } 1303 | } 1304 | 1305 | module.exports = LazyIterator; 1306 | 1307 | /** 1308 | * @callback Mapping 1309 | * @param {any} item Item to map. 1310 | * @returns {any} Mapped item. 1311 | */ 1312 | 1313 | /** 1314 | * @callback Predicate 1315 | * @param {any} item Item to check. 1316 | * @returns {boolean} Whether or not the item passed. 1317 | */ 1318 | 1319 | /** 1320 | * @callback Consumer 1321 | * @param {any} item Item to use. 1322 | * @returns {void} Nothing. 1323 | */ 1324 | 1325 | /** 1326 | * @callback Reducer 1327 | * @param {any} accum The accumulator. 1328 | * @param {any} item The current item. 1329 | * @returns {any} The new accumulator. 1330 | */ 1331 | 1332 | /** 1333 | * @callback Comparator 1334 | * @param {any} a Item to compare. 1335 | * @param {any} b Item to compare. 1336 | * @returns {number} The ordering of the items. 1337 | */ 1338 | 1339 | /** 1340 | * @callback CollectionConstructor 1341 | * @returns {any} The empty collection. 1342 | */ 1343 | 1344 | /** 1345 | * @callback CollectionExtender 1346 | * @param {any} coll The collection. 1347 | * @param {any} item The item to add to the collection. 1348 | * @returns {any} The extended collection. 1349 | */ 1350 | 1351 | /** 1352 | * @callback Equality 1353 | * @param {any} a Item to compare. 1354 | * @param {any} b Item to compare. 1355 | * @returns {boolean} Whether the items are equal. 1356 | */ 1357 | 1358 | /** 1359 | * @callback Generating 1360 | * @returns {any} A value. 1361 | */ 1362 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./LazyIterator'); 2 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const lazy = require('..'); 3 | 4 | const equal = (a, b) => { 5 | try { 6 | assert.deepStrictEqual(a, b); 7 | return true; 8 | } catch (e) { 9 | return false; 10 | } 11 | }; 12 | 13 | const should = (desc, fn) => { 14 | if (!fn()) { 15 | throw new Error(`Test did not ${desc}`); 16 | } 17 | }; 18 | 19 | should('take in an iterable', () => { 20 | const res = lazy.from([1, 2, 3, 4]).collect(); 21 | return equal(res, [1, 2, 3, 4]); 22 | }); 23 | 24 | should('take in an iterator', () => { 25 | const res = lazy.from([1, 2, 3, 4][Symbol.iterator]()).collect(); 26 | return equal(res, [1, 2, 3, 4]); 27 | }); 28 | 29 | should('get the nth element', () => { 30 | const res = lazy.from([1, 2, 3, 4]).at(2); 31 | return res === 3; 32 | }); 33 | 34 | should('count the amount of elements', () => { 35 | const res = lazy.from([1, 2, 3, 4]).count(); 36 | return res === 4; 37 | }); 38 | 39 | should('retrieve the last element', () => { 40 | const res = lazy.from([8, 7, 6, 5]).last(); 41 | return res === 5; 42 | }); 43 | 44 | should('step by a certain interval', () => { 45 | const res = lazy.from([1, 2, 3, 4]) 46 | .stepBy(2) 47 | .collect(); 48 | return equal(res, [1, 3]); 49 | }); 50 | 51 | should('skip by a certain amount', () => { 52 | const res = lazy.from([1, 2, 3, 4]) 53 | .skip(2) 54 | .collect(); 55 | return equal(res, [3, 4]); 56 | }); 57 | 58 | should('take only a certain amount', () => { 59 | const res = lazy.from([1, 2, 3, 4]) 60 | .take(2) 61 | .collect(); 62 | return equal(res, [1, 2]); 63 | }); 64 | 65 | should('skip while a certain condition is met', () => { 66 | const res = lazy.from([1, 2, 3, 4]) 67 | .skipWhile(n => n < 3) 68 | .collect(); 69 | return equal(res, [3, 4]); 70 | }); 71 | 72 | should('take while a certain condition met', () => { 73 | const res = lazy.from([1, 2, 3, 4]) 74 | .takeWhile(n => n < 3) 75 | .collect(); 76 | return equal(res, [1, 2]); 77 | }); 78 | 79 | should('put the iterator into chunks', () => { 80 | const res = lazy.from([1, 2, 3, 4, 5, 6, 7, 8, 9]) 81 | .chunk(2) 82 | .collect(); 83 | return equal(res, [[1, 2], [3, 4], [5, 6], [7, 8], [9]]); 84 | }); 85 | 86 | should('enumerate the iterator', () => { 87 | const res = lazy.from([1, 2, 3, 4]) 88 | .enumerate() 89 | .collect(); 90 | return equal(res, [[0, 1], [1, 2], [2, 3], [3, 4]]); 91 | }); 92 | 93 | should('concatenate two iterators', () => { 94 | const res = lazy.from([1, 2, 3, 4]) 95 | .concat([5, 6, 7, 8]) 96 | .collect(); 97 | return equal(res, [1, 2, 3, 4, 5, 6, 7, 8]); 98 | }); 99 | 100 | should('cycle on forever', () => { 101 | const res = lazy.from([1, 2]) 102 | .cycle() 103 | .take(11) 104 | .collect(); 105 | return equal(res, [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1]); 106 | }); 107 | 108 | should('map each value', () => { 109 | const res = lazy.from([1, 2, 3, 4]) 110 | .map(n => n * 2) 111 | .collect(); 112 | return equal(res, [2, 4, 6, 8]); 113 | }); 114 | 115 | should('filter values based on a predicate', () => { 116 | const res = lazy.from([1, 2, 3, 4]) 117 | .filter(n => n % 2 === 0) 118 | .collect(); 119 | return equal(res, [2, 4]); 120 | }); 121 | 122 | should('do iterations holding an internal state with initial value', () => { 123 | const res = lazy.from([1, 2, 3, 4]) 124 | .scan((acc, n) => acc + n, 0) 125 | .collect(); 126 | return equal(res, [0, 1, 3, 6, 10]); 127 | }); 128 | 129 | should('do iterations holding an internal state without initial value', () => { 130 | const res = lazy.from([1, 2, 3, 4]) 131 | .scan((acc, n) => acc + n) 132 | .collect(); 133 | return equal(res, [1, 3, 6, 10]); 134 | }); 135 | 136 | should('zip multiple iterators together', () => { 137 | const res = lazy.from([1, 2, 3, 4]) 138 | .zip(['a', 'b', 'c', 'd'], [true, false, true, false]) 139 | .collect(); 140 | return equal(res, [[1, 'a', true], [2, 'b', false], [3, 'c', true], [4, 'd', false]]); 141 | }); 142 | 143 | should('flatten with depth of infinity', () => { 144 | const res = lazy.from([[1, 2], 3, [4], [5, [6, 7], 8, [[9], 10], 11], [12, 13, 14], 15]) 145 | .flat(Infinity) 146 | .collect(); 147 | return equal(res, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); 148 | }); 149 | 150 | should('flatten with depth of 1', () => { 151 | const res = lazy.from([[1, 2], [3, 4], [[5, 6, 7, 8]], 9, 10]) 152 | .flat(1) 153 | .collect(); 154 | return equal(res, [1, 2, 3, 4, [5, 6, 7, 8], 9, 10]); 155 | }); 156 | 157 | should('flatten with depth of 2', () => { 158 | const res = lazy.from([[1, 2], [3, 4], [[5, 6, 7, 8]], 9, 10]) 159 | .flat(2) 160 | .collect(); 161 | return equal(res, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 162 | }); 163 | 164 | should('flatten values mapped into iterators', () => { 165 | const res = lazy.from([3, 4, 5]) 166 | .flatMap(n => lazy.range(1, 4).map(i => n * i)) 167 | .collect(); 168 | return equal(res, [3, 6, 9, 4, 8, 12, 5, 10, 15]); 169 | }); 170 | 171 | should('join the iterator with some value', () => { 172 | const res = lazy.from([1, 2, 3, 4]) 173 | .join(5) 174 | .collect(); 175 | return equal(res, [1, 5, 2, 5, 3, 5, 4]); 176 | }); 177 | 178 | should('join the iterator with another iterator', () => { 179 | const res = lazy.from([1, 2, 3, 4]) 180 | .joinWith([5, 6]) 181 | .collect(); 182 | return equal(res, [1, 5, 6, 2, 5, 6, 3, 5, 6, 4]); 183 | }); 184 | 185 | should('call a function for each element', () => { 186 | let count1 = 0; 187 | let count2 = 0; 188 | lazy.from([1, 2, 3, 4]).each(() => count1++).forEach(() => count2++); 189 | return count1 === count2 && count1 === 4; 190 | }); 191 | 192 | should('reduce without an initial value', () => { 193 | const res = lazy.from([1, 2, 3, 4]).reduce((acc, n) => acc + n); 194 | return res === 10; 195 | }); 196 | 197 | should('reduce with an initial value', () => { 198 | const res = lazy.from([1, 2, 3, 4]).reduce((acc, n) => acc + n, 5); 199 | return res === 15; 200 | }); 201 | 202 | should('error when reducing empty iterator without initial value', () => { 203 | try { 204 | lazy.from([]).reduce((acc, n) => acc + n); 205 | return false; 206 | } catch (e) { 207 | return /^Reduce of empty sequence with no initial value$/.test(e.message); 208 | } 209 | }); 210 | 211 | should('take the conjuction of an iterator', () => { 212 | const res = lazy.from([true, true, true]).and(); 213 | return res; 214 | }); 215 | 216 | should('take the disjunction of an iterator', () => { 217 | const res = lazy.from([true, false, true]).or(); 218 | return res; 219 | }); 220 | 221 | should('take the sum of an iterator', () => { 222 | const res = lazy.from([1, 2, 3, 4]).sum(); 223 | return res === 10; 224 | }); 225 | 226 | should('take the product of an iterator', () => { 227 | const res = lazy.from([1, 2, 3, 4]).product(); 228 | return res === 24; 229 | }); 230 | 231 | should('find a value in the iterator', () => { 232 | const res = lazy.from([1, 2, 3, 4]).find(n => n * 2 === 8); 233 | return res === 4; 234 | }); 235 | 236 | should('not find a value in the iterator', () => { 237 | const res = lazy.from([1, 2, 3, 4]).find(n => n * 2 === 9); 238 | return res === undefined; 239 | }); 240 | 241 | should('find an index in the iterator', () => { 242 | const res = lazy.from([1, 2, 3, 4]).findIndex(n => n * 2 === 8); 243 | return res === 3; 244 | }); 245 | 246 | should('not find an index in the iterator', () => { 247 | const res = lazy.from([1, 2, 3, 4]).findIndex(n => n * 2 === 9); 248 | return res === -1; 249 | }); 250 | 251 | should('check if the iterator includes a value', () => { 252 | const res = lazy.from([1, 2, 3, 4, 5]).includes(3); 253 | return res; 254 | }); 255 | 256 | should('check if the iterator includes a value from some index', () => { 257 | const res1 = lazy.from([1, 2, 3, 4, 5]).includes(3, 2); 258 | const res2 = lazy.from([1, 2, 3, 4, 5]).includes(3, 3); 259 | return res1 && !res2; 260 | }); 261 | 262 | should('check every element passes a predicate', () => { 263 | const res = lazy.from([2, 4, 6, 8]).every(n => n % 2 === 0); 264 | return res; 265 | }); 266 | 267 | should('check some element passes a predicate', () => { 268 | const res = lazy.from([3, 5, 6, 9]).some(n => n % 2 === 0); 269 | return res; 270 | }); 271 | 272 | should('find the maximum value', () => { 273 | const res = lazy.from([1, 2, 3, 4]).max(); 274 | return res === 4; 275 | }); 276 | 277 | should('find the minimum value', () => { 278 | const res = lazy.from([1, 2, 3, 4]).min(); 279 | return res === 1; 280 | }); 281 | 282 | should('find the maximum value by some key', () => { 283 | const res = lazy.from([1, 2, -3, -4]).max(n => Math.abs(n)); 284 | return res === -4; 285 | }); 286 | 287 | should('find the minimum value by some key', () => { 288 | const res = lazy.from([1, 2, -3, -4]).min(n => Math.abs(n)); 289 | return res === 1; 290 | }); 291 | 292 | should('find the maximum value by a comparator', () => { 293 | const res = lazy.from(['a', 'B', 'c', 'D']).maxBy((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())); 294 | return res === 'D'; 295 | }); 296 | 297 | should('find the minimum value by a comparator', () => { 298 | const res = lazy.from(['A', 'b', 'C', 'd']).minBy((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())); 299 | return res === 'A'; 300 | }); 301 | 302 | should('collect into a Set', () => { 303 | const res = lazy.from([1, 1, 2, 2, 3, 3]).collectSet(); 304 | return equal(res, new Set([1, 2, 3])); 305 | }); 306 | 307 | should('collect into a Map', () => { 308 | const res = lazy.from([[1, 1], [2, 2], [3, 3]]).collectMap(); 309 | return equal(res, new Map([[1, 1], [2, 2], [3, 3]])); 310 | }); 311 | 312 | should('collect into a string', () => { 313 | const res = lazy.from('abcd').collectString(); 314 | return res === 'abcd'; 315 | }); 316 | 317 | should('partition the iterator by a predicate', () => { 318 | const res = lazy.from([1, 2, 3, 4]).partition(n => n % 2 === 0); 319 | return equal(res, [[2, 4], [1, 3]]); 320 | }); 321 | 322 | should('unzip an iterator of tuples', () => { 323 | const res = lazy.from(['a', 'b', 'c', 'd']) 324 | .zip([1, 2, 3, 4], [5, 6, 7, 8]) 325 | .unzip(); 326 | return equal(res, [['a', 'b', 'c', 'd'], [1, 2, 3, 4], [5, 6, 7, 8]]); 327 | }); 328 | 329 | should('group consecutive equal elements', () => { 330 | const res = lazy.from([1, 1, 2, 2, 3, 1, 1, 1, 2, 2, 3]).group(); 331 | return equal(res, [[1, 1], [2, 2], [3], [1, 1, 1], [2, 2], [3]]); 332 | }); 333 | 334 | should('categorize elements by some criteria', () => { 335 | const res = lazy.from(['a', 'A', 'b', 'B', 'c', 'C']).categorize(c => c.toUpperCase()); 336 | return equal(res, new Map([ 337 | ['A', ['a', 'A']], 338 | ['B', ['b', 'B']], 339 | ['C', ['c', 'C']] 340 | ])); 341 | }); 342 | 343 | should('clone an iterator', () => { 344 | const iterator = lazy.from([1, 2, 3, 4]); 345 | iterator.next(); 346 | const clone = iterator.clone(); 347 | const res1 = iterator.collect(); 348 | const res2 = clone.collect(); 349 | return equal(res1, res2) && equal(res1, [2, 3, 4]); 350 | }); 351 | 352 | should('generate an exclusive range', () => { 353 | const res = lazy.range(1, 5).collect(); 354 | return equal(res, [1, 2, 3, 4]); 355 | }); 356 | 357 | should('generate an inclusive range', () => { 358 | const res = lazy.range(1, 5, 1, true).collect(); 359 | return equal(res, [1, 2, 3, 4, 5]); 360 | }); 361 | 362 | should('generate an inclusive range with a step', () => { 363 | const res = lazy.range(1, 5, 2, true).collect(); 364 | return equal(res, [1, 3, 5]); 365 | }); 366 | 367 | should('repeat an item forever', () => { 368 | const res = lazy.repeat(1) 369 | .take(5) 370 | .collect(); 371 | return equal(res, [1, 1, 1, 1, 1]); 372 | }); 373 | 374 | should('iterate only once', () => { 375 | let count = 0; 376 | const makeIterator = () => { 377 | const arr = [1, 2, 3, 4]; 378 | let index = 0; 379 | return { 380 | next: () => { 381 | count++; 382 | return { 383 | value: arr[index++], 384 | done: index - 1 === arr.length 385 | }; 386 | } 387 | }; 388 | }; 389 | 390 | lazy.from(makeIterator()) 391 | .map(n => n * 2) 392 | .filter(n => n > 2) 393 | .collect(); 394 | return count === 5; 395 | }); 396 | 397 | should('generate the fibonacci sequence', () => { 398 | const res = lazy.range() 399 | .scan(([a, b]) => [b, a + b], [0, 1]) 400 | .map(([a]) => a) 401 | .take(10) 402 | .collect(); 403 | return equal(res, [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]); 404 | }); 405 | --------------------------------------------------------------------------------