minimistjs / minimist

parse argument options
MIT License
515 stars 30 forks source link

Add an opts.array #65

Open shadowspawn opened 2 months ago

shadowspawn commented 2 months ago

An issue from the original Minimist repo from @stevendesu with 11 upvotes

https://web.archive.org/web/20200904203616/https://github.com/substack/minimist/issues/136/


I have a command line argument that I wish to always be an array, but it may only contain one value:

Current Behavior

const argv = require("minimist")(process.argv.slice(2), {
    alias: {
        "distributions": ["d"]
    }
});

console.log(argv);
$> node ./index.js -d one -d two
{ _: [],
  distributions: ['one', 'two'],
  d: ['one', 'two']
}
$> node ./index.js -d one
{ _: [],
  distributions: 'one',
  d: 'one'
}

Desired New Option

const argv = require("minimist")(process.argv.slice(2), {
    array: ["distributions"], // <-----------------------------------
    alias: {
        "distributions": ["d"]
    }
});

console.log(argv);
$> node ./index.js -d one
{ _: [],
  distributions: ['one'],
  d: ['one']
}
shadowspawn commented 2 months ago

Related, Deno has made the array behaviour explicit with opts.collect : https://deno.com/blog/v1.23#collect-option

ghost commented 2 months ago

I would prefer arrays to be parsed without having to specify the arg name for each array value, e.g. node ./index.js -d one two three -> d: ["one", "two", "three"] similar to how Yargs parses arrays.

Perhaps there could be 2 new options: collect for the Deno style outlined in the original request and array for the Yargs style.

ljharb commented 2 months ago

That seems very strange, and not what I'm familiar with from yargs. Options - single or double dashed - are only ever followed by a single value, and it seems very surprising to allow an interface that deviates from that.

In yargs, I typically do -a 1 -a 2 -a 3.

shadowspawn commented 2 months ago

I would prefer arrays to be parsed without having to specify the arg name for each array value

yargs-parser defaults to greedy arrays for an explicit array, but that has caused enough parsing problems that might be changed to off by default in Yargs v18.

const yargsFactory = require('yargs/yargs')

const argv = yargsFactory(process.argv.slice(2))
   .array('arr')
   .parse();

console.log(argv);
% node arr.js --arr 1 2 3
{ _: [], arr: [ 1, 2, 3 ], '$0': 'arr.js' }

Greedy arrays work ok if there are not positional arguments. When there might be positional arguments it leads to ambiguous parsing. Withfoo -d one two is two the second option value in an array, or is it a positional?

ghost commented 2 months ago

Withfoo -d one two is two the second option value in an array, or is it a positional?

My assumption would be that it's decided by however the -d option is configured. Ideally, I would be able to specify that the -d option should take 2 and only 2 values. As I type this though, I realize that it doesn't really jive with the minimist way where options are not configured individually.

Since I'm out of my depth here as a non-CLI argument/option patterns and practices expert, I'll just leave you with a description of what I wanted to do yesterday and why:

TLDR; One of the options I was trying to add to my script was --static src-dir dest-dir but minimist made me do
--from src-dir --to dest-dir. The former looks simpler and makes more sense to me, the latter causes my eyes to do more work to match pairs, especially when more than one --static could be specified.

Backstory:

I wanted to add some nice CLI options to my reusable esbuild script and make it easy for the other devs to use. I started out with Yargs because I had used it in the past. As I re-familiarized myself with it's API, I started realizing it was way too complex to simply add some options to a script. I didn't need a whole command-group based parser with 7 dependencies, just a simple options parser. Unfortunately I didn't look more closely at those 7 dependencies because then I might have realized that I could have just used yargs-parser. Since npmtrends.com didn't help me find that, I settled on minimist which I remembered seeing lots of times in the past decade or so.

As I shifted over to using minimist I found out that my CLI options would have to change from how I planned them with Yargs. I had an option --static src-dir dest-dir and with minimist I had to switch it to --from src-dir --to dest-dir. I don't love this change, but it's done now and maybe next time I will consider using yargs-parser as that seems pretty popular on it's own with 20 million downloads a week more than the root yargs package.