UNPKG

scramjet-core

Version:

A pluggable minimal version of Scramjet that focuses only on stream transform and exposes only core features

117 lines (103 loc) 4.1 kB
const ignore = () => 0; const { StreamError } = require("./stream-errors"); /** * Generate transform methods on the stream class. * * @internal * @memberof PromiseTransformStream * @param {DataStreamOptions} newOptions Sanitized options passed to scramjet stream * @return {Boolean} returns true if creation of new stream is not necessary (promise can be pushed to queue) */ module.exports = ({filter}) => function mkTransform(newOptions) { this.setOptions( { transforms: [], beforeTransform: newOptions.beforeTransform, afterTransform: newOptions.afterTransform, promiseFlush: newOptions.promiseFlush } ); this.cork(); if (newOptions.referrer instanceof this.constructor && !newOptions.referrer._tapped && !newOptions.referrer._options.promiseFlush) { return true; } process.nextTick(this.uncork.bind(this)); this.pushTransform(newOptions); if (this._scramjet_options.transforms.length) { const processing = []; let last = Promise.resolve(); this._transform = (chunk, encoding, callback) => { if (!this._scramjet_options.transforms.length) { return last.then( () => callback(null, chunk) ); } const prev = last; const ref = last = Promise .all([ this._scramjet_options.transforms.reduce( (prev, transform) => prev.then(transform), Promise.resolve(chunk) ).catch( (err) => err === filter ? filter : Promise.reject(err) ), prev ]) .catch( async (e) => { if (e instanceof Error) { return Promise.all([ this.raise(new StreamError(e, this, "EXTERNAL", chunk), chunk), prev ]); } else { throw new Error("New stream error raised without cause!"); } } ) .then( (args) => { if (args && args[0] !== filter && typeof args[0] !== "undefined") { try { this.push(args[0]); } catch(e) { return this.raise(new StreamError(e, this, "INTERNAL", chunk), chunk); } } } ); processing.push(ref); // append item to queue if (processing.length >= this._options.maxParallel) { processing[processing.length - this._options.maxParallel] .then(() => callback()) .catch(ignore); } else { callback(); } ref.then( () => { const next = processing.shift(); return ref !== next && this.raise(new StreamError(new Error(`Promise resolved out of sequence in ${this.name}!`), this, "TRANSFORM_OUT_OF_SEQ", chunk), chunk); } ); }; this._flush = (callback) => { if (this._scramjet_options.runFlush) { last .then(this._scramjet_options.runFlush) .then( (data) => { if (Array.isArray(data)) data.forEach(item => this.push(item)); else if (data) this.push(data); }, e => this.raise(e) ) .then(() => callback()); } else { last.then(() => callback()); } }; } };