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

Refactor help internals into separate interface/class #1365

Merged
merged 66 commits into from Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
dde2535
Start filling out HelpUtils to try pattern
shadowspawn Sep 28, 2020
70038b5
Shift the largestFoo routines into helper
shadowspawn Sep 28, 2020
9c08b35
Update generation of Commands section of help
shadowspawn Sep 28, 2020
59d988e
Rework helpInformation in consistent new style
shadowspawn Sep 28, 2020
fe26f38
Remove unused routines
shadowspawn Sep 28, 2020
f8c5cb2
Make columns part of HelpUtils
shadowspawn Sep 28, 2020
720b382
Offer a light weight override to HelpUtils
shadowspawn Sep 28, 2020
65edc7a
Tweak comment
shadowspawn Sep 28, 2020
08cc506
Add chain test for helpUtilOverrides
shadowspawn Sep 28, 2020
c81b322
Add itemIndent as another proof of concept of allowing overrides
shadowspawn Sep 28, 2020
3b8fa89
Avoid Utils contraction
shadowspawn Sep 28, 2020
fc5e4da
Update comments
shadowspawn Sep 28, 2020
9d1cc4d
Switch columns from function to data property
shadowspawn Sep 29, 2020
965b7f9
Remove itemIndent(), not useful enough alone or as a pattern for now
shadowspawn Sep 29, 2020
8a2bbfa
Make _helpToolsOverrides inherited
shadowspawn Sep 29, 2020
fa73c6c
Improve naming for termWidth
shadowspawn Sep 29, 2020
c91c515
Move usage into HelpTools
shadowspawn Sep 29, 2020
f4de668
Add term and description routines to HelpTools so symmetrical pattern
shadowspawn Sep 29, 2020
478e86c
Name the magic numbers
shadowspawn Sep 29, 2020
11be18a
More consistent naming
shadowspawn Sep 29, 2020
78017aa
Remove reference to removed routine
shadowspawn Sep 29, 2020
162dca6
Move help formatting into HelpTools
shadowspawn Sep 29, 2020
a0d1862
Fix typescript-checkJS errors
shadowspawn Sep 29, 2020
f17be74
Simpler naming
shadowspawn Sep 30, 2020
943d01a
Slightly simplify code
shadowspawn Sep 30, 2020
79deb3a
Add getter/setter to assist overrides
shadowspawn Oct 2, 2020
9425003
Add sort overrides
shadowspawn Oct 2, 2020
8fc29df
First cut at TypeScript definitions for Help, no TSDoc yet
shadowspawn Oct 3, 2020
63f58d9
Replace pad and low level indents with modern calls
shadowspawn Oct 3, 2020
25f240f
Rename and rework type for HelpConfiguration
shadowspawn Oct 3, 2020
d8ba2c0
Combine optionalWrap and wrap
shadowspawn Oct 3, 2020
d1da3f7
Add createHelp to TypeScript definition
shadowspawn Oct 3, 2020
ee0a71b
Add test-all script
shadowspawn Oct 3, 2020
2ea7619
More carefully make concrete help option for displaying
shadowspawn Oct 3, 2020
36b3be7
Fix test with valid parameters for custom help
shadowspawn Oct 3, 2020
8ec5342
Start adding Help tests
shadowspawn Oct 3, 2020
5e895fc
Add largestCommandTermLength tests
shadowspawn Oct 3, 2020
71acb69
Add more Help tests
shadowspawn Oct 3, 2020
a946cda
Add commandUsage tests
shadowspawn Oct 3, 2020
8230fe5
Add test for commandDescription
shadowspawn Oct 3, 2020
09c460e
Add missing Command properties, and default description to empty string
shadowspawn Oct 3, 2020
1e60ab1
Add tests for optionDescription
shadowspawn Oct 3, 2020
7e75235
Add padWidth tests
shadowspawn Oct 3, 2020
b96c528
Add sort tests
shadowspawn Oct 3, 2020
e195b78
Add columns and wrap tests
shadowspawn Oct 3, 2020
74c2adf
Add test for legacy commandTerm behaviour
shadowspawn Oct 3, 2020
f654c9a
Add TypeScript usage tests for Help
shadowspawn Oct 3, 2020
ed68199
Refactor Help tests into separate files
shadowspawn Oct 3, 2020
c26f943
Add tests for createHelp and configureHelp
shadowspawn Oct 3, 2020
3707814
Add JSDoc for Help.
shadowspawn Oct 4, 2020
d99ec22
Add TSDoc for Help
shadowspawn Oct 4, 2020
9133df3
Test special caes of implicit help flags
shadowspawn Oct 4, 2020
82d43f5
Clarify method naming
shadowspawn Oct 7, 2020
8c0ae2e
Shift the Usage prefix into formatHelp
shadowspawn Oct 9, 2020
c6e7f58
Add Help class mention and reorder help
shadowspawn Oct 11, 2020
cc3a322
Add simple configure-help example
shadowspawn Oct 14, 2020
142bcaa
Add example file to README
shadowspawn Oct 16, 2020
ec77a66
Rename to sortSubcommands to match other naming
shadowspawn Oct 16, 2020
5fd56e0
Do not weaken configuration type, user can extend as required
shadowspawn Oct 18, 2020
b0850b0
Do not cache implicit help command calculation so safer (no need, not…
shadowspawn Oct 18, 2020
b6503f6
Add JSDoc for configureHelp
shadowspawn Oct 18, 2020
ea676a8
Add TSDoc
shadowspawn Oct 18, 2020
634828b
Add missing TSDoc
shadowspawn Oct 18, 2020
ee48a67
Switch option sort to use attributeName, with negative after positive
shadowspawn Oct 21, 2020
67ea43c
No need for string template literal
shadowspawn Oct 21, 2020
7266d89
No need for string template literal
shadowspawn Oct 22, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
201 changes: 109 additions & 92 deletions Readme.md
Expand Up @@ -16,23 +16,22 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
- [Common option types, boolean and value](#common-option-types-boolean-and-value)
- [Default option value](#default-option-value)
- [Other option types, negatable boolean and boolean|value](#other-option-types-negatable-boolean-and-booleanvalue)
- [Extra option features](#extra-option-features)
- [Custom option processing](#custom-option-processing)
- [Required option](#required-option)
- [Variadic option](#variadic-option)
- [Version option](#version-option)
- [More configuration](#more-configuration)
- [Custom option processing](#custom-option-processing)
- [Commands](#commands)
- [Specify the argument syntax](#specify-the-argument-syntax)
- [Action handler (sub)commands](#action-handler-subcommands)
- [Stand-alone executable (sub)commands](#stand-alone-executable-subcommands)
- [Automated help](#automated-help)
- [Custom help](#custom-help)
- [Display help from code](#display-help-from-code)
- [.usage and .name](#usage-and-name)
- [.help()](#help)
- [.outputHelp()](#outputhelp)
- [.helpInformation()](#helpinformation)
- [.helpOption(flags, description)](#helpoptionflags-description)
- [.addHelpCommand()](#addhelpcommand)
- [More configuration](#more-configuration-1)
- [Custom event listeners](#custom-event-listeners)
- [Bits and pieces](#bits-and-pieces)
- [.parse() and .parseAsync()](#parse-and-parseasync)
Expand Down Expand Up @@ -208,7 +207,79 @@ add cheese type mozzarella

For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).

### Extra option features
### Required option

You may specify a required (mandatory) option using `.requiredOption`. The option must have a value after parsing, usually specified on the command line, or perhaps from a default value (say from environment). The method is otherwise the same as `.option` in format, taking flags and description, and optional default value or custom processing.

Example file: [options-required.js](./examples/options-required.js)

```js
program
.requiredOption('-c, --cheese <type>', 'pizza must have cheese');

program.parse(process.argv);
```

```bash
$ pizza
error: required option '-c, --cheese <type>' not specified
```

### Variadic option

You may make an option variadic by appending `...` to the value placeholder when declaring the option. On the command line you
can then specify multiple option-arguments, and the parsed option value will be an array. The extra arguments
are read until the first argument starting with a dash. The special argument `--` stops option processing entirely. If a value
is specified in the same argument as the option then no further values are read.

Example file: [options-variadic.js](./examples/options-variadic.js)

```js
program
.option('-n, --number <numbers...>', 'specify numbers')
.option('-l, --letter [letters...]', 'specify letters');

program.parse();

console.log('Options: ', program.opts());
console.log('Remaining arguments: ', program.args);
```

```bash
$ collect -n 1 2 3 --letter a b c
Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
Remaining arguments: []
$ collect --letter=A -n80 operand
Options: { number: [ '80' ], letter: [ 'A' ] }
Remaining arguments: [ 'operand' ]
$ collect --letter -n 1 -n 2 3 -- operand
Options: { number: [ '1', '2', '3' ], letter: true }
Remaining arguments: [ 'operand' ]
```

For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).

### Version option

The optional `version` method adds handling for displaying the command version. The default option flags are `-V` and `--version`, and when present the command prints the version number and exits.

```js
program.version('0.0.1');
```

```bash
$ ./examples/pizza -V
0.0.1
```

You may change the flags and description by passing additional parameters to the `version` method, using
the same syntax for flags as the `option` method.

```js
program.version('0.0.1', '-v, --vers', 'output the current version');
```

### More configuration

You can add most options using the `.option()` method, but there are some additional features available
by constructing an `Option` explicitly for less common cases.
Expand Down Expand Up @@ -294,78 +365,6 @@ $ custom --list x,y,z
[ 'x', 'y', 'z' ]
```

### Required option

You may specify a required (mandatory) option using `.requiredOption`. The option must have a value after parsing, usually specified on the command line, or perhaps from a default value (say from environment). The method is otherwise the same as `.option` in format, taking flags and description, and optional default value or custom processing.

Example file: [options-required.js](./examples/options-required.js)

```js
program
.requiredOption('-c, --cheese <type>', 'pizza must have cheese');

program.parse(process.argv);
```

```bash
$ pizza
error: required option '-c, --cheese <type>' not specified
```

### Variadic option

You may make an option variadic by appending `...` to the value placeholder when declaring the option. On the command line you
can then specify multiple option-arguments, and the parsed option value will be an array. The extra arguments
are read until the first argument starting with a dash. The special argument `--` stops option processing entirely. If a value
is specified in the same argument as the option then no further values are read.

Example file: [options-variadic.js](./examples/options-variadic.js)

```js
program
.option('-n, --number <numbers...>', 'specify numbers')
.option('-l, --letter [letters...]', 'specify letters');

program.parse();

console.log('Options: ', program.opts());
console.log('Remaining arguments: ', program.args);
```

```bash
$ collect -n 1 2 3 --letter a b c
Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
Remaining arguments: []
$ collect --letter=A -n80 operand
Options: { number: [ '80' ], letter: [ 'A' ] }
Remaining arguments: [ 'operand' ]
$ collect --letter -n 1 -n 2 3 -- operand
Options: { number: [ '1', '2', '3' ], letter: true }
Remaining arguments: [ 'operand' ]
```

For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).

### Version option

The optional `version` method adds handling for displaying the command version. The default option flags are `-V` and `--version`, and when present the command prints the version number and exits.

```js
program.version('0.0.1');
```

```bash
$ ./examples/pizza -V
0.0.1
```

You may change the flags and description by passing additional parameters to the `version` method, using
the same syntax for flags as the `option` method.

```js
program.version('0.0.1', '-v, --vers', 'output the current version');
```

## Commands

You can specify (sub)commands using `.command()` or `.addCommand()`. There are two ways these can be implemented: using an action handler attached to the command, or as a stand-alone executable file (described in more detail later). The subcommands may be nested ([example](./examples/nestedCommands.js)).
Expand Down Expand Up @@ -582,6 +581,14 @@ The second parameter can be a string, or a function returning a string. The func
- error: a boolean for whether the help is being displayed due to a usage error
- command: the Command which is displaying the help

### Display help from code

`.help()`: display help information and exit immediately. You can optionally pass `{ error: true }` to display on stderr and exit with an error status.

`.outputHelp()`: output help information without exiting. You can optionally pass `{ error: true }` to display on stderr.

`.helpInformation()`: get the built-in command help information as a string for processing or displaying yourself.

### .usage and .name

These allow you to customise the usage description in the first line of the help. The name is otherwise
Expand All @@ -599,21 +606,9 @@ The help will start with:
Usage: my-command [global options] command
```

### .help()

Output help information and exit immediately. You can optionally pass `{ error: true }` to display on stderr and exit with an error status.

### .outputHelp()

Output help information without exiting. You can optionally pass `{ error: true }` to display on stderr.

### .helpInformation()

Get the built-in command help information as a string for processing or displaying yourself.

### .helpOption(flags, description)

Override the default help flags and description. Pass false to disable the built-in help option.
By default every command has a help option. Override the default help flags and description. Pass false to disable the built-in help option.

```js
program
Expand All @@ -622,14 +617,36 @@ program

### .addHelpCommand()

You can explicitly turn on or off the implicit help command with `.addHelpCommand()` and `.addHelpCommand(false)`.
A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.addHelpCommand()` and `.addHelpCommand(false)`.

You can both turn on and customise the help command by supplying the name and description:

```js
program.addHelpCommand('assist [command]', 'show assistance');
```

### More configuration

The built-in help is formatted using the Help class.
You can configure the Help behaviour by modifying data properties and methods using `.configureHelp()`, or by subclassing using `.createHelp()` if you prefer.

The data properties are:

- `columns`: specify the wrap width, useful for unit tests
- `sortSubcommands`: sort the subcommands alphabetically
- `sortOptions`: sort the options alphabetically

There are methods getting the visible lists of arguments, options, and subcommands. There are methods for formatting the items in the lists, with each item having a _term_ and _description_. Take a look at `.formatHelp()` to see how they are used.

Example file: [configure-help.js](./examples/configure-help.js)

```
program.configureHelp({
sortSubcommands: true,
subcommandTerm: (cmd) => cmd.name() // Just show the name, instead of short usage.
});
```

## Custom event listeners

You can execute custom actions by listening to command and option events.
Expand Down
24 changes: 24 additions & 0 deletions examples/configure-help.js
@@ -0,0 +1,24 @@
// const commander = require('commander'); // (normal include)
const commander = require('../'); // include commander in git clone of commander repo

const program = new commander.Command();

// This example shows a simple use of configureHelp.
// This is used as an example in the README.

program.configureHelp({
sortSubcommands: true,
subcommandTerm: (cmd) => cmd.name() // Just show the name, instead of short usage.
});

program.command('zebra <herd-size>', 'African equines with distinctive black-and-white striped coats');
program.command('aardvark [colour]', 'medium-sized, burrowing, nocturnal mammal');
program
.command('beaver', 'large, semiaquatic rodent')
.option('--pond')
.option('--river');

program.parse();

// Try the following:
// node configure-help.js --help