Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/forms / danger / Makefile.shell.ts
Size: Mime:
import {
  ChildProcess,
  ExecOptions,
  ExecFileOptions,
  SpawnOptions,
  ForkOptions,
} from 'child_process'
import * as child_process from 'child_process'

export interface Output {
  stdout?: string | Buffer
  stderr?: string | Buffer
}

export type ErrorWithOutput = Error &
  Output & {
    code?: number
    signal?: string
  }

type ChildProcessPromise = ChildProcess & Promise<Output>

function joinChunks(
  chunks: ReadonlyArray<string | Buffer>,
  encoding: string
): string | Buffer {
  if (chunks[0] instanceof Buffer) {
    const buffer = Buffer.concat(chunks as any)
    if (encoding) {
      return buffer.toString(encoding as any)
    }
    return buffer
  }
  return chunks.join('')
}

export function promisifyChildProcess(
  child: ChildProcess,
  options: { encoding?: string } = {}
): ChildProcessPromise {
  const _promise = new Promise(
    (
      resolve: (result: Output) => void,
      reject: (err: ErrorWithOutput) => void
    ) => {
      const stdoutChunks: Array<string | Buffer> = []
      const stderrChunks: Array<string | Buffer> = []
      if (child.stdout) {
        child.stdout.on('data', data => stdoutChunks.push(data))
      }
      if (child.stderr) {
        child.stderr.on('data', data => stderrChunks.push(data))
      }

      child.on('error', reject)
      function done(code: number, signal: string) {
        // as any because ignoring assignment with this async promise
        let error: ErrorWithOutput = undefined as any
        if (code !== null && code !== 0) {
          error = new Error(`Process exited with code ${code}`)
        } else if (signal !== null) {
          error = new Error(`Process was killed with ${signal}`)
        }
        const output: Output = {}
        if (child.stdout) {
          output.stdout = joinChunks(stdoutChunks, options.encoding as string)
        }
        if (child.stderr) {
          output.stderr = joinChunks(stderrChunks, options.encoding as string)
        }
        if (error) {
          if (code !== null) {
            error.code = code
          }
          if (signal !== null) {
            error.signal = signal
          }
          if (output.stdout) {
            error.stdout = output.stdout
          }
          if (output.stderr) {
            error.stderr = output.stderr
          }
          reject(error)
        } else {
          resolve(output)
        }
      }
      child.on('close', done)
      child.on('exit', done)
    }
  )
  return Object.create(child, {
    then: { value: _promise.then.bind(_promise) },
    catch: { value: _promise.catch.bind(_promise) },
  }) as any
}

export function spawn(
  command: string,
  args?: ReadonlyArray<string> | SpawnOptions,
  options?: SpawnOptions
): ChildProcessPromise {
  return promisifyChildProcess(
    child_process.spawn(command, args as ReadonlyArray<string>, options),
    (Array.isArray(args) ? options : args) as any
  )
}

export function fork(
  module: string,
  args?: ReadonlyArray<string> | ForkOptions,
  options?: ForkOptions
): ChildProcessPromise {
  return promisifyChildProcess(
    child_process.fork(module, args as ReadonlyArray<string>, options),
    (Array.isArray(args) ? options : args) as any
  )
}

function promisifyExecMethod(method: any): any {
  return (...args: any[]): ChildProcessPromise => {
    // as any because ignoring assignment with this async promise
    let child: ChildProcess = undefined as any
    const _promise = new Promise(
      (
        resolve: (output: Output) => void,
        reject: (error: ErrorWithOutput) => void
      ) => {
        child = method(
          ...args,
          (
            err: ErrorWithOutput,
            stdout: Buffer | string,
            stderr: Buffer | string
          ) => {
            if (err) {
              err.stdout = stdout
              err.stderr = stderr
              reject(err)
            } else {
              resolve({ stdout, stderr })
            }
          }
        )
      }
    )
    if (!child) {
      throw new Error('unexpected error: child has not been initialized')
    }
    return Object.create(child as any, {
      then: { value: _promise.then.bind(_promise) },
      catch: { value: _promise.catch.bind(_promise) },
    }) as any
  }
}

export const exec: (
  command: string,
  options?: ExecOptions
) => ChildProcessPromise = promisifyExecMethod(child_process.exec)

export const execFile: (
  file: string,
  args?: string[] | ExecFileOptions,
  options?: ExecOptions
) => ChildProcessPromise = promisifyExecMethod(child_process.execFile)