/** * @file stream.js */ /** * A lightweight readable stream implemention that handles event dispatching. * * @class Stream */ export default class Stream { constructor() { this.listeners = {}; } /** * Add a listener for a specified event type. * * @param {String} type the event name * @param {Function} listener the callback to be invoked when an event of * the specified type occurs */ on(type, listener) { if (!this.listeners[type]) { this.listeners[type] = []; } this.listeners[type].push(listener); } /** * Remove a listener for a specified event type. * * @param {String} type the event name * @param {Function} listener a function previously registered for this * type of event through `on` * @return {Boolean} if we could turn it off or not */ off(type, listener) { let index; if (!this.listeners[type]) { return false; } index = this.listeners[type].indexOf(listener); this.listeners[type].splice(index, 1); return index > -1; } /** * Trigger an event of the specified type on this stream. Any additional * arguments to this function are passed as parameters to event listeners. * * @param {String} type the event name */ trigger(type) { let callbacks; let i; let length; let args; callbacks = this.listeners[type]; if (!callbacks) { return; } // Slicing the arguments on every invocation of this method // can add a significant amount of overhead. Avoid the // intermediate object creation for the common case of a // single callback argument if (arguments.length === 2) { length = callbacks.length; for (i = 0; i < length; ++i) { callbacks[i].call(this, arguments[1]); } } else { args = Array.prototype.slice.call(arguments, 1); length = callbacks.length; for (i = 0; i < length; ++i) { callbacks[i].apply(this, args); } } } /** * Destroys the stream and cleans up. */ dispose() { this.listeners = {}; } /** * Forwards all `data` events on this stream to the destination stream. The * destination stream should provide a method `push` to receive the data * events as they arrive. * * @param {Stream} destination the stream that will receive all `data` events * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options */ pipe(destination) { this.on('data', function(data) { destination.push(data); }); } }