#!/usr/bin/env node
/**
 * An executable command which will be added to $PATH.
 *
 * @copyright Copyright 2017 Kevin Locke <kevin@kevinlocke.name>
 * @license MIT
 */

'use strict';

var Yargs = require('yargs/yargs');
var assign = require('object-assign');
var modulename = require('..');

/** Calls <code>yargs.parse</code> and passes any thrown errors to the callback.
 * Workaround for https://github.com/yargs/yargs/issues/755
 */
function parseYargs(yargs, args, callback) {
  try {
    yargs.parse(args, callback);
  } catch (err) {
    // Since yargs doesn't nextTick its callback, don't here either
    callback(err);
  }
}

/** Options for command entry points.
 *
 * @typedef {{
 *   in: (stream.Readable|undefined),
 *   out: (stream.Writable|undefined),
 *   err: (stream.Writable|undefined)
 * }} CommandOptions
 * @property {stream.Readable=} in Stream from which input is read. (default:
 * <code>process.stdin</code>)
 * @property {stream.Writable=} out Stream to which output is written.
 * (default: <code>process.stdout</code>)
 * @property {stream.Writable=} err Stream to which errors (and non-output
 * status messages) are written. (default: <code>process.stderr</code>)
 */
// var CommandOptions;

/** Entry point for this command.
 *
 * @param {!Array<string>} args Command-line arguments.
 * @param {CommandOptions=} options Options.
 * @param {?function(Error, number=)=}
 * callback Callback for the exit code or an <code>Error</code>.  Required if
 * <code>global.Promise</code> is not defined.
 * @return {Promise<number>|undefined} If <code>callback</code> is not given
 * and <code>global.Promise</code> is defined, a <code>Promise</code> with the
 * exit code or <code>Error</code>.
 */
function modulenameCmd(args, options, callback) {
  if (!callback && typeof options === 'function') {
    callback = options;
    options = null;
  }

  if (!callback && typeof Promise === 'function') {
    // eslint-disable-next-line no-undef
    return new Promise(function(resolve, reject) {
      modulenameCmd(args, options, function(err, result) {
        if (err) { reject(err); } else { resolve(result); }
      });
    });
  }

  if (typeof callback !== 'function') {
    throw new TypeError('callback must be a function');
  }

  try {
    if (args === undefined ||
        args === null ||
        (typeof args === 'object' && args.length === 0)) {
      args = [];
    } else if (typeof args !== 'object' ||
               Math.floor(args.length) !== args.length ||
               args.length < 2) {
      throw new TypeError('args must be Array-like with at least 2 elements');
    } else {
      args = Array.prototype.slice.call(args, 2).map(String);
    }

    if (options !== undefined && typeof options !== 'object') {
      throw new TypeError('options must be an object');
    }

    options = assign(
      {
        in: process.stdin,
        out: process.stdout,
        err: process.stderr
      },
      options
    );

    if (!options.in || typeof options.in.on !== 'function') {
      throw new TypeError('options.in must be a stream.Readable');
    }
    if (!options.out || typeof options.out.write !== 'function') {
      throw new TypeError('options.out must be a stream.Writable');
    }
    if (!options.err || typeof options.err.write !== 'function') {
      throw new TypeError('options.err must be a stream.Writable');
    }
  } catch (err) {
    process.nextTick(function() {
      callback(err);
    });
    return undefined;
  }

  var yargs = new Yargs()
    .usage('Usage: $0 [options] [args...]')
    .help()
    .option('quiet', {
      alias: 'q',
      describe: 'Print less output',
      count: true
    })
    .option('verbose', {
      alias: 'v',
      describe: 'Print more output',
      count: true
    })
    .version()
    .strict();
  parseYargs(yargs, args, function(err, argOpts, output) {
    if (err) {
      options.err.write(output ?
                          output + '\n' :
                          err.name + ': ' + err.message + '\n');
      callback(null, 1);
      return;
    }

    if (output) {
      options.out.write(output + '\n');
    }

    if (argOpts.help || argOpts.version) {
      callback(null, 0);
      return;
    }

    if (argOpts._.length !== 1) {
      options.err.write('Error: Exactly one argument is required.\n');
      callback(null, 1);
      return;
    }

    // Parse arguments then call API function with parsed options
    var cmdOpts = {
      files: argOpts._,
      verbosity: argOpts.verbose - argOpts.quiet
    };
    modulename(cmdOpts, callback);
  });

  return undefined;
}

modulenameCmd.default = modulenameCmd;
module.exports = modulenameCmd;

if (require.main === module) {
  // This file was invoked directly.
  /* eslint-disable no-process-exit */
  var mainOptions = {
    in: process.stdin,
    out: process.stdout,
    err: process.stderr
  };
  modulenameCmd(process.argv, mainOptions, function(err, exitCode) {
    if (err) {
      if (err.stdout) { process.stdout.write(err.stdout); }
      if (err.stderr) { process.stderr.write(err.stderr); }
      process.stderr.write(err.name + ': ' + err.message + '\n');

      exitCode = typeof err.exitCode === 'number' ? err.exitCode : 1;
    }

    process.exit(exitCode);
  });
}

@@ -3566,16 +3566,64 @@
 .help()%0A
+    .alias('help', 'h')%0A    .alias('help', '?')%0A
     .opt
@@ -3837,16 +3837,43 @@
 rsion()%0A
+    .alias('version', 'V')%0A
     .str

Add -h, -?, -V aliases