mute.js
1 var Stream = require('stream') 2 3 module.exports = MuteStream 4 5 // var out = new MuteStream(process.stdout) 6 // argument auto-pipes 7 function 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 22 MuteStream.prototype = Object.create(Stream.prototype) 23 24 Object.defineProperty(MuteStream.prototype, 'constructor', { 25 value: MuteStream, 26 enumerable: false 27 }) 28 29 MuteStream.prototype.mute = function () { 30 this.muted = true 31 } 32 33 MuteStream.prototype.unmute = function () { 34 this.muted = false 35 } 36 37 Object.defineProperty(MuteStream.prototype, '_onpipe', { 38 value: onPipe, 39 enumerable: false, 40 writable: true, 41 configurable: true 42 }) 43 44 function onPipe (src) { 45 this._src = src 46 } 47 48 Object.defineProperty(MuteStream.prototype, 'isTTY', { 49 get: getIsTTY, 50 set: setIsTTY, 51 enumerable: true, 52 configurable: true 53 }) 54 55 function 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 63 function setIsTTY (isTTY) { 64 Object.defineProperty(this, 'isTTY', { 65 value: isTTY, 66 enumerable: true, 67 writable: true, 68 configurable: true 69 }) 70 } 71 72 Object.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 79 Object.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 87 MuteStream.prototype.pipe = function (dest, options) { 88 this._dest = dest 89 return Stream.prototype.pipe.call(this, dest, options) 90 } 91 92 MuteStream.prototype.pause = function () { 93 if (this._src) return this._src.pause() 94 } 95 96 MuteStream.prototype.resume = function () { 97 if (this._src) return this._src.resume() 98 } 99 100 MuteStream.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 124 MuteStream.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 136 function 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 143 MuteStream.prototype.destroy = proxy('destroy') 144 MuteStream.prototype.destroySoon = proxy('destroySoon') 145 MuteStream.prototype.close = proxy('close')