Commander.js

Commander is a light-weight, expressive, and powerful command-line framework for node.js.

exports.Command

Expose Command.

Source

exports.Command = Command;

exports.Option

Expose Option.

Source

exports.Option = Option;

Option()

Initialize a new Option with the given flags and description.

Source

function Option(flags, description) {
  this.flags = flags;
  this.required = ~flags.indexOf('<');
  this.optional = ~flags.indexOf('[');
  this.bool = !~flags.indexOf('-no-');
  flags = flags.split(/[ ,|]+/)
  this.short = flags.shift();
  this.long = flags.shift();
  this.description = description;
}

Command()

Initialize a new Command.

Source

function Command(name) {
  this.commands = [];
  this.options = [];
  this.args = [];
  this.name = name;
}

Command#command()

Add command name.

The .action() callback is invoked when the
command name is specified via ARGV,
and the remaining arguments are applied to the
function for access.

When the name is "*" an un-matched command
will be passed as the first arg, followed by
the rest of ARGV remaining.

Examples

 program
   .version('0.0.1')
   .option('-C, --chdir <path>', 'change the working directory')
   .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
   .option('-T, --no-tests', 'ignore test hook')

 program
   .command('setup')
   .description('run remote setup commands')
   .action(function(){
     console.log('setup');
   });

 program
   .command('exec <cmd>')
   .description('run the given remote command')
   .action(function(cmd){
     console.log('exec "%s"', cmd);
   });

 program
   .command('*')
   .description('deploy the given env')
   .action(function(env){
     console.log('deploying "%s"', env);
   });

 program.parse(process.argv);

Source

Command.prototype.command = function(name){
  var args = name.split(/ +/);
  var cmd = new Command(args.shift());
  this.commands.push(cmd);
  cmd.parseExpectedArgs(args);
  cmd.parent = this;
  return cmd;
};

Command#action()

Register callback fn for the command.

Examples

 program
   .command('help')
   .description('display verbose help')
   .action(function(){
      // output help here
   });

Source

Command.prototype.action = function(fn){
  var self = this;
  this.parent.on(this.name, function(args){
    self.args.forEach(function(arg, i){
      if (arg.required && null == args[i]) {
        self.missingArgument(arg.name);
      }
    });
    fn.apply(this, args);
  });
  return this;
};

Command#option()

Define option with flags, description and optional
coercion fn.

The flags string should contain both the short and long flags,
separated by comma, a pipe or space. The following are all valid
all will output this way when --help is used.

"-p, --pepper"
"-p|--pepper"
"-p --pepper"

Examples

// simple boolean defaulting to false
program.option('-p, --pepper', 'add pepper');

--pepper
program.pepper
// => Boolean

// simple boolean defaulting to false
program.option('-C, --no-cheese', 'remove cheese');

program.cheese
// => true

--no-cheese
program.cheese
// => true

// required argument
program.option('-C, --chdir <path>', 'change the working directory');

--chdir /tmp
program.chdir
// => "/tmp"

// optional argument
program.option('-c, --cheese [type]', 'add cheese [marble]');

Source

Command.prototype.option = function(flags, description, fn, defaultValue){
  var self = this
    , option = new Option(flags, description)
    , oname = option.name()
    , name = camelcase(oname);

  // default as 3rd arg
  if ('function' != typeof fn) defaultValue = fn, fn = null;

  // preassign default value only for --no-*, [optional], or 
  if (false == option.bool || option.optional || option.required) {
    // when --no-* we make sure default is true
    if (false == option.bool) defaultValue = true;
    // preassign only if we have a default
    if (undefined !== defaultValue) self[name] = defaultValue;
  }

  // register the option
  this.options.push(option);

  // when it's passed assign the value
  // and conditionally invoke the callback
  this.on(oname, function(val){
    // coercion
    if (null != val && fn) val = fn(val);

    // unassigned or bool
    if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
      // if no value, bool true, and we have a default, then use it!
      if (null == val) {
        self[name] = option.bool
          ? defaultValue || true
          : false;
      } else {
        self[name] = val;
      }
    } else if (null !== val) {
      // reassign
      self[name] = val;
    }
  });

  return this;
};

Command#parse()

Parse argv, settings options and invoking commands when defined.

Source

Command.prototype.parse = function(argv){
  // store raw args
  this.rawArgs = argv;

  // guess name
  if (!this.name) this.name = basename(argv[1]);

  // process argv
  this.args = this.parseOptions(this.normalize(argv));
  return this.parseArgs(this.args);
};

Command#description()

Set the description str.

Source

Command.prototype.description = function(str){
  if (0 == arguments.length) return this._description;
  this._description = str;
  return this;
};

Command#usage()

Set / get the command usage str.

Source

Command.prototype.usage = function(str){
  var usage = '[options'
    + (this.commands.length ? '] [command' : '')
    + ']';
  if (0 == arguments.length) return this._usage || usage;
  this._usage = str;
  return this;
};

Command#prompt()

Prompt str and callback fn(val)

Commander supports single-line and multi-line prompts.
To issue a single-line prompt simply add white-space
to the end of str, something like "name: ", whereas
for a multi-line prompt omit this "description:".

Examples

program.prompt('Username: ', function(name){
  console.log('hi %s', name);
});

program.prompt('Description:', function(desc){
  console.log('description was "%s"', desc.trim());
});

Source

Command.prototype.prompt = function(str, fn){
  if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments);
  this.promptMultiLine(str, fn);
};

Command#password()

Prompt for password with str, mask char and callback fn(val).

The mask string defaults to '', aka no output is
written while typing, you may want to use "*" etc.

Examples

program.password('Password: ', function(pass){
  console.log('got "%s"', pass);
  process.stdin.destroy();
});

program.password('Password: ', '*', function(pass){
  console.log('got "%s"', pass);
  process.stdin.destroy();
});

Source

Command.prototype.password = function(str, mask, fn){
  var self = this
    , buf = '';

  // default mask
  if ('function' == typeof mask) {
    fn = mask;
    mask = '';
  }

  tty.setRawMode(true);
  process.stdout.write(str);

  // keypress
  process.stdin.on('keypress', function(c, key){
    if (key && 'enter' == key.name) {
      console.log();
      process.stdin.removeAllListeners('keypress');
      tty.setRawMode(false);
      if (!buf.trim().length) return self.password(str, mask, fn);
      fn(buf);
      return;
    }

    if (key && key.ctrl && 'c' == key.name) {
      console.log('%s', buf);
      process.exit();
    }

    process.stdout.write(mask);
    buf += c;
  }).resume();
};

Command#confirm()

Confirmation prompt with str and callback fn(bool)

Examples

 program.confirm('continue? ', function(ok){
   console.log(' got %j', ok);
   process.stdin.destroy();
 });

Source

Command.prototype.confirm = function(str, fn){
  var self = this;
  this.prompt(str, function(ok){
    if (!ok.trim()) {
      return self.confirm(str, fn);
    }
    fn(parseBool(ok));
  });
};

Command#choose()

Choice prompt with list of items and callback fn(index, item)

Examples

 var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];

 console.log('Choose the coolest pet:');
 program.choose(list, function(i){
   console.log('you chose %d "%s"', i, list[i]);
   process.stdin.destroy();
 });

Source

Command.prototype.choose = function(list, fn){
  var self = this;

  list.forEach(function(item, i){
    console.log('  %d) %s', i + 1, item);
  });

  function again() {
    self.prompt('  : ', function(val){
      val = parseInt(val, 10) - 1;
      if (null == list[val]) {
        again();
      } else {
        fn(val, list[val]);
      }
    });
  }

  again();
};