1var Stream = require('stream') 2 3module.exports = MuteStream 4 5// var out = new MuteStream(process.stdout) 6// argument auto-pipes 7function MuteStream (opts) { 8 Stream.apply(this) 9 opts = opts || {} 10 this.writable = this.readable = true 11 this.muted = false 12 this.on('pipe', this._onpipe) 13 this.replace = opts.replace 14 15 // For readline-type situations 16 // This much at the start of a line being redrawn after a ctrl char 17 // is seen (such as backspace) won't be redrawn as the replacement 18 this._prompt = opts.prompt || null 19 this._hadControl = false 20} 21 22MuteStream.prototype = Object.create(Stream.prototype) 23 24Object.defineProperty(MuteStream.prototype, 'constructor', { 25 value: MuteStream, 26 enumerable: false 27}) 28 29MuteStream.prototype.mute = function () { 30 this.muted = true 31} 32 33MuteStream.prototype.unmute = function () { 34 this.muted = false 35} 36 37Object.defineProperty(MuteStream.prototype, '_onpipe', { 38 value: onPipe, 39 enumerable: false, 40 writable: true, 41 configurable: true 42}) 43 44function onPipe (src) { 45 this._src = src 46} 47 48Object.defineProperty(MuteStream.prototype, 'isTTY', { 49 get: getIsTTY, 50 set: setIsTTY, 51 enumerable: true, 52 configurable: true 53}) 54 55function getIsTTY () { 56 return( (this._dest) ? this._dest.isTTY 57 : (this._src) ? this._src.isTTY 58 : false 59 ) 60} 61 62// basically just get replace the getter/setter with a regular value 63function setIsTTY (isTTY) { 64 Object.defineProperty(this, 'isTTY', { 65 value: isTTY, 66 enumerable: true, 67 writable: true, 68 configurable: true 69 }) 70} 71 72Object.defineProperty(MuteStream.prototype, 'rows', { 73 get: function () { 74 return( this._dest ? this._dest.rows 75 : this._src ? this._src.rows 76 : undefined ) 77 }, enumerable: true, configurable: true }) 78 79Object.defineProperty(MuteStream.prototype, 'columns', { 80 get: function () { 81 return( this._dest ? this._dest.columns 82 : this._src ? this._src.columns 83 : undefined ) 84 }, enumerable: true, configurable: true }) 85 86 87MuteStream.prototype.pipe = function (dest, options) { 88 this._dest = dest 89 return Stream.prototype.pipe.call(this, dest, options) 90} 91 92MuteStream.prototype.pause = function () { 93 if (this._src) return this._src.pause() 94} 95 96MuteStream.prototype.resume = function () { 97 if (this._src) return this._src.resume() 98} 99 100MuteStream.prototype.write = function (c) { 101 if (this.muted) { 102 if (!this.replace) return true 103 if (c.match(/^\u001b/)) { 104 if(c.indexOf(this._prompt) === 0) { 105 c = c.substr(this._prompt.length); 106 c = c.replace(/./g, this.replace); 107 c = this._prompt + c; 108 } 109 this._hadControl = true 110 return this.emit('data', c) 111 } else { 112 if (this._prompt && this._hadControl && 113 c.indexOf(this._prompt) === 0) { 114 this._hadControl = false 115 this.emit('data', this._prompt) 116 c = c.substr(this._prompt.length) 117 } 118 c = c.toString().replace(/./g, this.replace) 119 } 120 } 121 this.emit('data', c) 122} 123 124MuteStream.prototype.end = function (c) { 125 if (this.muted) { 126 if (c && this.replace) { 127 c = c.toString().replace(/./g, this.replace) 128 } else { 129 c = null 130 } 131 } 132 if (c) this.emit('data', c) 133 this.emit('end') 134} 135 136function proxy (fn) { return function () { 137 var d = this._dest 138 var s = this._src 139 if (d && d[fn]) d[fn].apply(d, arguments) 140 if (s && s[fn]) s[fn].apply(s, arguments) 141}} 142 143MuteStream.prototype.destroy = proxy('destroy') 144MuteStream.prototype.destroySoon = proxy('destroySoon') 145MuteStream.prototype.close = proxy('close') 146