what's a good command-line option parser for node.js these days: I was using posix-argv-parser, which works, but is deprecated, I have ruled out nopt and util.parseArgs() as broken
strictly speaking parseArgs() is merely irritatingly under-powered, whereas nopt is unusably broken
also: curses to people who write testing tools/frameworks that adopt cutting edge syntax so cannot be used to test anything more than a couple years old

how has this been in production for over a decade

> require('nopt')({ foo: String, bar: String }, {}, ['--foo', '--bar'], 0)
{
foo: '',
bar: ''
}

in nopt it is not possible to create an argument whose value may resemble a switch. which means you can't use it for searching or completion
@oclif/core has the same problem. how are these projects building parsers that let the input tell them which flags exist instead making the defined flags dictate how the input is consumed. this is completely broken parser design
years of effort redesigning the storage backend, a few evenings of modernising the codebase and replacing the test framework, and now I'm hitting a wall that node.js has no acceptable command line parser
utils.parseArgs() has the same bug! who is teaching JS devs to write parsers
and yargs has the same bug, *and* it does obnoxious things like cause --help to _exit the process_?!
conclusion: there are no acceptable command line argument parsers for node.js and I have wasted much of my afternoon. week off's going great
yargs has also gone ESM-only, obviously
I also keep running into a bug in npm where whenever I install something, which I'm doing very frequently, it uninstalls something else listed in package.json
I'd forgotten how hostile yargs is to the basics of being able to write programs. it's full of cases where it will exit the process and/or write unbidden to stdout even if told not to
its output mixes data and metadata in a really unhelpful way that means you can't actually use its output as a combined object, and its whole philosophy of "don't tell us what your options are, we'll just guess" is actively dangerous
this is reminding me how much I enjoy programming until I have to take on a dependency at which point everything goes sideways
I think my best option is to use util.parseArgs(), and accept this forces me to drop some older node versions, which actively sucks considering I had put prior effort in elsewhere to keep them working? seems like a bad trade off
parseArgs() is the least actively broken one in that it can be made to understand when a value looks like a switch, except it forces the user to use '=' to express this, its output is the cleanest and it doesn't make any guesses
yargs is just incompatible with software engineering since it effectively makes it impossible to unit test your program
the security warning on minimist is like, yeah, that'll happen if you let the options be defined by user input instead of by the program, so why does every library do the former https://www.npmjs.com/package/minimist
minimist

parse argument options. Latest version: 1.2.8, last published: 2 years ago. Start using minimist in your project by running `npm i minimist`. There are 25119 other projects in the npm registry using minimist.

npm
I am absolutely baffled that every single option parsing library in node.js makes the same fundamental design mistake of guessing the options from user input
like this is fundamentally not how you approach parsing. I'd expect *some* libraries to make this design error, but all of them? literally every single popular one?

@jcoglan
Perhaps there's an "original sin", a blog post or conference talk that says "this is how NOT to do it", and everyone adopted it, similar to how "waterfall model" became a standard.

https://en.wikipedia.org/wiki/Waterfall_model#History

Waterfall model - Wikipedia

@jcoglan Have you tested commander.js? I believe it addresses one of your issues but I'm not certain about the other
@mcc this certainly looks more promising in terms of parsing switches with values correctly, but I can't figure out how to get positional args out of it. do you know how?
@mcc it also crashes your process on errors b/c it wants to be an "application framework" instead of a parsing library
@jcoglan Here is an example from a previous project where I do it with .arguments() and .args(). https://github.com/mcclure/twitter-archiver/blob/5f266f572ff5c7f5aaf4a58d730acbc29ddafae5/exec.ts#L21
twitter-archiver/exec.ts at 5f266f572ff5c7f5aaf4a58d730acbc29ddafae5 · mcclure/twitter-archiver

Make your own simple, public, searchable Twitter archive - mcclure/twitter-archiver

GitHub
@jcoglan As disclosure: There used to be a weird interaction between mixing positional and named args, but the dev claims it has been addressed. I haven't tested it. https://github.com/tj/commander.js/issues/561
When arguments() argument is provided, unrecognized flags are silently deleted (no error prints) · Issue #561 · tj/commander.js

I am using commander 2.9.0 (graceful-readlink 1.0.1) on node v4.4.7 (on Windows, running in MSYS2, if it matters). I run the following test program: var commander = require("commander") commander ....

GitHub
@jcoglan As for your other issue: "By default, Commander calls process.exit when it detects errors, or after displaying the help or version. You can override this behaviour and optionally supply a callback. The default override throws a CommanderError.". Does this not satisfy your use case?
@mcc the issue is that if you declare an argument, it seems to become required, which would mean I'd need to change my program's interface. might be possible, I'm not sure, but it's also a symptom of this library assuming you want to use it to define a bunch of subcommands
@mcc this is the most tempting thing for me to put effort into at least, just because its parsing approach doesn't seem fundamentally broken

@jcoglan Can you work around this by declaring a default value, for example, as in https://github.com/tj/commander.js?tab=readme-ov-file#default-option-value ? It appears .argument() also supports a default. Some defaults such as 0 or the empty string might "obviously" equate to "not specified", even if they are surfaced to other user.

I think there might also be a way to not declare an argument and just get a list of positional arguments, but I don't remember exactly and this might produce ugly --help.

GitHub - tj/commander.js: node.js command-line interfaces made easy

node.js command-line interfaces made easy. Contribute to tj/commander.js development by creating an account on GitHub.

GitHub