cli-max v6.0.0
cli-max
An opinionated solution for building CLI applications using Node.js.
Contents
- Understanding CLI Application Categories
- Understanding CLI Command invocation
- Introduction to
cli-max - Getting Started
cli-maxin Action (example)- API in detail
Understanding CLI Application Categories
CLI Applications can be categorized into two types
- Single Command Apps
- Multi Command Apps
Single Command Apps
Single Command Apps usually have just one main action.
Examples: mkdir, touch, ls, etc.,
Multi Command Apps
Multi Command Apps are usually a collection of actions.
They have sub-commands that perform different operations.
Examples: git, npm, etc.,
Understanding CLI Command invocation
Structure
$ command sub-command <...[--options]> <...parameters>Examples
$ mkdir "New Folder"mkdiris the command- the value
New Folderis called a parameter or an argument.
$ git pull --quiet origin mastergitis the commandpullis the sub-command--quietis an optionoriginandmasterare the parameters
Introduction to cli-max
cli-max is a library that tries to make the experience of building a CLI app easy and pleasant.
The API of cli-max consciously tries to make your code more declarative and thus be easier to build, understand and maintain.
Features
- Single and Multi Command CLI Apps, both can be implemented using
cli-max - A Command can be configured as a default. and this will be executed when no valid command name is passed at runtime
- Sub-Commands can have aliases, making it easy for end-users to pass alternative command names
- Options can have aliases too (supports both short flags and long alternatives)
- Options can be configured with default values
- "help" details for every command is auto-generated using the details provided in the configuration
Getting Started
The approach to building CLI apps using cli-max, can broadly be described as a two-step process:
- Configure
- Execute
Step 1 - Configure
You can configure and implement the functionality of your CLI app using the API createCLI().
function createCLI(command: Command, config: CLIConfig): ExecuteFnThe createCLI() API takes two parameters of types Command and CLIConfig respectively.
You can build a Single Command CLI App by implementing all its functionality in the action property of the command argument passed to createCLI().
For building Multi Command CLI App, you can configure sub-commands and implement their functionality in corresponding action property of each sub-command.
If invoked with proper configuration as mentioned above createCLI() API returns a function.
This function is what is used in the next step.
Step 2 - Execute
The function returned by the createCLI() API is what invokes the actual functionality.
One can call the function returned by createCLI() as cli or execute or run or parse or compute or anything similar.
This function encapsulates the idea of processing and evaluating the actual arguments and flags passed at runtime and hence any of the above names.
The type for the function returned by createCLI() is ExecuteFn
Note: To explain easily, this document will from now on refer this function as
executeFn. But, remember it can be named anything per your convenience.
const executeFn = createCLI(someCommand, someConfig); // step-1
const result = executeFn(process.argv); // step-2The executeFn expects the arguments received by the Node.js process at runtime.
One can access these arguments passed to a Node.js process from the global property process.argv. (read more about process.argv)
Invoking executeFn with runtime arguments properly will parse the arguments and execute the corresponding command configured in the 1st step.
executeFn also returns the output value of the command executed from the configured commands.
Some insight on process.argv
process.argv is an array of the command line arguments received by the Node.js process
Launching a Node.js process as
$ node process-args.js one two=three fourwould generate the process.argv with the following values
[
"/path/to/the/node/executable",
"/path/to/the/file/process-args.js",
"one",
"two=three",
"four"
] cli-max in Action
const execute = createCLI({
name: 'give',
description: 'Greetings made easy!',
subCommands: [
{
name: 'greetings',
action: ({ flags: { to } }) => {
console.log(`Hello ${to}! How are you?`);
},
options:[
{
name: 'to',
aliases: ['t'],
description: 'this option specifies whom to greet',
required: false,
defaultValue: 'there',
},
],
isDefault: true,
},
{
name: 'compliment',
action: ({ flags: { to } }) => {
console.log(`Hey ${to}, You look good! :)`);
},
options:[
{
name: 'to',
aliases: ['t'],
description: 'this option specifies whom to complient',
required: false,
defaultValue: 'there',
},
],
}
],
});
execute(process.argv);
/*
Output:
$ give greetings
Hello there! How are you?
$ give greetings --to John
Hello John! How are you?
$ give compliment
Hey there, You look good! :)
$ give greetings --to John
Hey John, You look good! :)
*/API in detail
API:
Types:
Interfaces:
createCLI()
This API is used to configure the command, sub-commands, options and actions
function createCLI(command: Command, config: CLIConfig): ExecuteFnparams
Expects two arguments
return value:
returns a function of type ExecuteFn
ExecuteFn
This is the type for the function returned by createCLI() API
type ExecuteFn = function (processArgs: string[]): anyparams
Expects one argument
processArgs- an array of strings
processArgs is supposed to be process.argv i.e, the list of arguments received by the process
return value
returns the output of the command executed from the list of sub-commands configured
Action
This is the type for the callback function that is configured in a Command or a SubCommand to implement its functionality.
An action callback configured in a Command or a SubCommand gets invoked automatically when executeFn receives the command-name in the processArgs.
type Action = function (params: ActionParams): any;params
Receives one argument
params- an object of type ActionParams
GetHelpFn
This is the type for the function that generates "help" details for a command or a sub-command.
This function getHelp can be accessed as a property in the ActionParams received by the action.
If you want to display "help" for a command, you can just invoke this function (available as a property in the object received by the action configured for the command) and it would return the "help" details generated specifically for the command in context.
type GetHelpFn = function (): string;Command
This type encapsulates the details needed to configure a command
{
name: string;
description: string;
usage: string;
action?: Action;
options?: Option[];
subCommands?: SubCommand[];
}Note: To auto-generate proper "help" details for a
command, it is assumed that at the least thename,descriptionandusageproperties are assigned non-empty values.
To create a Single Command CLI App one can just implement the action property in the Command object being passed to createCLI() API.
To create a Multi Command CLI App one has to configure subCommands property in the command object that is passed to createCLI() API. For these Apps the main action property is optional but it can be used to handle cases where end-user invokes just the main command.
SubCommand
This type encapsulates the details needed to configure a sub-command
{
name: string;
description: string;
usage: string;
action: Action;
aliases?: string[];
options?: Option[];
isDefault?: boolean;
}Note: To auto-generate proper "help" details for a
sub-command, it is assumed that at the least thename,descriptionandusageproperties are assigned non-empty values.
Option
This type encapsulates the details needed to configure an option for either a command or a sub-command
{
name: string;
aliases: string[];
description: string;
defaultValue: any;
required: boolean;
}Note: To auto-generate proper "help" details for
optionsin acommandor asub-command, it is assumed that at the least thenameanddescriptionfor individual options are assigned non-empty values.
ActionParams
This type represents the object passed to an action of a command or a sub-command
{
parameters: string[];
flags: RuntimeFlags;
getHelp: GetHelpFn;
}RuntimeFlags
This type represents the collection of flags received at runtime.
each flag and its value received at runtime is assigned as a property and the corresponding value in this object
{
[key: string]: any;
}CLIConfig
This type encapsulates the customization options that can be passed to the createCLI() API
{
generateHelp?: boolean;
prettyHelp?: boolean;
paddingInDetails?: number;
}