Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a description to a command makes it the default command #1644

Closed
SrBrahma opened this issue Nov 22, 2021 · 4 comments
Closed

Adding a description to a command makes it the default command #1644

SrBrahma opened this issue Nov 22, 2021 · 4 comments

Comments

@SrBrahma
Copy link

SrBrahma commented Nov 22, 2021

If I run this code below without any command, it will properly error the help:

export async function parseMsg(argv: string[], output: (msg: string) => void): Promise<void> {
  const program = new Command();

  program
    .configureOutput({
      writeOut: (msg) => { output(msg) },
      writeErr: (msg) => { output(msg) }
    })
    .exitOverride()

  program
    .command('woof')
    .action(() => output('Woof!'))

  try {
    await program.parseAsync(argv)
  } catch (err) {
    // ignore. There may be invalid commands etc
  }

But by adding a description to the command, it will then run the only command if I don't enter any command.

  .command('woof', 'Woof?')

It will also even run this command if I enter a wrong command, like "a a a a a".

@SrBrahma
Copy link
Author

I've managed to add the description with the .description() instead using the 2nd parameter.

However, this still seems to be a bug so I will leave this open.

@shadowspawn
Copy link
Collaborator

For historical reasons, there are two very different behaviours when calling .command(). The example in the README at the top of the Commands sections shows the two styles: https://github.com/tj/commander.js#commands

.command('woof') (without a description) creates a new subcommand and returns the new subcommand for chaining further configuration. This is what you were expecting.

.command('woof', 'description') creates a reference to an external stand-alone subcommand and returns the "program" for chaining adding further stand-alone commands or other configuration. See the README section https://github.com/tj/commander.js#stand-alone-executable-subcommands

So what happened is you accidentally added an external stand-alone command, and then added an action handler to the program. The action handler got called when you didn't specify an argument or specified an argument which was not "woof" like "a a a a a". (And you would have got an error if you tried calling my-tool woof because Commander would not have been able to find the external file implementing "woof". The error message tries to help explain this potential confusion.)

@SrBrahma
Copy link
Author

I see and appreciate the once again quick answer I had here :)

I am closing this as my issue has been solved.

But, a sincere, technical and somewhat philosophical question from a still small dev: Why this "historical reason" that is error/mistake prone hasn't been removed/fixed in a major version? My biggest lib has 2k downloads/week, not even near the 70mi/w of commander. When I had to make a breaking change, I just changed it and warned on Changelog about it. If an user upgrades a lib to a new major, he should look at the changelog and fix the breaking changes in his code, or don't upgrade at all.

Are legacy functionalities worth on the long run? Doesn't this make the lib more complicated that it should, sometimes makes new good changes unfeasible and encourages other more modern libraries that don't need to satisfy legacy users to take its place?

Thanks!

@shadowspawn
Copy link
Collaborator

shadowspawn commented Nov 22, 2021

But, a sincere, technical and somewhat philosophical question from a still small dev: Why this "historical reason" that is error/mistake prone hasn't been removed/fixed in a major version?

Interesting question.

Commander has had this behaviour for a long time. For a big breaking change like removing this behaviour we are balancing the ease of existing users upgrading to a new major version, against the benefits of improving the experience for new users and ongoing.

A couple of years ago this historical behaviour was a common cause of reported user issues, and I collected together issues to consider: #938 , and asked how many people were using action handlers vs external stand-alone commands: #966

We improved the README and other documentation. And waited to see if and how much the changes helped... This confusion has been reported much less often since (but can still trip people up!). So currently still just monitoring...


Are legacy functionalities worth on the long run?

Interesting question.

In some cases we can "hide" old behaviours and just quietly retain the legacy behaviour, but document it as deprecated and something we would like to remove in the future. The maintainers still pay the price until the code is deleted, but at least new users do it the new way. Existing users can change their code when they are ready (or when the legacy behaviours get deleted!).

https://github.com/tj/commander.js/blob/master/docs/deprecated.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants