mute.js 3.45 KB
var Stream = require('stream')

module.exports = MuteStream

// var out = new MuteStream(process.stdout)
// argument auto-pipes
function MuteStream (opts) {
  Stream.apply(this)
  opts = opts || {}
  this.writable = this.readable = true
  this.muted = false
  this.on('pipe', this._onpipe)
  this.replace = opts.replace

  // For readline-type situations
  // This much at the start of a line being redrawn after a ctrl char
  // is seen (such as backspace) won't be redrawn as the replacement
  this._prompt = opts.prompt || null
  this._hadControl = false
}

MuteStream.prototype = Object.create(Stream.prototype)

Object.defineProperty(MuteStream.prototype, 'constructor', {
  value: MuteStream,
  enumerable: false
})

MuteStream.prototype.mute = function () {
  this.muted = true
}

MuteStream.prototype.unmute = function () {
  this.muted = false
}

Object.defineProperty(MuteStream.prototype, '_onpipe', {
  value: onPipe,
  enumerable: false,
  writable: true,
  configurable: true
})

function onPipe (src) {
  this._src = src
}

Object.defineProperty(MuteStream.prototype, 'isTTY', {
  get: getIsTTY,
  set: setIsTTY,
  enumerable: true,
  configurable: true
})

function getIsTTY () {
  return( (this._dest) ? this._dest.isTTY
        : (this._src) ? this._src.isTTY
        : false
        )
}

// basically just get replace the getter/setter with a regular value
function setIsTTY (isTTY) {
  Object.defineProperty(this, 'isTTY', {
    value: isTTY,
    enumerable: true,
    writable: true,
    configurable: true
  })
}

Object.defineProperty(MuteStream.prototype, 'rows', {
  get: function () {
    return( this._dest ? this._dest.rows
          : this._src ? this._src.rows
          : undefined )
  }, enumerable: true, configurable: true })

Object.defineProperty(MuteStream.prototype, 'columns', {
  get: function () {
    return( this._dest ? this._dest.columns
          : this._src ? this._src.columns
          : undefined )
  }, enumerable: true, configurable: true })


MuteStream.prototype.pipe = function (dest, options) {
  this._dest = dest
  return Stream.prototype.pipe.call(this, dest, options)
}

MuteStream.prototype.pause = function () {
  if (this._src) return this._src.pause()
}

MuteStream.prototype.resume = function () {
  if (this._src) return this._src.resume()
}

MuteStream.prototype.write = function (c) {
  if (this.muted) {
    if (!this.replace) return true
    if (c.match(/^\u001b/)) {
      if(c.indexOf(this._prompt) === 0) {
        c = c.substr(this._prompt.length);
        c = c.replace(/./g, this.replace);
        c = this._prompt + c;
      }
      this._hadControl = true
      return this.emit('data', c)
    } else {
      if (this._prompt && this._hadControl &&
          c.indexOf(this._prompt) === 0) {
        this._hadControl = false
        this.emit('data', this._prompt)
        c = c.substr(this._prompt.length)
      }
      c = c.toString().replace(/./g, this.replace)
    }
  }
  this.emit('data', c)
}

MuteStream.prototype.end = function (c) {
  if (this.muted) {
    if (c && this.replace) {
      c = c.toString().replace(/./g, this.replace)
    } else {
      c = null
    }
  }
  if (c) this.emit('data', c)
  this.emit('end')
}

function proxy (fn) { return function () {
  var d = this._dest
  var s = this._src
  if (d && d[fn]) d[fn].apply(d, arguments)
  if (s && s[fn]) s[fn].apply(s, arguments)
}}

MuteStream.prototype.destroy = proxy('destroy')
MuteStream.prototype.destroySoon = proxy('destroySoon')
MuteStream.prototype.close = proxy('close')