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

[Suggestion] Add option property containing all args grouped by option #2067

Closed
BJaQuadient opened this issue Nov 7, 2023 · 5 comments
Closed

Comments

@BJaQuadient
Copy link

BJaQuadient commented Nov 7, 2023

Hello,
I recently had to use Option.argParser to change the default behaviour array of string by an array of object.


So first of all, thanks to allow user to play with this kind of function which allow to do everything they want.
Very pleasant to discover it.
Thanks four this beautifull tool.

Command :
command -p arg1 arg2 -f arg3 arg4 -j arg5 arg6 --f arg7 arg8 arg9

Default option parsing :
f content : ['arg3', 'arg4', 'arg7', 'arg8']

Custom option parsing wanted :
f content :

[ 
   {first: 'arg3', others: ['arg4'] }, 
   {first: 'arg7', others: ['arg8', 'arg9']}
]

To do that, at the first call of the Option.argParser , I generate the result and return it.
In the other call, I do nothing except returning previous.

The currentValue of the arg was not enough to accomplish this.
I used the command.parent.args to get the full args list.
As in this context only the options f was important to me, I had to filter them like this

            // In 
            let fArgs = []
            let currentFOption = false
            for (const arg of myCommand.parent.args.slice(1)) {
                if (arg.slice(0,1) === '-' ) 
                    currentFOption = ['-f', '--f'].includes(arg)
                if (currentFrOption)
                    filtersArgs.push(arg)
            }

In Option.argParser context, we do not have acces to an array of the option args.
We have to get them from myCommand.parent.args and have to parse it ourself.

I think it works for my simple case but in a more complex it become difficult to think about all the cases.
I think it is a little painfull to implement this when we work in commander which parse for us.
I understand than in Option.argParser we want to do it ourself, but I think than instead to restart for 0 a little help could be nice.

For this reason, I think than adding a kind of property, accessible from the Option.argParser context, containing for exemple all the args options grouped by option should be usefull :

[
            { '-p': [['arg1', 'arg2']] },
            { '-f': [['arg3', 'arg4']] },
            { '-j': [['arg5', 'arg6']] }
            { '--f': [['arg7', 'arg8', 'arg9']]
]

or

[
            [ '-p', 'arg1', 'arg2'],
            [ '-f', 'arg3', 'arg4'],
            [ '-j', 'arg5', 'arg6'],
            [ '--f', 'arg7', 'arg8', 'arg9']
]

It is just ideas, perhaps it exists others smarters implementations.

What do you think ?

@shadowspawn
Copy link
Collaborator

@shadowspawn
Copy link
Collaborator

Hmm... There isn't any state available from Commander, other than the already processed options. The specific case of detecting the first option-argument in a variadic group is awkward. I think the most pragmatic approach might be to use a custom syntax so the extra implied context is explicit. I'll have a think about that...

@shadowspawn
Copy link
Collaborator

For interest and similar to what you suggest, parseArgs in node can return a "tokens" array for further processing: https://nodejs.org/dist/latest-v20.x/docs/api/util.html#parseargs-tokens

@shadowspawn
Copy link
Collaborator

I suggest using a comma separated argument would make the grouping more explicit in the UX and easier to process in the code.

const { program  } = require('commander');

program.option('-f, --files <csv>', 'comma separated files to be processed, can be specified more than once', (csv, previous) => {
  previous = previous ?? [];
  const paths = csv.split(',');
  previous.push({first: paths[0], others: paths.slice(1)});
  return previous;
});

program.parse();
console.log(JSON.stringify(program.opts(), null, 2));
% node index.js -f 1,2,3 -f a,b,c         
{
  "files": [
    {
      "first": "1",
      "others": [
        "2",
        "3"
      ]
    },
    {
      "first": "a",
      "others": [
        "b",
        "c"
      ]
    }
  ]
}

@shadowspawn
Copy link
Collaborator

An answer was provided, and no further activity in a month. Closing this as resolved.

Feel free to open a new issue if it comes up again, with new information and renewed interest.

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