Source: utils/commands.js

/**
 *  @overview this library defines functions which implement the various
 *            commands that are given to the chapi command-line tool
 *  @author Ben Watson <ben.watson@coxautoinc.com>
 */

var tty = require('tty');
var CloudHealth = require('..');
var utils = CloudHealth.utils;

/**
 *  @namespace module:cox-chapi.commands
 */
var commands = {
  make_api_call,
  resolve_component,
  resolve_inputs,
  resolve_func,
  run_script,
  set_api_key,
  show_help,
  show_version,
  use_api,
}

/**
 *  makes an api call by calling <component_name>#<func_name> with params
 *  @memberof module:cox-chapi.commands
 *  @param {string} component_name - the name of the component to call func_name on
 *  @param {string} func_name - the name of the function to call
 *  @param {string[]} params - an array of parameters to give to func_name
 *  @param {mixedCallback} cb - yields the result of the api call
 */
function make_api_call(component_name, func_name, params, cb) {
  utils.find_api_key((err, api_key) => {
    if (err) return cb(err, api_key);

    var component = this.resolve_component(component_name, api_key);
    var func = this.resolve_func(component, func_name);

    utils.execute(component, func, params, cb);
  });
}

/**
 *  resolves a name of a component and retrieves the actual component
 *  @memberof module:cox-chapi.commands
 *  @param {string} name - the name of the component
 *  @param {string} [api_key] - the api_key to use when creating the component
 *  @return {object} the component object
 */
function resolve_component(name, api_key) {
  var class_name = name.slice(0, 1).toUpperCase() + name.slice(1).toLowerCase();
  switch(class_name) {
    case 'Account':
    case 'Accounts':
    case 'Acct':
      return new CloudHealth.Account(api_key);
    case 'Asset':
    case 'Assets':
    case 'Asst':
      return new CloudHealth.Asset(api_key);
    case 'Perspective':
    case 'Perspectives':
    case 'Pers':
      return new CloudHealth.Perspective(api_key);
    case 'Tag':
    case 'Tags':
    case 'Tagging':
      return new CloudHealth.Tag(api_key);
    case 'Report':
    case 'Reports':
    case 'Reporting':
      return new CloudHealth.Report(api_key);
    default:
      return new Error(class_name + ' is an invalid component name');
  }
}

/**
 *  calls the appropriate command based on the given arguments
 *  @memberof module:cox-chapi.commands
 *  @param {string[]} args - and array of arguments
 */
function resolve_inputs(args) {
  if (!args.length) args = [ 'help' ];

  switch (args[0]) {
    case 'help':
    case '--help':
    case 'usage':
    case '--usage':
      this.show_help();
      break;
    case 'set_api_key':
    case 'set-api-key':
    case 'set_key':
    case 'set-key':
    case '-A':
      this.set_api_key(args[1]);
      break;
    case 'run':
    case 'script':
    case 'exec':
    case 'execute':
    case '-R':
      this.run_script(...args.slice(1));
      break;
    case 'version':
    case '--version':
    case '-V':
      this.show_version();
      break;
    default:
      this.use_api(args);
  }
}

/**
 *  retrieves the function with the given name for the given component
 *  @memberof module:cox-chapi.commands
 *  @param {object} component - the component object containing the desired function
 *  @param {string} func_name - the name of the function to retrieve
 *  @return {function} the function
 */
function resolve_func(component, func_name) {
  if (func_name.charAt(0) === '_') {
    return new Error('private functions cannot be called from the command-line');
  }
  func_name = func_name.replace(/-/g, '_');
  var func = component[func_name.toLowerCase()];
  if (!func) {
    return new Error(`function ${func_name} does not exist on component ${JSON.stringify(component)}`);
  }
  return func;
}

/**
 *  executes a script in the scripts folder with the given arguments
 *  @memberof module:cox-chapi.commands
 *  @param {string} name - the name of the script
 */
function run_script(name, ...args) {
  utils.run(name, ...args);
}

/**
 *  sets the api key and prints a message on success
 *  @memberof module:cox-chapi.commands
 *  @param {string} api_key - the api key to set
 */
function set_api_key(api_key) {
  utils.set_api_key(api_key, (err, api_key) => {
    if (err) return utils.print_response(err, api_key);
    utils.print_response(null, 'api key has been set');
  });
}

/**
 *  prints a message explaining the usage of the tool
 *  @memberof module:cox-chapi.commands
 */
function show_help() {
  console.error(
`usage:
chapi <component> <function> [<flags>] [<other-arguments>]

<component> - the name of the component to use (ie. perspective, account, etc.)
<function> - the name of the function to call (ie. get, find_by, list, etc.)
<flags> - any flags taken by the function (in the form --key=value)
<other-arguments> - parameters to pass to the function`
  );
}

/**
 *  prints the name and version number of this tool
 *  @memberof module:cox-chapi.commands
 */
function show_version() {
  utils.get_package_json((err, json) => {
    if (err) return utils.print_response(err, json);
    utils.print_response(null, `${json.name} version ${json.version}`);
  });
}

/**
 *  reads parameters from stdin (if any), adds them to the list of params, and
 *  makes an api call based on the given args
 *  @memberof module:cox-chapi.commands
 *  @param {string[]} args - an array in the form [component, function, parameters]
 */
function use_api(args) {
  // if data is piped in, read from stdin, otherwise execute with given params
  var cb = utils.print_response;
  if (tty.isatty(0)) {
    this.make_api_call(args[0], args[1], args.slice(2), cb);
  }
  else {
    utils.read_stdin((err, data) => {
      if (err) return utils.print_response(err, data);

      var parsed_data = utils._parse_stdin_data(data);
      params = args.slice(2).concat(parsed_data);

      this.make_api_call(args[0], args[1], params, cb);
    });
  }
}

module.exports = commands;