1
1
import { spawn } from 'child_process' ;
2
- import events from 'events' ;
3
- const { EventEmitter } = events ;
2
+ import { EventEmitter } from 'events' ;
4
3
import B from 'bluebird' ;
5
4
import { quote } from 'shell-quote' ;
6
5
import _ from 'lodash' ;
7
6
import { formatEnoent } from './helpers' ;
8
7
import { createInterface } from 'node:readline' ;
9
8
10
- class SubProcess extends EventEmitter {
9
+ /**
10
+ * @template {SubProcessOptions} TSubProcessOptions
11
+ */
12
+ export class SubProcess extends EventEmitter {
13
+ /**
14
+ * @callback StartDetector
15
+ * @param {TSubProcessOptions extends TIsBufferOpts ? Buffer : string } stdout
16
+ * @param {TSubProcessOptions extends TIsBufferOpts ? Buffer : string } [stderr]
17
+ * @returns {any }
18
+ */
11
19
12
- /** @type {import('child_process').ChildProcess? } */
20
+ /** @type {import('child_process').ChildProcess | null } */
13
21
proc ;
14
-
15
22
/** @type {string[] } */
16
23
args ;
17
-
18
24
/**
19
25
* @type {string }
20
26
*/
21
27
cmd ;
22
-
23
28
/**
24
- * @type {any }
29
+ * @type {SubProcessOptions }
25
30
*/
26
31
opts ;
27
-
28
32
/**
29
33
* @type {boolean }
30
34
*/
31
35
expectingExit ;
32
-
33
36
/**
34
37
* @type {string }
35
38
*/
36
39
rep ;
37
40
38
41
/**
39
42
* @param {string } cmd
40
- * @param {string[] } [args]
41
- * @param {any } [opts]
43
+ * @param {string[] } [args=[] ]
44
+ * @param {TSubProcessOptions } [opts]
42
45
*/
43
- constructor ( cmd , args = [ ] , opts = { } ) {
46
+ constructor ( cmd , args = [ ] , opts ) {
44
47
super ( ) ;
45
48
if ( ! cmd ) throw new Error ( 'Command is required' ) ; // eslint-disable-line curly
46
49
if ( ! _ . isString ( cmd ) ) throw new Error ( 'Command must be a string' ) ; // eslint-disable-line curly
@@ -49,7 +52,7 @@ class SubProcess extends EventEmitter {
49
52
this . cmd = cmd ;
50
53
this . args = args ;
51
54
this . proc = null ;
52
- this . opts = opts ;
55
+ this . opts = opts ?? { } ;
53
56
this . expectingExit = false ;
54
57
55
58
// get a quoted representation of the command for error strings
@@ -128,8 +131,10 @@ class SubProcess extends EventEmitter {
128
131
129
132
// this function handles output that we collect from the subproc
130
133
/**
131
- *
132
- * @param { {stdout: string, stderr: string} } streams
134
+ * @param { {
135
+ * stdout: TSubProcessOptions extends TIsBufferOpts ? Buffer : string,
136
+ * stderr: TSubProcessOptions extends TIsBufferOpts ? Buffer : string
137
+ * } } streams
133
138
*/
134
139
const handleOutput = ( streams ) => {
135
140
const { stdout, stderr} = streams ;
@@ -154,7 +159,7 @@ class SubProcess extends EventEmitter {
154
159
this . proc ?. kill ( 'SIGINT' ) ;
155
160
156
161
if ( err . code === 'ENOENT' ) {
157
- err = await formatEnoent ( err , this . cmd , this . opts ?. cwd ) ;
162
+ err = await formatEnoent ( err , this . cmd , this . opts ?. cwd ?. toString ( ) ) ;
158
163
}
159
164
reject ( err ) ;
160
165
@@ -182,14 +187,22 @@ class SubProcess extends EventEmitter {
182
187
183
188
if ( this . proc . stdout ) {
184
189
this . proc . stdout . on ( 'data' , ( chunk ) =>
185
- handleOutput ( { stdout : isBuffer ? chunk : chunk . toString ( encoding ) , stderr : '' } ) ,
190
+ handleOutput ( {
191
+ stdout : isBuffer ? chunk : chunk . toString ( encoding ) ,
192
+ // @ts -ignore This is OK
193
+ stderr : isBuffer ? Buffer . alloc ( 0 ) : '' ,
194
+ } ) ,
186
195
) ;
187
196
handleStreamLines ( 'stdout' , this . proc . stdout ) ;
188
197
}
189
198
190
199
if ( this . proc . stderr ) {
191
200
this . proc . stderr . on ( 'data' , ( chunk ) =>
192
- handleOutput ( { stdout : '' , stderr : isBuffer ? chunk : chunk . toString ( encoding ) } ) ,
201
+ handleOutput ( {
202
+ // @ts -ignore This is OK
203
+ stdout : isBuffer ? Buffer . alloc ( 0 ) : '' ,
204
+ stderr : isBuffer ? chunk : chunk . toString ( encoding )
205
+ } ) ,
193
206
) ;
194
207
handleStreamLines ( 'stderr' , this . proc . stderr ) ;
195
208
}
@@ -302,12 +315,15 @@ class SubProcess extends EventEmitter {
302
315
}
303
316
}
304
317
305
- export { SubProcess } ;
306
318
export default SubProcess ;
307
319
308
320
/**
309
- * @callback StartDetector
310
- * @param {string } stdout
311
- * @param {string } [stderr]
312
- * @returns {any }
321
+ * @typedef {Object } SubProcessCustomOptions
322
+ * @property {boolean } [isBuffer]
323
+ * @property {string } [encoding]
324
+ */
325
+
326
+ /**
327
+ * @typedef {SubProcessCustomOptions & import('child_process').SpawnOptionsWithoutStdio } SubProcessOptions
328
+ * @typedef {{isBuffer: true} } TIsBufferOpts
313
329
*/
0 commit comments