1 | import process from 'node:process';
|
2 | import readline from 'node:readline';
|
3 | import {BufferListStream} from 'bl';
|
4 |
|
5 | const ASCII_ETX_CODE = 0x03;
|
6 |
|
7 | export class StdinDiscarder {
|
8 | #requests = 0;
|
9 | #mutedStream = new BufferListStream();
|
10 | #ourEmit;
|
11 | #rl;
|
12 |
|
13 | constructor() {
|
14 | this.#mutedStream.pipe(process.stdout);
|
15 |
|
16 | const self = this;
|
17 | this.#ourEmit = function (event, data, ...args) {
|
18 | const {stdin} = process;
|
19 | if (self.#requests > 0 || stdin.emit === self.#ourEmit) {
|
20 | if (event === 'keypress') {
|
21 | return;
|
22 | }
|
23 |
|
24 | if (event === 'data' && data.includes(ASCII_ETX_CODE)) {
|
25 | process.emit('SIGINT');
|
26 | }
|
27 |
|
28 | Reflect.apply(self.#ourEmit, this, [event, data, ...args]);
|
29 | } else {
|
30 | Reflect.apply(process.stdin.emit, this, [event, data, ...args]);
|
31 | }
|
32 | };
|
33 | }
|
34 |
|
35 | start() {
|
36 | this.#requests++;
|
37 |
|
38 | if (this.#requests === 1) {
|
39 | this._realStart();
|
40 | }
|
41 | }
|
42 |
|
43 | stop() {
|
44 | if (this.#requests <= 0) {
|
45 | throw new Error('`stop` called more times than `start`');
|
46 | }
|
47 |
|
48 | this.#requests--;
|
49 |
|
50 | if (this.#requests === 0) {
|
51 | this._realStop();
|
52 | }
|
53 | }
|
54 |
|
55 |
|
56 | _realStart() {
|
57 |
|
58 | if (process.platform === 'win32') {
|
59 | return;
|
60 | }
|
61 |
|
62 | this.#rl = readline.createInterface({
|
63 | input: process.stdin,
|
64 | output: this.#mutedStream,
|
65 | });
|
66 |
|
67 | this.#rl.on('SIGINT', () => {
|
68 | if (process.listenerCount('SIGINT') === 0) {
|
69 | process.emit('SIGINT');
|
70 | } else {
|
71 | this.#rl.close();
|
72 | process.kill(process.pid, 'SIGINT');
|
73 | }
|
74 | });
|
75 | }
|
76 |
|
77 | _realStop() {
|
78 | if (process.platform === 'win32') {
|
79 | return;
|
80 | }
|
81 |
|
82 | const {stdin} = process;
|
83 | const wasPaused = stdin.isPaused();
|
84 |
|
85 | this.#rl.close();
|
86 |
|
87 |
|
88 |
|
89 | if (!wasPaused && stdin.isPaused()) {
|
90 | stdin.resume();
|
91 | }
|
92 |
|
93 | this.#rl = undefined;
|
94 | }
|
95 | }
|