tj / commander.js

node.js command-line interfaces made easy
MIT License
26.64k stars 1.69k forks source link

"error: unknown command" when using addCommand #2212

Open subeeshb opened 3 months ago

subeeshb commented 3 months ago

When using addCommand to add a preconfigured command, the command is listed when running with the --help flag, but fails with an "error: unknown command" message when trying to run the command. This happens with 12.1.0.

I've created a sample implementation here: https://codesandbox.io/p/devbox/upbeat-aj-cxxmw2?file=%2Findex.js

Sample code

const { Command } = require("commander");

const program = new Command();

program.name("CLI").description("A sample CLI.").version("1.0.0");

const subCommand = new Command("createfunction <name>")
  .description("Create a new function")
  .action((name) => {
    console.log("Executing createfunction command", name);
  });
program.addCommand(subCommand);

program.parse(process.argv);

Output

$ node index.js --help             
Usage: CLI [options] [command]

A sample CLI.

Options:
  -V, --version          output the version number
  -h, --help             display help for command

Commands:
  createfunction <name>  Create a new function
  help [command]         display help for command

$ node index.js createfunction test
error: unknown command 'createfunction'

If I configure the command inline, it works as expected:

program
  .command("createfunction <name>")
  .description("Create a new function")
  .action((name) => {
    console.log("Executing createfunction command", name);
  });
shadowspawn commented 3 months ago

The problem is .command('name <arg>') supports specifying the name and command-argument together, but new Command('name') only allows specifying the name.

Instead of

const subCommand = new Command("createfunction <name>")
  .description("Create a new function")
...

try

const subCommand = new Command("createfunction")
  .argument('<name>')
  .description("Create a new function")
...
subeeshb commented 3 months ago

Thanks, that worked! Is it expected then that specifying the name and argument together appears to work without any errors, and even lists the command in the --help output?

shadowspawn commented 3 months ago

Thanks, that worked! Is it expected then that specifying the name and argument together appears to work without any errors, and even lists the command in the --help output?

It isn't designed to work that way, it is is just how it works out. The command ends up with a very confusing name of createfunction <name>. You can see this with your original code:

 % node index.js 'createfunction <name>'
Executing createfunction command {}

If this trips up many people, we could have it throw an error when arguments are included inline for new Command(). In general Commander works hard to detect misuse by the end user of the CLI, but doesn't catch everything the author can get wrong.

shadowspawn commented 3 months ago

A PR was suggested to make this work in #1941 but at that time I didn't want to do that. Thinking about other behaviours, new Option('-e <value>)` does work, so we are not doing this consistently.

shadowspawn commented 3 months ago

(Thanks for the clear example code and description.)

subeeshb commented 3 months ago

The command ends up with a very confusing name of createfunction .

Ah, that makes sense. Hadn't realised that was what's happening since the way the command gets listed in the help output is the same.

If this trips up many people, we could have it throw an error when arguments are included inline for new Command().

Given that I didn't find any other mentions of people facing similar issues, I guess this isn't a common occurrence so I'm ok to close this issue - but I'll leave it to you or other maintainers to decide if it's worth updating it to make it consistent with how Commander handles other behaviours.