Security News
JSR Working Group Kicks Off with Ambitious Roadmap and Plans for Open Governance
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
command-line-interface
Advanced tools
command-line-interface is a foundation for CLI applications.
Category | Status |
---|---|
Version | |
Dependencies | |
Dev dependencies | |
Build | |
License |
$ npm install command-line-interface
First you need to add a reference to command-line-interface to your application:
const { runCli, Command } = require('command-line-interface');
If you use TypeScript, use the following code instead:
import { runCli, Command } from 'command-line-interface';
Before being able to run a CLI, you must create a command. A command represents a piece of logic callable from the command line. In that sense, a command has a name
, a description
, a list of optionDefinitions
, and a handle
function:
const hello = {
name: 'hello',
description: 'Say hello on the command line.',
optionDefinitions: [
{
name: 'name',
description: 'The name to use.',
type: 'string',
alias: 'n',
defaultValue: 'Jane'
}
],
handle ({ options }) {
console.log(`Hello ${options.name}!`);
}
};
Then you can use the runCli
function to run your CLI application. For that, hand over the command and provide the command line parameters, usually taken from process.argv
:
await runCli({ rootCommand: hello, argv: process.argv });
Now you can run your CLI application and use it to say hello:
$ node app.js
Hello Jane!
Since you configured a name
option, you may adjust the name by providing the --name
or -n
flag:
$ node app.js --name Jenny
Hello Jenny!
You may also ask for help by using the --help
flag, which is automatically available:
$ node.js app.js --help
The handle
function may be synchronous or asynchronous, so you may use async
depending on your needs. If you throw an error from within that function, the CLI application will end with exit code 1
, and print the exception's message as well as its stack trace to the terminal.
If you are using TypeScript, you may want to use types for the command and its options. First, define an interface for the command's options, such as:
export interface HelloOptions {
name: string;
}
Please note that it is highly recommended to put the interface for a command's options into a file of its own instead of putting it into the same file as the command it belongs to. This make it easier to extend and re-use interfaces when implementing sub-commands.
Additionally, provide the correct type for the variable that contains the command:
const hello: Command<HelloOptions> = {
// ...
};
Everything else stays the same, but now you will have type support.
As you have already seen, you can define options for commands. An option needs to have at least a name
and a type
, with the following types being supported and verified:
boolean
number
string
Additionally, you may provide a description
and an alias
. While the former is used when printing the usage, the latter is used to give a single-character alias for an otherwise lengthy option. You have seen this with the alias n
for the option name
in the examples above.
Sometimes it make sense to allow providing an option more than once. For that, add the multiple
option to the option definitions, and set it to on
. This lets you provide the appropriate option value multiple times on the command line:
$ node.js app.js --name Jane,Jenny
If instead you want to provide multiple values, but with an individual flag each, set it to lazy
:
$ node.js app.js --name Jane --name Jenny
If an option is mandatory, set the isRequired
property to true
. For optional options, it usually makes sense to specify a default value. For that, use the defaultValue
property and set it to the desired value. This can be seen in the example above as well.
If you want to give a dedicated name to the value, you can set it using the parameterName
property. This sometimes makes sense, to e.g. show off that a parameter is not just a string
, but a url
or another domain-specific concept.
Last but not least, you can define whether an option is the default option of a command by setting the defaultOption
property to true
. In this case you can skip the option's flag, and just provide its value.
For more complex applications, you might want to setup a variety of commands, and let the user decide which one to run. Typical CLI applications that make use of this concept are git
and docker
. The command that you hand over to runCli
is the so-called root command.
To define additional commands, you need to define them as sub-commands. Actually, you can also define sub-command on sub-commands, and nest them arbitrarily deep (although this doesn't make too much sense). To define a sub-command, first define a command as already known, and then add them using the subcommands
property of an already defined command:
const hello = {
name: 'hello',
description: 'Say hello on the command line.',
optionDefinitions: [
{
name: 'name',
description: 'The name to use.',
type: 'string',
alias: 'n',
defaultValue: 'Jane'
}
],
handle ({ options }) {
console.log(`Hello ${options.name}!`);
},
subcommands: {
anotherCommand,
anotherOtherCommand
}
};
All the flags that are given on the command line to the parent command are handed over to the handle
function of the sub-command.
Please note that if you are using TypeScript, make sure to derive the sub-commands options interface from the parent commands' one.
By default, all commands automatically come with a --help
flag. Additionally, every application automatically gets a dedicated help
command that you can use to show help for each command.
Sometimes you may want to show the usage manually from within a command. For that, add the parameters getUsage
and ancestors
to your handle
function, run the getUsage
function and hand over an array containing the path to the name of the current command. You may use the ancestors
array to get the list of names of the parent commands:
const hello = {
name: 'hello',
description: 'Say hello on the command line.',
optionDefinitions: [
// ...
],
handle ({ options, getUsage, ancestors }) {
console.log(getUsage([ ...ancestors, 'hello' ]));
}
};
To build this module use roboter.
$ npx roboter
FAQs
command-line-interface is a foundation for CLI applications.
We found that command-line-interface demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.
Security News
Research
An advanced npm supply chain attack is leveraging Ethereum smart contracts for decentralized, persistent malware control, evading traditional defenses.
Security News
Research
Attackers are impersonating Sindre Sorhus on npm with a fake 'chalk-node' package containing a malicious backdoor to compromise developers' projects.