Electron

A tiny cli framework for node.js.

Features

  • tbd

Installation

Node

electron package is available through npm.

npm install electron

Argument Parsing

The electron argument parser takes the node.js standard process.argv array and constructs an object with helpers that can easily be queried. This helper is publicly exposed so it can be used independant of the cli framework.

var electron = require('electron')
  , argv = electron.argv(process.argv);

When constructed, the electron argv parser recognizes three types command line arguments: commands, modes, and parameters.

Each of these types also has a helper that will provide quick access to whether a command or mode is present, or the value of a parameter.

Commands

Commands are the simplest of arguments. They are any arguments that are listed to that do not start with the - prefix. Essentially, they are a list of keys.

// $ node cli.js hello universe
argv.commands === [ 'hello', 'universe' ];
Modes

Modes are also a non-value list of keys, but they can be expressed differently by using the - or -- prefix. When using modes, if it begins with a single -, each letter will be parsed as its own mode.

// $ node cli.js --universe -abc
argv.modes === [ 'universe', 'a', 'b', 'c' ];
Parameters

Paremeters are key:value pairs that are declared in a similiar manner as modes. They can be declared in any of the following ways.

// $ node cli.js --noun unverse -v say --topic=hello -w=now
argv.params === {
    noun: 'universe'
  , v: 'say'
  , topic: 'hello'
  , w: 'now'
};

.command (cmd, [cmd], [...])

  • @param{ String }command(s)to check

The command helper takes a list of commands and will return true if any of them exist in the commands list.

// node cli.js hello universe
var greeting = argv.command('hi', 'hello') // true
  , world = argv.command('world', 'earth'); // false

.mode (mode, [mode], [...])

  • @param{ String }mode(s)to check

The mode helper takes a list of modes and will return true if any of them exist in the modes list.

// node cli.js --hello -abc
var greeting = argv.mode('h', 'hello') // true
  , world = argv.mode('w', 'world'); // false

.param (param, [param], [...])

  • @param{ String }mode(s)to check

The param helper takes a list of parameters and will return the value of the first parameter that matches, or null if none of the parameters exist in the params list.

// node cli.js --hello universe
var greeting = argv.param('h', 'hello') // 'universe'
  , world = argv.param('w', 'world'); // null

Program Framework

.command (name)

  • @param{ String }commandname

The most important aspect of an application is defining the different commands that can be executed for it. Some people prefer a CLI tool that does one thing based on a set of options. Others prefer a command line tool that can pivot based on a command string. Electron supports both.

When using the command method, it will return a constructed command object with a different set of methods for chaining. Please read the "Constructing Commands" section for all available chainable methods and their respective purpose.

Single Command

As you understand how Electron parses command-line options, you know that a command is any option that does not start with - or --. Therefor, a single-command electron application is one that does not require any commands, but will execute a single action. Best demonstrated...

$ node app.js -p 8080

In the case of single-command applications, we will define a default command for electron to run.

program
  .command('default')
  .action(function (argv) {
    var port = argv.param('p', 'port');
    // something cool
  });

The default command will run when no commands are passed in, but it will not run if a command is provided.

Multiple Commands

You can also create many different commands for your application based on a simple string. These can be used in conjunction with default if you would like.

$ node app.js hello --universe

In this case we want to only run an action when the comamnd hello is present. This can easily be achieved.

program
  .command('hello')
  .action(fn);

There are also cases where you might want to have multipe layers of commands.

$ node app.js hello universe

Using the same mechanism, we can easily define this action.

program
  .command('hello universe')
  .action(fn);

One final option to explore with multiple commands is wildcards. Wildcards can exist at any level in a multi-word command, but they only work for entire words, not substrings.

program
  .command('hello *')
  .action(function (argv) {
    var where = argv.commands[1];
  });

Would respond for any command starting with hello and is two commands long, such as...

$ node app.js hello world
$ node app.js hello universe
Absent Commands

Should you want to notify your users when they attempt to use a command is not support, you may use the absent command. This is also useful if you want to have a single command app but support a list of items as "options", such as a list of files or directories.

$ node build.js file1.js files2.js

