| 1 | // Convert a Node stream to an Async Iterator |
| 2 | export function fromNodeStream(stream) { |
| 3 | // Use native async iteration if it's available. |
| 4 | const asyncIterator = Object.getOwnPropertyDescriptor( |
| 5 | stream, |
| 6 | Symbol.asyncIterator |
| 7 | ) |
| 8 | if (asyncIterator && asyncIterator.enumerable) { |
| 9 | return stream |
| 10 | } |
| 11 | // Author's Note |
| 12 | // I tried many MANY ways to do this. |
| 13 | // I tried two npm modules (stream-to-async-iterator and streams-to-async-iterator) with no luck. |
| 14 | // I tried using 'readable' and .read(), and .pause() and .resume() |
| 15 | // It took me two loooong evenings to get to this point. |
| 16 | // So if you are horrified that this solution just builds up a queue with no backpressure, |
| 17 | // and turns Promises inside out, too bad. This is the first code that worked reliably. |
| 18 | let ended = false |
| 19 | const queue = [] |
| 20 | let defer = {} |
| 21 | stream.on('data', chunk => { |
| 22 | queue.push(chunk) |
| 23 | if (defer.resolve) { |
| 24 | defer.resolve({ value: queue.shift(), done: false }) |
| 25 | defer = {} |
| 26 | } |
| 27 | }) |
| 28 | stream.on('error', err => { |
| 29 | if (defer.reject) { |
| 30 | defer.reject(err) |
| 31 | defer = {} |
| 32 | } |
| 33 | }) |
| 34 | stream.on('end', () => { |
| 35 | ended = true |
| 36 | if (defer.resolve) { |
| 37 | defer.resolve({ done: true }) |
| 38 | defer = {} |
| 39 | } |
| 40 | }) |
| 41 | return { |
| 42 | next() { |
| 43 | return new Promise((resolve, reject) => { |
| 44 | if (queue.length === 0 && ended) { |
| 45 | return resolve({ done: true }) |
| 46 | } else if (queue.length > 0) { |
| 47 | return resolve({ value: queue.shift(), done: false }) |
| 48 | } else if (queue.length === 0 && !ended) { |
| 49 | defer = { resolve, reject } |
| 50 | } |
| 51 | }) |
| 52 | }, |
| 53 | return() { |
| 54 | stream.removeAllListeners() |
| 55 | if (stream.destroy) stream.destroy() |
| 56 | }, |
| 57 | [Symbol.asyncIterator]() { |
| 58 | return this |
| 59 | }, |
| 60 | } |