├── .circleci
└── config.yml
├── .gitignore
├── LICENSE
├── README.md
├── dist
├── bundle
│ ├── for-await.js
│ ├── index.js
│ ├── index.mjs
│ └── module.js
└── declarations
│ └── index.d.ts
├── examples
├── browser
│ ├── browser-adapter.js
│ └── fromFetch.js
├── csv-parser.js
├── fixture.csv
├── index.html
├── node.js
├── node
│ └── fromFile.js
├── readme.md
└── scripts
│ ├── fixtures.js
│ └── rollup.node.js
├── package-lock.json
├── package.json
├── rollup
├── build.js
└── test.js
├── src
├── index.d.ts
├── index.js
└── lib
│ ├── operators.js
│ ├── stream.js
│ └── util.js
└── test
├── concat.js
├── every.js
├── filter.js
├── find.js
├── flatMap.js
├── includes.js
├── index.js
├── map.js
├── reduce.js
├── skip.js
├── slice.js
├── some.js
├── stream.js
├── take.js
├── util
└── source.js
└── utils.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/node:9
11 |
12 | steps:
13 | - checkout
14 |
15 | # Download and cache dependencies
16 | - restore_cache:
17 | keys:
18 | - v1-dependencies-{{ checksum "package.json" }}
19 | # fallback to using the latest cache if no exact match is found
20 | - v1-dependencies-
21 |
22 | - run: npm install
23 |
24 | - save_cache:
25 | paths:
26 | - node_modules
27 | key: v1-dependencies-{{ checksum "package.json" }}
28 |
29 | # run tests!
30 | - run: npm run test:ci
31 |
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | .idea
61 |
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 RENARD Laurent
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 | [](https://circleci.com/gh/lorenzofox3/for-await)
2 |
3 | # for-await
4 |
5 | Operators and stream semantic for asyncIterators.
6 |
7 | ``npm install @lorenzofox3/for-await``
8 |
9 | ## Motivation
10 |
11 | [AsyncIterator](https://tc39.github.io/proposal-async-iteration/#sec-asynciterator-interface) and [AsyncGenerator](https://tc39.github.io/proposal-async-iteration/#sec-asyncgenerator-objects) (and the `for await` statement to consume them) have been integrated into es2018 specification and have started to land in different Javascript engines:
12 |
13 | 1. Nodejs > v9 (with harmony flag for some versions)
14 | 2. Chrome
15 | 3. Firefox
16 |
17 | They provide a new way to create data structures which have the semantic of readable streams: ie that produce values in time (asynchronously)
18 |
19 | ```Javascript
20 | const wait = (time = 100) => new Promise(resolve => {
21 | setTimeout(() => resolve(),time);
22 | });
23 |
24 | // produce a sequence of integer every 100ms
25 | const counter = async function * (limit = 5){
26 | let i = 0;
27 | while(true){
28 | if(i >= limit){
29 | break;
30 | }
31 | await wait();
32 | yield i;
33 | i++;
34 | }
35 | }
36 |
37 | // consume it
38 | for await (const i of counter()){
39 | console.log(i);
40 | }
41 |
42 | // > 0 (after 100ms)
43 | // > 1 (after 200ms)
44 | // ..
45 | // > 4 (after 500ms)
46 | ```
47 |
48 | And this is very powerful !
49 |
50 | This library aims at providing operators and data structures with almost the same API than regular synchronous collections (like Array) implement, so you can manipulate
51 | these streams as if they were synchronous collections.
52 |
53 | ```Javascript
54 | import {stream} from 'for-await';
55 |
56 | const oddSquaredCounter = stream(counter())
57 | .filter(i => i % 2 === 0) // keep odd
58 | .map(i => i * i) // square it
59 |
60 | // and consume it
61 |
62 | for await (const v of oddSquaredCounter){
63 | console.log(v);
64 | }
65 |
66 | // > 0 (after 100 ms)
67 | // > 4 (after 300 ms)
68 | // > 16 (after 500 ms)
69 | ```
70 |
71 | This could sound familiar to anyone who has already tried [reactive programming](https://en.wikipedia.org/wiki/Reactive_programming) or have used the same kind of abstractions on streams provided by some nodejs libraries (like [through](https://www.npmjs.com/package/through2)).
72 |
73 | However this implementation relies only on native EcmaScript features which makes it very lightweight and easier to use on different platforms.
74 |
75 | You will only have to implement an adapter (I will likely write modules for common data source in Nodejs and in the Browser) so your data source implements the standard asyncIterator interface (and this has become way more easier with async generators).
76 |
77 | [See our csv parser for nodejs and browser]('./examples').
78 |
79 | ## Operators
80 |
81 | ### semantic
82 | If you are not familiar with the synchronous iterable/iterator protocol, I strongly recommend the [Reginald Braithwaite book](https://leanpub.com/javascriptallongesix) and [his essays](http://raganwald.com/2017/07/22/closing-iterables-is-a-leaky-abstraction.html)
83 |
84 | Note all the operators which do not return a scalar value follow the same semantic than the underlying source:
85 | 1. If source streams are consumable once the resulting iterable is consumable once
86 | 2. If source streams implements control flow hooks (like return or throw), these hooks will be called as well so your data source is properly released etc
87 |
88 | For example in a synchronous world you already know that
89 | ```Javascript
90 | const array = [0,1,2] // implements Iterable protocol
91 |
92 | for (const i of array){
93 | console.log(i);
94 | }
95 |
96 | for (const i of array){
97 | console.log(i);
98 | }
99 |
100 | // > 0
101 | // > 1
102 | // > 2
103 | // > 0
104 | // > 1
105 | // > 2
106 |
107 | // However
108 |
109 | const counterGen = function * (){
110 | yield 0;
111 | yield 1;
112 | yield 3;
113 | }
114 |
115 | const oneTwoThree = counterGen();
116 |
117 | for (const i of onTwoThree){
118 | console.log(i);
119 | }
120 |
121 | for (const i of onTwoTree){
122 | console.log(i);
123 | }
124 |
125 | // > 0
126 | // > 1
127 | // > 2
128 | // And nothing as the generator is already exhausted
129 | ```
130 |
131 | The will be the same for our async iterators
132 | ```Javascript
133 | import {map} from 'for-await';
134 |
135 | // Assuming the asynchronous counter of the introduction
136 | const zeroOneTwoSquared = map(x=>x*x, counter(3));
137 |
138 | for await (const i of zeroOneTwoSquared){
139 | console.log(i);
140 | }
141 |
142 | for await (const i of zeroOneTwoSquared){
143 | console.log(i);
144 | }
145 |
146 | // > 0 (100ms)
147 | // > 1 (200ms)
148 | // > 4 (300ms)
149 | // And nothing as the generator is already exhausted
150 |
151 | //However
152 |
153 | const iteratable = {
154 | [Symbol.asyncIterator]:counter
155 | }
156 |
157 | for await (const i of iterable){
158 | console.log(i);
159 | }
160 |
161 | for await (const i of iterable){
162 | console.log(i);
163 | }
164 |
165 | // > 0 (100ms)
166 | // > 1 (200ms)
167 | // > 4 (300ms)
168 | // > 9 (400ms)
169 | // > 16 (500ms)
170 | // > 0 (600ms)
171 | // > 1 (700ms)
172 | // > 4 (800ms)
173 | // > 9 (900ms)
174 | // > 16 (1000ms)
175 | ```
176 |
177 | Most of the operators are curried:
178 |
179 | ```Javascript
180 | import {map} from 'for-await';
181 |
182 | const square=map(x=>x*x);
183 |
184 | for await (const i of square(counter()){
185 | // do something
186 | }
187 |
188 | //and another one
189 | for await (const i of square(counter()){
190 | // do something
191 | }
192 | ```
193 |
194 | ### operators list
195 |
196 | #### return a new Async Iterable
197 | 1. map
198 | 2. filter
199 | 3. slice
200 | 4. flatMap (flatten stream of streams)
201 | 5. concat
202 |
203 | #### Return a scalar (as a promise)
204 | 1. reduce
205 | 2. find
206 | 3. findIndex
207 | 4. includes
208 | 5. every
209 | 6. some
210 |
211 | ## Data structure
212 |
213 | Even more convenient you can use the stream data structure which gives you almost the same API than Arrays.
214 | 1. An instance of a stream will implement all the operators above
215 | 2. Every method which returns an async Iterable will actually return a new instance of stream (so you can chain them together)
216 |
--------------------------------------------------------------------------------
/dist/bundle/for-await.js:
--------------------------------------------------------------------------------
1 | var ForAwait = (function (exports) {
2 | 'use strict';
3 |
4 | // with two arguments
5 | const curry = (fn) => (a, b) => b === void 0 ? b => fn(a, b) : fn(a, b);
6 | const toCurriedIterable = gen => curry((a, b) => ({
7 | [Symbol.asyncIterator]() {
8 | return gen(a, b);
9 | }
10 | }));
11 | const toIterable = gen => (...args) => ({
12 | [Symbol.asyncIterator]() {
13 | return gen(...args);
14 | }
15 | });
16 |
17 | const map = toCurriedIterable(async function* (fn, asyncIterable) {
18 | let index = 0;
19 | for await (const i of asyncIterable) {
20 | yield fn(i, index, asyncIterable);
21 | index++;
22 | }
23 | });
24 |
25 | const filter = toCurriedIterable(async function* (fn, asyncIterable) {
26 | let index = 0;
27 | for await (const i of asyncIterable) {
28 | if (fn(i, index, asyncIterable) === true) {
29 | yield i;
30 | }
31 | index++;
32 | }
33 | });
34 |
35 | const take = toCurriedIterable(async function* (number, asyncIterable) {
36 | let count = 1;
37 | for await (const i of asyncIterable) {
38 | if (number !== undefined && count > number) {
39 | break;
40 | }
41 | yield i;
42 | count++;
43 | }
44 | });
45 |
46 | const skip = toCurriedIterable(async function* (limit, asyncIterable) {
47 | let count = 0;
48 | for await (const i of asyncIterable) {
49 | if (count < limit) {
50 | count++;
51 | continue;
52 | }
53 | yield i;
54 | }
55 | });
56 |
57 | const flatMap = toCurriedIterable(async function* (fn, asyncIterable) {
58 | for await (const i of asyncIterable) {
59 | if (i[Symbol.asyncIterator]) {
60 | yield* map(fn, i);
61 | } else {
62 | yield fn(i);
63 | }
64 | }
65 | });
66 |
67 | const acutalSlice = toIterable(async function* (s, e, iterable) {
68 | const toSkip = skip(s);
69 | const toTake = take(e !== void 0 ? e - s : e);
70 | for await (const i of toTake(toSkip(iterable))) {
71 | yield i;
72 | }
73 | });
74 | const slice = (start, end, asyncIterable) => {
75 | let s = start || 0;
76 | let e = end;
77 | let iterable = asyncIterable;
78 | if (start && start[Symbol.asyncIterator] !== void 0) {
79 | iterable = start;
80 | s = 0;
81 | e = void 0;
82 | } else if (end && end[Symbol.asyncIterator] !== void 0) {
83 | iterable = end;
84 | s = start;
85 | e = void 0;
86 | } else if (asyncIterable === void 0) {
87 | return iterable => acutalSlice(s, e, iterable);
88 | }
89 | return acutalSlice(s, e, iterable);
90 | };
91 |
92 | const concat = toIterable(async function* (...values) {
93 | for (const i of values) {
94 | if (i[Symbol.asyncIterator]) {
95 | yield* i;
96 | } else {
97 | yield i;
98 | }
99 | }
100 | });
101 |
102 | const actualReduce = async (fn, initialValue, asyncIterable) => {
103 | let index = -1;
104 | const iterator = asyncIterable[Symbol.asyncIterator]();
105 | const next = async () => {
106 | index++;
107 | return iterator.next();
108 | };
109 | let acc = initialValue;
110 |
111 | if (initialValue === void 0) {
112 | acc = (await next()).value;
113 | }
114 |
115 | while (true) {
116 | const {value, done} = await next();
117 | if (done === true) {
118 | return acc;
119 | }
120 | acc = fn(acc, value, index, asyncIterable);
121 | }
122 | };
123 | const reduce = (fn, initVal, asyncIterable) => {
124 | let acc = initVal;
125 | let iterable = asyncIterable;
126 |
127 | if (initVal && initVal[Symbol.asyncIterator] !== void 0) {
128 | iterable = initVal;
129 | acc = void 0;
130 | }
131 |
132 | if (iterable === void 0) {
133 | return iterable => actualReduce(fn, acc, iterable);
134 | }
135 |
136 | return actualReduce(fn, acc, iterable);
137 | };
138 |
139 | const findTuple = async (fn, asyncIterable) => {
140 | let index = 0;
141 | for await (const i of asyncIterable) {
142 | if (fn(i, index, asyncIterable)) {
143 | return {value: i, index: index};
144 | }
145 | index++;
146 | }
147 | return {value: void 0, index: -1};
148 | };
149 |
150 | const find = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).value);
151 |
152 | const findIndex = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).index);
153 |
154 | const actualIncludes = async (item, from, iterable) => {
155 | const strictEqualToItem = findIndex(x => x === item);
156 | return (await strictEqualToItem(skip(from, iterable))) > -1;
157 | };
158 | const includes = (item, from, asyncIterable) => {
159 | let start = from;
160 | let iterable = asyncIterable;
161 |
162 | if (from && from[Symbol.asyncIterator] !== void 0) {
163 | start = 0;
164 | iterable = from;
165 | }
166 |
167 | if (iterable === void 0) {
168 | return iterable => actualIncludes(item, start, iterable);
169 | }
170 |
171 | return actualIncludes(item, start, iterable);
172 | };
173 |
174 | const every = curry(async (fn, asyncIterable) => {
175 | let index = 0;
176 | for await(const i of asyncIterable) {
177 | if (!fn(i, index, asyncIterable)) {
178 | return false;
179 | }
180 | index++;
181 | }
182 | return true;
183 | });
184 |
185 | const some = curry(async (fn, asyncIterable) => {
186 | let index = 0;
187 | for await(const i of asyncIterable) {
188 | if (fn(i, index, asyncIterable)) {
189 | return true;
190 | }
191 | index++;
192 | }
193 | return false;
194 | });
195 |
196 | /*
197 | The iterable won't always be consumed with a for await statement (which implicitly convert an iterable into a asyncIterable) so we need to explicitly make it async iterable
198 | for await (const t of [1,2,3,4,5]){
199 | //no problem
200 | }
201 |
202 | but
203 |
204 | const iterator = [1,2,3][Symbol.asyncIterator]();
205 | //problem
206 | */
207 | const toAsync = toIterable(async function* (iterable) {
208 | yield* iterable;
209 | });
210 |
211 | const proto = {
212 | [Symbol.asyncIterator]() {
213 | return this._source[Symbol.asyncIterator]();
214 | },
215 | map(fn) {
216 | return stream(map(fn, this));
217 | },
218 | filter(fn) {
219 | return stream(filter(fn, this));
220 | },
221 | flatMap(fn) {
222 | return stream(flatMap(fn, this));
223 | },
224 | slice(start = 0, end = void 0) {
225 | return stream(slice(start, end, this));
226 | },
227 | concat(...values) {
228 | return stream(concat(this, ...values));
229 | },
230 | reduce(fn, initialValue) {
231 | return reduce(fn, initialValue, this);
232 | },
233 | find(fn) {
234 | return find(fn, this);
235 | },
236 | findIndex(fn) {
237 | return findIndex(fn, this);
238 | },
239 | includes(item, from = 0) {
240 | return includes(item, from, this);
241 | },
242 | every(fn) {
243 | return every(fn, this);
244 | },
245 | some(fn) {
246 | return some(fn, this);
247 | }
248 | };
249 |
250 | const stream = iterable => {
251 | const source = !iterable[Symbol.asyncIterator] ? toAsync(iterable) : iterable; // we make a difference as any wrap of iterable has performance impact (for the moment)
252 | return Object.create(proto, {_source: {value: source}});
253 | };
254 |
255 | exports.concat = concat;
256 | exports.every = every;
257 | exports.filter = filter;
258 | exports.find = find;
259 | exports.findIndex = findIndex;
260 | exports.flatMap = flatMap;
261 | exports.from = toAsync;
262 | exports.includes = includes;
263 | exports.map = map;
264 | exports.reduce = reduce;
265 | exports.skip = skip;
266 | exports.slice = slice;
267 | exports.some = some;
268 | exports.stream = stream;
269 | exports.take = take;
270 |
271 | return exports;
272 |
273 | }({}));
274 |
--------------------------------------------------------------------------------
/dist/bundle/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', { value: true });
4 |
5 | // with two arguments
6 | const curry = (fn) => (a, b) => b === void 0 ? b => fn(a, b) : fn(a, b);
7 | const toCurriedIterable = gen => curry((a, b) => ({
8 | [Symbol.asyncIterator]() {
9 | return gen(a, b);
10 | }
11 | }));
12 | const toIterable = gen => (...args) => ({
13 | [Symbol.asyncIterator]() {
14 | return gen(...args);
15 | }
16 | });
17 |
18 | const map = toCurriedIterable(async function* (fn, asyncIterable) {
19 | let index = 0;
20 | for await (const i of asyncIterable) {
21 | yield fn(i, index, asyncIterable);
22 | index++;
23 | }
24 | });
25 |
26 | const filter = toCurriedIterable(async function* (fn, asyncIterable) {
27 | let index = 0;
28 | for await (const i of asyncIterable) {
29 | if (fn(i, index, asyncIterable) === true) {
30 | yield i;
31 | }
32 | index++;
33 | }
34 | });
35 |
36 | const take = toCurriedIterable(async function* (number, asyncIterable) {
37 | let count = 1;
38 | for await (const i of asyncIterable) {
39 | if (number !== undefined && count > number) {
40 | break;
41 | }
42 | yield i;
43 | count++;
44 | }
45 | });
46 |
47 | const skip = toCurriedIterable(async function* (limit, asyncIterable) {
48 | let count = 0;
49 | for await (const i of asyncIterable) {
50 | if (count < limit) {
51 | count++;
52 | continue;
53 | }
54 | yield i;
55 | }
56 | });
57 |
58 | const flatMap = toCurriedIterable(async function* (fn, asyncIterable) {
59 | for await (const i of asyncIterable) {
60 | if (i[Symbol.asyncIterator]) {
61 | yield* map(fn, i);
62 | } else {
63 | yield fn(i);
64 | }
65 | }
66 | });
67 |
68 | const acutalSlice = toIterable(async function* (s, e, iterable) {
69 | const toSkip = skip(s);
70 | const toTake = take(e !== void 0 ? e - s : e);
71 | for await (const i of toTake(toSkip(iterable))) {
72 | yield i;
73 | }
74 | });
75 | const slice = (start, end, asyncIterable) => {
76 | let s = start || 0;
77 | let e = end;
78 | let iterable = asyncIterable;
79 | if (start && start[Symbol.asyncIterator] !== void 0) {
80 | iterable = start;
81 | s = 0;
82 | e = void 0;
83 | } else if (end && end[Symbol.asyncIterator] !== void 0) {
84 | iterable = end;
85 | s = start;
86 | e = void 0;
87 | } else if (asyncIterable === void 0) {
88 | return iterable => acutalSlice(s, e, iterable);
89 | }
90 | return acutalSlice(s, e, iterable);
91 | };
92 |
93 | const concat = toIterable(async function* (...values) {
94 | for (const i of values) {
95 | if (i[Symbol.asyncIterator]) {
96 | yield* i;
97 | } else {
98 | yield i;
99 | }
100 | }
101 | });
102 |
103 | const actualReduce = async (fn, initialValue, asyncIterable) => {
104 | let index = -1;
105 | const iterator = asyncIterable[Symbol.asyncIterator]();
106 | const next = async () => {
107 | index++;
108 | return iterator.next();
109 | };
110 | let acc = initialValue;
111 |
112 | if (initialValue === void 0) {
113 | acc = (await next()).value;
114 | }
115 |
116 | while (true) {
117 | const {value, done} = await next();
118 | if (done === true) {
119 | return acc;
120 | }
121 | acc = fn(acc, value, index, asyncIterable);
122 | }
123 | };
124 | const reduce = (fn, initVal, asyncIterable) => {
125 | let acc = initVal;
126 | let iterable = asyncIterable;
127 |
128 | if (initVal && initVal[Symbol.asyncIterator] !== void 0) {
129 | iterable = initVal;
130 | acc = void 0;
131 | }
132 |
133 | if (iterable === void 0) {
134 | return iterable => actualReduce(fn, acc, iterable);
135 | }
136 |
137 | return actualReduce(fn, acc, iterable);
138 | };
139 |
140 | const findTuple = async (fn, asyncIterable) => {
141 | let index = 0;
142 | for await (const i of asyncIterable) {
143 | if (fn(i, index, asyncIterable)) {
144 | return {value: i, index: index};
145 | }
146 | index++;
147 | }
148 | return {value: void 0, index: -1};
149 | };
150 |
151 | const find = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).value);
152 |
153 | const findIndex = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).index);
154 |
155 | const actualIncludes = async (item, from, iterable) => {
156 | const strictEqualToItem = findIndex(x => x === item);
157 | return (await strictEqualToItem(skip(from, iterable))) > -1;
158 | };
159 | const includes = (item, from, asyncIterable) => {
160 | let start = from;
161 | let iterable = asyncIterable;
162 |
163 | if (from && from[Symbol.asyncIterator] !== void 0) {
164 | start = 0;
165 | iterable = from;
166 | }
167 |
168 | if (iterable === void 0) {
169 | return iterable => actualIncludes(item, start, iterable);
170 | }
171 |
172 | return actualIncludes(item, start, iterable);
173 | };
174 |
175 | const every = curry(async (fn, asyncIterable) => {
176 | let index = 0;
177 | for await(const i of asyncIterable) {
178 | if (!fn(i, index, asyncIterable)) {
179 | return false;
180 | }
181 | index++;
182 | }
183 | return true;
184 | });
185 |
186 | const some = curry(async (fn, asyncIterable) => {
187 | let index = 0;
188 | for await(const i of asyncIterable) {
189 | if (fn(i, index, asyncIterable)) {
190 | return true;
191 | }
192 | index++;
193 | }
194 | return false;
195 | });
196 |
197 | /*
198 | The iterable won't always be consumed with a for await statement (which implicitly convert an iterable into a asyncIterable) so we need to explicitly make it async iterable
199 | for await (const t of [1,2,3,4,5]){
200 | //no problem
201 | }
202 |
203 | but
204 |
205 | const iterator = [1,2,3][Symbol.asyncIterator]();
206 | //problem
207 | */
208 | const toAsync = toIterable(async function* (iterable) {
209 | yield* iterable;
210 | });
211 |
212 | const proto = {
213 | [Symbol.asyncIterator]() {
214 | return this._source[Symbol.asyncIterator]();
215 | },
216 | map(fn) {
217 | return stream(map(fn, this));
218 | },
219 | filter(fn) {
220 | return stream(filter(fn, this));
221 | },
222 | flatMap(fn) {
223 | return stream(flatMap(fn, this));
224 | },
225 | slice(start = 0, end = void 0) {
226 | return stream(slice(start, end, this));
227 | },
228 | concat(...values) {
229 | return stream(concat(this, ...values));
230 | },
231 | reduce(fn, initialValue) {
232 | return reduce(fn, initialValue, this);
233 | },
234 | find(fn) {
235 | return find(fn, this);
236 | },
237 | findIndex(fn) {
238 | return findIndex(fn, this);
239 | },
240 | includes(item, from = 0) {
241 | return includes(item, from, this);
242 | },
243 | every(fn) {
244 | return every(fn, this);
245 | },
246 | some(fn) {
247 | return some(fn, this);
248 | }
249 | };
250 |
251 | const stream = iterable => {
252 | const source = !iterable[Symbol.asyncIterator] ? toAsync(iterable) : iterable; // we make a difference as any wrap of iterable has performance impact (for the moment)
253 | return Object.create(proto, {_source: {value: source}});
254 | };
255 |
256 | exports.concat = concat;
257 | exports.every = every;
258 | exports.filter = filter;
259 | exports.find = find;
260 | exports.findIndex = findIndex;
261 | exports.flatMap = flatMap;
262 | exports.from = toAsync;
263 | exports.includes = includes;
264 | exports.map = map;
265 | exports.reduce = reduce;
266 | exports.skip = skip;
267 | exports.slice = slice;
268 | exports.some = some;
269 | exports.stream = stream;
270 | exports.take = take;
271 |
--------------------------------------------------------------------------------
/dist/bundle/index.mjs:
--------------------------------------------------------------------------------
1 | // with two arguments
2 | const curry = (fn) => (a, b) => b === void 0 ? b => fn(a, b) : fn(a, b);
3 | const toCurriedIterable = gen => curry((a, b) => ({
4 | [Symbol.asyncIterator]() {
5 | return gen(a, b);
6 | }
7 | }));
8 | const toIterable = gen => (...args) => ({
9 | [Symbol.asyncIterator]() {
10 | return gen(...args);
11 | }
12 | });
13 |
14 | const map = toCurriedIterable(async function* (fn, asyncIterable) {
15 | let index = 0;
16 | for await (const i of asyncIterable) {
17 | yield fn(i, index, asyncIterable);
18 | index++;
19 | }
20 | });
21 |
22 | const filter = toCurriedIterable(async function* (fn, asyncIterable) {
23 | let index = 0;
24 | for await (const i of asyncIterable) {
25 | if (fn(i, index, asyncIterable) === true) {
26 | yield i;
27 | }
28 | index++;
29 | }
30 | });
31 |
32 | const take = toCurriedIterable(async function* (number, asyncIterable) {
33 | let count = 1;
34 | for await (const i of asyncIterable) {
35 | if (number !== undefined && count > number) {
36 | break;
37 | }
38 | yield i;
39 | count++;
40 | }
41 | });
42 |
43 | const skip = toCurriedIterable(async function* (limit, asyncIterable) {
44 | let count = 0;
45 | for await (const i of asyncIterable) {
46 | if (count < limit) {
47 | count++;
48 | continue;
49 | }
50 | yield i;
51 | }
52 | });
53 |
54 | const flatMap = toCurriedIterable(async function* (fn, asyncIterable) {
55 | for await (const i of asyncIterable) {
56 | if (i[Symbol.asyncIterator]) {
57 | yield* map(fn, i);
58 | } else {
59 | yield fn(i);
60 | }
61 | }
62 | });
63 |
64 | const acutalSlice = toIterable(async function* (s, e, iterable) {
65 | const toSkip = skip(s);
66 | const toTake = take(e !== void 0 ? e - s : e);
67 | for await (const i of toTake(toSkip(iterable))) {
68 | yield i;
69 | }
70 | });
71 | const slice = (start, end, asyncIterable) => {
72 | let s = start || 0;
73 | let e = end;
74 | let iterable = asyncIterable;
75 | if (start && start[Symbol.asyncIterator] !== void 0) {
76 | iterable = start;
77 | s = 0;
78 | e = void 0;
79 | } else if (end && end[Symbol.asyncIterator] !== void 0) {
80 | iterable = end;
81 | s = start;
82 | e = void 0;
83 | } else if (asyncIterable === void 0) {
84 | return iterable => acutalSlice(s, e, iterable);
85 | }
86 | return acutalSlice(s, e, iterable);
87 | };
88 |
89 | const concat = toIterable(async function* (...values) {
90 | for (const i of values) {
91 | if (i[Symbol.asyncIterator]) {
92 | yield* i;
93 | } else {
94 | yield i;
95 | }
96 | }
97 | });
98 |
99 | const actualReduce = async (fn, initialValue, asyncIterable) => {
100 | let index = -1;
101 | const iterator = asyncIterable[Symbol.asyncIterator]();
102 | const next = async () => {
103 | index++;
104 | return iterator.next();
105 | };
106 | let acc = initialValue;
107 |
108 | if (initialValue === void 0) {
109 | acc = (await next()).value;
110 | }
111 |
112 | while (true) {
113 | const {value, done} = await next();
114 | if (done === true) {
115 | return acc;
116 | }
117 | acc = fn(acc, value, index, asyncIterable);
118 | }
119 | };
120 | const reduce = (fn, initVal, asyncIterable) => {
121 | let acc = initVal;
122 | let iterable = asyncIterable;
123 |
124 | if (initVal && initVal[Symbol.asyncIterator] !== void 0) {
125 | iterable = initVal;
126 | acc = void 0;
127 | }
128 |
129 | if (iterable === void 0) {
130 | return iterable => actualReduce(fn, acc, iterable);
131 | }
132 |
133 | return actualReduce(fn, acc, iterable);
134 | };
135 |
136 | const findTuple = async (fn, asyncIterable) => {
137 | let index = 0;
138 | for await (const i of asyncIterable) {
139 | if (fn(i, index, asyncIterable)) {
140 | return {value: i, index: index};
141 | }
142 | index++;
143 | }
144 | return {value: void 0, index: -1};
145 | };
146 |
147 | const find = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).value);
148 |
149 | const findIndex = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).index);
150 |
151 | const actualIncludes = async (item, from, iterable) => {
152 | const strictEqualToItem = findIndex(x => x === item);
153 | return (await strictEqualToItem(skip(from, iterable))) > -1;
154 | };
155 | const includes = (item, from, asyncIterable) => {
156 | let start = from;
157 | let iterable = asyncIterable;
158 |
159 | if (from && from[Symbol.asyncIterator] !== void 0) {
160 | start = 0;
161 | iterable = from;
162 | }
163 |
164 | if (iterable === void 0) {
165 | return iterable => actualIncludes(item, start, iterable);
166 | }
167 |
168 | return actualIncludes(item, start, iterable);
169 | };
170 |
171 | const every = curry(async (fn, asyncIterable) => {
172 | let index = 0;
173 | for await(const i of asyncIterable) {
174 | if (!fn(i, index, asyncIterable)) {
175 | return false;
176 | }
177 | index++;
178 | }
179 | return true;
180 | });
181 |
182 | const some = curry(async (fn, asyncIterable) => {
183 | let index = 0;
184 | for await(const i of asyncIterable) {
185 | if (fn(i, index, asyncIterable)) {
186 | return true;
187 | }
188 | index++;
189 | }
190 | return false;
191 | });
192 |
193 | /*
194 | The iterable won't always be consumed with a for await statement (which implicitly convert an iterable into a asyncIterable) so we need to explicitly make it async iterable
195 | for await (const t of [1,2,3,4,5]){
196 | //no problem
197 | }
198 |
199 | but
200 |
201 | const iterator = [1,2,3][Symbol.asyncIterator]();
202 | //problem
203 | */
204 | const toAsync = toIterable(async function* (iterable) {
205 | yield* iterable;
206 | });
207 |
208 | const proto = {
209 | [Symbol.asyncIterator]() {
210 | return this._source[Symbol.asyncIterator]();
211 | },
212 | map(fn) {
213 | return stream(map(fn, this));
214 | },
215 | filter(fn) {
216 | return stream(filter(fn, this));
217 | },
218 | flatMap(fn) {
219 | return stream(flatMap(fn, this));
220 | },
221 | slice(start = 0, end = void 0) {
222 | return stream(slice(start, end, this));
223 | },
224 | concat(...values) {
225 | return stream(concat(this, ...values));
226 | },
227 | reduce(fn, initialValue) {
228 | return reduce(fn, initialValue, this);
229 | },
230 | find(fn) {
231 | return find(fn, this);
232 | },
233 | findIndex(fn) {
234 | return findIndex(fn, this);
235 | },
236 | includes(item, from = 0) {
237 | return includes(item, from, this);
238 | },
239 | every(fn) {
240 | return every(fn, this);
241 | },
242 | some(fn) {
243 | return some(fn, this);
244 | }
245 | };
246 |
247 | const stream = iterable => {
248 | const source = !iterable[Symbol.asyncIterator] ? toAsync(iterable) : iterable; // we make a difference as any wrap of iterable has performance impact (for the moment)
249 | return Object.create(proto, {_source: {value: source}});
250 | };
251 |
252 | export { concat, every, filter, find, findIndex, flatMap, toAsync as from, includes, map, reduce, skip, slice, some, stream, take };
253 |
--------------------------------------------------------------------------------
/dist/bundle/module.js:
--------------------------------------------------------------------------------
1 | // with two arguments
2 | const curry = (fn) => (a, b) => b === void 0 ? b => fn(a, b) : fn(a, b);
3 | const toCurriedIterable = gen => curry((a, b) => ({
4 | [Symbol.asyncIterator]() {
5 | return gen(a, b);
6 | }
7 | }));
8 | const toIterable = gen => (...args) => ({
9 | [Symbol.asyncIterator]() {
10 | return gen(...args);
11 | }
12 | });
13 |
14 | const map = toCurriedIterable(async function* (fn, asyncIterable) {
15 | let index = 0;
16 | for await (const i of asyncIterable) {
17 | yield fn(i, index, asyncIterable);
18 | index++;
19 | }
20 | });
21 |
22 | const filter = toCurriedIterable(async function* (fn, asyncIterable) {
23 | let index = 0;
24 | for await (const i of asyncIterable) {
25 | if (fn(i, index, asyncIterable) === true) {
26 | yield i;
27 | }
28 | index++;
29 | }
30 | });
31 |
32 | const take = toCurriedIterable(async function* (number, asyncIterable) {
33 | let count = 1;
34 | for await (const i of asyncIterable) {
35 | if (number !== undefined && count > number) {
36 | break;
37 | }
38 | yield i;
39 | count++;
40 | }
41 | });
42 |
43 | const skip = toCurriedIterable(async function* (limit, asyncIterable) {
44 | let count = 0;
45 | for await (const i of asyncIterable) {
46 | if (count < limit) {
47 | count++;
48 | continue;
49 | }
50 | yield i;
51 | }
52 | });
53 |
54 | const flatMap = toCurriedIterable(async function* (fn, asyncIterable) {
55 | for await (const i of asyncIterable) {
56 | if (i[Symbol.asyncIterator]) {
57 | yield* map(fn, i);
58 | } else {
59 | yield fn(i);
60 | }
61 | }
62 | });
63 |
64 | const acutalSlice = toIterable(async function* (s, e, iterable) {
65 | const toSkip = skip(s);
66 | const toTake = take(e !== void 0 ? e - s : e);
67 | for await (const i of toTake(toSkip(iterable))) {
68 | yield i;
69 | }
70 | });
71 | const slice = (start, end, asyncIterable) => {
72 | let s = start || 0;
73 | let e = end;
74 | let iterable = asyncIterable;
75 | if (start && start[Symbol.asyncIterator] !== void 0) {
76 | iterable = start;
77 | s = 0;
78 | e = void 0;
79 | } else if (end && end[Symbol.asyncIterator] !== void 0) {
80 | iterable = end;
81 | s = start;
82 | e = void 0;
83 | } else if (asyncIterable === void 0) {
84 | return iterable => acutalSlice(s, e, iterable);
85 | }
86 | return acutalSlice(s, e, iterable);
87 | };
88 |
89 | const concat = toIterable(async function* (...values) {
90 | for (const i of values) {
91 | if (i[Symbol.asyncIterator]) {
92 | yield* i;
93 | } else {
94 | yield i;
95 | }
96 | }
97 | });
98 |
99 | const actualReduce = async (fn, initialValue, asyncIterable) => {
100 | let index = -1;
101 | const iterator = asyncIterable[Symbol.asyncIterator]();
102 | const next = async () => {
103 | index++;
104 | return iterator.next();
105 | };
106 | let acc = initialValue;
107 |
108 | if (initialValue === void 0) {
109 | acc = (await next()).value;
110 | }
111 |
112 | while (true) {
113 | const {value, done} = await next();
114 | if (done === true) {
115 | return acc;
116 | }
117 | acc = fn(acc, value, index, asyncIterable);
118 | }
119 | };
120 | const reduce = (fn, initVal, asyncIterable) => {
121 | let acc = initVal;
122 | let iterable = asyncIterable;
123 |
124 | if (initVal && initVal[Symbol.asyncIterator] !== void 0) {
125 | iterable = initVal;
126 | acc = void 0;
127 | }
128 |
129 | if (iterable === void 0) {
130 | return iterable => actualReduce(fn, acc, iterable);
131 | }
132 |
133 | return actualReduce(fn, acc, iterable);
134 | };
135 |
136 | const findTuple = async (fn, asyncIterable) => {
137 | let index = 0;
138 | for await (const i of asyncIterable) {
139 | if (fn(i, index, asyncIterable)) {
140 | return {value: i, index: index};
141 | }
142 | index++;
143 | }
144 | return {value: void 0, index: -1};
145 | };
146 |
147 | const find = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).value);
148 |
149 | const findIndex = curry(async (fn, asyncIterable) => (await findTuple(fn, asyncIterable)).index);
150 |
151 | const actualIncludes = async (item, from, iterable) => {
152 | const strictEqualToItem = findIndex(x => x === item);
153 | return (await strictEqualToItem(skip(from, iterable))) > -1;
154 | };
155 | const includes = (item, from, asyncIterable) => {
156 | let start = from;
157 | let iterable = asyncIterable;
158 |
159 | if (from && from[Symbol.asyncIterator] !== void 0) {
160 | start = 0;
161 | iterable = from;
162 | }
163 |
164 | if (iterable === void 0) {
165 | return iterable => actualIncludes(item, start, iterable);
166 | }
167 |
168 | return actualIncludes(item, start, iterable);
169 | };
170 |
171 | const every = curry(async (fn, asyncIterable) => {
172 | let index = 0;
173 | for await(const i of asyncIterable) {
174 | if (!fn(i, index, asyncIterable)) {
175 | return false;
176 | }
177 | index++;
178 | }
179 | return true;
180 | });
181 |
182 | const some = curry(async (fn, asyncIterable) => {
183 | let index = 0;
184 | for await(const i of asyncIterable) {
185 | if (fn(i, index, asyncIterable)) {
186 | return true;
187 | }
188 | index++;
189 | }
190 | return false;
191 | });
192 |
193 | /*
194 | The iterable won't always be consumed with a for await statement (which implicitly convert an iterable into a asyncIterable) so we need to explicitly make it async iterable
195 | for await (const t of [1,2,3,4,5]){
196 | //no problem
197 | }
198 |
199 | but
200 |
201 | const iterator = [1,2,3][Symbol.asyncIterator]();
202 | //problem
203 | */
204 | const toAsync = toIterable(async function* (iterable) {
205 | yield* iterable;
206 | });
207 |
208 | const proto = {
209 | [Symbol.asyncIterator]() {
210 | return this._source[Symbol.asyncIterator]();
211 | },
212 | map(fn) {
213 | return stream(map(fn, this));
214 | },
215 | filter(fn) {
216 | return stream(filter(fn, this));
217 | },
218 | flatMap(fn) {
219 | return stream(flatMap(fn, this));
220 | },
221 | slice(start = 0, end = void 0) {
222 | return stream(slice(start, end, this));
223 | },
224 | concat(...values) {
225 | return stream(concat(this, ...values));
226 | },
227 | reduce(fn, initialValue) {
228 | return reduce(fn, initialValue, this);
229 | },
230 | find(fn) {
231 | return find(fn, this);
232 | },
233 | findIndex(fn) {
234 | return findIndex(fn, this);
235 | },
236 | includes(item, from = 0) {
237 | return includes(item, from, this);
238 | },
239 | every(fn) {
240 | return every(fn, this);
241 | },
242 | some(fn) {
243 | return some(fn, this);
244 | }
245 | };
246 |
247 | const stream = iterable => {
248 | const source = !iterable[Symbol.asyncIterator] ? toAsync(iterable) : iterable; // we make a difference as any wrap of iterable has performance impact (for the moment)
249 | return Object.create(proto, {_source: {value: source}});
250 | };
251 |
252 | export { concat, every, filter, find, findIndex, flatMap, toAsync as from, includes, map, reduce, skip, slice, some, stream, take };
253 |
--------------------------------------------------------------------------------
/dist/declarations/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | interface MapCallback {
4 | (item: T, index: number, iterable: AsyncIterable): U | Promise;
5 | }
6 |
7 | declare function map(callback: MapCallback): (iterable: AsyncIterable) => AsyncIterable;
8 | declare function map(callback: MapCallback, iterable: AsyncIterable): AsyncIterable;
9 |
10 | interface PredicateCallback {
11 | (item: T, index: number, iterable: AsyncIterable): boolean;
12 | }
13 |
14 | declare function filter(callback: PredicateCallback): (iterable: AsyncIterable) => AsyncIterable;
15 | declare function filter(callback: PredicateCallback, iterable: AsyncIterable): AsyncIterable;
16 |
17 | declare function take(number: number): (iterable: AsyncIterable) => AsyncIterable;
18 | declare function take(number: number, iterable: AsyncIterable): AsyncIterable;
19 |
20 | declare function skip(number: number): (iterable: AsyncIterable) => AsyncIterable;
21 | declare function skip(number: number, iterable: AsyncIterable): AsyncIterable;
22 |
23 | type ItemOrAsyncIterable = T | AsyncIterable;
24 |
25 | declare function flatMap(fn: MapCallback): (iterable: AsyncIterable>) => AsyncIterable;
26 | declare function flatMap(fn: MapCallback, iterable: AsyncIterable>): AsyncIterable;
27 |
28 | declare function slice(iterable: AsyncIterable): AsyncIterable;
29 | declare function slice(start: number, iterable: AsyncIterable): AsyncIterable;
30 | declare function slice(start: number, end: number, iterable: AsyncIterable): AsyncIterable;
31 | declare function slice(start?: number, end?: number): (iterable: AsyncIterable) => AsyncIterable;
32 |
33 | declare function concat(...args: ItemOrAsyncIterable[]): AsyncIterable;
34 |
35 | interface ReduceCallback {
36 | (accumulator: U, currentItem: T, index: number, iterable: AsyncIterable): Promise;
37 | }
38 |
39 | declare function reduce(fn: ReduceCallback, initialValue?: U): (iterable: AsyncIterable) => Promise;
40 | declare function reduce(fn: ReduceCallback, iterable: AsyncIterable): Promise;
41 | declare function reduce(fn: ReduceCallback, initialValue: U, iterable: AsyncIterable): Promise;
42 |
43 | interface TupleCallback {
44 | (item: T, index: number, iterable: AsyncIterable): boolean;
45 | }
46 |
47 | declare function find(fn: TupleCallback): (iterable: AsyncIterable) => Promise;
48 | declare function find(fn: TupleCallback, iterable: AsyncIterable): Promise;
49 |
50 | declare function findIndex(fn: TupleCallback): (iterable: AsyncIterable) => Promise;
51 | declare function findIndex(fn: TupleCallback, iterable: AsyncIterable): Promise;
52 |
53 | declare function includes(item: T, from ?: number): (iterable: AsyncIterable) => Promise;
54 | declare function includes(item: T, iterable: AsyncIterable): Promise;
55 | declare function includes(item: T, from: number, iterable: AsyncIterable): Promise;
56 |
57 | declare function every(fn: PredicateCallback, iterable: AsyncIterable): Promise;
58 | declare function every(fn: PredicateCallback): (iterable: AsyncIterable) => Promise;
59 |
60 | declare function some(fn: PredicateCallback, iterable: AsyncIterable): Promise;
61 | declare function some(fn: PredicateCallback): (iterable: AsyncIterable) => Promise;
62 |
63 | declare function from(iterable: Iterable): AsyncIterable;
64 |
65 | export interface Stream extends AsyncIterable {
66 | map(fn: MapCallback): Stream;
67 |
68 | filter(fn: PredicateCallback): Stream;
69 |
70 | flatMap(fn: MapCallback): Stream;
71 |
72 | slice(start?: number, end?: number): Stream;
73 |
74 | concat(...values: ItemOrAsyncIterable[]): Stream;
75 |
76 | reduce(fn: ReduceCallback, initialValue?: U): Promise;
77 |
78 | find(fn: TupleCallback): Promise;
79 |
80 | findIndex(fn: TupleCallback): Promise;
81 |
82 | includes(item: T, from?: number): Promise;
83 |
84 | every(fn: PredicateCallback): Promise;
85 |
86 | some(fn: PredicateCallback): Promise;
87 | }
88 |
89 | declare function stream(iterable: Iterable | AsyncIterable): Stream;
90 |
--------------------------------------------------------------------------------
/examples/browser/browser-adapter.js:
--------------------------------------------------------------------------------
1 | export default async function* (readable) {
2 | let exhausted = false;
3 | const reader = readable.getReader();
4 | try {
5 | while (true) {
6 | const {value, done} = await reader.read();
7 | exhausted = done;
8 | if (done) {
9 | break;
10 | }
11 | yield value;
12 | }
13 | }
14 | finally {
15 | reader.cancel();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/browser/fromFetch.js:
--------------------------------------------------------------------------------
1 | import iterable from './browser-adapter.js';
2 |
3 | export default (path, otps = {}) => {
4 | return {
5 | [Symbol.asyncIterator]: async function* () {
6 | const res = await fetch(path);
7 | for await (const chunk of iterable(res.body)) {
8 | // decode
9 | yield String.fromCodePoint(...chunk);
10 | }
11 | }
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/examples/csv-parser.js:
--------------------------------------------------------------------------------
1 | import {stream} from '../dist/bundle/module.js';
2 |
3 | // take chunks stream (whether they come from file or network) and yield lines.
4 | export const lines = chunkStream => ({
5 | [Symbol.asyncIterator]: async function* () {
6 | let remaining = ''; // chunk may ends in the middle of a line
7 | for await (const chunk of chunkStream) {
8 | const chunkLines = (remaining + chunk).split('\n');
9 | remaining = chunkLines.pop();
10 | yield* chunkLines;
11 | }
12 | yield remaining;
13 | }
14 | });
15 |
16 | export async function parser(source) {
17 | const iterable = stream(lines(source))
18 | .map(i => i.split(','));
19 |
20 | const headers = await iterable
21 | .slice(0, 1)
22 | .reduce(acc => acc);
23 |
24 | return stream(iterable)
25 | .slice(1)
26 | .map(line => {
27 | const item = {};
28 | for (let i = 0; i < headers.length; i++) {
29 | item[headers[i]] = line[i];
30 | }
31 | return item;
32 | });
33 | }
34 |
35 |
36 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/node.js:
--------------------------------------------------------------------------------
1 | import {parser} from './csv-parser.js';
2 | import fromFile from './node/fromFile.js';
3 |
4 | //program
5 | (async function () {
6 | const stream = await parser(fromFile('./examples/fixture.csv'));
7 | for await (const line of stream) {
8 | console.log(line);
9 | }
10 | })();
11 |
--------------------------------------------------------------------------------
/examples/node/fromFile.js:
--------------------------------------------------------------------------------
1 | import {createReadStream} from 'fs';
2 |
3 | // note: create a new stream on every asyncIterator invocation
4 | export default (file, opts = {encoding: 'utf8'}) => {
5 | return ({
6 | [Symbol.asyncIterator]() {
7 | return createReadStream(file, opts)[Symbol.asyncIterator]();
8 | }
9 | });
10 | }
11 |
--------------------------------------------------------------------------------
/examples/readme.md:
--------------------------------------------------------------------------------
1 | # examples
2 |
3 | ### run for nodejs (version > 9)
4 |
5 | ``npm run example:node``
6 |
7 | ### run for browser (chrome without transpilation)
8 |
9 | ``npm run example:browser``
10 |
11 | [open in the browser](http://localhost:8080/examples/index.html
--------------------------------------------------------------------------------
/examples/scripts/fixtures.js:
--------------------------------------------------------------------------------
1 | console.log('id,foo,bar,bim');
2 |
3 | const int = () => Math.floor(Math.random() * 10);
4 |
5 | for (let i = 0; i<10000;i++){
6 | console.log(`${i},${int()},${int()},${int()}`);
7 | }
8 |
--------------------------------------------------------------------------------
/examples/scripts/rollup.node.js:
--------------------------------------------------------------------------------
1 | import node from 'rollup-plugin-node-resolve';
2 |
3 | export default {
4 | input: './examples/node.js',
5 | output: [{
6 | format: 'cjs'
7 | }],
8 | plugins:[node()]
9 | };
10 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@lorenzofox3/for-await",
3 | "version": "0.2.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@types/estree": {
8 | "version": "0.0.41",
9 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.41.tgz",
10 | "integrity": "sha512-rIAmXyJlqw4KEBO7+u9gxZZSQHaCNnIzYrnNmYVpgfJhxTqO0brCX0SYpqUTkVI5mwwUwzmtspLBGBKroMeynA==",
11 | "dev": true
12 | },
13 | "@types/node": {
14 | "version": "13.1.1",
15 | "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.1.tgz",
16 | "integrity": "sha512-hx6zWtudh3Arsbl3cXay+JnkvVgCKzCWKv42C9J01N2T2np4h8w5X8u6Tpz5mj38kE3M9FM0Pazx8vKFFMnjLQ==",
17 | "dev": true
18 | },
19 | "@types/resolve": {
20 | "version": "0.0.8",
21 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
22 | "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
23 | "dev": true,
24 | "requires": {
25 | "@types/node": "*"
26 | }
27 | },
28 | "acorn": {
29 | "version": "7.1.0",
30 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
31 | "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
32 | "dev": true
33 | },
34 | "ansi-regex": {
35 | "version": "2.1.1",
36 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
37 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
38 | "dev": true
39 | },
40 | "ansi-styles": {
41 | "version": "2.2.1",
42 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
43 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
44 | "dev": true
45 | },
46 | "argparse": {
47 | "version": "1.0.10",
48 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
49 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
50 | "dev": true,
51 | "requires": {
52 | "sprintf-js": "~1.0.2"
53 | }
54 | },
55 | "builtin-modules": {
56 | "version": "3.1.0",
57 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
58 | "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
59 | "dev": true
60 | },
61 | "chalk": {
62 | "version": "1.1.3",
63 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
64 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
65 | "dev": true,
66 | "requires": {
67 | "ansi-styles": "^2.2.1",
68 | "escape-string-regexp": "^1.0.2",
69 | "has-ansi": "^2.0.0",
70 | "strip-ansi": "^3.0.0",
71 | "supports-color": "^2.0.0"
72 | }
73 | },
74 | "core-util-is": {
75 | "version": "1.0.2",
76 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
77 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
78 | "dev": true
79 | },
80 | "diff": {
81 | "version": "2.2.3",
82 | "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.3.tgz",
83 | "integrity": "sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=",
84 | "dev": true
85 | },
86 | "duplexer": {
87 | "version": "0.1.1",
88 | "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
89 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
90 | "dev": true
91 | },
92 | "escape-string-regexp": {
93 | "version": "1.0.5",
94 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
95 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
96 | "dev": true
97 | },
98 | "esprima": {
99 | "version": "4.0.1",
100 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
101 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
102 | "dev": true
103 | },
104 | "estree-walker": {
105 | "version": "0.6.1",
106 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
107 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
108 | "dev": true
109 | },
110 | "events-to-array": {
111 | "version": "1.1.2",
112 | "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz",
113 | "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=",
114 | "dev": true
115 | },
116 | "figures": {
117 | "version": "1.7.0",
118 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
119 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
120 | "dev": true,
121 | "requires": {
122 | "escape-string-regexp": "^1.0.5",
123 | "object-assign": "^4.1.0"
124 | }
125 | },
126 | "has-ansi": {
127 | "version": "2.0.0",
128 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
129 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
130 | "dev": true,
131 | "requires": {
132 | "ansi-regex": "^2.0.0"
133 | }
134 | },
135 | "inherits": {
136 | "version": "2.0.3",
137 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
138 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
139 | "dev": true
140 | },
141 | "is-finite": {
142 | "version": "1.0.2",
143 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
144 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
145 | "dev": true,
146 | "requires": {
147 | "number-is-nan": "^1.0.0"
148 | }
149 | },
150 | "is-module": {
151 | "version": "1.0.0",
152 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
153 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
154 | "dev": true
155 | },
156 | "is-reference": {
157 | "version": "1.1.4",
158 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz",
159 | "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==",
160 | "dev": true,
161 | "requires": {
162 | "@types/estree": "0.0.39"
163 | },
164 | "dependencies": {
165 | "@types/estree": {
166 | "version": "0.0.39",
167 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
168 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
169 | "dev": true
170 | }
171 | }
172 | },
173 | "isarray": {
174 | "version": "1.0.0",
175 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
176 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
177 | "dev": true
178 | },
179 | "js-yaml": {
180 | "version": "3.13.1",
181 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
182 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
183 | "dev": true,
184 | "requires": {
185 | "argparse": "^1.0.7",
186 | "esprima": "^4.0.0"
187 | }
188 | },
189 | "magic-string": {
190 | "version": "0.25.4",
191 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz",
192 | "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==",
193 | "dev": true,
194 | "requires": {
195 | "sourcemap-codec": "^1.4.4"
196 | }
197 | },
198 | "number-is-nan": {
199 | "version": "1.0.1",
200 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
201 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
202 | "dev": true
203 | },
204 | "object-assign": {
205 | "version": "4.1.1",
206 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
207 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
208 | "dev": true
209 | },
210 | "parse-ms": {
211 | "version": "1.0.1",
212 | "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz",
213 | "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=",
214 | "dev": true
215 | },
216 | "path-parse": {
217 | "version": "1.0.6",
218 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
219 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
220 | "dev": true
221 | },
222 | "plur": {
223 | "version": "1.0.0",
224 | "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz",
225 | "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=",
226 | "dev": true
227 | },
228 | "pretty-ms": {
229 | "version": "2.1.0",
230 | "resolved": "http://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz",
231 | "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=",
232 | "dev": true,
233 | "requires": {
234 | "is-finite": "^1.0.1",
235 | "parse-ms": "^1.0.0",
236 | "plur": "^1.0.0"
237 | }
238 | },
239 | "process-nextick-args": {
240 | "version": "2.0.0",
241 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
242 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
243 | "dev": true
244 | },
245 | "readable-stream": {
246 | "version": "2.3.6",
247 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
248 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
249 | "dev": true,
250 | "requires": {
251 | "core-util-is": "~1.0.0",
252 | "inherits": "~2.0.3",
253 | "isarray": "~1.0.0",
254 | "process-nextick-args": "~2.0.0",
255 | "safe-buffer": "~5.1.1",
256 | "string_decoder": "~1.1.1",
257 | "util-deprecate": "~1.0.1"
258 | }
259 | },
260 | "resolve": {
261 | "version": "1.14.1",
262 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz",
263 | "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==",
264 | "dev": true,
265 | "requires": {
266 | "path-parse": "^1.0.6"
267 | }
268 | },
269 | "rollup": {
270 | "version": "1.27.14",
271 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.14.tgz",
272 | "integrity": "sha512-DuDjEyn8Y79ALYXMt+nH/EI58L5pEw5HU9K38xXdRnxQhvzUTI/nxAawhkAHUQeudANQ//8iyrhVRHJBuR6DSQ==",
273 | "dev": true,
274 | "requires": {
275 | "@types/estree": "*",
276 | "@types/node": "*",
277 | "acorn": "^7.1.0"
278 | }
279 | },
280 | "rollup-plugin-commonjs": {
281 | "version": "10.1.0",
282 | "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz",
283 | "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==",
284 | "dev": true,
285 | "requires": {
286 | "estree-walker": "^0.6.1",
287 | "is-reference": "^1.1.2",
288 | "magic-string": "^0.25.2",
289 | "resolve": "^1.11.0",
290 | "rollup-pluginutils": "^2.8.1"
291 | }
292 | },
293 | "rollup-plugin-node-resolve": {
294 | "version": "5.2.0",
295 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
296 | "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
297 | "dev": true,
298 | "requires": {
299 | "@types/resolve": "0.0.8",
300 | "builtin-modules": "^3.1.0",
301 | "is-module": "^1.0.0",
302 | "resolve": "^1.11.1",
303 | "rollup-pluginutils": "^2.8.1"
304 | }
305 | },
306 | "rollup-pluginutils": {
307 | "version": "2.8.2",
308 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
309 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
310 | "dev": true,
311 | "requires": {
312 | "estree-walker": "^0.6.1"
313 | }
314 | },
315 | "safe-buffer": {
316 | "version": "5.1.2",
317 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
318 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
319 | "dev": true
320 | },
321 | "sourcemap-codec": {
322 | "version": "1.4.6",
323 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz",
324 | "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==",
325 | "dev": true
326 | },
327 | "sprintf-js": {
328 | "version": "1.0.3",
329 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
330 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
331 | "dev": true
332 | },
333 | "string_decoder": {
334 | "version": "1.1.1",
335 | "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
336 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
337 | "dev": true,
338 | "requires": {
339 | "safe-buffer": "~5.1.0"
340 | }
341 | },
342 | "strip-ansi": {
343 | "version": "3.0.1",
344 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
345 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
346 | "dev": true,
347 | "requires": {
348 | "ansi-regex": "^2.0.0"
349 | }
350 | },
351 | "supports-color": {
352 | "version": "2.0.0",
353 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
354 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
355 | "dev": true
356 | },
357 | "tap-diff": {
358 | "version": "0.1.1",
359 | "resolved": "https://registry.npmjs.org/tap-diff/-/tap-diff-0.1.1.tgz",
360 | "integrity": "sha1-j78zM9hWQ/7qG/F1m5CCCwSjfd8=",
361 | "dev": true,
362 | "requires": {
363 | "chalk": "^1.1.1",
364 | "diff": "^2.2.1",
365 | "duplexer": "^0.1.1",
366 | "figures": "^1.4.0",
367 | "pretty-ms": "^2.1.0",
368 | "tap-parser": "^1.2.2",
369 | "through2": "^2.0.0"
370 | }
371 | },
372 | "tap-parser": {
373 | "version": "1.3.2",
374 | "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-1.3.2.tgz",
375 | "integrity": "sha1-EgxQiciMPIp5PvKIhn3jIeGPjCI=",
376 | "dev": true,
377 | "requires": {
378 | "events-to-array": "^1.0.1",
379 | "inherits": "~2.0.1",
380 | "js-yaml": "^3.2.7",
381 | "readable-stream": "^2"
382 | }
383 | },
384 | "through2": {
385 | "version": "2.0.3",
386 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
387 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
388 | "dev": true,
389 | "requires": {
390 | "readable-stream": "^2.1.5",
391 | "xtend": "~4.0.1"
392 | }
393 | },
394 | "util-deprecate": {
395 | "version": "1.0.2",
396 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
397 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
398 | "dev": true
399 | },
400 | "xtend": {
401 | "version": "4.0.1",
402 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
403 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
404 | "dev": true
405 | },
406 | "zora": {
407 | "version": "3.1.8",
408 | "resolved": "https://registry.npmjs.org/zora/-/zora-3.1.8.tgz",
409 | "integrity": "sha512-AArEyKiLWi3eLXW2uRbfPvANfSQgV8VHoCuXCihCTQyUv7brFrghGbsUqKxqucc+QodQ1G2+O8Gpsz8RVpeiRQ==",
410 | "dev": true
411 | }
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@lorenzofox3/for-await",
3 | "version": "0.2.1",
4 | "description": "operators and stream utilities for async iterators",
5 | "engines": {
6 | "node": ">=9.3.0"
7 | },
8 | "directories": {
9 | "test": "test"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/lorenzofox3/for-await.git"
14 | },
15 | "main": "./dist/bundle/index",
16 | "module": "./dist/bundle/module.js",
17 | "types": "./dist/bundle/index.d.ts",
18 | "scripts": {
19 | "build:clean": "rm -rf ./dist && mkdir -p ./dist/bundle ./dist/declarations",
20 | "build:bundle": "rollup -c ./rollup/build.js && cp ./src/index.d.ts ./dist/declarations/",
21 | "build": "npm run build:clean && npm run build:bundle",
22 | "test": "rollup -c ./rollup/test.js --output.format cjs | node",
23 | "test:ci": "rollup -c ./rollup/test.js --output.format cjs | node | tap-diff",
24 | "example:node": "rollup -c ./examples/scripts/rollup.node.js | node"
25 | },
26 | "files": [
27 | "dist/bundle",
28 | "dist/declarations"
29 | ],
30 | "keywords": [
31 | "stream",
32 | "for-await",
33 | "reactive-programming",
34 | "iterator",
35 | "async-iterator",
36 | "asyncIterator",
37 | "generator",
38 | "async"
39 | ],
40 | "author": "Laurent Renard",
41 | "license": "MIT",
42 | "devDependencies": {
43 | "rollup": "^1.27.14",
44 | "rollup-plugin-commonjs": "^10.1.0",
45 | "rollup-plugin-node-resolve": "^5.2.0",
46 | "tap-diff": "^0.1.1",
47 | "zora": "^3.1.8"
48 | },
49 | "dependencies": {}
50 | }
51 |
--------------------------------------------------------------------------------
/rollup/build.js:
--------------------------------------------------------------------------------
1 | export default {
2 | input: './src/index.js',
3 | output: [{
4 | file: './dist/bundle/index.js',
5 | format: 'cjs'
6 | }, {
7 | file: './dist/bundle/index.mjs',
8 | format: 'es'
9 | }, {
10 | file: './dist/bundle/module.js',
11 | format: 'es'
12 | }, {
13 | file: './dist/bundle/for-await.js',
14 | format: 'iife',
15 | name: 'ForAwait'
16 | }]
17 | };
18 |
--------------------------------------------------------------------------------
/rollup/test.js:
--------------------------------------------------------------------------------
1 | import node from 'rollup-plugin-node-resolve';
2 | import cjs from 'rollup-plugin-commonjs';
3 |
4 | export default {
5 | input: './test/index.js',
6 | plugins: [node(), cjs()]
7 | };
8 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | interface MapCallback {
4 | (item: T, index: number, iterable: AsyncIterable): U | Promise;
5 | }
6 |
7 | declare function map(callback: MapCallback): (iterable: AsyncIterable) => AsyncIterable;
8 | declare function map(callback: MapCallback, iterable: AsyncIterable): AsyncIterable;
9 |
10 | interface PredicateCallback {
11 | (item: T, index: number, iterable: AsyncIterable): boolean;
12 | }
13 |
14 | declare function filter(callback: PredicateCallback): (iterable: AsyncIterable) => AsyncIterable;
15 | declare function filter(callback: PredicateCallback, iterable: AsyncIterable): AsyncIterable;
16 |
17 | declare function take(number: number): (iterable: AsyncIterable) => AsyncIterable;
18 | declare function take(number: number, iterable: AsyncIterable): AsyncIterable;
19 |
20 | declare function skip(number: number): (iterable: AsyncIterable) => AsyncIterable;
21 | declare function skip(number: number, iterable: AsyncIterable): AsyncIterable;
22 |
23 | type ItemOrAsyncIterable = T | AsyncIterable;
24 |
25 | declare function flatMap(fn: MapCallback): (iterable: AsyncIterable>) => AsyncIterable;
26 | declare function flatMap(fn: MapCallback, iterable: AsyncIterable>): AsyncIterable;
27 |
28 | declare function slice(iterable: AsyncIterable): AsyncIterable;
29 | declare function slice(start: number, iterable: AsyncIterable): AsyncIterable;
30 | declare function slice(start: number, end: number, iterable: AsyncIterable): AsyncIterable;
31 | declare function slice(start?: number, end?: number): (iterable: AsyncIterable) => AsyncIterable;
32 |
33 | declare function concat(...args: ItemOrAsyncIterable[]): AsyncIterable;
34 |
35 | interface ReduceCallback {
36 | (accumulator: U, currentItem: T, index: number, iterable: AsyncIterable): Promise;
37 | }
38 |
39 | declare function reduce(fn: ReduceCallback, initialValue?: U): (iterable: AsyncIterable) => Promise;
40 | declare function reduce(fn: ReduceCallback, iterable: AsyncIterable): Promise;
41 | declare function reduce(fn: ReduceCallback, initialValue: U, iterable: AsyncIterable): Promise;
42 |
43 | interface TupleCallback {
44 | (item: T, index: number, iterable: AsyncIterable): boolean;
45 | }
46 |
47 | declare function find(fn: TupleCallback): (iterable: AsyncIterable) => Promise;
48 | declare function find(fn: TupleCallback, iterable: AsyncIterable): Promise;
49 |
50 | declare function findIndex(fn: TupleCallback): (iterable: AsyncIterable) => Promise;
51 | declare function findIndex(fn: TupleCallback, iterable: AsyncIterable): Promise;
52 |
53 | declare function includes(item: T, from ?: number): (iterable: AsyncIterable) => Promise;
54 | declare function includes(item: T, iterable: AsyncIterable): Promise;
55 | declare function includes(item: T, from: number, iterable: AsyncIterable): Promise;
56 |
57 | declare function every(fn: PredicateCallback, iterable: AsyncIterable): Promise;
58 | declare function every(fn: PredicateCallback): (iterable: AsyncIterable