Mirror: 🎩 A tiny but capable push & pull stream library for TypeScript and Flow

feat: Implement fromIterable and replace fromArray (#115)

* Replace array-only implementation with iterable

* Add fromAsyncIterable

* Add wonka@4 to suite

* Rename factory to lazy

* Combine functions for ease of use

* Split fromIterable/fromAsyncIterable back out

That's simply less bytes somehow

* Fix fromPromise test

authored by kitten.sh and committed by GitHub 4efbf851 e08d998b

Changed files
+83 -7
perf
src
+1
perf/package.json
··· 11 11 "benchr": "^4.3.0" 12 12 }, 13 13 "dependencies": { 14 + "wonka-v4": "npm:wonka@^4.0.0", 14 15 "most": "^1.7.3", 15 16 "rxjs": "^6.3.3" 16 17 }
+11
perf/suite.js
··· 1 1 const Wonka = require('..'); 2 + const Wonka4 = require('wonka-v4'); 2 3 const Rx = require('rxjs'); 3 4 const RxOperators = require('rxjs/operators'); 4 5 const most = require('most'); ··· 13 14 Wonka.filter(x => x > 4), 14 15 Wonka.scan((acc, x) => acc + x, 0), 15 16 Wonka.toPromise 17 + ); 18 + }); 19 + 20 + benchmark('Wonka v4', () => { 21 + return Wonka4.pipe( 22 + Wonka4.fromArray(input), 23 + Wonka4.map(x => x * 2), 24 + Wonka4.filter(x => x > 4), 25 + Wonka4.scan((acc, x) => acc + x, 0), 26 + Wonka4.toPromise 16 27 ); 17 28 }); 18 29
+5
perf/yarn.lock
··· 156 156 integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= 157 157 dependencies: 158 158 defaults "^1.0.3" 159 + 160 + "wonka-v4@npm:wonka@^4.0.0": 161 + version "4.0.15" 162 + resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.15.tgz#9aa42046efa424565ab8f8f451fcca955bf80b89" 163 + integrity sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==
+1
src/__tests__/sources.test.ts
··· 274 274 275 275 expect(signals).toEqual([start(expect.any(Function))]); 276 276 277 + await Promise.resolve(); 277 278 await promise; 278 279 await Promise.resolve(); 279 280
+65 -7
src/sources.ts
··· 2 2 import { push, start, talkbackPlaceholder, teardownPlaceholder } from './helpers'; 3 3 import { share } from './operators'; 4 4 5 - export function fromArray<T>(array: T[]): Source<T> { 5 + export function lazy<T>(make: () => Source<T>): Source<T> { 6 + return sink => make()(sink); 7 + } 8 + 9 + export function fromAsyncIterable<T>(iterable: AsyncIterable<T>): Source<T> { 6 10 return sink => { 11 + const iterator = iterable[Symbol.asyncIterator](); 7 12 let ended = false; 8 13 let looping = false; 9 14 let pulled = false; 10 - let current = 0; 15 + let next: IteratorResult<T>; 11 16 sink( 12 - start(signal => { 17 + start(async signal => { 13 18 if (signal === TalkbackKind.Close) { 14 19 ended = true; 20 + if (iterator.return) iterator.return(); 15 21 } else if (looping) { 16 22 pulled = true; 17 23 } else { 18 - for (pulled = looping = true; pulled && !ended; current++) { 19 - if (current < array.length) { 20 - pulled = false; 21 - sink(push(array[current])); 24 + for (pulled = looping = true; pulled && !ended; ) { 25 + if ((next = await iterator.next()).done) { 26 + ended = true; 27 + if (iterator.return) await iterator.return(); 28 + sink(SignalKind.End); 22 29 } else { 30 + try { 31 + pulled = false; 32 + sink(push(next.value)); 33 + } catch (error) { 34 + if (iterator.throw) { 35 + if ((ended = !!(await iterator.throw(error)).done)) sink(SignalKind.End); 36 + } else { 37 + throw error; 38 + } 39 + } 40 + } 41 + } 42 + looping = false; 43 + } 44 + }) 45 + ); 46 + }; 47 + } 48 + 49 + export function fromIterable<T>(iterable: Iterable<T> | AsyncIterable<T>): Source<T> { 50 + if (iterable[Symbol.asyncIterator]) return fromAsyncIterable(iterable as AsyncIterable<T>); 51 + return sink => { 52 + const iterator = iterable[Symbol.iterator](); 53 + let ended = false; 54 + let looping = false; 55 + let pulled = false; 56 + let next: IteratorResult<T>; 57 + sink( 58 + start(signal => { 59 + if (signal === TalkbackKind.Close) { 60 + ended = true; 61 + if (iterator.return) iterator.return(); 62 + } else if (looping) { 63 + pulled = true; 64 + } else { 65 + for (pulled = looping = true; pulled && !ended; ) { 66 + if ((next = iterator.next()).done) { 23 67 ended = true; 68 + if (iterator.return) iterator.return(); 24 69 sink(SignalKind.End); 70 + } else { 71 + try { 72 + pulled = false; 73 + sink(push(next.value)); 74 + } catch (error) { 75 + if (iterator.throw) { 76 + if ((ended = !!iterator.throw(error).done)) sink(SignalKind.End); 77 + } else { 78 + throw error; 79 + } 80 + } 25 81 } 26 82 } 27 83 looping = false; ··· 30 86 ); 31 87 }; 32 88 } 89 + 90 + export const fromArray: <T>(array: T[]) => Source<T> = fromIterable; 33 91 34 92 export function fromValue<T>(value: T): Source<T> { 35 93 return sink => {