promisify-child-process 4.1.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,141 @@
1
+ import child_process from 'child_process';
2
+ function joinChunks(chunks, encoding) {
3
+ if (!chunks) return undefined;
4
+ const buffer = Buffer.concat(chunks);
5
+ return encoding && encoding !== 'buffer' ? buffer.toString(encoding) : buffer;
6
+ }
7
+ export function promisifyChildProcess(child, options) {
8
+ var _promise$finally;
9
+ const promise = new Promise((resolve, reject) => {
10
+ var _child$stdout, _child$stderr;
11
+ const encoding = options === null || options === void 0 ? void 0 : options.encoding;
12
+ const killSignal = options === null || options === void 0 ? void 0 : options.killSignal;
13
+ const captureStdio = encoding != null || (options === null || options === void 0 ? void 0 : options.maxBuffer) != null;
14
+ const maxBuffer = (options === null || options === void 0 ? void 0 : options.maxBuffer) ?? 1024 * 1024;
15
+ let bufferSize = 0;
16
+ let error;
17
+ const stdoutChunks = captureStdio && child.stdout ? [] : undefined;
18
+ const stderrChunks = captureStdio && child.stderr ? [] : undefined;
19
+ const capture = chunks => data => {
20
+ if (typeof data === 'string') data = Buffer.from(data);
21
+ const remaining = Math.max(0, maxBuffer - bufferSize);
22
+ bufferSize += Math.min(remaining, data.length);
23
+ if (data.length > remaining) {
24
+ error = new Error('maxBuffer exceeded');
25
+ child.kill(killSignal ?? 'SIGTERM');
26
+ data = data.subarray(0, remaining);
27
+ }
28
+ chunks.push(data);
29
+ };
30
+ const captureStdout = stdoutChunks ? capture(stdoutChunks) : undefined;
31
+ const captureStderr = stderrChunks ? capture(stderrChunks) : undefined;
32
+ if (captureStdout) (_child$stdout = child.stdout) === null || _child$stdout === void 0 || _child$stdout.on('data', captureStdout);
33
+ if (captureStderr) (_child$stderr = child.stderr) === null || _child$stderr === void 0 || _child$stderr.on('data', captureStderr);
34
+ function onError(err) {
35
+ error = err;
36
+ done();
37
+ }
38
+ child.on('error', onError);
39
+ function done(code = null, signal = null) {
40
+ var _child$stdout2, _child$stderr2;
41
+ child.removeListener('error', onError);
42
+ child.removeListener('close', done);
43
+ if (captureStdout) (_child$stdout2 = child.stdout) === null || _child$stdout2 === void 0 || _child$stdout2.removeListener('data', captureStdout);
44
+ if (captureStderr) (_child$stderr2 = child.stderr) === null || _child$stderr2 === void 0 || _child$stderr2.removeListener('data', captureStderr);
45
+ const stdout = joinChunks(stdoutChunks, encoding);
46
+ const stderr = joinChunks(stderrChunks, encoding);
47
+ if (error || code != null && code != 0 || signal != null) {
48
+ reject(Object.assign(error || new Error(signal != null ? `Process was killed with ${signal}` : `Process exited with code ${code}`), {
49
+ code,
50
+ signal,
51
+ killed: signal != null,
52
+ stdout,
53
+ stderr
54
+ }));
55
+ } else {
56
+ resolve({
57
+ stderr,
58
+ stdout,
59
+ code,
60
+ signal,
61
+ killed: false
62
+ });
63
+ }
64
+ }
65
+ child.on('close', done);
66
+ });
67
+ return Object.create(child, {
68
+ then: {
69
+ value: promise.then.bind(promise)
70
+ },
71
+ catch: {
72
+ value: promise.catch.bind(promise)
73
+ },
74
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
75
+ finally: {
76
+ value: (_promise$finally = promise.finally) === null || _promise$finally === void 0 ? void 0 : _promise$finally.bind(promise)
77
+ }
78
+ });
79
+ }
80
+ function isArray(t) {
81
+ return Array.isArray(t);
82
+ }
83
+ export function spawn(command, args, options) {
84
+ if (!isArray(args)) {
85
+ options = args;
86
+ args = [];
87
+ }
88
+ return promisifyChildProcess(child_process.spawn(command, args, options), options);
89
+ }
90
+ export function fork(module, args, options) {
91
+ if (!isArray(args)) {
92
+ options = args;
93
+ args = [];
94
+ }
95
+ return promisifyChildProcess(child_process.fork(module, args, options), options);
96
+ }
97
+ function promisifyExecMethod(method) {
98
+ return (...args) => {
99
+ var _promise$finally2;
100
+ let child;
101
+ const promise = new Promise((resolve, reject) => {
102
+ child = method(...args, (err, stdout, stderr) => {
103
+ if (err) {
104
+ reject(Object.assign(err, {
105
+ stdout,
106
+ stderr
107
+ }));
108
+ } else {
109
+ resolve({
110
+ code: 0,
111
+ signal: null,
112
+ killed: false,
113
+ stdout: stdout,
114
+ stderr: stderr
115
+ });
116
+ }
117
+ });
118
+ });
119
+ if (!child) {
120
+ throw new Error('unexpected error: child has not been initialized');
121
+ }
122
+ return Object.create(child, {
123
+ then: {
124
+ value: promise.then.bind(promise)
125
+ },
126
+ catch: {
127
+ value: promise.catch.bind(promise)
128
+ },
129
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
130
+ finally: {
131
+ value: (_promise$finally2 = promise.finally) === null || _promise$finally2 === void 0 ? void 0 : _promise$finally2.bind(promise)
132
+ }
133
+ });
134
+ };
135
+ }
136
+ export const exec = promisifyExecMethod(child_process.exec);
137
+ export const execFile = promisifyExecMethod(child_process.execFile);
138
+ export function isChildProcessError(error) {
139
+ return error instanceof Error && 'code' in error && 'signal' in error;
140
+ }
141
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["child_process","joinChunks","chunks","encoding","undefined","buffer","Buffer","concat","toString","promisifyChildProcess","child","options","_promise$finally","promise","Promise","resolve","reject","_child$stdout","_child$stderr","killSignal","captureStdio","maxBuffer","bufferSize","error","stdoutChunks","stdout","stderrChunks","stderr","capture","data","from","remaining","Math","max","min","length","Error","kill","subarray","push","captureStdout","captureStderr","on","onError","err","done","code","signal","_child$stdout2","_child$stderr2","removeListener","Object","assign","killed","create","then","value","bind","catch","finally","isArray","t","Array","spawn","command","args","fork","module","promisifyExecMethod","method","_promise$finally2","exec","execFile","isChildProcessError"],"sources":["src/index.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,81 +1,13 @@
1
1
  {
2
2
  "name": "promisify-child-process",
3
- "version": "4.1.2",
3
+ "version": "5.0.1",
4
4
  "description": "seriously like the best async child process library",
5
5
  "engines": {
6
- "node": ">=8"
6
+ "node": ">=16"
7
7
  },
8
- "main": "./index.cjs",
9
- "exports": {
10
- "types": "./index.d.ts",
11
- "import": "./index.mjs",
12
- "require": "./index.cjs"
13
- },
14
- "types": "./index.d.ts",
15
- "files": [
16
- "index.cjs",
17
- "index.mjs",
18
- "index.d.ts",
19
- "index.js.flow"
20
- ],
8
+ "types": "index.d.cts",
9
+ "type": "module",
21
10
  "sideEffects": false,
22
- "scripts": {
23
- "lint": "eslint src test --cache",
24
- "lint:fix": "eslint --fix src test --cache",
25
- "lint:watch": "esw --watch src test --cache",
26
- "prettier": "prettier --write *.json *.md *.js *.ts '{src,test}/**/*.js'",
27
- "prettier:check": "prettier --list-different *.json *.md *.js *.ts '{src,test}/**/*.js'",
28
- "flow": "flow",
29
- "flow:coverage": "for file in src/**.js test/**.js; do echo $file; flow coverage $file; done",
30
- "flow:watch": "flow-watch -e js,js.flow,flowconfig --ignore es/ --ignore node_modules/ --watch .flowconfig --watch src/ --watch test/",
31
- "build": "babel src/index.js -o index.cjs && flow-copy-source -v src/ .",
32
- "test": "cross-env NODE_ENV=test mocha $npm_package_config_mocha && cross-env NODE_ENV=test BABEL_ENV=coverage nyc --reporter=lcov --reporter=text mocha $npm_package_config_mocha",
33
- "test:watch": "cross-env NODE_ENV=test BABEL_ENV=test mocha --watch $npm_package_config_mocha",
34
- "test:debug": "cross-env NODE_ENV=test BABEL_ENV=test mocha --inspect-brk $npm_package_config_mocha",
35
- "codecov": "nyc report --reporter=text-lcov > coverage.lcov; codecov",
36
- "prepublishOnly": "npm run prettier:check && npm run lint && flow && tsc && npm test && npm run build",
37
- "open:coverage": "open coverage/lcov-report/index.html",
38
- "semantic-release": "semantic-release"
39
- },
40
- "husky": {
41
- "hooks": {
42
- "pre-commit": "lint-staged && npm run lint && flow && tsc",
43
- "commit-msg": "commitlint -e $GIT_PARAMS",
44
- "pre-push": "npm test"
45
- }
46
- },
47
- "lint-staged": {
48
- "*.{js,json,css,md,ts}": [
49
- "prettier --write",
50
- "git add"
51
- ]
52
- },
53
- "commitlint": {
54
- "extends": [
55
- "@jedwards1211/commitlint-config"
56
- ]
57
- },
58
- "prettier": {
59
- "semi": false,
60
- "singleQuote": true,
61
- "trailingComma": "es5"
62
- },
63
- "config": {
64
- "mocha": "-r @babel/register test/configure.js 'test/**/*.js'",
65
- "commitizen": {
66
- "path": "cz-conventional-changelog"
67
- }
68
- },
69
- "nyc": {
70
- "include": [
71
- "src/**/*.js"
72
- ],
73
- "require": [
74
- "@babel/register"
75
- ],
76
- "sourceMap": false,
77
- "instrument": false
78
- },
79
11
  "repository": {
80
12
  "type": "git",
81
13
  "url": "https://github.com/jcoreio/promisify-child-process.git"
@@ -100,62 +32,24 @@
100
32
  "url": "https://github.com/jcoreio/promisify-child-process/issues"
101
33
  },
102
34
  "homepage": "https://github.com/jcoreio/promisify-child-process#readme",
103
- "devDependencies": {
104
- "@babel/cli": "^7.1.5",
105
- "@babel/core": "^7.1.6",
106
- "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
107
- "@babel/preset-env": "^7.1.6",
108
- "@babel/preset-flow": "^7.0.0",
109
- "@babel/register": "^7.0.0",
110
- "@commitlint/cli": "^8.0.0",
111
- "@commitlint/config-conventional": "^8.0.0",
112
- "@jedwards1211/commitlint-config": "^1.0.0",
113
- "@jedwards1211/eslint-config": "^2.0.0",
114
- "@jedwards1211/eslint-config-flow": "^2.0.0",
115
- "@types/node": "^12.12.17",
116
- "babel-eslint": "^10.0.1",
117
- "babel-plugin-istanbul": "^5.1.0",
118
- "chai": "^4.2.0",
119
- "codecov": "^3.1.0",
120
- "copy": "^0.3.2",
121
- "cross-env": "^5.2.0",
122
- "eslint": "^5.9.0",
123
- "eslint-config-prettier": "^3.3.0",
124
- "eslint-plugin-flowtype": "^3.2.0",
125
- "eslint-watch": "^4.0.2",
126
- "flow-bin": "^0.135.0",
127
- "flow-copy-source": "^2.0.2",
128
- "flow-watch": "^1.1.4",
129
- "fs-extra": "^7.0.1",
130
- "husky": "^1.1.4",
131
- "istanbul": "^0.4.5",
132
- "lint-staged": "^8.0.4",
133
- "mocha": "^6.2.1",
134
- "nyc": "^13.1.0",
135
- "prettier": "^1.15.2",
136
- "prettier-eslint": "^8.8.2",
137
- "rimraf": "^2.6.0",
138
- "semantic-release": "^15.13.31",
139
- "typescript": "^3.7.3",
140
- "waait": "^1.0.5"
141
- },
142
- "dependencies": {},
143
- "renovate": {
144
- "extends": [
145
- ":separateMajorReleases",
146
- ":combinePatchMinorReleases",
147
- ":ignoreUnstable",
148
- ":prImmediately",
149
- ":renovatePrefix",
150
- ":updateNotScheduled",
151
- ":preserveSemverRanges",
152
- ":semanticPrefixFixDepsChoreOthers",
153
- ":automergeDisabled",
154
- "group:monorepos"
155
- ],
156
- "automerge": true,
157
- "major": {
158
- "automerge": false
35
+ "main": "index.cjs",
36
+ "module": "index.js",
37
+ "exports": {
38
+ "./package.json": "./package.json",
39
+ ".": {
40
+ "types": {
41
+ "import": "./index.d.ts",
42
+ "default": "./index.d.cts"
43
+ },
44
+ "import": "./index.js",
45
+ "default": "./index.cjs"
159
46
  }
47
+ },
48
+ "packageManager": "pnpm@10.6.5",
49
+ "dependencies": {
50
+ "@babel/runtime": "^7.26.0"
51
+ },
52
+ "@jcoreio/toolchain": {
53
+ "migratedVersion": "5.8.8"
160
54
  }
161
55
  }
package/src/index.ts ADDED
@@ -0,0 +1,323 @@
1
+ import { ChildProcess, IOType } from 'child_process'
2
+ import child_process from 'child_process'
3
+ import Stream, { Pipe, Readable, Writable } from 'stream'
4
+
5
+ type StdioElement = IOType | Stream | number | null | undefined
6
+
7
+ type StdioOptions =
8
+ | IOType
9
+ | [StdioElement, StdioElement, StdioElement, ...Array<StdioElement | 'ipc'>]
10
+ | Array<StdioElement | 'ipc'>
11
+
12
+ interface IOOptions {
13
+ silent?: boolean
14
+ stdio?: StdioOptions
15
+ encoding?: BufferEncoding | 'buffer' | null
16
+ maxBuffer?: number
17
+ }
18
+
19
+ type ChunkTypeHelper<MaxBuffer, Encoding> =
20
+ MaxBuffer extends number ?
21
+ Encoding extends BufferEncoding ?
22
+ string
23
+ : Buffer
24
+ : Encoding extends BufferEncoding ? string
25
+ : Encoding extends 'buffer' ? Buffer
26
+ : undefined
27
+
28
+ type ChunkType<Options extends IOOptions> = ChunkTypeHelper<
29
+ 'maxBuffer' extends keyof Options ? Options['maxBuffer'] : undefined,
30
+ 'encoding' extends keyof Options ? Options['encoding'] : undefined
31
+ >
32
+
33
+ type IsPipeHelper<Stdio, Silent, Fd extends 0 | 1 | 2> =
34
+ Stdio extends unknown[] ?
35
+ Stdio[Fd] extends infer Value ?
36
+ Value extends 'pipe' | 'overlapped' ?
37
+ true
38
+ : false
39
+ : false
40
+ : Stdio extends null | undefined | 'pipe' | 'overlapped' ? true
41
+ : Stdio extends null | undefined ?
42
+ Silent extends true ?
43
+ false
44
+ : true
45
+ : false
46
+
47
+ type IsPipe<Options extends IOOptions, Fd extends 0 | 1 | 2> = IsPipeHelper<
48
+ 'stdio' extends keyof Options ? Options['stdio'] : undefined,
49
+ 'silent' extends keyof Options ? Options['silent'] : undefined,
50
+ Fd
51
+ >
52
+
53
+ type Contains<A, T> =
54
+ A extends [infer Head, ...infer Tail] ?
55
+ Head extends T ?
56
+ true
57
+ : Contains<Tail, T>
58
+ : false
59
+
60
+ export interface ChildProcessResult<Options extends IOOptions> {
61
+ stdout: IsPipe<Options, 1> extends true ? ChunkType<Options> : undefined
62
+ stderr: IsPipe<Options, 2> extends true ? ChunkType<Options> : undefined
63
+ code: number | null
64
+ signal: string | null
65
+ killed: boolean
66
+ }
67
+
68
+ type StdioStreams<Stdio> = {
69
+ [K in keyof Stdio]: Stdio[K] extends 'pipe' | 'overlapped' ?
70
+ K extends 0 | '0' ?
71
+ Writable
72
+ : Readable
73
+ : null
74
+ }
75
+
76
+ export interface ChildProcessPromise<Options extends IOOptions>
77
+ extends ChildProcess, Promise<ChildProcessResult<Options>> {
78
+ stdin: IsPipe<Options, 0> extends true ? Writable : null
79
+ stdout: IsPipe<Options, 1> extends true ? Readable : null
80
+ stderr: IsPipe<Options, 2> extends true ? Readable : null
81
+ readonly channel: Options['stdio'] extends infer Stdio ?
82
+ Contains<Stdio, 'ipc'> extends true ?
83
+ Pipe
84
+ : undefined
85
+ : undefined
86
+ readonly stdio: Options['stdio'] extends infer Stdio ?
87
+ Stdio extends unknown[] ? StdioStreams<Stdio>
88
+ : Stdio extends null | undefined | 'pipe' | 'overlapped' ?
89
+ [Writable, Readable, Readable, undefined, undefined]
90
+ : [null, null, null, undefined, undefined]
91
+ : [null, null, null, undefined, undefined]
92
+ }
93
+
94
+ interface PromisifyChildProcessBaseOptions extends IOOptions {
95
+ killSignal?: NodeJS.Signals | number
96
+ }
97
+
98
+ function joinChunks(
99
+ chunks: Buffer[] | undefined,
100
+ encoding: BufferEncoding | 'buffer' | null | undefined
101
+ ): string | Buffer | undefined {
102
+ if (!chunks) return undefined
103
+ const buffer = Buffer.concat(chunks)
104
+ return encoding && encoding !== 'buffer' ? buffer.toString(encoding) : buffer
105
+ }
106
+
107
+ export function promisifyChildProcess<
108
+ Options extends PromisifyChildProcessBaseOptions,
109
+ >(child: ChildProcess, options?: Options): ChildProcessPromise<Options> {
110
+ const promise = new Promise<ChildProcessResult<Options>>(
111
+ (resolve, reject) => {
112
+ const encoding = options?.encoding
113
+ const killSignal = options?.killSignal
114
+ const captureStdio = encoding != null || options?.maxBuffer != null
115
+ const maxBuffer = options?.maxBuffer ?? 1024 * 1024
116
+ let bufferSize = 0
117
+ let error: Error | undefined
118
+ const stdoutChunks: Buffer[] | undefined =
119
+ captureStdio && child.stdout ? [] : undefined
120
+ const stderrChunks: Buffer[] | undefined =
121
+ captureStdio && child.stderr ? [] : undefined
122
+ const capture = (chunks: Buffer[]) => (data: string | Buffer) => {
123
+ if (typeof data === 'string') data = Buffer.from(data)
124
+ const remaining = Math.max(0, maxBuffer - bufferSize)
125
+ bufferSize += Math.min(remaining, data.length)
126
+ if (data.length > remaining) {
127
+ error = new Error('maxBuffer exceeded')
128
+ child.kill(killSignal ?? 'SIGTERM')
129
+ data = data.subarray(0, remaining)
130
+ }
131
+ chunks.push(data)
132
+ }
133
+ const captureStdout = stdoutChunks ? capture(stdoutChunks) : undefined
134
+ const captureStderr = stderrChunks ? capture(stderrChunks) : undefined
135
+ if (captureStdout) child.stdout?.on('data', captureStdout)
136
+ if (captureStderr) child.stderr?.on('data', captureStderr)
137
+ function onError(err: Error) {
138
+ error = err
139
+ done()
140
+ }
141
+ child.on('error', onError)
142
+ function done(code: number | null = null, signal: string | null = null) {
143
+ child.removeListener('error', onError)
144
+ child.removeListener('close', done)
145
+ if (captureStdout) child.stdout?.removeListener('data', captureStdout)
146
+ if (captureStderr) child.stderr?.removeListener('data', captureStderr)
147
+
148
+ const stdout = joinChunks(
149
+ stdoutChunks,
150
+ encoding
151
+ ) as ChildProcessResult<Options>['stdout']
152
+ const stderr = joinChunks(
153
+ stderrChunks,
154
+ encoding
155
+ ) as ChildProcessResult<Options>['stderr']
156
+
157
+ if (error || (code != null && code != 0) || signal != null) {
158
+ reject(
159
+ Object.assign(
160
+ error ||
161
+ new Error(
162
+ signal != null ?
163
+ `Process was killed with ${signal}`
164
+ : `Process exited with code ${code}`
165
+ ),
166
+ {
167
+ code,
168
+ signal,
169
+ killed: signal != null,
170
+ stdout,
171
+ stderr,
172
+ }
173
+ )
174
+ )
175
+ } else {
176
+ resolve({ stderr, stdout, code, signal, killed: false })
177
+ }
178
+ }
179
+ child.on('close', done)
180
+ }
181
+ )
182
+ return Object.create(child, {
183
+ then: { value: promise.then.bind(promise) },
184
+ catch: { value: promise.catch.bind(promise) },
185
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
186
+ finally: { value: promise.finally?.bind(promise) },
187
+ })
188
+ }
189
+
190
+ export interface SpawnOptions extends child_process.SpawnOptions {
191
+ stdio?: StdioOptions
192
+ encoding?: BufferEncoding
193
+ maxBuffer?: number
194
+ }
195
+
196
+ function isArray(t: unknown): t is unknown[] | readonly unknown[] {
197
+ return Array.isArray(t)
198
+ }
199
+
200
+ export function spawn<Options extends SpawnOptions>(
201
+ command: string,
202
+ args: readonly string[],
203
+ options?: Options
204
+ ): ChildProcessPromise<Options>
205
+ export function spawn<Options extends SpawnOptions>(
206
+ command: string,
207
+ options?: Options
208
+ ): ChildProcessPromise<Options>
209
+ export function spawn<Options extends SpawnOptions>(
210
+ command: string,
211
+ args?: readonly string[] | Options,
212
+ options?: Options
213
+ ): ChildProcessPromise<Options> {
214
+ if (!isArray(args)) {
215
+ options = args
216
+ args = []
217
+ }
218
+ return promisifyChildProcess(
219
+ child_process.spawn(command, args, options as child_process.SpawnOptions),
220
+ options
221
+ )
222
+ }
223
+
224
+ export interface ForkOptions extends child_process.ForkOptions {
225
+ stdio?: StdioOptions
226
+ encoding?: BufferEncoding
227
+ maxBuffer?: number
228
+ }
229
+
230
+ export function fork<Options extends ForkOptions>(
231
+ module: string,
232
+ args: Array<string>,
233
+ options?: Options
234
+ ): ChildProcessPromise<Options>
235
+ export function fork<Options extends ForkOptions>(
236
+ module: string,
237
+ options?: Options
238
+ ): ChildProcessPromise<Options>
239
+ export function fork<Options extends ForkOptions>(
240
+ module: string,
241
+ args?: Array<string> | Options,
242
+ options?: Options
243
+ ): ChildProcessPromise<Options> {
244
+ if (!isArray(args)) {
245
+ options = args
246
+ args = []
247
+ }
248
+ return promisifyChildProcess(
249
+ child_process.fork(module, args, options),
250
+ options
251
+ )
252
+ }
253
+ function promisifyExecMethod(method: (...args: any[]) => ChildProcess) {
254
+ return (...args: any[]): ChildProcessPromise<any> => {
255
+ let child: ChildProcess | undefined
256
+ const promise = new Promise<ChildProcessResult<any>>((resolve, reject) => {
257
+ child = method(
258
+ ...args,
259
+ (
260
+ err: Error | null,
261
+ stdout: string | Buffer,
262
+ stderr: string | Buffer
263
+ ) => {
264
+ if (err) {
265
+ reject(Object.assign(err, { stdout, stderr }))
266
+ } else {
267
+ resolve({
268
+ code: 0,
269
+ signal: null,
270
+ killed: false,
271
+ stdout: stdout as any,
272
+ stderr: stderr as any,
273
+ })
274
+ }
275
+ }
276
+ )
277
+ })
278
+ if (!child) {
279
+ throw new Error('unexpected error: child has not been initialized')
280
+ }
281
+ return Object.create(child, {
282
+ then: { value: promise.then.bind(promise) },
283
+ catch: { value: promise.catch.bind(promise) },
284
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
285
+ finally: { value: promise.finally?.bind(promise) },
286
+ })
287
+ }
288
+ }
289
+
290
+ export interface ExecOptions extends child_process.ExecOptions {
291
+ encoding?: BufferEncoding | 'buffer'
292
+ }
293
+
294
+ export const exec: <Options extends ExecOptions>(
295
+ command: string,
296
+ options?: Options
297
+ ) => ChildProcessPromise<Options> = promisifyExecMethod(child_process.exec)
298
+
299
+ export interface ExecFileOptions extends child_process.ExecFileOptions {
300
+ encoding?: BufferEncoding | 'buffer'
301
+ }
302
+
303
+ export const execFile: {
304
+ <Options extends ExecFileOptions>(
305
+ file: string,
306
+ args: readonly string[],
307
+ options?: Options
308
+ ): ChildProcessPromise<Options>
309
+ <Options extends ExecFileOptions>(
310
+ file: string,
311
+ options?: Options
312
+ ): ChildProcessPromise<Options>
313
+ } = promisifyExecMethod(child_process.execFile)
314
+
315
+ export function isChildProcessError(error: unknown): error is Error & {
316
+ code: number | null
317
+ signal: NodeJS.Signals | null
318
+ killed: boolean
319
+ stdout?: string | Buffer
320
+ stderr?: string | Buffer
321
+ } {
322
+ return error instanceof Error && 'code' in error && 'signal' in error
323
+ }