| 'use strict'; | 
| const path = require('path'); | 
| const childProcess = require('child_process'); | 
| const crossSpawn = require('cross-spawn'); | 
| const stripFinalNewline = require('strip-final-newline'); | 
| const npmRunPath = require('npm-run-path'); | 
| const onetime = require('onetime'); | 
| const makeError = require('./lib/error'); | 
| const normalizeStdio = require('./lib/stdio'); | 
| const {spawnedKill, spawnedCancel, setupTimeout, setExitHandler} = require('./lib/kill'); | 
| const {handleInput, getSpawnedResult, makeAllStream, validateInputSync} = require('./lib/stream.js'); | 
| const {mergePromise, getSpawnedPromise} = require('./lib/promise.js'); | 
| const {joinCommand, parseCommand} = require('./lib/command.js'); | 
|   | 
| const DEFAULT_MAX_BUFFER = 1000 * 1000 * 100; | 
|   | 
| const getEnv = ({env: envOption, extendEnv, preferLocal, localDir, execPath}) => { | 
|     const env = extendEnv ? {...process.env, ...envOption} : envOption; | 
|   | 
|     if (preferLocal) { | 
|         return npmRunPath.env({env, cwd: localDir, execPath}); | 
|     } | 
|   | 
|     return env; | 
| }; | 
|   | 
| const handleArguments = (file, args, options = {}) => { | 
|     const parsed = crossSpawn._parse(file, args, options); | 
|     file = parsed.command; | 
|     args = parsed.args; | 
|     options = parsed.options; | 
|   | 
|     options = { | 
|         maxBuffer: DEFAULT_MAX_BUFFER, | 
|         buffer: true, | 
|         stripFinalNewline: true, | 
|         extendEnv: true, | 
|         preferLocal: false, | 
|         localDir: options.cwd || process.cwd(), | 
|         execPath: process.execPath, | 
|         encoding: 'utf8', | 
|         reject: true, | 
|         cleanup: true, | 
|         all: false, | 
|         windowsHide: true, | 
|         ...options | 
|     }; | 
|   | 
|     options.env = getEnv(options); | 
|   | 
|     options.stdio = normalizeStdio(options); | 
|   | 
|     if (process.platform === 'win32' && path.basename(file, '.exe') === 'cmd') { | 
|         // #116 | 
|         args.unshift('/q'); | 
|     } | 
|   | 
|     return {file, args, options, parsed}; | 
| }; | 
|   | 
| const handleOutput = (options, value, error) => { | 
|     if (typeof value !== 'string' && !Buffer.isBuffer(value)) { | 
|         // When `execa.sync()` errors, we normalize it to '' to mimic `execa()` | 
|         return error === undefined ? undefined : ''; | 
|     } | 
|   | 
|     if (options.stripFinalNewline) { | 
|         return stripFinalNewline(value); | 
|     } | 
|   | 
|     return value; | 
| }; | 
|   | 
| const execa = (file, args, options) => { | 
|     const parsed = handleArguments(file, args, options); | 
|     const command = joinCommand(file, args); | 
|   | 
|     let spawned; | 
|     try { | 
|         spawned = childProcess.spawn(parsed.file, parsed.args, parsed.options); | 
|     } catch (error) { | 
|         // Ensure the returned error is always both a promise and a child process | 
|         const dummySpawned = new childProcess.ChildProcess(); | 
|         const errorPromise = Promise.reject(makeError({ | 
|             error, | 
|             stdout: '', | 
|             stderr: '', | 
|             all: '', | 
|             command, | 
|             parsed, | 
|             timedOut: false, | 
|             isCanceled: false, | 
|             killed: false | 
|         })); | 
|         return mergePromise(dummySpawned, errorPromise); | 
|     } | 
|   | 
|     const spawnedPromise = getSpawnedPromise(spawned); | 
|     const timedPromise = setupTimeout(spawned, parsed.options, spawnedPromise); | 
|     const processDone = setExitHandler(spawned, parsed.options, timedPromise); | 
|   | 
|     const context = {isCanceled: false}; | 
|   | 
|     spawned.kill = spawnedKill.bind(null, spawned.kill.bind(spawned)); | 
|     spawned.cancel = spawnedCancel.bind(null, spawned, context); | 
|   | 
|     const handlePromise = async () => { | 
|         const [{error, exitCode, signal, timedOut}, stdoutResult, stderrResult, allResult] = await getSpawnedResult(spawned, parsed.options, processDone); | 
|         const stdout = handleOutput(parsed.options, stdoutResult); | 
|         const stderr = handleOutput(parsed.options, stderrResult); | 
|         const all = handleOutput(parsed.options, allResult); | 
|   | 
|         if (error || exitCode !== 0 || signal !== null) { | 
|             const returnedError = makeError({ | 
|                 error, | 
|                 exitCode, | 
|                 signal, | 
|                 stdout, | 
|                 stderr, | 
|                 all, | 
|                 command, | 
|                 parsed, | 
|                 timedOut, | 
|                 isCanceled: context.isCanceled, | 
|                 killed: spawned.killed | 
|             }); | 
|   | 
|             if (!parsed.options.reject) { | 
|                 return returnedError; | 
|             } | 
|   | 
|             throw returnedError; | 
|         } | 
|   | 
|         return { | 
|             command, | 
|             exitCode: 0, | 
|             stdout, | 
|             stderr, | 
|             all, | 
|             failed: false, | 
|             timedOut: false, | 
|             isCanceled: false, | 
|             killed: false | 
|         }; | 
|     }; | 
|   | 
|     const handlePromiseOnce = onetime(handlePromise); | 
|   | 
|     crossSpawn._enoent.hookChildProcess(spawned, parsed.parsed); | 
|   | 
|     handleInput(spawned, parsed.options.input); | 
|   | 
|     spawned.all = makeAllStream(spawned, parsed.options); | 
|   | 
|     return mergePromise(spawned, handlePromiseOnce); | 
| }; | 
|   | 
| module.exports = execa; | 
|   | 
| module.exports.sync = (file, args, options) => { | 
|     const parsed = handleArguments(file, args, options); | 
|     const command = joinCommand(file, args); | 
|   | 
|     validateInputSync(parsed.options); | 
|   | 
|     let result; | 
|     try { | 
|         result = childProcess.spawnSync(parsed.file, parsed.args, parsed.options); | 
|     } catch (error) { | 
|         throw makeError({ | 
|             error, | 
|             stdout: '', | 
|             stderr: '', | 
|             all: '', | 
|             command, | 
|             parsed, | 
|             timedOut: false, | 
|             isCanceled: false, | 
|             killed: false | 
|         }); | 
|     } | 
|   | 
|     const stdout = handleOutput(parsed.options, result.stdout, result.error); | 
|     const stderr = handleOutput(parsed.options, result.stderr, result.error); | 
|   | 
|     if (result.error || result.status !== 0 || result.signal !== null) { | 
|         const error = makeError({ | 
|             stdout, | 
|             stderr, | 
|             error: result.error, | 
|             signal: result.signal, | 
|             exitCode: result.status, | 
|             command, | 
|             parsed, | 
|             timedOut: result.error && result.error.code === 'ETIMEDOUT', | 
|             isCanceled: false, | 
|             killed: result.signal !== null | 
|         }); | 
|   | 
|         if (!parsed.options.reject) { | 
|             return error; | 
|         } | 
|   | 
|         throw error; | 
|     } | 
|   | 
|     return { | 
|         command, | 
|         exitCode: 0, | 
|         stdout, | 
|         stderr, | 
|         failed: false, | 
|         timedOut: false, | 
|         isCanceled: false, | 
|         killed: false | 
|     }; | 
| }; | 
|   | 
| module.exports.command = (command, options) => { | 
|     const [file, ...args] = parseCommand(command); | 
|     return execa(file, args, options); | 
| }; | 
|   | 
| module.exports.commandSync = (command, options) => { | 
|     const [file, ...args] = parseCommand(command); | 
|     return execa.sync(file, args, options); | 
| }; | 
|   | 
| module.exports.node = (scriptPath, args, options = {}) => { | 
|     if (args && !Array.isArray(args) && typeof args === 'object') { | 
|         options = args; | 
|         args = []; | 
|     } | 
|   | 
|     const stdio = normalizeStdio.node(options); | 
|     const defaultExecArgv = process.execArgv.filter(arg => !arg.startsWith('--inspect')); | 
|   | 
|     const { | 
|         nodePath = process.execPath, | 
|         nodeOptions = defaultExecArgv | 
|     } = options; | 
|   | 
|     return execa( | 
|         nodePath, | 
|         [ | 
|             ...nodeOptions, | 
|             scriptPath, | 
|             ...(Array.isArray(args) ? args : []) | 
|         ], | 
|         { | 
|             ...options, | 
|             stdin: undefined, | 
|             stdout: undefined, | 
|             stderr: undefined, | 
|             stdio, | 
|             shell: false | 
|         } | 
|     ); | 
| }; |