type Proc = { connect(sig: "stdout" | "stderr", fn: (_: any, out: string) => void): number } type Config

= { defaultOut(stdout: string): void defaultErr(stdout: string): void subprocess(cmd: string): P subprocessv(cmd: string[]): P exec(cmd: string): string | null execv(cmd: string[]): string | null execAsync(cmd: string): P execAsyncv(cmd: string[]): P } type Args = { cmd: string | string[], out?: (stdout: string) => Out, err?: (stderr: string) => Err, } export default function

(config: Config

) { function args(argsOrCmd: Args | string | string[], onOut: O, onErr: E) { const params = Array.isArray(argsOrCmd) || typeof argsOrCmd === "string" return { cmd: params ? argsOrCmd : argsOrCmd.cmd, err: params ? onErr : argsOrCmd.err || onErr, out: params ? onOut : argsOrCmd.out || onOut, } } function subprocess(args: Args): P function subprocess( cmd: string | string[], onOut?: (stdout: string) => void, onErr?: (stderr: string) => void, ): P function subprocess( argsOrCmd: Args | string | string[], onOut: (stdout: string) => void = config.defaultOut, onErr: (stderr: string) => void = config.defaultErr, ) { const { cmd, err, out } = args(argsOrCmd, onOut, onErr) const proc = Array.isArray(cmd) ? config.subprocessv(cmd) : config.subprocess(cmd) proc.connect("stdout", (_, stdout: string) => out(stdout)) proc.connect("stderr", (_, stderr: string) => err(stderr)) return proc } function exec( args: Args ): Out | Err function exec( cmd: string | string[], onOut?: (stdout: string) => Out, onErr?: (stderr: string) => Err, ): Out | Err function exec( argsOrCmd: Args | string | string[], onOut: (stdout: string) => Out = out => out as Out, onErr: (stderr: string) => Err = out => out as Err, ): Out | Err { const { cmd, err, out } = args(argsOrCmd, onOut, onErr) return Array.isArray(cmd) ? out(config.execv(cmd)!) as Out : err(config.exec(cmd)!) as Err } function execAsync(cmd: string | string[]): Promise { const proc = Array.isArray(cmd) ? config.execAsyncv(cmd) : config.execAsync(cmd) return new Promise((resolve, reject) => { proc.connect("stdout", (_, out: string) => resolve(out)) proc.connect("stderr", (_, err: string) => reject(err)) }) } return { subprocess, exec, execAsync } }