-
Notifications
You must be signed in to change notification settings - Fork 8
Description
In order to support some more niche use-cases I am coming across I was wondering if it is worth creating an AsyncIterator-ext package (see example below).
IMO the best way to go about this would be:
- Create an
AsyncIteratororganisation - Move the
AsyncIteratorrepo to a repo in this organisation [Requires @RubenVerborgh due to repo permissions] - Create a monorepo of extension components that get released under the
@asynciterator/extension-nameschema (I am happy to take responsibility for maintenance of this new repo) - Additionally export all of the extensions in the package
@asynciterator/ext
The downside of having these in a separate package is that it is hard to use these functions as methods of an iterator (as if we just extended the existing AsyncIterator with an AsyncIteratorExt class then using a method like map would return an AsyncIterator class without any of the extension functionality).
An example of an export from that package would be the following maybeIterator function which returns undefined on emptyIterators and an iterator otherwise (the use case for me is to terminate a forward chaining procedure in reasoning components):
import { AsyncIterator } from 'asynciterator';
/**
* @param source An AsyncIterator
* @returns The AsyncIterator if it is not empty, otherwise undefined
*/
async function maybeIterator<T>(source: AsyncIterator<T>): Promise<null | AsyncIterator<T>> {
// Avoid creating a new iterator where possible
if ((source instanceof ArrayIterator || source instanceof BufferedIterator) && source._buffer.length > 0) {
return source
}
if (source instanceof IntegerIterator) {
return source.step >= 0 ? source.next > source.last : source.next : source.last
}
let item;
do {
if ((item = source.read()) !== null)
return source.append([item]);
await awaitReadable(source);
} while (!source.done);
return null;
}
function awaitReadable<T>(source: AsyncIterator<T>): Promise<void> {
return new Promise<void>((res, rej) => {
if (source.readable || source.done)
res();
function done() {
cleanup();
res();
}
function err() {
cleanup();
rej();
}
function cleanup() {
source.removeListener('readable', done);
source.removeListener('end', done);
source.removeListener('error', err);
}
source.on('readable', done);
source.on('end', done);
source.on('error', err);
});
}