tj / commander.js

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

List all command's arguments using Helper #1823

Closed grallm closed 1 year ago

grallm commented 2 years ago

I want to list all the arguments (or sub-commands, not sure of the difference) of my command.

If I look the property _args, I can confirm my command has an argument:

[
  {
    "description": "",
    "variadic": false,
    "required": false,
    "_name": "commands"
  }
]
Screenshot of the Argument object image

To not use a private property, I try to access this argument with the Help class and the visibleArguments method (see the code)

The problem, I do not have any description for my argument and the implementation of visibleArguments requires one.

Is this a problem? If not, can someone explain it to me? Is there any other clean way?

Thank you! 😁

shadowspawn commented 2 years ago

I want to list all the arguments (or sub-commands, not sure of the difference) of my command.

When you type something on the command line like

git clone my-repo

clone is a subcommand, and my-repo is a command-argument.

To not use a private property, I try to access this argument with the Help class and the visibleArguments method [...] The problem, I do not have any description for my argument and the implementation of visibleArguments requires one.

Using visibleArguments to get the argument objects is an intended as a way to access the arguments, but as you discovered the "visible" part is that they are only returned if at least one of them has a description so that they appear in the help.

There are not any other methods to return the arguments from the private property _args.

As a work-around, could you add a description to your arguments so visibleArguments returns them? (What are you listing them for?)

grallm commented 2 years ago

Thank you for your answer @shadowspawn 😄

clone is a subcommand, and my-repo is a command-argument.

The example is clear, but in the documentation of Commander I am just lost when speaking of sub-commands in the part of arguments while you can declare them with .command 😅

Is there an explanation of why a Visible Argument is one only with a description? I may have missed something in your explanation, but still, the argument is displayed in the usage part of the help 🤔

To describe my situation, I am using NestJS Console, based on top of Commander, and it seems I can't add argument description (it uses .arguments to define the arguments) 😊 For the listing part, I am trying to generate dynamic configuration files.

Thanks again for the answer !

shadowspawn commented 2 years ago

Is there an explanation of why a Visible Argument is one only with a description? I may have missed something in your explanation, but still, the argument is displayed in the usage part of the help 🤔

It comes from an existing behaviour that the arguments are only described in detail if there are some descriptions. I like the symmetry with visibleOptions and visibleCommands, but have to admit it does not make as much sense for arguments!

const { Command } = require('commander');
const program = new Command();
program.name('git');
program.command('clone')
  .argument('repo')
  .action((repo) => console.log(`Target repo is ${repo}`));
program.parse();
% node index.js clone --help
Usage: git clone [options] <repo>

Options:
  -h, --help  display help for command

But with .argument('repo', 'target repository') get

% node index.js clone --help
Usage: git clone [options] <repo>

Arguments:
  repo        target repository

Options:
  -h, --help  display help for command
shadowspawn commented 2 years ago

For the listing part, I am trying to generate dynamic configuration files.

With the current code, I think you may need to iterate through cmd._args to access the configured arguments.

If the _args property was renamed to be public, what should it be called? The other similar properties are options and commands, but arguments is already a method name. Maybe commandArguments?

grallm commented 2 years ago

Thanks again for your answers!

I see there is a method opts() to get the list of options as a Map, maybe a method args() ?

shadowspawn commented 2 years ago

There are already properties and methods on Command for:

We can't use the same pattern as option()/options and command()/commands since arguments is not available.

shadowspawn commented 1 year ago

There is a shortcoming that there is not a public way to get the full array of Argument objects. I'll leave this issue open to see if this gets upvotes, and/or a nice suggestion for a property name.

cenfun commented 1 year ago

Although it is a private property, but believe it is pretty stable. just write a small tool to show all commands and options:

const { program } = require('commander');
const commanderHelp = require('commander-help');

program
    .name('cli-name')
    .description('CLI to some JavaScript string utilities')
    .argument('<username>', 'user to login')
    .argument('[password...]', 'password for user, if required', 'empty')
    .option('-t, --title <honorific>', 'title to use before name')
    .option('-d, --debug', 'display some debugging')
    .version('0.8.0', '-v, --version');

program.command('split')
    .description('Split a string into substrings')
    .argument('<string>', 'string to split')
    .alias('s')
    .option('--first', 'display just the first substring', '#')
    .option('-s, --separator <char>', 'separator character', ',')
    .action(() => {});

program
    .command('clone <source> [dest]')
    .description('clone a repository into a newly created directory')
    .alias('c')
    .action((source, destination) => {
        console.log('clone command called');
    });

program
    .command('start <service>', 'start named service')
    .command('stop [service...]', 'stop named service, or all if no name supplied');

// hide default help
program.helpInformation = function() {
    return '';
};
// custom help
program.on('--help', function() {
    console.log('Usage and help');
    commanderHelp(program);
});

program.parse();

Usage and help
┌──────────────────────────────────┬───────────────────────────────────────────────────┬───────┐
│ Commands/Options                 │ Description                                       │ Alias │
├──────────────────────────────────┼───────────────────────────────────────────────────┼───────┤
│ ├ cli-name                       │ CLI to some JavaScript string utilities           │       │
│ │ ├  -t, --title <honorific>     │ title to use before name                          │       │
│ │ ├  -d, --debug                 │ display some debugging                            │       │
│ │ ├  -v, --version               │ output the version number                         │       │
│ │ └  -h, --help                  │ display help for command                          │       │
│ ├ cli-name <username>            │ user to login                                     │       │
│ ├ cli-name [password...]         │ password for user, if required (default: empty)   │       │
├──────────────────────────────────┼───────────────────────────────────────────────────┼───────┤
│ ├ cli-name split <string>        │ Split a string into substrings                    │ s     │
│ │ ├  --first                     │ display just the first substring (default: #)     │       │
│ │ └  -s, --separator <char>      │ separator character (default: ,)                  │       │
├──────────────────────────────────┼───────────────────────────────────────────────────┼───────┤
│ ├ cli-name clone <source> [dest] │ clone a repository into a newly created directory │ c     │
├──────────────────────────────────┼───────────────────────────────────────────────────┼───────┤
│ ├ cli-name start <service>       │ start named service                               │       │
├──────────────────────────────────┼───────────────────────────────────────────────────┼───────┤
│ └ cli-name stop [service...]     │ stop named service, or all if no name supplied    │       │
└──────────────────────────────────┴───────────────────────────────────────────────────┴───────┘

https://github.com/cenfun/commander-help

shadowspawn commented 1 year ago

I had another think about a public accessor, and came up with .declaredArguments or .getArguments().

shadowspawn commented 1 year ago

Adding .registeredArguments in #2010 (as suggested in #1970)

shadowspawn commented 1 year ago

Shipped in Commander v11.1.0