pkgjs / parseargs

Polyfill of `util.parseArgs()`
Apache License 2.0
121 stars 9 forks source link

stopping at first positional #125

Open bakkot opened 2 years ago

bakkot commented 2 years ago

Several parsers, including minimist (stopEarly), getOpts (stopEarly), command-line-args(stopAtFirstUnknown), and yargs (halt-at-non-option), have an option which says to treat everything after the first positional (including that argument) as being either positional or otherwise a not parsed as a normal option.

This is helpful for building git/npm style subcommands (read the first positional, treat it as naming the subcommand, then parse everything after using an options config specific to that subcommand), and also for things like node itself where e.g. node --inspect script.js --bar is treated as passing --inspect to node, but --bar is sliced out and passed to script.js.

This was mentioned by @julien-f on the PR, which is now merged (🎉 ), and I wanted to make sure it didn't get lost.

I note that it is possible to get this behavior just by reporting indices: parse once with strict: false, find the index of the first positional, split the original array at that point, then re-parse the stuff before that with strict: true. With this prototype, that would look something like

let options = {
  inspect: { type: 'boolean' },
};
let args = process.mainArgs;
let { elements } = util.parseArgs({ options, args, strict: false });
let firstPositionalIndex = elements.find(e => e.kind === 'positional')?.argIndex ?? args.length;
let { values } = util.parseArgs({ options, args: args.slice(0, firstPositionalIndex), strict: true });
let tail = args.slice(firstPositionalIndex);
// and then do whatever you want with `values` and `tail`

Maybe that's good enough? It feels somewhat awkward, but maybe this is a niche enough case that we should call that sufficient.

shadowspawn commented 2 years ago

(Thanks for great write-up!)

shadowspawn commented 2 years ago

Maybe that's good enough?

Whether or not the example is good enough, it shows the potential for returning deeper parse information, which I think should come first.