protogram
v1.1.3
Published
Handle command line arguments and sub arguments and sub sub arguments and sub sub sub arguments, etc.
Downloads
4,368
Maintainers
Readme
protogram
A node.js module to recursively create command-line programs and sub-programs. Easily handle command line arguments and sub arguments and sub sub arguments and sub sub sub arguments, etc... with just a little bit of fat. Some things this module provides:
- a minimal, yet easily scalable interface
- flexible control over the handling of argument flags and sub-commands
- ability to handle sub-contexts as arguments a la subarg.
- autogenerate help information via protogram-help
Installation
npm install --save protogram
Basic Usage
Include and Create your Program
var program = require('protogram').create();
Add Option Flags
Add option flags to your program. Shortcuts will automatically be made based on the first available character of the specified option name.
program
.option('--optionA') // shortcut will be -o
.option('--optionB'); // shortcut will be -O
Set an Action For When Your Program Runs
program.action = function(args, flags){
if(flags.optionA) console.log("optionA set to:", flags.optionA)
if(flags.optionB) console.log("optionB set to:", flags.optionB)
console.log("passed in arguments:", args)
};
Parse Your Arguments to Execute
Finally, the most important step! Now that you've set everything up, you're ready to parse your program's arguments.
program.parse(process.argv);
Test It
node example.js 198787 "Arg 2" --optionA [ A 29787 "b C" -A -B 29872 ] --optionB "This Is A Long String"
Will output:
optionA set to: { _: [ "A", 29787, "b C"], A: true, B: 29872 }
optionB set to: "This Is A Long String"
passed in arguments: [ 198787, "Arg 2" ]
Advanced Usage
The above was just to get you started. The API is super flexible and you can control the flow of your program to near infinite specificity.
Advanced Option Specification
Take more control over how flags are specified and handled by passing in options to your option
setting. Aside from the first argument specifying the flag name, all of the flag settings below are of course optional.
program.option('--optionA', {
shortcut: '-a',
description: 'Use a generic flag to do anything',
required: 'a value'
action: function(value){
// called if the flag is set and there are no errors
console.log("optionA was set to:", value);
},
error: function(err, value){
// called if the 'required' value is not specified when executing
console.error(err.message);
}
});
Add Commands as Sub-Programs
Recursively add git-style commands to your program, and build them as you would your main program.
var sub_program = program.command('run', {
description: 'execute a command',
required: 'path name',
action: function(args, flags){
// executed if there are no errors
console.log("path to execute:", args[0]);
if(flags.now) // executing now
},
error: function(err, args){
// called if the required argument is missing
// or if any flags' required arguments are missing.
console.error(err.message);
}
});
sub_program.option('--now')
Use a Wildcard for Configuring All Commands
program.command('*', {
includeRoot: true // also apply all these settings to the root program
}).option('--version', {
action: function(value){
console.log("My Program v4.0.0")
}
});
Add Automated Help to Your Program
Want to output usage instructions automatically for your program? Use the protogram-help module. Refer to the documentation for how to use.
Bubble Up Execution Paths
By default the execution of action
methods of a program does not bubble up to the parent commands.
For example, let's say we create a program with a system of sub commands:
var program = protogram.create({
action: function(args, flags) {
console.log("main program activated"); // will not be executed
}
});
var sub_program = program.command('sub-command', {
action: function(args, flags) {
console.log("sub-command activated"); // will not be executed
}
});
sub_program.command('sub-sub-command', {
action: function(args, flags) {
console.log("sub-sub-command activated"); // will be executed
}
});
And execute:
node example.js sub-command sub-sub-command
Only the sub-sub-command
action method would be trigged. We can change this by setting the bubbleUp
option on any parent command.
var program = protogram.create({
action: function(args, flags) {
console.log("main program activated"); // will not be executed
}
});
var sub_program = program.command('sub-command', {
bubbleUp: true,
action: function(args, flags) {
console.log("sub-command activated"); // will be executed
}
});
sub_program.command('sub-sub-command', {
action: function(args, flags) {
console.log("sub-sub-command activated"); // will be executed
}
});
Now both the sub-command
and the sub-sub-command
actions will be executed.
Halt on Error
By default if there is an error (ie. a required argument is missing) for a parent command, the program will continue to parse and evaluate sub-commands and flags. Prevent this by setting the haltOnError
option to true
when you create your program.
var program = protogram.create({haltOnError: true});
or apply to specific sub-commands:
var sub_program = program.command('run', {
haltOnError: true,
required: 'path name',
action: function(args, flags){ },
error: function(err, args){ }
})
sub_program.command('at', {
required: 'a time',
action: function(args, flags){ },
error: function(err, args){ }
});
node example.js run at "13:34"
Now in the above example, even though the sub-command at
is specified, it will not execute because the required argument path name
is missing for the run
command. The error will be handled by the run
's error
property.
Test Flags
If you'd prefer the good ol' fashioned way of testing your flags, instead of using handlers, just test their existence after you've parsed your arguments:
if(program.flagged['generic']){
console.log('the --generic flag has been used!')
}
API
Protogram.create(options)
Returns a new Protogram
command object.
options
Object:description
String: Specify a description for the sub-command.required
String: Describe a required value that must be be passed in by the user if this sub-command is used.optional
String: Describe an optional value that can be passed in when this sub-command is used. Ifrequired
is set,optional
will be ignored.action
Function(args, program): A handler method called if the sub-command is set without any errors. Receives allargs
passed in.error
Function(error, value, program): A handler method called if the flag is set but has an error (ie.required
was set and no value was passed in by the user).haltOnError
Boolean: Set whether the program should stop parsing if there is an error.bubbleUp
Boolean: Set whether the program'saction
method should be executed along with sub-commands.
var program = protogram.create({
action: function(args, flags) {
console.log("running your program");
}
});
Protogram.command(command_name, options)
Returns a new Protogram
command object.
Add a sub-command to your program. The sub-command is a new instance of Protogram
.
command_name
String: Name of the sub-command to your program. Use the*
command name to apply this setting to all sub-commands of the program.options
Object: Since the Protogram.command method returns a new Protogram object, you can set the same options as Protogram.create().
Minimal Example
program.command('run', {
action: function(args, flags) {
console.log("executed the run command");
}
});
Example with a Required Argument
program.command('run', {
required: 'file path',
action: function(args, flags) {
console.log("executed the run command successfully");
},
error: function(err, args){
console.log(err.message); // missing required <file path>
}
});
The Special *
Wildcard Command Setting
Set the command_name
to '*'
to apply universal settings to all sub-commands on your program. You can use the includeRoot
option.
program.command('*', {
includeRoot: true // also apply all these settings to the root program
error: function(err, args){
console.log("A universal error message");
}
}).option('--version', {
action: function(value){
console.log("My Program v4.0.0")
}
});
program.command('run');
The run
command, as well as the main program
will inherit the settings from the *
command configuration, as well as the flag options specified (ie. version
).
Protogram.option(flag_name, options)
Add a Flag
as an option to your program.
flag_name
String: Name of the option of your program.options
Object:shortcut
String: Specify a shortcut letter for the flag. Defaults to the first available letter of theflag_name
.description
String: Specify a description for the flag.required
String: Describe a required value that must be be passed in when this flag is set.optional
String: Describe an optional value that can be passed in when this flag is set. Ifrequired
is set,optional
will be ignored.action
Function(value, program): A handler method called if the flag is set without any errors.error
Function(error, value, program): A handler method called if the flag is set but has an error (ie.required
was set and no value was passed in by the user).added
Function(program, flag): A method called when your option has been added to the program.
returns the parent Protogram
command object.
Minimal Example
Add an option (--name
) to your program. Protogram will automatically create a shortcut (-n
) to your program.
program.option('--name');
The Works
program.option('--name', {
shortcut: '-n',
description: 'Set the name of the user',
required: 'username',
action: function(err, value){
if(err) console.error('Required value needed when using the --name flag');
else console.log("Name set to:", value);
}
});
Protogram.parse(argv)
After your program is configured, pass in your full process.argv
array into the Protogram.parse() method to begin parsing the command-line arguments.
program.parse(process.argv);
Protogram.flagged & Protogram.flagged[flag_name]
An object you can use to check to see whether the user has used a flag, and retrieve the passed in value. This will only work after the arguments have been parsed by program.parse
.
if(program.flagged['name']){
console.log('the --name flag has been set to', program.flagged['name'])
}
License
The MIT License (MIT)
Copyright (c) 2014 Arjun Mehta