UNPKG

graphile-build

Version:

Build a GraphQL schema from plugins

103 lines (95 loc) 2.64 kB
// @flow /* eslint-disable flowtype/no-weak-types */ // Turn a callback-based listener into an async iterator // From https://raw.githubusercontent.com/withspectrum/callback-to-async-iterator/master/src/index.js // License MIT (Copyright (c) 2017 Maximilian Stoiber) // Based on https://github.com/apollographql/graphql-subscriptions/blob/master/src/event-emitter-to-async-iterator.ts import { $$asyncIterator } from "iterall"; const defaultOnError = (err: Error) => { throw err; }; export default function callbackToAsyncIterator< CallbackInput: any, ReturnVal: any >( listener: ((arg: CallbackInput) => any) => ?ReturnVal | Promise<?ReturnVal>, options?: { onError?: (err: Error) => void, onClose?: (arg?: ?ReturnVal) => void, buffering?: boolean, } = {} ) { const { onError = defaultOnError, buffering = true, onClose } = options; let pullQueue = []; let pushQueue = []; let listening = true; let listenerReturnValue; function pushValue(value) { if (pullQueue.length !== 0) { pullQueue.shift()({ value, done: false }); } else if (buffering === true) { pushQueue.push(value); } } function pullValue() { return new Promise(resolve => { if (pushQueue.length !== 0) { resolve({ value: pushQueue.shift(), done: false }); } else { pullQueue.push(resolve); } }); } function emptyQueue() { if (listening) { listening = false; pullQueue.forEach(resolve => resolve({ value: undefined, done: true })); pullQueue = []; pushQueue = []; onClose && onClose(listenerReturnValue); } } try { // Start listener Promise.resolve(listener(value => pushValue(value))) .then(a => { listenerReturnValue = a; }) .catch(err => { onError(err); }); return { next(): Promise<{ value?: CallbackInput, done: boolean }> { return listening ? pullValue() : this.return(); }, return(): Promise<{ value: typeof undefined, done: boolean }> { emptyQueue(); return Promise.resolve({ value: undefined, done: true }); }, throw(error: Error) { emptyQueue(); onError(error); return Promise.reject(error); }, [$$asyncIterator]() { return this; }, }; } catch (err) { onError(err); return { next() { return Promise.reject(err); }, return() { return Promise.reject(err); }, throw(error: Error) { return Promise.reject(error); }, [$$asyncIterator]() { return this; }, }; } }