All files / src/execCmd execCmd.js

87.03% Statements 47/54
65.21% Branches 15/23
85.71% Functions 6/7
90.19% Lines 46/51

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 1081x 1x 1x 1x 1x     6x 6x       7x 7x     7x   3x   3x 18x 18x 15x     3x   1x                       7x 7x 7x 7x 7x   6x   8x 8x     2x   2x 1x   1x     2x   6x 6x 30x 30x           6x 6x 6x       6x   6x 6x     6x   2x     6x 6x   24x                             1x  
const cp = require('promisify-child-process');
const commandConvert = require('cross-env/src/command');
const varValueConvert = require('cross-env/src/variable');
const parse = require('cross-spawn/lib/parse');
const { InvalidTypeError } = require('../errors');
 
async function spawn(command, args, options) {
  const parsed = parse(command, args, options);
  return await cp.spawn(parsed.command, parsed.args, parsed.options);
}
 
function parseArgs(args) {
  const pattern = new RegExp(/[^\s"']+|["']([^"']*)["']/gi);
  const newArgs = [];
  let match;
 
  switch (typeof args) {
    case 'object':
      return Array.isArray(args) ? args : Object.values(args);
    case 'string':
      do {
        match = pattern.exec(args);
        if (match != null) {
          newArgs.push(match[1] ? match[1] : match[0]);
        }
      } while (match != null);
      return newArgs;
    default:
      throw new InvalidTypeError('args', args, 'object or string');
  }
}
 
/**
 * Execute an asynchronous cli command as sub process.
 *
 * @param {string[] | string} args An array or whitespace separated string with cli args.
 * @returns {import("promisify-child-process").ChildProcessPromise | null} The cli results or null.
 * @throws {InvalidTypeError} if type of args param is invalid.
 */
async function execCmd(args) {
  const envSetterRegex = /(\w+)=('(.*)'|"(.*)"|(.*))/gi;
  const envSetters = {};
  let command = null;
  let commandArgs = [];
  const parsedArgs = parseArgs(args);
 
  for (let i = 0; i < parsedArgs.length; i++) {
    // eslint-disable-next-line security/detect-object-injection
    const match = envSetterRegex.exec(parsedArgs[i]);
    if (match) {
      let value;
 
      Iif (typeof match[3] !== 'undefined') {
        value = match[3];
      } else if (typeof match[4] === 'undefined') {
        value = match[5];
      } else {
        value = match[4];
      }
 
      envSetters[match[1]] = value;
    } else {
      let cStart = [];
      cStart = parsedArgs.slice(i).map((a) => {
        const re = /\\\\|(\\)?'|([\\])(?=[$"\\])/g;
        return a.replace(re, (m) => {
          if (m === '\\\\') return '\\';
          if (m === '\\\'') return '\'';
          return '';
        });
      });
      command = cStart[0];
      commandArgs = cStart.slice(1);
      break;
    }
  }
 
  const env = { ...process.env };
 
  Eif (process.env.APPDATA) {
    env.APPDATA = process.env.APPDATA;
  }
 
  Object.keys(envSetters).forEach((varName) => {
    // eslint-disable-next-line security/detect-object-injection
    env[varName] = varValueConvert(envSetters[varName], varName);
  });
 
  Eif (command) {
    return await spawn(
      commandConvert(command, env, true),
      commandArgs.map((arg) => commandConvert(arg, env)),
      {
        stdio: 'inherit',
        shell: true,
        env,
      },
      {
        allowUnmatched: true,
      },
    );
  }
 
  return null;
}
 
module.exports = { execCmd };