├── .eslintrc.js ├── .github └── workflows │ ├── codacy-coverage-reporter.yml │ ├── main.yml │ └── size.yml ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── async.ts ├── index.ts ├── sync.ts └── utils │ ├── index.ts │ ├── isAsyncIterable.ts │ └── isIterable.ts ├── test ├── async.test.ts └── sync.test.ts └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": [ 3 | "react-app", 4 | "prettier/@typescript-eslint", 5 | "plugin:prettier/recommended" 6 | ], 7 | "settings": { 8 | "react": { 9 | "version": "999.999.999" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.github/workflows/codacy-coverage-reporter.yml: -------------------------------------------------------------------------------- 1 | name: codacy-coverage-reporter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | codacy-coverage-reporter: 9 | runs-on: ubuntu-latest 10 | name: codacy-coverage-reporter 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Install deps and build (with cache) 14 | uses: bahmutov/npm-install@v1 15 | - run: npm run coverage 16 | - name: Run codacy-coverage-reporter 17 | uses: codacy/codacy-coverage-reporter-action@v1 18 | with: 19 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} 6 | 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | node: ['10.x', '12.x', '14.x'] 11 | os: [ubuntu-latest, windows-latest, macOS-latest] 12 | 13 | steps: 14 | - name: Checkout repo 15 | uses: actions/checkout@v2 16 | 17 | - name: Use Node ${{ matrix.node }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node }} 21 | 22 | - name: Install deps and build (with cache) 23 | uses: bahmutov/npm-install@v1 24 | 25 | - name: Lint 26 | run: npm run lint 27 | 28 | - name: Test 29 | run: npm run test --ci --coverage --maxWorkers=2 30 | 31 | - name: Build 32 | run: npm run build 33 | -------------------------------------------------------------------------------- /.github/workflows/size.yml: -------------------------------------------------------------------------------- 1 | name: size 2 | on: [pull_request] 3 | jobs: 4 | size: 5 | runs-on: ubuntu-latest 6 | env: 7 | CI_JOB_NUMBER: 1 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: andresz1/size-limit-action@v1 11 | with: 12 | github_token: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | dist 5 | .vscode 6 | coverage -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Umut Özdemir 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # split-lazy 🗡🦥 2 | 3 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/ae3028bdccea48bf9a7b05ed91284fbd)](https://www.codacy.com/gh/miyavsu-limited/split-lazy/dashboard?utm_source=github.com&utm_medium=referral&utm_content=miyavsu-limited/split-lazy&utm_campaign=Badge_Grade) 4 | ![Codacy coverage](https://img.shields.io/codacy/coverage/ae3028bdccea48bf9a7b05ed91284fbd) 5 | ![npm bundle size](https://img.shields.io/bundlephobia/minzip/split-lazy) 6 | 7 | This package provides ways to split arrays, strings or other iterables (sync and async) lazily. It returns an iterable that calculates the result lazily (while iterating on it). 8 | 9 | [👉 Learn more about iterators here.][iterators] 10 | 11 | ## Installing 12 | 13 | Use `yarn` or `npm` to install it. 14 | 15 | ``` 16 | npm install split-lazy 17 | ``` 18 | 19 | ## `splitLazy` 20 | 21 | ```ts 22 | function splitLazy>( 23 | iterable: T, 24 | separator: unknown 25 | ): Generator 26 | ``` 27 | 28 | First argument is iterable to search inside and split. Second argument is either an iterable or an element to look for in the given first argument. 29 | 30 | `separator` can be an `Iterable` or anything else as an element. If separator is an iterable, it will be searched as a sub iterator. 31 | 32 | ### Examples 33 | 34 | ```ts 35 | import { splitLazy } from "split-lazy"; 36 | 37 | const arr = [1, 3, 5, 7, 9]; 38 | const result = splitLazy(arr, 5); 39 | 40 | for (const item of result) { 41 | console.log(item); 42 | } 43 | // outputs: 44 | // [1, 3] 45 | // [7, 9] 46 | ``` 47 | 48 | ```ts 49 | import { splitLazy } from "split-lazy"; 50 | 51 | const arr = [1, 3, 5, 7, 9]; 52 | const iterable = splitLazy(arr, 5); 53 | 54 | expect(iterable.next().value).toEqual([1, 3]); // ✅ 55 | expect(iterable.next().value).toEqual([7, 9]); // ✅ 56 | ``` 57 | 58 | ```ts 59 | import { splitLazy } from "split-lazy"; 60 | 61 | function* generator() { 62 | yield 1; 63 | yield 3; 64 | yield 5; 65 | yield 7; 66 | yield 9; 67 | } 68 | 69 | const iterable = generator(); 70 | const result = splitLazy(iterable, 5); 71 | 72 | for (const item of result) { 73 | console.log(item); 74 | } 75 | // outputs: 76 | // [1, 3] 77 | // [7, 9] 78 | ``` 79 | 80 | It can also search for sub-iterables in iterables: 81 | 82 | ```ts 83 | import { splitLazy } from "split-lazy"; 84 | 85 | const arr = [1, 3, 5, 7, 9, 11]; 86 | const iterable = splitLazy(arr, [5, 7]); 87 | 88 | expect(iterable.next().value).toEqual([1, 3]); // ✅ 89 | expect(iterable.next().value).toEqual([9, 11]); // ✅ 90 | ``` 91 | 92 | ## `asyncSplitLazy` 93 | 94 | ```ts 95 | async function* asyncSplitLazy>( 96 | iterable: T, 97 | separator: unknown 98 | ): AsyncGenerator 99 | ``` 100 | 101 | Iterable can be an `AsyncIterable`. Separator can be an `Iterable`, `AsyncIterable` or anything else as an element. If `separator` is an iterable, it will be searched as a sub iterator. 102 | 103 | Note that if `separator` argument is an `AsyncIterable`, `asyncSplitLazy` fully iterates the given separator before it starts searching for it in the first argument (`iterable`). 104 | 105 | ## Contributing 106 | 107 | Help is needed for documentation in general. Adding/improving TSDoc, a better README, added/improved reference would be amazing 💫. Please open/find an issue to discuss. 108 | 109 | ## Tests 110 | 111 | Jest tests are set up to run with `npm test`. 112 | 113 | [iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators 114 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.3", 3 | "license": "MIT", 4 | "main": "dist/index.js", 5 | "typings": "dist/index.d.ts", 6 | "files": [ 7 | "dist", 8 | "src" 9 | ], 10 | "engines": { 11 | "node": ">=10" 12 | }, 13 | "scripts": { 14 | "start": "tsdx watch", 15 | "build": "tsdx build", 16 | "test": "tsdx test", 17 | "lint": "tsdx lint", 18 | "prepare": "tsdx build", 19 | "size": "size-limit", 20 | "analyze": "size-limit --why", 21 | "coverage": "tsdx test --coverage" 22 | }, 23 | "peerDependencies": {}, 24 | "husky": { 25 | "hooks": { 26 | "pre-commit": "tsdx lint" 27 | } 28 | }, 29 | "prettier": { 30 | "printWidth": 80, 31 | "semi": true, 32 | "singleQuote": true, 33 | "trailingComma": "es5" 34 | }, 35 | "name": "split-lazy", 36 | "author": "Umut Özdemir", 37 | "module": "dist/split-lazy.esm.js", 38 | "size-limit": [ 39 | { 40 | "path": "dist/split-lazy.cjs.production.min.js", 41 | "limit": "10 KB" 42 | }, 43 | { 44 | "path": "dist/split-lazy.esm.js", 45 | "limit": "10 KB" 46 | } 47 | ], 48 | "devDependencies": { 49 | "@size-limit/preset-small-lib": "^7.0.3", 50 | "husky": "^7.0.4", 51 | "size-limit": "^7.0.4", 52 | "tsdx": "^0.14.1", 53 | "tslib": "^2.3.1", 54 | "typescript": "^4.5.3" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/async.ts: -------------------------------------------------------------------------------- 1 | import { isAsyncIterable, isIterable } from './utils'; 2 | 3 | export async function* asyncSplitLazyWithSeparator< 4 | I, 5 | T extends AsyncIterable 6 | >(iterable: T, separator: I) { 7 | let yieldNext: I[] = []; 8 | 9 | for await (const item of iterable) { 10 | if (item === separator) { 11 | yield yieldNext; 12 | yieldNext = []; 13 | } else { 14 | yieldNext.push(item); 15 | } 16 | } 17 | 18 | yield yieldNext; 19 | } 20 | 21 | export async function* asyncSplitLazyWithSubIterator< 22 | I, 23 | T extends AsyncIterable 24 | >(iterable: T, subIterable: Iterable | AsyncIterable) { 25 | let yieldNext: I[] = []; 26 | let subIterableItems = []; 27 | 28 | if (isAsyncIterable(subIterable) || isIterable(subIterable)) { 29 | for await (const item of subIterable) { 30 | subIterableItems.push(item); 31 | } 32 | } 33 | 34 | let foundSubIterator = 0; 35 | 36 | for await (const item of iterable) { 37 | if (item === subIterableItems[foundSubIterator]) { 38 | if (subIterableItems.length - 1 === foundSubIterator) { 39 | yield yieldNext; 40 | yieldNext = []; 41 | foundSubIterator = 0; 42 | } else { 43 | foundSubIterator++; 44 | } 45 | } else { 46 | if (foundSubIterator > 0) { 47 | yieldNext = yieldNext.concat( 48 | subIterableItems.slice(0, foundSubIterator) as ConcatArray 49 | ); 50 | 51 | foundSubIterator = 0; 52 | } 53 | 54 | yieldNext.push(item); 55 | } 56 | } 57 | 58 | yield yieldNext; 59 | } 60 | 61 | export async function* asyncSplitLazy>( 62 | iterable: T, 63 | separator: unknown 64 | ): AsyncGenerator { 65 | if (isAsyncIterable(separator) || isIterable(separator)) { 66 | for await (const value of asyncSplitLazyWithSubIterator( 67 | iterable, 68 | separator 69 | )) { 70 | yield value as I[]; 71 | } 72 | } else { 73 | for await (const value of asyncSplitLazyWithSeparator( 74 | iterable, 75 | separator 76 | )) { 77 | yield value as I[]; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './async'; 2 | export * from './sync'; 3 | -------------------------------------------------------------------------------- /src/sync.ts: -------------------------------------------------------------------------------- 1 | import { isIterable } from './utils'; 2 | 3 | export function* joinAll(iterable: Iterable) { 4 | for (const el of iterable) { 5 | yield el.join(''); 6 | } 7 | } 8 | 9 | export function* splitLazyWithSeparator>( 10 | iterable: T, 11 | separator: unknown 12 | ): Generator { 13 | let yieldNext: I[] = []; 14 | 15 | for (const item of iterable) { 16 | if (item === separator) { 17 | yield yieldNext; 18 | yieldNext = []; 19 | } else { 20 | yieldNext.push(item); 21 | } 22 | } 23 | 24 | yield yieldNext; 25 | } 26 | 27 | export function* splitLazyWithSubIterator>( 28 | iterable: T, 29 | subIterable: Iterable 30 | ): Generator { 31 | let yieldNext: I[] = []; 32 | let subIterableItems = Array.from(subIterable); 33 | let foundSubIterator = 0; 34 | 35 | for (const item of iterable) { 36 | if (item === subIterableItems[foundSubIterator]) { 37 | if (subIterableItems.length - 1 === foundSubIterator) { 38 | yield yieldNext; 39 | yieldNext = []; 40 | foundSubIterator = 0; 41 | } else { 42 | foundSubIterator++; 43 | } 44 | } else { 45 | if (foundSubIterator > 0) { 46 | yieldNext = yieldNext.concat( 47 | subIterableItems.slice(0, foundSubIterator) as ConcatArray // we are sure this is correct 48 | ); 49 | 50 | foundSubIterator = 0; 51 | } 52 | 53 | yieldNext.push(item); 54 | } 55 | } 56 | 57 | yield yieldNext; 58 | } 59 | 60 | export function splitLazy>( 61 | iterable: T, 62 | separator: unknown 63 | ): Generator { 64 | if (isIterable(separator)) { 65 | return splitLazyWithSubIterator(iterable, separator); 66 | } else { 67 | return splitLazyWithSeparator(iterable, separator); 68 | } 69 | } 70 | 71 | export function splitLazyString(iterable: string, separator: string) { 72 | return joinAll( 73 | splitLazyWithSubIterator(iterable, separator) as Generator< 74 | string[], 75 | void, 76 | void 77 | > 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './isIterable'; 2 | export * from './isAsyncIterable'; 3 | -------------------------------------------------------------------------------- /src/utils/isAsyncIterable.ts: -------------------------------------------------------------------------------- 1 | export const isAsyncIterable = ( 2 | value: any 3 | ): value is AsyncIterable => { 4 | return Symbol.asyncIterator in Object(value); 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/isIterable.ts: -------------------------------------------------------------------------------- 1 | export const isIterable = ( 2 | value: any 3 | ): value is Iterable => { 4 | return Symbol.iterator in Object(value); 5 | }; 6 | -------------------------------------------------------------------------------- /test/async.test.ts: -------------------------------------------------------------------------------- 1 | import { asyncSplitLazy } from '../src'; 2 | 3 | async function* dummyGenerator() { 4 | yield 1; 5 | yield 3; 6 | yield 5; 7 | yield 7; 8 | yield 9; 9 | yield 11; 10 | yield 5; 11 | yield 7; 12 | yield 13; 13 | yield 7; 14 | yield 9; 15 | } 16 | 17 | describe('ASYNC', () => { 18 | describe('splitting an async iterator', () => { 19 | it('should yield with array of splitted items correctly', async () => { 20 | const iterable = dummyGenerator(); 21 | const result = asyncSplitLazy(iterable, 5); 22 | 23 | expect((await result.next()).value).toEqual([1, 3]); 24 | expect((await result.next()).value).toEqual([7, 9, 11]); 25 | expect((await result.next()).value).toEqual([7, 13, 7, 9]); 26 | expect((await result.next()).value).toEqual(undefined); 27 | }); 28 | 29 | it('should yield empty array first if given separator is found in the beginning of iterable', async () => { 30 | const iterable = dummyGenerator(); 31 | const result = asyncSplitLazy(iterable, 1); 32 | 33 | expect((await result.next()).value).toEqual([]); 34 | expect((await result.next()).value).toEqual([ 35 | 3, 36 | 5, 37 | 7, 38 | 9, 39 | 11, 40 | 5, 41 | 7, 42 | 13, 43 | 7, 44 | 9, 45 | ]); 46 | expect((await result.next()).value).toEqual(undefined); 47 | }); 48 | 49 | it('should yield empty array last if given separator is found in the end of iterable', async () => { 50 | const iterable = dummyGenerator(); 51 | const result = asyncSplitLazy(iterable, 9); 52 | 53 | expect((await result.next()).value).toEqual([1, 3, 5, 7]); 54 | expect((await result.next()).value).toEqual([11, 5, 7, 13, 7]); 55 | expect((await result.next()).value).toEqual([]); 56 | expect((await result.next()).value).toEqual(undefined); 57 | }); 58 | 59 | it('should yield all elements if found nothing', async () => { 60 | const iterable = dummyGenerator(); 61 | const result = asyncSplitLazy(iterable, 0); 62 | 63 | expect((await result.next()).value).toEqual([ 64 | 1, 65 | 3, 66 | 5, 67 | 7, 68 | 9, 69 | 11, 70 | 5, 71 | 7, 72 | 13, 73 | 7, 74 | 9, 75 | ]); 76 | expect((await result.next()).value).toEqual(undefined); 77 | }); 78 | }); 79 | 80 | describe('splitting an async iterator with sub array', () => { 81 | it('should yield with array of splitted items correctly', async () => { 82 | const iterable = dummyGenerator(); 83 | const result = asyncSplitLazy(iterable, [5, 7]); 84 | 85 | expect((await result.next()).value).toEqual([1, 3]); 86 | expect((await result.next()).value).toEqual([9, 11]); 87 | expect((await result.next()).value).toEqual([13, 7, 9]); 88 | expect((await result.next()).value).toEqual(undefined); 89 | }); 90 | 91 | it('should yield empty array first if given separator is found in the beginning of iterable', async () => { 92 | const iterable = dummyGenerator(); 93 | const result = asyncSplitLazy(iterable, [1, 3]); 94 | 95 | expect((await result.next()).value).toEqual([]); 96 | expect((await result.next()).value).toEqual([ 97 | 5, 98 | 7, 99 | 9, 100 | 11, 101 | 5, 102 | 7, 103 | 13, 104 | 7, 105 | 9, 106 | ]); 107 | expect((await result.next()).value).toEqual(undefined); 108 | }); 109 | 110 | it('should yield empty array last if given separator is found in the end of iterable', async () => { 111 | const iterable = dummyGenerator(); 112 | const result = asyncSplitLazy(iterable, [7, 9]); 113 | 114 | expect((await result.next()).value).toEqual([1, 3, 5]); 115 | expect((await result.next()).value).toEqual([11, 5, 7, 13]); 116 | expect((await result.next()).value).toEqual([]); 117 | expect((await result.next()).value).toEqual(undefined); 118 | }); 119 | 120 | it('should yield all elements if found nothing', async () => { 121 | const iterable = dummyGenerator(); 122 | const result = asyncSplitLazy(iterable, [0]); 123 | 124 | expect((await result.next()).value).toEqual([ 125 | 1, 126 | 3, 127 | 5, 128 | 7, 129 | 9, 130 | 11, 131 | 5, 132 | 7, 133 | 13, 134 | 7, 135 | 9, 136 | ]); 137 | expect((await result.next()).value).toEqual(undefined); 138 | }); 139 | }); 140 | 141 | describe('splitting an async iterator with async sub iterator', () => { 142 | it('should yield with array of splitted items correctly', async () => { 143 | async function* separatorGenerator() { 144 | yield 5; 145 | yield 7; 146 | } 147 | 148 | const iterable = dummyGenerator(); 149 | const separator = separatorGenerator(); 150 | const result = asyncSplitLazy(iterable, separator); 151 | 152 | expect((await result.next()).value).toEqual([1, 3]); 153 | expect((await result.next()).value).toEqual([9, 11]); 154 | expect((await result.next()).value).toEqual([13, 7, 9]); 155 | expect((await result.next()).value).toEqual(undefined); 156 | }); 157 | 158 | it('should yield empty array first if given separator is found in the beginning of iterable', async () => { 159 | async function* separatorGenerator() { 160 | yield 1; 161 | yield 3; 162 | } 163 | 164 | const iterable = dummyGenerator(); 165 | const separator = separatorGenerator(); 166 | const result = asyncSplitLazy(iterable, separator); 167 | 168 | expect((await result.next()).value).toEqual([]); 169 | expect((await result.next()).value).toEqual([ 170 | 5, 171 | 7, 172 | 9, 173 | 11, 174 | 5, 175 | 7, 176 | 13, 177 | 7, 178 | 9, 179 | ]); 180 | expect((await result.next()).value).toEqual(undefined); 181 | }); 182 | 183 | it('should yield empty array last if given separator is found in the end of iterable', async () => { 184 | async function* separatorGenerator() { 185 | yield 7; 186 | yield 9; 187 | } 188 | 189 | const iterable = dummyGenerator(); 190 | const separator = separatorGenerator(); 191 | const result = asyncSplitLazy(iterable, separator); 192 | 193 | expect((await result.next()).value).toEqual([1, 3, 5]); 194 | expect((await result.next()).value).toEqual([11, 5, 7, 13]); 195 | expect((await result.next()).value).toEqual([]); 196 | expect((await result.next()).value).toEqual(undefined); 197 | }); 198 | 199 | it('should yield all elements if found nothing', async () => { 200 | async function* separatorGenerator() { 201 | yield 0; 202 | } 203 | 204 | const iterable = dummyGenerator(); 205 | const separator = separatorGenerator(); 206 | const result = asyncSplitLazy(iterable, separator); 207 | 208 | expect((await result.next()).value).toEqual([ 209 | 1, 210 | 3, 211 | 5, 212 | 7, 213 | 9, 214 | 11, 215 | 5, 216 | 7, 217 | 13, 218 | 7, 219 | 9, 220 | ]); 221 | expect((await result.next()).value).toEqual(undefined); 222 | }); 223 | }); 224 | 225 | describe('splitting an async iterator with non-async sub iterator', () => { 226 | it('should yield with array of splitted items correctly', async () => { 227 | function* separatorGenerator() { 228 | yield 5; 229 | yield 7; 230 | } 231 | 232 | const iterable = dummyGenerator(); 233 | const separator = separatorGenerator(); 234 | 235 | const result = asyncSplitLazy(iterable, separator); 236 | 237 | expect((await result.next()).value).toEqual([1, 3]); 238 | expect((await result.next()).value).toEqual([9, 11]); 239 | expect((await result.next()).value).toEqual([13, 7, 9]); 240 | expect((await result.next()).value).toEqual(undefined); 241 | }); 242 | 243 | it('should yield empty array first if given separator is found in the beginning of iterable', async () => { 244 | function* separatorGenerator() { 245 | yield 1; 246 | yield 3; 247 | } 248 | 249 | const iterable = dummyGenerator(); 250 | const separator = separatorGenerator(); 251 | const result = asyncSplitLazy(iterable, separator); 252 | 253 | expect((await result.next()).value).toEqual([]); 254 | expect((await result.next()).value).toEqual([ 255 | 5, 256 | 7, 257 | 9, 258 | 11, 259 | 5, 260 | 7, 261 | 13, 262 | 7, 263 | 9, 264 | ]); 265 | expect((await result.next()).value).toEqual(undefined); 266 | }); 267 | 268 | it('should yield empty array last if given separator is found in the end of iterable', async () => { 269 | function* separatorGenerator() { 270 | yield 7; 271 | yield 9; 272 | } 273 | 274 | const iterable = dummyGenerator(); 275 | const separator = separatorGenerator(); 276 | const result = asyncSplitLazy(iterable, separator); 277 | 278 | expect((await result.next()).value).toEqual([1, 3, 5]); 279 | expect((await result.next()).value).toEqual([11, 5, 7, 13]); 280 | expect((await result.next()).value).toEqual([]); 281 | expect((await result.next()).value).toEqual(undefined); 282 | }); 283 | 284 | it('should yield all elements if found nothing', async () => { 285 | function* separatorGenerator() { 286 | yield 0; 287 | } 288 | 289 | const iterable = dummyGenerator(); 290 | const separator = separatorGenerator(); 291 | const result = asyncSplitLazy(iterable, separator); 292 | 293 | expect((await result.next()).value).toEqual([ 294 | 1, 295 | 3, 296 | 5, 297 | 7, 298 | 9, 299 | 11, 300 | 5, 301 | 7, 302 | 13, 303 | 7, 304 | 9, 305 | ]); 306 | expect((await result.next()).value).toEqual(undefined); 307 | }); 308 | }); 309 | }); 310 | -------------------------------------------------------------------------------- /test/sync.test.ts: -------------------------------------------------------------------------------- 1 | import { splitLazy, splitLazyString } from '../src'; 2 | 3 | function* dummyGenerator() { 4 | yield 1; 5 | yield 3; 6 | yield 5; 7 | yield 7; 8 | yield 9; 9 | yield 11; 10 | yield 5; 11 | yield 7; 12 | yield 13; 13 | yield 7; 14 | yield 9; 15 | } 16 | 17 | describe('SYNC', () => { 18 | describe('splitting an array', () => { 19 | it('should yield with array of splitted items correctly', () => { 20 | const arr = [1, 3, 5, 7, 9]; 21 | const iterable = splitLazy(arr, 5); 22 | 23 | expect(iterable.next().value).toEqual([1, 3]); 24 | expect(iterable.next().value).toEqual([7, 9]); 25 | expect(iterable.next().value).toEqual(undefined); 26 | }); 27 | 28 | it('should yield empty array first if given separator is found in the beginning of iterable', () => { 29 | const arr = [1, 3, 5, 7, 9]; 30 | const iterable = splitLazy(arr, 1); 31 | 32 | expect(iterable.next().value).toEqual([]); 33 | expect(iterable.next().value).toEqual([3, 5, 7, 9]); 34 | expect(iterable.next().value).toEqual(undefined); 35 | }); 36 | 37 | it('should yield empty array last if given separator is found in the end of iterable', () => { 38 | const arr = [1, 3, 5, 7, 9]; 39 | const iterable = splitLazy(arr, 9); 40 | 41 | expect(iterable.next().value).toEqual([1, 3, 5, 7]); 42 | expect(iterable.next().value).toEqual([]); 43 | expect(iterable.next().value).toEqual(undefined); 44 | }); 45 | 46 | it('should yield all elements if not found anything', () => { 47 | const arr = [1, 3, 5, 7, 9]; 48 | const iterable = splitLazy(arr, 0); 49 | 50 | expect(iterable.next().value).toEqual([1, 3, 5, 7, 9]); 51 | expect(iterable.next().value).toEqual(undefined); 52 | }); 53 | }); 54 | 55 | describe('splitting an iterator', () => { 56 | it('should yield with array of splitted items correctly', () => { 57 | const iterable = dummyGenerator(); 58 | const result = splitLazy(iterable, 5); 59 | 60 | expect(result.next().value).toEqual([1, 3]); 61 | expect(result.next().value).toEqual([7, 9, 11]); 62 | expect(result.next().value).toEqual([7, 13, 7, 9]); 63 | expect(result.next().value).toEqual(undefined); 64 | }); 65 | 66 | it('should yield empty array first if given separator is found in the beginning of iterable', () => { 67 | const iterable = dummyGenerator(); 68 | const result = splitLazy(iterable, 1); 69 | 70 | expect(result.next().value).toEqual([]); 71 | expect(result.next().value).toEqual([3, 5, 7, 9, 11, 5, 7, 13, 7, 9]); 72 | expect(result.next().value).toEqual(undefined); 73 | }); 74 | 75 | it('should yield empty array last if given separator is found in the end of iterable', () => { 76 | const iterable = dummyGenerator(); 77 | const result = splitLazy(iterable, 9); 78 | 79 | expect(result.next().value).toEqual([1, 3, 5, 7]); 80 | expect(result.next().value).toEqual([11, 5, 7, 13, 7]); 81 | expect(result.next().value).toEqual([]); 82 | expect(result.next().value).toEqual(undefined); 83 | }); 84 | 85 | it('should yield all elements if not found anything', () => { 86 | const iterable = dummyGenerator(); 87 | const result = splitLazy(iterable, 0); 88 | 89 | expect(result.next().value).toEqual([1, 3, 5, 7, 9, 11, 5, 7, 13, 7, 9]); 90 | expect(result.next().value).toEqual(undefined); 91 | }); 92 | }); 93 | 94 | describe('splitting an iterator with sub array', () => { 95 | it('should yield with array of splitted items correctly', () => { 96 | const iterable = dummyGenerator(); 97 | const result = splitLazy(iterable, [5, 7]); 98 | 99 | expect(result.next().value).toEqual([1, 3]); 100 | expect(result.next().value).toEqual([9, 11]); 101 | expect(result.next().value).toEqual([13, 7, 9]); 102 | expect(result.next().value).toEqual(undefined); 103 | }); 104 | 105 | it('should yield empty array first if given separator is found in the beginning of iterable', () => { 106 | const iterable = dummyGenerator(); 107 | const result = splitLazy(iterable, [1, 3]); 108 | 109 | expect(result.next().value).toEqual([]); 110 | expect(result.next().value).toEqual([5, 7, 9, 11, 5, 7, 13, 7, 9]); 111 | expect(result.next().value).toEqual(undefined); 112 | }); 113 | 114 | it('should yield empty array last if given separator is found in the end of iterable', () => { 115 | const iterable = dummyGenerator(); 116 | const result = splitLazy(iterable, [7, 9]); 117 | 118 | expect(result.next().value).toEqual([1, 3, 5]); 119 | expect(result.next().value).toEqual([11, 5, 7, 13]); 120 | expect(result.next().value).toEqual([]); 121 | expect(result.next().value).toEqual(undefined); 122 | }); 123 | 124 | it('should yield all elements if not found anything', () => { 125 | const iterable = dummyGenerator(); 126 | const result = splitLazy(iterable, [0]); 127 | 128 | expect(result.next().value).toEqual([1, 3, 5, 7, 9, 11, 5, 7, 13, 7, 9]); 129 | expect(result.next().value).toEqual(undefined); 130 | }); 131 | }); 132 | 133 | describe('splitting an iterator with sub iterator', () => { 134 | it('should yield with array of splitted items correctly', () => { 135 | function* separatorGenerator() { 136 | yield 5; 137 | yield 7; 138 | } 139 | 140 | const iterable = dummyGenerator(); 141 | const separator = separatorGenerator(); 142 | 143 | const result = splitLazy(iterable, separator); 144 | 145 | expect(result.next().value).toEqual([1, 3]); 146 | expect(result.next().value).toEqual([9, 11]); 147 | expect(result.next().value).toEqual([13, 7, 9]); 148 | expect(result.next().value).toEqual(undefined); 149 | }); 150 | 151 | it('should yield empty array first if given separator is found in the beginning of iterable', () => { 152 | function* separatorGenerator() { 153 | yield 1; 154 | yield 3; 155 | } 156 | 157 | const iterable = dummyGenerator(); 158 | const separator = separatorGenerator(); 159 | const result = splitLazy(iterable, separator); 160 | 161 | expect(result.next().value).toEqual([]); 162 | expect(result.next().value).toEqual([5, 7, 9, 11, 5, 7, 13, 7, 9]); 163 | expect(result.next().value).toEqual(undefined); 164 | }); 165 | 166 | it('should yield empty array last if given separator is found in the end of iterable', () => { 167 | function* separatorGenerator() { 168 | yield 7; 169 | yield 9; 170 | } 171 | 172 | const iterable = dummyGenerator(); 173 | const separator = separatorGenerator(); 174 | const result = splitLazy(iterable, separator); 175 | 176 | expect(result.next().value).toEqual([1, 3, 5]); 177 | expect(result.next().value).toEqual([11, 5, 7, 13]); 178 | expect(result.next().value).toEqual([]); 179 | expect(result.next().value).toEqual(undefined); 180 | }); 181 | 182 | it('should yield all elements if not found anything', () => { 183 | function* separatorGenerator() { 184 | yield 0; 185 | } 186 | 187 | const iterable = dummyGenerator(); 188 | const separator = separatorGenerator(); 189 | const result = splitLazy(iterable, separator); 190 | 191 | expect(result.next().value).toEqual([1, 3, 5, 7, 9, 11, 5, 7, 13, 7, 9]); 192 | expect(result.next().value).toEqual(undefined); 193 | }); 194 | }); 195 | }); 196 | 197 | describe('splitting a string with splitLazyString', () => { 198 | it('should yield with iterable of splitted parts', () => { 199 | const str = 'test/1'; 200 | const iterable = splitLazyString(str, '/'); 201 | 202 | expect(iterable.next().value).toEqual('test'); 203 | expect(iterable.next().value).toEqual('1'); 204 | expect(iterable.next().value).toEqual(undefined); 205 | }); 206 | 207 | it('should yield empty array first if given sub iterable is found in the beginning of iterable', () => { 208 | const str = 'test/1'; 209 | const iterable = splitLazyString(str, 't'); 210 | 211 | expect(iterable.next().value).toEqual(''); 212 | expect(iterable.next().value).toEqual('es'); 213 | expect(iterable.next().value).toEqual('/1'); 214 | expect(iterable.next().value).toEqual(undefined); 215 | }); 216 | 217 | it('should yield empty array last if given separator is found in the end of iterable', () => { 218 | const str = 'test/1'; 219 | const iterable = splitLazyString(str, '1'); 220 | 221 | expect(iterable.next().value).toEqual('test/'); 222 | expect(iterable.next().value).toEqual(''); 223 | expect(iterable.next().value).toEqual(undefined); 224 | }); 225 | 226 | it('should all elements if not found anything', () => { 227 | const str = 'test/1'; 228 | const iterable = splitLazyString(str, '0'); 229 | 230 | expect(iterable.next().value).toEqual('test/1'); 231 | expect(iterable.next().value).toEqual(undefined); 232 | }); 233 | }); 234 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs 3 | "include": ["src", "types"], 4 | "compilerOptions": { 5 | "module": "esnext", 6 | "lib": ["dom", "esnext"], 7 | "importHelpers": true, 8 | // output .d.ts declaration files for consumers 9 | "declaration": true, 10 | // output .js.map sourcemap files for consumers 11 | "sourceMap": true, 12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index 13 | "rootDir": "./src", 14 | // stricter type-checking for stronger correctness. Recommended by TS 15 | "strict": true, 16 | // linter checks for common issues 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative 20 | "noUnusedParameters": true, 21 | // use Node's module resolution algorithm, instead of the legacy TS one 22 | "moduleResolution": "node", 23 | // transpile JSX to React.createElement 24 | "jsx": "react", 25 | // interop between ESM and CJS modules. Recommended by TS 26 | "esModuleInterop": true, 27 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS 28 | "skipLibCheck": true, 29 | // error out if import and file system have a casing mismatch. Recommended by TS 30 | "forceConsistentCasingInFileNames": true, 31 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` 32 | "noEmit": true, 33 | "downlevelIteration": true, 34 | "noUnusedLocals": true, 35 | } 36 | } 37 | --------------------------------------------------------------------------------