Skip to content

Conversation

@miguelmarcondesf
Copy link
Contributor

@miguelmarcondesf miguelmarcondesf commented Jun 28, 2025

Issue: 56184

Add support to print help/usage of util.parseArgs

This PR adds help text functionality to util.parseArgs, allowing developers to easily generate and display help information for their CLI applications.

Checklist

  • Help Text for Individual Options
  • General Help Text
  • Help Text Generation with printUsage added to return object
  • Test coverage for all features
  • Documentation

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module. labels Jun 28, 2025
* // returns '--foo <arg> help text'
*/
function formatHelpTextForPrint(longOption, optionConfig) {
const layoutSpacing = 30;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found print has some logic related to layout spacing, maybe we can use something similar here.

@codecov
Copy link

codecov bot commented Jun 28, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.55%. Comparing base (fa33ba3) to head (f6b6199).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #58875      +/-   ##
==========================================
- Coverage   88.55%   88.55%   -0.01%     
==========================================
  Files         704      704              
  Lines      207824   207916      +92     
  Branches    40040    40058      +18     
==========================================
+ Hits       184046   184117      +71     
- Misses      15805    15847      +42     
+ Partials     7973     7952      -21     
Files with missing lines Coverage Δ
lib/internal/util/parse_args/parse_args.js 99.38% <100.00%> (+0.10%) ⬆️

... and 42 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ljharb
Copy link
Member

ljharb commented Jun 30, 2025

In general, what I'd expect is that -h and --help display the help text and exit zero; that it should probably be part of the default behavior of parseArgs if possible, but either way, it should be controllable via a boolean option; that on any argument validation error, the help text is also displayed, but it would exit nonzero; and that the developer has the ability to explicitly trigger the help text when doing their own validation.

@bakkot
Copy link
Contributor

bakkot commented Jun 30, 2025

@ljharb I'm not sure about printing the full help on validation failures. Once you have even three or four options that ends up being a lot of text, almost all of which is irrelevant to the actual error. Compare the output of node -C to node --help, for example.

I might be supportive of an option which makes validation failures just print the error and exit, instead of throwing a noisy error, but I don't think it makes sense to dump the full help text.

@ljharb
Copy link
Member

ljharb commented Jun 30, 2025

That's a solid argument for allowing, but not defaulting, that behavior :-)

@bakkot
Copy link
Contributor

bakkot commented Jun 30, 2025

I think that having commands print their full help text on argument validation failure is sufficiently unusual that it doesn't make sense to support it; parseArgs is supposed to only handle the really common cases.

I can't actually find any commands on my system that have that behavior, after trying a bunch at random.

@ljharb
Copy link
Member

ljharb commented Jun 30, 2025

Interesting, I've seen that a lot in CLI tools on npm, albeit not in shell/OS ones.

As long as the ability to trigger the help text exists, it can be worked around, so that's fine.

@miguelmarcondesf
Copy link
Contributor Author

Hey @bakkot @ljharb
I made some changes, and now we check for the presence of -h --help together with the enableHelpPrinting flag for the display of text + exit.
For now, I haven't added anything regarding the possibility of showing the help text also in scenarios with validation errors.

doc/api/util.md Outdated
* `positionals` {string\[]} Positional arguments.
* `tokens` {Object\[] | undefined} See [parseArgs tokens](#parseargs-tokens)
section. Only returned if `config` includes `tokens: true`.
* `printUsage` {string | undefined} Formatted help text for all options provided. Only included if general `help` text
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some of the original discussion, printUsage was a function and hence the name. It was suggested that simpler to just return a string, which is what you have done here. So I think the name could be changed.

Suggested change
* `printUsage` {string | undefined} Formatted help text for all options provided. Only included if general `help` text
* `usage` {string | undefined} Formatted help text for all options provided. Only included if general `help` text

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think a function is better, because then it allows the implementation to defer formatting of the text if it wishes to.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a function in the parse results? I find the idea of returning a function a bit surprising, I am expecting a plain old javascript object (POJO). And the function is presumably going to have to hold onto the passed arguments to process later.

Are there other APIs in node that behave like this and return mixed data and functions? (Not counting classes...)

Side note: if there is a function, it should return the string not output the string.

@bakkot had commented here:

Although I'd just always return a usage when there's any help options specified, instead of returning a
printUsage function (so that you can print it some other way, e.g. as part of a larger message about invalid
arguments, or with a footer or something. It's not like it's expensive to compute the string up front).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I wouldn't be surprised by a separate function to call to get the formatted help, but that isn't as integrated.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the function would return the string, yes. If it's actually not expensive to compute the string then it's fine to just return a string.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might worry more about deferring the cost of assembling the string in other contexts, but here it's really only going to happen once per script launch, so I wouldn't expect it to matter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I've updated values.help to return the string as it was.

To be honest, I think in general we would want to values return a value and not a behavior function 🤔 on the other hand, we will only have computation when being called, like @bakkot mentioned, but I think it is a cheap cost.
I would stick with the string value until we can find maybe future formatting parameters for that.

Let me know your thoughts @shadowspawn @ljharb @bakkot

@bakkot
Copy link
Contributor

bakkot commented Sep 12, 2025

Why wouldn't we give them only one place to configure the help option?

We are giving them one place to configure the help option. It's the same place as all the other options - there is nothing special about an option which happens to be spelled help. As such, just like every option, merely configuring the option does nothing except allow it on the CLI: the program must check for it and respond appropriately, e.g. by using the returned helpText.

@miguelmarcondesf
Copy link
Contributor Author

miguelmarcondesf commented Sep 28, 2025

Hey @bakkot @ljharb @shadowspawn
After reviewing the last feedback from you, I'd like to summarize where we are and point out what needs to reach a consensus:

  • Agreed on removing returnHelpText and addHelpOption, which also makes sense to me;
  • I think we can go with the approach we have before, with no general help text injected and only having that if provided, and also using the general help text as the guard to show the options help texts

Let me know what we think, and thanks in advance!

@miguelmarcondesf
Copy link
Contributor Author

Hey @bakkot @ljharb @shadowspawn After reviewing the last feedback from you, I'd like to summarize where we are and point out what needs to reach a consensus:

  • Agreed on removing returnHelpText and addHelpOption, which also makes sense to me;
  • I think we can go with the approach we have before, with no general help text injected and only having that if provided, and also using the general help text as the guard to show the options help texts

Let me know what we think, and thanks in advance!

Hey everyone @bakkot @ljharb @shadowspawn
A friendly reminder for when you have some time, thanks in advance!

@shadowspawn
Copy link
Member

shadowspawn commented Nov 1, 2025

@miguelmarcondesf

Agreed on removing returnHelpText and addHelpOption, which also makes sense to me;

Yes. I suggested those, and they didn't work out! I'm happy to do a PR to remove those on your PR it you like.

@miguelmarcondesf
Copy link
Contributor Author

@miguelmarcondesf

Agreed on removing returnHelpText and addHelpOption, which also makes sense to me;

Yes. I suggested those, and they didn't work out! I'm happy to do a PR to remove those on your PR it you like.

@shadowspawn No worries, just pushed that change!
Actually, when removing those flags, it occurred to me that keeping the -h, --help auto-inject enabled when a general help text is present makes sense.

Comment on lines +2164 to +2165
help: {
type: 'boolean',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the user wants their custom option to be called "ayuda", how would that disable the auto-added --help?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljharb Good point, but in that case, everything we're using in relation to the help general and each help option would be impacted, considering some kind of translation.

If it's only related to injecting --help when the general help option isn't available, we can simply remove that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove what? I'm confused.

Personally, I think the help option should only ever be named "--help", and be a boolean, but others argued upthread that it should be customizable. However, now we don't have any way to know if the user is passing a "help" option or not, because it could be named anything.

That's why I suggested type: "help", which can only be a boolean, because then we only inject our own help option when no type help options are provided by the user.

@kitaharata kitaharata mentioned this pull request Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants