Spaces:
Running
Running
| const Stream = require('stream') | |
| class MuteStream extends Stream { | |
| #isTTY = null | |
| constructor (opts = {}) { | |
| super(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 | |
| } | |
| #destSrc (key, def) { | |
| if (this._dest) { | |
| return this._dest[key] | |
| } | |
| if (this._src) { | |
| return this._src[key] | |
| } | |
| return def | |
| } | |
| #proxy (method, ...args) { | |
| if (typeof this._dest?.[method] === 'function') { | |
| this._dest[method](...args) | |
| } | |
| if (typeof this._src?.[method] === 'function') { | |
| this._src[method](...args) | |
| } | |
| } | |
| get isTTY () { | |
| if (this.#isTTY !== null) { | |
| return this.#isTTY | |
| } | |
| return this.#destSrc('isTTY', false) | |
| } | |
| // basically just get replace the getter/setter with a regular value | |
| set isTTY (val) { | |
| this.#isTTY = val | |
| } | |
| get rows () { | |
| return this.#destSrc('rows') | |
| } | |
| get columns () { | |
| return this.#destSrc('columns') | |
| } | |
| mute () { | |
| this.muted = true | |
| } | |
| unmute () { | |
| this.muted = false | |
| } | |
| _onpipe (src) { | |
| this._src = src | |
| } | |
| pipe (dest, options) { | |
| this._dest = dest | |
| return super.pipe(dest, options) | |
| } | |
| pause () { | |
| if (this._src) { | |
| return this._src.pause() | |
| } | |
| } | |
| resume () { | |
| if (this._src) { | |
| return this._src.resume() | |
| } | |
| } | |
| write (c) { | |
| if (this.muted) { | |
| if (!this.replace) { | |
| return true | |
| } | |
| // eslint-disable-next-line no-control-regex | |
| if (c.match(/^\u001b/)) { | |
| if (c.indexOf(this._prompt) === 0) { | |
| c = c.slice(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.slice(this._prompt.length) | |
| } | |
| c = c.toString().replace(/./g, this.replace) | |
| } | |
| } | |
| this.emit('data', c) | |
| } | |
| end (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') | |
| } | |
| destroy (...args) { | |
| return this.#proxy('destroy', ...args) | |
| } | |
| destroySoon (...args) { | |
| return this.#proxy('destroySoon', ...args) | |
| } | |
| close (...args) { | |
| return this.#proxy('close', ...args) | |
| } | |
| } | |
| module.exports = MuteStream | |