Jam3/adviser

View on GitHub
src/cli/cli.js

Summary

Maintainability
A
3 hrs
Test Coverage
/**
 * @fileoverview Parses the CLI parameters options
 *
 */

'use strict';

const debug = require('debug')('adviser:cli');
const chalk = require('chalk');

const Config = require('../core/config/config');
const Engine = require('../core/engine');
const Formatter = require('../core/formatters/formatter');
const Spinner = require('./spinner');
const EVENTS = require('../core/constants/events');

const options = require('./options');
const logger = require('../utils/logger');
const packageInfo = require('../package-info');

/**
 * CLI Entry point and option parser class
 *
 * @class CLI
 */
class CLI {
  /**
   * Execute CLI logic based on parameters
   *
   * @param {Array} args Process.argv output
   */
  execute(args, callback) {
    let currentOptions;
    let errorCode = 0;

    try {
      debug('Parsing the CLI options');
      currentOptions = options.parse(args);
    } catch (error) {
      logger.error(error.message);
      logger.info(`\nRun 'adviser -h' to discover the available parameters`);

      debug('Error parsing the CLI options', error);

      errorCode = 2;
      callback(errorCode);
      return;
    }

    if (currentOptions.version) {
      debug('Retrieving package version');
      logger.info(`v${packageInfo.getVersion()}`);
    } else if (currentOptions.help) {
      debug('Retrieving CLI help');
      logger.info(options.generateHelp());
    } else {
      debug(`Parsing CLI arguments ${JSON.stringify(currentOptions)} for the engine`);
      const engineOptions = this._prepareEngineOptions(currentOptions);

      const config = new Config(engineOptions['configFile'] || engineOptions.cwd);
      debug(`Engine called with the parameters ${JSON.stringify(engineOptions)}`);
      const engine = new Engine(config, engineOptions);

      if (!currentOptions.debug) {
        console.log(`Adviser v${packageInfo.getVersion()}\n`);

        const spinner = new Spinner();

        engine
          .on(EVENTS.ENGINE.LOAD_RULES, () => {
            spinner.progress('Loading rules');
          })
          .on(EVENTS.ENGINE.RUN, () => {
            spinner.progress('Rules loaded', 'The engine is executing the rules');
          })
          .on(EVENTS.ENGINE.STOP, () => {
            spinner.succeed('Rules executed');
          });
      }

      engine
        .run()
        .then(() => {
          const issues = engine.getIssues();
          const processedRules = engine.getRules();

          if (issues.items.length > 0) {
            this.printResults(issues, processedRules, {
              format: engineOptions.outputFormat,
              verbose: currentOptions.verbose
            });

            errorCode = 2;

            if (currentOptions.quiet && issues.total.errors === 0) {
              errorCode = 0;
            }
          }

          if (currentOptions.verbose) {
            if (issues.items.length > 0) {
              this.printResults(issues, processedRules, {
                format: 'verbose'
              });
            }

            if (processedRules.length > 0) {
              this.printResults(issues, processedRules, {
                format: 'summary'
              });
            }
          } else {
            const verboseResults = issues.items.filter(result => result.params.verbose !== undefined);

            if (verboseResults.length >= 1) {
              console.log(
                `Some rules reported a verbose result, call Adviser with ${chalk.gray('--verbose')} for more details.\n`
              );
            }
          }

          callback(errorCode);
        })
        .catch(error => {
          logger.error('Some rules has failed the run', error);
          callback(errorCode);
        });
    }
  }

  /**
   * Print results in the console
   *
   * @param {String} format
   * @param {Array} issues
   * @param {Object} options
   * @memberof CLI
   */
  printResults(issues, rules, options) {
    const formatter = new Formatter(options.format);

    const output = formatter.getOutput(issues, rules);

    if (output) {
      logger.info(output);
    }
  }

  /**
   * Create the engine options object
   *
   * @param {Object} cliOptions
   */
  _prepareEngineOptions(cliOptions) {
    const engineOptions = {
      outputFormat: 'base',
      cwd: process.cwd(),
      verboseMode: cliOptions['verbose'] || false
    };

    cliOptions.config && (engineOptions['configFile'] = cliOptions.config);
    cliOptions.tags && (engineOptions['tags'] = cliOptions.tags);

    return engineOptions;
  }
}

module.exports = new CLI();