package/LICENSE000644 0000001375 3560116604 010273 0ustar00000000 000000 The ISC License Copyright (c) Isaac Z. Schlueter and Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. package/index.js000644 0000006524 3560116604 010734 0ustar00000000 000000 const Minipass = require('minipass') const EE = require('events') const isStream = s => s && s instanceof EE && ( typeof s.pipe === 'function' || // readable (typeof s.write === 'function' && typeof s.end === 'function') // writable ) const _head = Symbol('_head') const _tail = Symbol('_tail') const _linkStreams = Symbol('_linkStreams') const _setHead = Symbol('_setHead') const _setTail = Symbol('_setTail') const _onError = Symbol('_onError') const _onData = Symbol('_onData') const _onEnd = Symbol('_onEnd') const _onDrain = Symbol('_onDrain') const _streams = Symbol('_streams') class Pipeline extends Minipass { constructor (opts, ...streams) { if (isStream(opts)) { streams.unshift(opts) opts = {} } super(opts) this[_streams] = [] if (streams.length) this.push(...streams) } [_linkStreams] (streams) { // reduce takes (left,right), and we return right to make it the // new left value. return streams.reduce((src, dest) => { src.on('error', er => dest.emit('error', er)) src.pipe(dest) return dest }) } push (...streams) { this[_streams].push(...streams) if (this[_tail]) streams.unshift(this[_tail]) const linkRet = this[_linkStreams](streams) this[_setTail](linkRet) if (!this[_head]) this[_setHead](streams[0]) } unshift (...streams) { this[_streams].unshift(...streams) if (this[_head]) streams.push(this[_head]) const linkRet = this[_linkStreams](streams) this[_setHead](streams[0]) if (!this[_tail]) this[_setTail](linkRet) } destroy (er) { // set fire to the whole thing. this[_streams].forEach(s => typeof s.destroy === 'function' && s.destroy()) return super.destroy(er) } // readable interface -> tail [_setTail] (stream) { this[_tail] = stream stream.on('error', er => this[_onError](stream, er)) stream.on('data', chunk => this[_onData](stream, chunk)) stream.on('end', () => this[_onEnd](stream)) stream.on('finish', () => this[_onEnd](stream)) } // errors proxied down the pipeline // they're considered part of the "read" interface [_onError] (stream, er) { if (stream === this[_tail]) this.emit('error', er) } [_onData] (stream, chunk) { if (stream === this[_tail]) super.write(chunk) } [_onEnd] (stream) { if (stream === this[_tail]) super.end() } pause () { super.pause() return this[_tail] && this[_tail].pause && this[_tail].pause() } // NB: Minipass calls its internal private [RESUME] method during // pipe drains, to avoid hazards where stream.resume() is overridden. // Thus, we need to listen to the resume *event*, not override the // resume() method, and proxy *that* to the tail. emit (ev, ...args) { if (ev === 'resume' && this[_tail] && this[_tail].resume) this[_tail].resume() return super.emit(ev, ...args) } // writable interface -> head [_setHead] (stream) { this[_head] = stream stream.on('drain', () => this[_onDrain](stream)) } [_onDrain] (stream) { if (stream === this[_head]) this.emit('drain') } write (chunk, enc, cb) { return this[_head].write(chunk, enc, cb) && (this.flowing || this.buffer.length === 0) } end (chunk, enc, cb) { this[_head].end(chunk, enc, cb) return this } } module.exports = Pipeline package/package.json000644 0000001114 3560116604 011543 0ustar00000000 000000 { "name": "minipass-pipeline", "version": "1.2.4", "description": "create a pipeline of streams using Minipass", "author": "Isaac Z. Schlueter (https://izs.me)", "license": "ISC", "scripts": { "test": "tap", "snap": "tap", "preversion": "npm test", "postversion": "npm publish", "postpublish": "git push origin --follow-tags" }, "tap": { "check-coverage": true }, "devDependencies": { "tap": "^14.6.9" }, "dependencies": { "minipass": "^3.0.0" }, "files": [ "index.js" ], "engines": { "node": ">=8" } } package/README.md000644 0000004277 3560116604 010551 0ustar00000000 000000 # minipass-pipeline Create a pipeline of streams using Minipass. Calls `.pipe()` on all the streams in the list. Returns a stream where writes got to the first pipe in the chain, and reads are from the last. Errors are proxied along the chain and emitted on the Pipeline stream. ## USAGE ```js const Pipeline = require('minipass-pipeline') // the list of streams to pipeline together, // a bit like `input | transform | output` in bash const p = new Pipeline(input, transform, output) p.write('foo') // writes to input p.on('data', chunk => doSomething()) // reads from output stream // less contrived example (but still pretty contrived)... const decode = new bunzipDecoder() const unpack = tar.extract({ cwd: 'target-dir' }) const tbz = new Pipeline(decode, unpack) fs.createReadStream('archive.tbz').pipe(tbz) // specify any minipass options if you like, as the first argument // it'll only try to pipeline event emitters with a .pipe() method const p = new Pipeline({ objectMode: true }, input, transform, output) // If you don't know the things to pipe in right away, that's fine. // use p.push(stream) to add to the end, or p.unshift(stream) to the front const databaseDecoderStreamDoohickey = (connectionInfo) => { const p = new Pipeline() logIntoDatabase(connectionInfo).then(connection => { initializeDecoderRing(connectionInfo).then(decoderRing => { p.push(connection, decoderRing) getUpstreamSource(upstream => { p.unshift(upstream) }) }) }) // return to caller right away // emitted data will be upstream -> connection -> decoderRing pipeline return p } ``` Pipeline is a [minipass](http://npm.im/minipass) stream, so it's as synchronous as the streams it wraps. It will buffer data until there is a reader, but no longer, so make sure to attach your listeners before you pipe it somewhere else. ## `new Pipeline(opts = {}, ...streams)` Create a new Pipeline with the specified Minipass options and any streams provided. ## `pipeline.push(stream, ...)` Attach one or more streams to the pipeline at the end (read) side of the pipe chain. ## `pipeline.unshift(stream, ...)` Attach one or more streams to the pipeline at the start (write) side of the pipe chain.