I have a CLI application that uses commander.js and defines two commands, foo and bar. Since I am using git-style commands, basically my main file looks like this:
.command('foo', 'does something')
.command('bar', 'does something else')
.parse(process.argv);
if (process.argv.length === 2) {
program.help();
}
This works if I call my app without any arguments (then the help is shown, as intended), and it works if I call it with foo or bar as commands.
What does not work is if I specify a non-existing command. In this case, simply nothing happens at all:
$ myapp baz
How can I catch this case? I read that you may use
program.on('*', function () {
// ...
});
and basically this works, but this executes not only for unknown commands, but for any command. In the same way, specifying a wildcard command does not work either: If I add
program.command('*').action(function () { ... });
this catches unknown commands (which is exactly what I want), but now if you run the app with --help it lists a * command (which is obviously not what I want).
So, to cut a long story short: How do I deal correctly with unknown commands?
My $0.02 - by default commander.js should sanitize commands and automatically show usage and exit if an unsupported command is used (it doesn't currently).
Basically I agree with you, but sometimes it could be useful to handle arbitrary input that is not a valid command.
@chrishiestand That's not too hard to implement yourself, and like @goloroden, people might want other options.
Unfortunately, at this time program.on('*' is your best bet. I don't think we'll be setting any defaults soon.
@SomeKittens: Why has this been closed? Just because what @chrishiestand is not too hard to implement, my original question has not yet been answered. Is
Unfortunately, at this time
program.on('*'is your best bet.
really the last word on this?
So, I finally ended up with this:
program
.version(...)
.command(...)
.on('*', function (command) {
this.commands.some(function (command) {
return command._name === argv[0];
}) || this.help();
})
parse(...);
This does the job perfectly for me :-)
For me:
program.version(pkg.version)
.command("clean", "...")
// ...
.parse(process.argv)
if (cli.args.length < 1) {
program.help()
} else {
if (!program._execs[program.args[0]]) {
// unknown option
}
}
@goloroden There's nothing wrong with your suggestion - on the contrary, this is something lots of folks hit. I don't think we'll be implementing a default at this time (but I want to revisit this when if/when the plugin system ever happens).
I hit this same problem but I couldn't use @goloroden suggestion because I wasn't using git like commands. Instead I created a executed variable that is false and I make it true if a command executes. Then I just check against it to print the help message:
var executed = false;
program
.command('foo')
.action(foo);
program.parse(process.argv);
if (!executed) {
program.help();
}
function foo() {
executed = true;
// ...
}
For those coming to this issue - the @goloroden solution does not work now. But there is official way mentioned in README:
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
In my use case, I wanted a single command that the cli program defaults to when executed.
So I added a the command to the arguments array like this
const foo = (options) => {
console.log(options.file)
}
program
.command('foo')
.option('-f, --file <filename>', 'The file you want node to read')
.usage('--file data.csv')
.action(foo)
process.argv.splice(2, 0, 'foo') # <------ this is the workaround
program.parse(process.argv)
For those coming to this issue - the @goloroden solution does not work now. But there is official way mentioned in README:
// error on unknown commands program.on('command:*', function () { console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' ')); process.exit(1); });
But this seems to work for the root tree:
cli.on('command:*', function (args) {
if( this._execs[args[0]] )
return;
console.error('Invalid command: %s\nSee --help for a list of available commands.', cli.args.join(' '));
process.exit(1);
});
@vitalets This method wouldn't work on git-style subcommands.
For example in main.js
.command('foo', 'this is foo')
.command('bar' 'this is bar')
.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
In this case, even if I do
$node main.js foo
It still gets intercepted by the 'on' method and deemed as invalid command. Any idea how to solve it?
I just ran into this as well, and this seems to work quite well, @frankcchen:
.command('postgres <command>', 'manage a local Postgres container')
.command('start [options]', 'start the service')
.command('stop [options]', 'stop the service')
.on('command:*', function (command) {
const firstCommand = command[0];
if (!this.commands.find(c => c._name == firstCommand)) {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
}
})
.parse(process.argv);
This is more or less a combination of the solution @goloroden offered at one point, and the adaption to a newer version of commander. This is tested with version 2.19.0.
Unsupported commands are detected by default from Commander v5, available now as a published pre-release (#1163)
@vitalets That solution does not work with default commands:
.command('install', { isDefault: true })
...
Most helpful comment
My $0.02 - by default commander.js should sanitize commands and automatically show usage and exit if an unsupported command is used (it doesn't currently).