promisify-child-process 4.1.2 → 5.0.0

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.0",
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,314 @@
1
+ import { ChildProcess, StdioOptions } from 'child_process'
2
+ import child_process from 'child_process'
3
+ import { Pipe, Readable, Writable } from 'stream'
4
+
5
+ interface IOOptions {
6
+ silent?: boolean
7
+ stdio?: StdioOptions
8
+ encoding?: BufferEncoding | 'buffer' | null
9
+ maxBuffer?: number
10
+ }
11
+
12
+ type ChunkTypeHelper<MaxBuffer, Encoding> =
13
+ MaxBuffer extends number ?
14
+ Encoding extends BufferEncoding ?
15
+ string
16
+ : Buffer
17
+ : Encoding extends BufferEncoding ? string
18
+ : Encoding extends 'buffer' ? Buffer
19
+ : undefined
20
+
21
+ type ChunkType<Options extends IOOptions> = ChunkTypeHelper<
22
+ 'maxBuffer' extends keyof Options ? Options['maxBuffer'] : undefined,
23
+ 'encoding' extends keyof Options ? Options['encoding'] : undefined
24
+ >
25
+
26
+ type IsPipeHelper<Stdio, Silent, Fd extends 0 | 1 | 2> =
27
+ Stdio extends unknown[] ?
28
+ Stdio[Fd] extends infer Value ?
29
+ Value extends 'pipe' | 'overlapped' ?
30
+ true
31
+ : false
32
+ : false
33
+ : Stdio extends null | undefined | 'pipe' | 'overlapped' ? true
34
+ : Stdio extends null | undefined ?
35
+ Silent extends true ?
36
+ false
37
+ : true
38
+ : false
39
+
40
+ type IsPipe<Options extends IOOptions, Fd extends 0 | 1 | 2> = IsPipeHelper<
41
+ 'stdio' extends keyof Options ? Options['stdio'] : undefined,
42
+ 'silent' extends keyof Options ? Options['silent'] : undefined,
43
+ Fd
44
+ >
45
+
46
+ type Contains<A, T> =
47
+ A extends [infer Head, ...infer Tail] ?
48
+ Head extends T ?
49
+ true
50
+ : Contains<Tail, T>
51
+ : false
52
+
53
+ export interface ChildProcessResult<Options extends IOOptions> {
54
+ stdout: IsPipe<Options, 1> extends true ? ChunkType<Options> : undefined
55
+ stderr: IsPipe<Options, 2> extends true ? ChunkType<Options> : undefined
56
+ code: number | null
57
+ signal: string | null
58
+ killed: boolean
59
+ }
60
+
61
+ type StdioStreams<Stdio> = {
62
+ [K in keyof Stdio]: Stdio[K] extends 'pipe' | 'overlapped' ?
63
+ K extends 0 | '0' ?
64
+ Writable
65
+ : Readable
66
+ : null
67
+ }
68
+
69
+ export interface ChildProcessPromise<Options extends IOOptions>
70
+ extends ChildProcess, Promise<ChildProcessResult<Options>> {
71
+ stdin: IsPipe<Options, 0> extends true ? Writable : null
72
+ stdout: IsPipe<Options, 1> extends true ? Readable : null
73
+ stderr: IsPipe<Options, 2> extends true ? Readable : null
74
+ readonly channel: Options['stdio'] extends infer Stdio ?
75
+ Contains<Stdio, 'ipc'> extends true ?
76
+ Pipe
77
+ : undefined
78
+ : undefined
79
+ readonly stdio: Options['stdio'] extends infer Stdio ?
80
+ Stdio extends unknown[] ? StdioStreams<Stdio>
81
+ : Stdio extends null | undefined | 'pipe' | 'overlapped' ?
82
+ [Writable, Readable, Readable, undefined, undefined]
83
+ : [null, null, null, undefined, undefined]
84
+ : [null, null, null, undefined, undefined]
85
+ }
86
+
87
+ interface PromisifyChildProcessBaseOptions extends IOOptions {
88
+ killSignal?: NodeJS.Signals | number
89
+ }
90
+
91
+ function joinChunks(
92
+ chunks: Buffer[] | undefined,
93
+ encoding: BufferEncoding | 'buffer' | null | undefined
94
+ ): string | Buffer | undefined {
95
+ if (!chunks) return undefined
96
+ const buffer = Buffer.concat(chunks)
97
+ return encoding && encoding !== 'buffer' ? buffer.toString(encoding) : buffer
98
+ }
99
+
100
+ export function promisifyChildProcess<
101
+ Options extends PromisifyChildProcessBaseOptions,
102
+ >(child: ChildProcess, options?: Options): ChildProcessPromise<Options> {
103
+ const promise = new Promise<ChildProcessResult<Options>>(
104
+ (resolve, reject) => {
105
+ const encoding = options?.encoding
106
+ const killSignal = options?.killSignal
107
+ const captureStdio = encoding != null || options?.maxBuffer != null
108
+ const maxBuffer = options?.maxBuffer ?? 1024 * 1024
109
+ let bufferSize = 0
110
+ let error: Error | undefined
111
+ const stdoutChunks: Buffer[] | undefined =
112
+ captureStdio && child.stdout ? [] : undefined
113
+ const stderrChunks: Buffer[] | undefined =
114
+ captureStdio && child.stderr ? [] : undefined
115
+ const capture = (chunks: Buffer[]) => (data: string | Buffer) => {
116
+ if (typeof data === 'string') data = Buffer.from(data)
117
+ const remaining = Math.max(0, maxBuffer - bufferSize)
118
+ bufferSize += Math.min(remaining, data.length)
119
+ if (data.length > remaining) {
120
+ error = new Error('maxBuffer exceeded')
121
+ child.kill(killSignal ?? 'SIGTERM')
122
+ data = data.subarray(0, remaining)
123
+ }
124
+ chunks.push(data)
125
+ }
126
+ const captureStdout = stdoutChunks ? capture(stdoutChunks) : undefined
127
+ const captureStderr = stderrChunks ? capture(stderrChunks) : undefined
128
+ if (captureStdout) child.stdout?.on('data', captureStdout)
129
+ if (captureStderr) child.stderr?.on('data', captureStderr)
130
+ function onError(err: Error) {
131
+ error = err
132
+ done()
133
+ }
134
+ child.on('error', onError)
135
+ function done(code: number | null = null, signal: string | null = null) {
136
+ child.removeListener('error', onError)
137
+ child.removeListener('close', done)
138
+ if (captureStdout) child.stdout?.removeListener('data', captureStdout)
139
+ if (captureStderr) child.stderr?.removeListener('data', captureStderr)
140
+
141
+ const stdout = joinChunks(
142
+ stdoutChunks,
143
+ encoding
144
+ ) as ChildProcessResult<Options>['stdout']
145
+ const stderr = joinChunks(
146
+ stderrChunks,
147
+ encoding
148
+ ) as ChildProcessResult<Options>['stderr']
149
+
150
+ if (error || (code != null && code != 0) || signal != null) {
151
+ reject(
152
+ Object.assign(
153
+ error ||
154
+ new Error(
155
+ signal != null ?
156
+ `Process was killed with ${signal}`
157
+ : `Process exited with code ${code}`
158
+ ),
159
+ {
160
+ code,
161
+ signal,
162
+ killed: signal != null,
163
+ stdout,
164
+ stderr,
165
+ }
166
+ )
167
+ )
168
+ } else {
169
+ resolve({ stderr, stdout, code, signal, killed: false })
170
+ }
171
+ }
172
+ child.on('close', done)
173
+ }
174
+ )
175
+ return Object.create(child, {
176
+ then: { value: promise.then.bind(promise) },
177
+ catch: { value: promise.catch.bind(promise) },
178
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
179
+ finally: { value: promise.finally?.bind(promise) },
180
+ })
181
+ }
182
+
183
+ export interface SpawnOptions extends child_process.SpawnOptions {
184
+ encoding?: BufferEncoding
185
+ maxBuffer?: number
186
+ }
187
+
188
+ function isArray(t: unknown): t is unknown[] | readonly unknown[] {
189
+ return Array.isArray(t)
190
+ }
191
+
192
+ export function spawn<Options extends SpawnOptions>(
193
+ command: string,
194
+ args: readonly string[],
195
+ options?: Options
196
+ ): ChildProcessPromise<Options>
197
+ export function spawn<Options extends SpawnOptions>(
198
+ command: string,
199
+ options?: Options
200
+ ): ChildProcessPromise<Options>
201
+ export function spawn<Options extends SpawnOptions>(
202
+ command: string,
203
+ args?: readonly string[] | Options,
204
+ options?: Options
205
+ ): ChildProcessPromise<Options> {
206
+ if (!isArray(args)) {
207
+ options = args
208
+ args = []
209
+ }
210
+ return promisifyChildProcess(
211
+ child_process.spawn(command, args, options as child_process.SpawnOptions),
212
+ options
213
+ )
214
+ }
215
+
216
+ export interface ForkOptions extends child_process.ForkOptions {
217
+ encoding?: BufferEncoding
218
+ maxBuffer?: number
219
+ }
220
+
221
+ export function fork<Options extends ForkOptions>(
222
+ module: string,
223
+ args: Array<string>,
224
+ options?: Options
225
+ ): ChildProcessPromise<Options>
226
+ export function fork<Options extends ForkOptions>(
227
+ module: string,
228
+ options?: Options
229
+ ): ChildProcessPromise<Options>
230
+ export function fork<Options extends ForkOptions>(
231
+ module: string,
232
+ args?: Array<string> | Options,
233
+ options?: Options
234
+ ): ChildProcessPromise<Options> {
235
+ if (!isArray(args)) {
236
+ options = args
237
+ args = []
238
+ }
239
+ return promisifyChildProcess(
240
+ child_process.fork(module, args, options),
241
+ options
242
+ )
243
+ }
244
+ function promisifyExecMethod(method: (...args: any[]) => ChildProcess) {
245
+ return (...args: any[]): ChildProcessPromise<any> => {
246
+ let child: ChildProcess | undefined
247
+ const promise = new Promise<ChildProcessResult<any>>((resolve, reject) => {
248
+ child = method(
249
+ ...args,
250
+ (
251
+ err: Error | null,
252
+ stdout: string | Buffer,
253
+ stderr: string | Buffer
254
+ ) => {
255
+ if (err) {
256
+ reject(Object.assign(err, { stdout, stderr }))
257
+ } else {
258
+ resolve({
259
+ code: 0,
260
+ signal: null,
261
+ killed: false,
262
+ stdout: stdout as any,
263
+ stderr: stderr as any,
264
+ })
265
+ }
266
+ }
267
+ )
268
+ })
269
+ if (!child) {
270
+ throw new Error('unexpected error: child has not been initialized')
271
+ }
272
+ return Object.create(child, {
273
+ then: { value: promise.then.bind(promise) },
274
+ catch: { value: promise.catch.bind(promise) },
275
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
276
+ finally: { value: promise.finally?.bind(promise) },
277
+ })
278
+ }
279
+ }
280
+
281
+ export interface ExecOptions extends child_process.ExecOptions {
282
+ encoding?: BufferEncoding | 'buffer'
283
+ }
284
+
285
+ export const exec: <Options extends ExecOptions>(
286
+ command: string,
287
+ options?: Options
288
+ ) => ChildProcessPromise<Options> = promisifyExecMethod(child_process.exec)
289
+
290
+ export interface ExecFileOptions extends child_process.ExecFileOptions {
291
+ encoding?: BufferEncoding | 'buffer'
292
+ }
293
+
294
+ export const execFile: {
295
+ <Options extends ExecFileOptions>(
296
+ file: string,
297
+ args: readonly string[],
298
+ options?: Options
299
+ ): ChildProcessPromise<Options>
300
+ <Options extends ExecFileOptions>(
301
+ file: string,
302
+ options?: Options
303
+ ): ChildProcessPromise<Options>
304
+ } = promisifyExecMethod(child_process.execFile)
305
+
306
+ export function isChildProcessError(error: unknown): error is Error & {
307
+ code: number | null
308
+ signal: NodeJS.Signals | null
309
+ killed: boolean
310
+ stdout?: string | Buffer
311
+ stderr?: string | Buffer
312
+ } {
313
+ return error instanceof Error && 'code' in error && 'signal' in error
314
+ }