program
  .command('absent')
  .action(function (argv) {
    var files = argv.commands.slice(0);
    // something cool
  });

.parse (process.argv)

  • @param{ Array }process.argvor compable array

The parse method will initiate the program with selection of arguments and run a matching action. It should be used once all commands and settings have been propogated.

program.parse();
program.parse(process.argv);
program.parse([ 'node', 'app.js', '--hello', '--universe' ]);

If no parameter is provided, parse will default to using the current processes process.argv array. You may alse provide your own array of commands if you like. Note that argv parsing expectes the first item to be the executing program and the second argument to be the script (as is with all node argv). These will be discarded.

.name (name)

  • @param{ String }formalname

Provide a formal name to be used when displaying the help for the given program. Returns the program for chaining.

program.name('Electron Framework');

.version (version)

  • @param{ String }applicationversion

Provide a program version to be used when displaying the version for the given program. Returns the program for chaining.

program.version(electron.version);

.desc (description)

  • @param{ String }applicationdescription

Provide a program discription to be used when displaying the the help for the given program. Returns the program for chaining.

program.desc('https://github.com/logicalparadox/electron');

.cwd (fqp)

  • @param{ String }fullyquialified path

Provide an alternative current working directory to be passed as part of the argv parameter to the action that has been executed. Returns the program for chaining.

// set
program.cwd(__dirname);

// get
program
  .command('universe')
  .action(function (argv) {
    var cwd = argv.cwd;
    // something cool
  });

.theme (theme, specifications)

  • @param{ String | Function }nameof electron theme or custom function
  • @param{ Object }optionsfor electron themes

You may change the appearance of the --help using a simple theming mechanism. Electron comes bundled with two themes. Each theme also supports minor tweaks. Returns the program for chaining.

clean (default)

A colorful and verbose theme useful for multi-command applications.

program
  .theme('clean', {
      noColor: false // set to true to disable color coding
    , prefix: '' // prefix written before each line, such as 'help:'
  });

Electron Clean Theme

simple

An "options only" theme useful for single command applications.

program
  .theme('simple', {
      noColor: false // set to true to disable color coding
    , command: 'default' // which command to show options for
    , usage: '<options>' // special usage instructions
  });

Electron Simple Theme

Use Your Own Function

You may also provide a function to theme to provide your own output. The following example will list all of the commands present in your program.

program.theme(function () {
  this.colorize();
  console.log('Usage: %s <command>', this.opts.base);
  this.commands.forEach(functioni (cmd) {
    console.log('  %s - %s', cmd.cmd, cmd.desc);
  });
});

Those interesting in building custom themes should view Electron on GitHub and explore lib/electron/themes.

.colorize ()

The colorize helper is available if you wish you implement a colorized but lightweight logging mechanism in your actions, or if you are building a custom help theme. colorize works by extending String.prototype with a number of color options. Just in case, if the current program is not running as a TTY, no string changes will be made.

console.log('hello universe'.green);
Colors
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • gray

Constructing Commands

Once you have decided to construct a command through program.command you will be returned a command object that you can manipulate through chainable methods.

.desc (description)

  • @param{ String }description

Provide a description for this command to be used when being display in help.

program
  .command('hello universe')
  .desc('Say "Hello" to the Universe.');

.option (opts, description, required)

  • @param{ String }optionsto parse
  • @param{ String }description
  • @param{ Boolean }required.defaults to false

You may define any number of options for each command. The opts string expects a comma delimited list of commands with an optional default value or indicator surrounded by brackets. You may also provide a description of the option and whether it is required.

This command may be called multiple times to define multiple options.

program
  .command('build')
  .option('-m, --minify', 'Flag to build minify version')
  .option('-f, --file [build.js]', 'Save filename', true);

.action (function)

  • @param{ Function }actionto perform

Provide the action to be used should this command be called. The function will receive one parameter of the parsed process.argv object. Multiple calls to action will replace the previous defined action.

program
  .command('build')
  .action(function (argv) {
    var minify = argv.mode('m', 'minify')
      , file = argv.param('f', 'file');
    // go!
  });