commander known bugs
npm29 known bugs in commander, with affected versions, fixes and workarounds. Sourced from upstream issue trackers.
29
bugs
Known bugs
| Severity | Affected | Fixed in | Title | Status | Source |
|---|---|---|---|---|---|
| medium | 2.9.0 | \u2014 | git-style subcommands mess up argument order when using boolean flags **index.js**
``` js
var command = require('commander')
var cmd = command
.command('hello', 'description')
.parse(process.argv)
```
**index-hello.js**
``` js
var command = require('commander')
var cmd = command
.option('--dry-run', 'prints actions, but takes none')
.parse(process.argv)
console.log('opts', cmd.opts())
console.log('args', cmd.args)
```
**output**
```
$ node index.js hello 1 2 --dry-run 3 4 5 6
opts { dryRun: true }
args [ '1', '2', '4', '5', '6', '3' ]
```
Note how `3` has been shifted to the end. This really messes with you when working with subcommands that expect a specific argument ordering.
_Found and tested against `[email protected]`_
| fixed | github:508 |
| medium | any | \u2014 | Cannot pass more than 4 arguments in literal mode Ref to https://github.com/Unitech/pm2/issues/2064
[This is the main pm2](https://github.com/Unitech/pm2/blob/development/bin/pm2) file on which we use commander.js, but we don't do anything fancy with commander.js
| fixed | github:552 |
| medium | 1.0.0 | \u2014 | Command log + option log When declaring a command with a defined name and declaring option with the same name, it does not works:
``` javascript
var program = require('commander');
program.version('1.0.0')
.option('--log [path]', 'log path')
program.command('logs')
.alias('log')
.action(function() {
console.log(program.log);
});
program.parse(process.argv);
```
``` bash
$ node test.js log --log 'test'
```
It throws:
```
/home/unitech/keymetrics/pm2/node_modules/commander/index.js:298
args.push(self);
^
TypeError: args.push is not a function
at Command.listener (/home/unitech/keymetrics/pm2/node_modules/commander/index.js:298:12)
at emitOne (events.js:82:20)
at Command.emit (events.js:169:7)
at Command.parseOptions (/home/unitech/keymetrics/pm2/node_modules/commander/index.js:699:14)
at Command.parse (/home/unitech/keymetrics/pm2/node_modules/commander/index.js:455:21)
at Object.<anonymous> (/home/unitech/keymetrics/pm2/test.js:13:9)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
```
| fixed | github:553 |
| medium | 0.0.1 | \u2014 | When arguments() argument is provided, unrecognized flags are silently deleted (no error prints) 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
.version("0.0.1")
.option('-x, --x-flag', 'A flag')
.arguments("<file>")
.parse(process.argv)
if (commander.xFlag)
console.log("Got -x")
console.log("Args:", commander.args)
```
I find that if I do not supply the `<file>` argument, if I pass a nonsense flag like --nonsense, I will get a nice error message. If I _do_ supply the `<file>` argument, then any nonsense flags included will be silently discarded. Moreover, commander appears to assume each nonsense flag takes one option-argument, and it silently discards that, too. These flags are not appended to commander.args or anything. They just disappear.
A demonstration:
```
$ node testcommander.js
Args: []
$ node testcommander.js -x
Got -x
Args: []
$ node testcommander.js --nonsense -x
error: unknown option `--nonsense'
$ node testcommander.js -x 1 2 3
Got -x
Args: [ '1', '2', '3' ]
$ node testcommander.js --NONSENSE 1 2 3
Args: [ '2', '3' ]
$ node testcommander.js 1 2 3 --NON-SENSE
Args: [ '1', '2', '3' ]
$ node testcommander.js 1 2 3 --NON-SENSE QQDFFR -x
Got -x
Args: [ '1', '2', '3' ]
```
**Expected behavior**: A --flag which is not recognized should result in commander printing an error.
This is a pretty bad bug. Not only does commander allow something which should be an error, and not only does it do it inconsistently for the same script depending on input, but since commander does this totally silently I cannot even write my own recovery code. If the lost arguments had been appended to `commander.args` at least I could detect it and raise my own error.
| fixed | github:561 |
| medium | any | \u2014 | Git-style subcommands not working if files are implicit '.js' but command is ran without '.js' If your command files use the `.js` extension, but you run the command via `node mycommand` instead of `node mycommand.js`, any git-style sub-commands will fail in `Command.prototype#executeSubCommand`
This failure is on line 531, column 15 of `index.js`:
```js
var f = argv[1];
// ...
link = fs.lstatSync(f).isSymbolicLink() ? fs.readlinkSync(f) : f;
```
Specifically this part is failing:
```js
fs.lstatSync(f)
```
This is causing an error because Commander is looking for the file that corresponds to argv[1], so in this specific case, argv[1] doesn't match the actual file name. | fixed | github:785 |
| medium | 0.1.0 | \u2014 | Option Coercion - parseInt when combined with a default value will result in NaN Adding a default value to an option with `parseInt` will result in `NaN` in many cases.
`parseInt` take two arguments -- `string` and `radix` -- and if you pass a default value to the option, the option will call `parseInt` with the default value as the `radix`. For example, an option with a default value of 90 and an actual value of 100 will invoke `parseInt(100, 90)`.
This is not a problem with `parseFloat` because it only takes one argument.
Source:
```javascript
#!/usr/bin/env node
'use strict';
const program = require('commander');
const version = require('./package.json').version;
process.title = 'my-app';
program
.name('my-app')
.version(version, '-v, --version');
program
.command('start')
.description('start the app')
.option('-d, --directory <directory>', 'directory for the thing', '/srv')
.option('-p, --port <port>', 'port number for the thing', parseInt, 8080)
.action(({ directory, port }) => console.log(directory, port));
program.parse(process.argv);
if (!program.args.length) program.help();
```
Expected:
```
$ ./cli.js start --port 80
/srv 80
```
Actual:
```
$ ./cli.js start --port 80
/srv NaN
```
I'm not sure what the fix should be in this case. Based on the Coercion section of the REAMDE, the way that commander deals with the default value argument is desirable. The `collect` function in particular shows that the default value of an empty array is being used as part of the coercion:
(reproduced from README)
```javascript
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
function collect(val, memo) {
memo.push(val);
return memo;
}
function increaseVerbosity(v, total) {
return total + 1;
}
program
.version('0.1.0')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.option('-c, --collect [value]', 'A repeatable value', collect, [])
.option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);
```
If this really is desirable, then I think a note about it in the Coercion section is appropriate. It's still possible to use parseInt, you just have to wrap it:
```javascript
#!/usr/bin/env node
'use strict';
const program = require('commander');
const version = require('./package.json').version;
process.title = 'my-app';
program
.name('my-app')
.version(version, '-v, --version');
const int = (value) => parseInt(value);
program
.command('start')
.description('start the app')
.option('-d, --directory <directory>', 'directory for the thing', '/srv')
.option('-p, --port <port>', 'port number for the thing', int, 8080)
.action(({ directory, port }) => console.log(directory, port));
program.parse(process.argv);
if (!program.args.length) program.help();
``` | fixed | github:834 |
| medium | 0.0.1 | \u2014 | Regression between v1.16 and v1.17 when no command are passed and '*' is registered There is a regression in the version v1.17
See this sample:
```js
var program = require("commander");
program
.version("0.0.1")
.command("*")
.description("test")
.action(function(cmd) {
cmdValue = cmd;
});
program.parse(process.argv);
if (typeof cmdValue === "undefined") {
console.error("no command given!");
} else {
console.log("command:", cmdValue);
}
```
## v1.16
```bash
$ node test.js
no command given!
```
## v1.17
```bash
$ node test.js
command: Command {
commands: [],
options: [],
_execs: {},
_allowUnknownOption: false,
_args: [],
_name: '*',
_noHelp: false,
parent:
Command {
commands: [ [Circular] ],
options: [ [Object] ],
_execs: {},
_allowUnknownOption: false,
_args: [],
_name: 'test',
Command: { [Function: Command] super_: [Object] },
Option: [Function: Option],
_version: '0.0.1',
_versionOptionName: 'version',
_events:
{ 'option:version': [Function],
'command:*': [Function: listener] },
_eventsCount: 2,
rawArgs:
[ 'C:\\Program Files\\nodejs\\node.exe',
'C:\\Users\\schroeterm\\Desktop\\test\\test.js' ],
args: [] },
_description: 'test',
_argsDescription: undefined }
```
| fixed | github:843 |
| medium | 0.0.1 | \u2014 | Built-in help subcommand does not work with aliased git-style commands # Example
```js
#!/usr/bin/env node
const program = require('commander');
program
.version('0.0.1')
.description('Fake package manager')
.command('install [name]', 'install one or more packages').alias('i');
program.parse(process.argv);
```
When running the built-in help command on the alias (`pm help i`), this happens:
## Expected Behavior
The alias gets resolved to `install`, and the information is read from `pm-install`
## Actual Behavior
The command attempts to read `pm-i` and fails, as it does not exist.
| fixed | github:948 |
| medium | 2.13.0 | \u2014 | Subcommand destroys ordering of options Commander.js version: 2.13.0
The feature "subcommand in dedicated binary" destroys option ordering for boolean longopts. The bug is that, for unknown options, commander always assumes they have an argument. Boolean longopts don't have an argument, so commander assumes the next option to be an argument to the boolean option. Unknown options get sorted to the end of the argument list, so option ordering is nonsensical after the aforementioned wrong assumption has taken place.
Example:
```
$ ls
somecommand somecommand-subcommand1
```
Contents of somecommand:
```
program.command('subcommand1', 'execute subcommand1').
```
Triggering the bug:
`$ ./somecommand subcommand1 --bool-option subcommand2 --subcommand2-option subcommand2-argument`
should result in
`./somecommand-subcommand1 --bool-option subcommand2 --subcommand2-option subcommand2-argument`
being called but commander executes
`./somecommand-subcommand1 subcommand2-argument --bool-option subcommand2`
This is a serious bug because the usage output cannot be made correct for the user, it is confusing the user and it results in the program not working without user feedback in combination with bug #961 .
It also could lead to random logic being executed if the options are implemented in a specific manner in the subcommand. | fixed | github:962 |
| medium | any | \u2014 | The Command.prototype.parse() method has issues. This method has the following issues:
* when registered `subcommand`, thier arguments and options isn't parsed to check valid.
* when registered `action`, `this.parseArgs()` called subcommand without parsing their arguments and options.
As a result, this method's arguments are not evaluted correctly in subcommand.
In the following code expect to occur `error: missing required argument "file"` but not now.
```
parse
.command('install <file>')
.parse('node', 'main.js', 'install') // Expect error but not.
```
Also now `the required argument` will not correctly work.
[Fix to fail if required arguments don't exist.](https://github.com/tj/commander.js/pull/941)
So it seems that this method should be reconsidered fundamentally.
Thank you for the wonderful library.
# Related
https://github.com/tj/commander.js/pull/941
| fixed | github:995 |
| medium | 0.0.1 | \u2014 | Passing command option leaves content in args As [discussed here](https://github.com/tj/commander.js/issues/978#issuecomment-525692913), opening as a new issue.
I'm trying to find out whether a command has been executed. The simple idea is that if a command is given, it should be executed (and nothing else). If no command is given, the default logic at the bottom should execute (but not otherwise). In all cases, the global option --load should be supported. Here's the test code:
```js
var program = require('commander');
program.version('0.0.1').option('-l, --load <name>', 'load something');
program
.command('doit [id]')
.description('do something')
.option('--better', 'do it better')
.action((id, cmd) => {
console.log('executing doit action');
console.log('id is', id);
console.log('global load option is ', cmd.parent.load);
console.log('cmd.better is', cmd.better);
});
program.parse(process.argv);
if (program.args.length === 0)
console.log('started without command, executing main logic');
```
This works correctly when I execute like this:
```shell
➜ node test.js -l loadname doit myid
executing doit action
id is myid
global load option is loadname
cmd.better is undefined
```
However, when I pass the --better option to the command, the whole thing breaks and the "main logic" is executed in addition to the command:
```shell
➜ node test.js -l loadname doit --better myid
executing doit action
id is myid
global load option is loadname
cmd.better is true
started without command, executing main logic
```
Unexpectedly, `args` contains information after the action has been executed, *if* the command option `--better` is passed. | fixed | github:1032 |
| medium | 0.0.1 | \u2014 | *Bug* When specify none-defined options followed by values don't exit program with error ```js
// File: index.js
const program = require('commander');
program
.version('0.0.1')
.parse(process.argv);
const args = program.args;
console.log(args);
```
```bash
$ node index.js --bug
error: unknown option '--bug'
$ node index.js --bug 0
error: unknown option '--bug'
$ node index.js --bug 0 1 2 3
[ '1', '2', '3' ]
```
dependency:
```json
$ cat package.json
{
"dependencies": {
"commander": "^3.0.1"
}
}
```
Expecting exit code with an error instead of continue of it.
| fixed | github:1039 |
| medium | any | \u2014 | Help option does not display help when using requiredOption Hi,
I wanted to have one option required. Once I added one, the help message will no longer show unless you include the required option. I would have expected it to show the help.
I created some sample code, from one of your samples.
Test Code:
```
const commander = require("commander");
const program = new commander.Command();
program
.option("-d, --debug", "output extra debugging")
.requiredOption("-s, --small", "small pizza size")
.option("-p, --pizza-type <type>", "flavour of pizza");
program.parse(process.argv);
if (program.debug) console.log(program.opts());
console.log("pizza details:");
if (program.small) console.log("- small pizza size");
if (program.pizzaType) console.log(`- ${program.pizzaType}`);
```
Output:
```
$ node test.js -h
error: required option '-s, --small' not specified
```
If I remove the requiredOption I get the expected output:
```
$ node test.js -h
Usage: test [options]
Options:
-d, --debug output extra debugging
-s, --small small pizza size
-p, --pizza-type <type> flavour of pizza
-h, --help output usage information
``` | fixed | github:1089 |
| medium | any | \u2014 | about commander -h and help command First, the cli code as:
```javascript
const cli = require('commander');
const plugin = require('./commandos/plugin');
cli.
command('plugin [command] [pluginName]').
description(DESCRIPTION.plugin).
action(plugin);
cli.
command('help').
description(DESCRIPTION.help).
action(()=>cli.help());
cli.parse(process.argv);
```
When I type the command as in terminal:
```shell
cli plugin help
```
it was not run the [plugin] function, I can not get [command] param, it just print help information in the terminal?
it is a bug, right? | fixed | github:1153 |
| medium | any | \u2014 | TypeError when running nested subcommand Repo with minimal example code to reproduce: https://github.com/maximilianschmitt/commander-debug
---
Hi!
I'm currently developing a CLI where I'm wanting to nest the subcommands.
I have the following files:
```
cli/
hello
hello-world # `hello world`
hello-world-germany # `hello world germany`
```
And I'm trying to run them like so:
```
$ node cli/hello
# Should run cli/hello
$ node cli/hello world
# Should run cli/hello-world
$ node cli/hello world germany
# Should run cli/hello-world-germany
```
I've read that when defining nested subcommands, you need to specify the `executableFile`, so I've done this in `cli/hello`:
```
#!/usr/bin/env node
const { program, Command } = require("commander");
const packageJSON = require("../package.json");
program.version(packageJSON.version);
const helloWorld = new Command("world");
helloWorld.command("germany", "Saying hello to Germany", {
executableFile: "hello-world-germany",
});
program.addCommand(helloWorld);
program.parse(process.argv);
```
However, when I run `node cli/hello world germany`, I get a TypeError:
```
~/Desktop/commander-debug $ node cli/hello world germany
internal/validators.js:120
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received null
at validateString (internal/validators.js:120:11)
at Object.extname (path.js:1229:5)
at Command._executeSubCommand (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:774:46)
at Command._dispatchSubcommand (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:863:12)
at Command._parseCommand (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:882:12)
at Command._dispatchSubcommand (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:865:18)
at Command._parseCommand (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:882:12)
at Command.parse (/Users/max/Desktop/commander-debug/node_modules/commander/index.js:717:10)
at Object.<anonymous> (/Users/max/Desktop/commander-debug/cli/hello:14:9)
at Module._compile (internal/modules/cjs/loader.js:1138:30) {
code: 'ERR_INVALID_ARG_TYPE'
}
```
Is this a bug or am I doing something wrong?
Thanks for your help! | fixed | github:1274 |
| medium | any | \u2014 | BUG: defining an option which includes `no-` makes the option true by default **Current Behavior -**
If we define an option whose name contains `no-` for e.g. `module-no-parse`, it makes the option `true` by default.
**Expected Behavior -**
It is supposed to do this only for flags with leading `no-` as mentioned in docs. https://github.com/tj/commander.js/#other-option-types-negatable-boolean-and-flagvalue
> You can specify a boolean option long name with a leading no- to set the option value to false when used. Defined alone this also makes the option true by default.
**Steps to reproduce -**
Define an option whose name includes `no-` e.g. `module-no-parse`.
Check its default value in the parser.

**Addition Info**
Bug found via https://github.com/webpack/webpack-cli/issues/1679 | fixed | github:1301 |
| medium | any | \u2014 | addHelpCommand missing from TypeScript definitions Hello,
It looks the addHelpCommand method definition is missing in the TypeScript definitions file here:
https://github.com/tj/commander.js/blob/master/typings/index.d.ts
Is this a bug? | fixed | github:1374 |
| medium | any | \u2014 | `command:<name>` event doesn't bubble to the parent Hey,
Not sure if I am using this correctly, but it does seem to be a good use case and not far away from working.
My program is as follows:
```
const config = program.commad('config');
const start = program.command('start');
program.on('command:*', () => /* handle unexpected command */);
program.on('command:config', () => /* never gets called */);
```
In the above example, when `config` command is executed, the `command:config` listener never gets executed.
After console logging around the Commander source code, I have found out that the reason this doesn't work is that listener is registered on `parent` (in this context, main program) whereas the `emit` function is called on a subcommand (`config`).
Changing `this.emit` to `this.parent.emit` fixes it https://github.com/tj/commander.js/blob/master/index.js#L1003
Is there any way to bubble events up? It seems to be quite natural to listen to `command:<name>` on the main object, otherwise, there's no difference from attaching a listener to `config` vs tweaking action handler. | fixed | github:1402 |
| medium | 4.0.1 | \u2014 | Options parsed before validating argument Hi there,
This is a great project, thank you for maintaining this.
We're in the process of upgrading from v4.0.1 to v7.0.0 with the new features. We have a small problem whereby options are being parsed before the arguments themselves are validated.
We were hoping to be able to continue to listen to `command:*` to detect bad arguments, as we've currently hooked it up to our own suggestion engine to provide "did you mean" suggestions for the bad argument. Upgrading to v7.0.0 has broken this functionality for us.
E.g.
```
$ program bad_argument --help
# Outputs the help menu instead of complaining that bad_argument is a bad argument
```
Another example:
```
$ program lintt --fix
# Complains that --fix is not a valid option. Instead, we expected `lintt` to be
# detected as a bad argument so we can suggest `lint` to the user.
```
Minimal reproduction:
```
import commander from 'commander';
const program = new commander.Command();
program.on('command:*', (arg: string) => {
console.log(`Detected bad arg: ${arg}`);
});
program.command('lint').action(() => {
console.log('lint');
});
program.parse();
```
I dug into the source code a bit and think I found it. It appears to be parsing the options and throwing the error first, before reaching the "command:*" section.
https://github.com/tj/commander.js/blob/034ad9f326ee2b26001b864adda5fea465ee148b/index.js#L1472
Is there a solution or workaround to this that I haven't found? Thanks :). | fixed | github:1460 |
| medium | any | \u2014 | Command' is not assignable to type CommanderStatic.Command I try to create an init command using TypeScript, as follows:
```ts
import { Command } from "commander";
export const init = ():Command => {
const init = new Command("init");
init
.arguments("[name]")
.option("--disable-lint", "disable lint", false)
.action(async (name = "", options) => {
// my action
});
return init;
};
```
But at last return init, typescript report error:
TS2322: Type 'import("/Users/qishaoxuan/work/leo/node_modules/commander/typings/index").Command' is not assignable to type 'import("/Users/qishaoxuan/work/leo/node_modules/commander/typings/index").CommanderStatic.Command'. The types returned by 'version(...)' are incompatible between these types. Type 'Command' is not assignable to type 'this'. 'Command' is assignable to the constraint of type 'this', but 'this' could be instantiated with a different subtype of constraint 'Command'.
| fixed | github:1465 |
| medium | any | \u2014 | [Question] How to get option name? From docs:
```
program
.option('-d, --debug', 'output extra debugging')
.option('-s, --small', 'small pizza size')
.option('-p, --pizza-type <type>', 'flavour of pizza');
program.parse(process.argv);
const options = program.opts();
if (options.debug) console.log(options);
console.log('pizza details:');
if (options.small) console.log('- small pizza size');
if (options.pizzaType) console.log(`- ${options.pizzaType}`);
```
so, the question is how do know option `pizza-type` after parse will get from field `pizzaType`? Do commanderjs provide any function to get value `pizzaType` after bind option `.option('-d, --debug', 'output extra debugging')`?
Thanks! | fixed | github:1480 |
| medium | any | \u2014 | Option.argumentRejected declared but not implemented. Hi in your typing file your write:
````typescript
/**
* Validation of option argument failed.
* Intended for use from custom argument processing functions.
*/
argumentRejected(messsage: string): never;
````
but `argumentRejected` do not exist anywhere.
| fixed | github:1598 |
| medium | 2.20.0 | \u2014 | Refactor option value processing to improve maintainability and fix bugs There is some subtle code in `addOption` which is hard to make sense of, and has some bugs. If is solid on options used once on command line, but from code inspection I was able to reproduce some logic errors affecting repeated options for boolean with a non-boolean default value (bit obscure!) and optional options.
The problems have been present for a long time. I was able to reproduce with v2.20.0 and traced code back to at least v1.1.0. The issues have not been generating reports, and the motivation for changing the code is as much to make the code easier to work on as to improve the behaviour.
https://github.com/tj/commander.js/blob/43f4743864e2f670db5eebcf88c92aa4612c54f1/lib/command.js#L515
| fixed | github:1648 |
| medium | 9.1.0 | \u2014 | 9.1.0 - option.conflicts not working I'm trying to use the option conflicts configuration, but it doesn't appear to catch the conflicts.
```
const { program, Option } = require("commander");
const handleAction = (command) => {
const options = program.opts();
//options.exact && (options.wild || options.all) && console.log("conflict");
console.log(
`${command.name()} with options ${JSON.stringify(program.opts())}`
);
};
//Global options
program
.addOption(
new Option("-a, --all", "all wallets").conflicts(["exact", "wild"])
)
.addOption(
new Option("-x, --exact <name>", "exact wallet name").conflicts([
"all",
"wild",
])
)
.addOption(
new Option("-w, --wild <partial>", "wild card").conflicts(["all", "exact"])
)
.option("-p, --password <password>");
//Sub commands
program.command("claim").action((options, command) => {
handleAction(command);
});
program.parse();
```
When I run with:
node commands.js claim -a -x OG
The result is:
claim with options {"all":true,"exact":"OG"}
Have I configured it incorrectly? Also tried specifying just the short names. Same result.
Thanks. | fixed | github:1710 |
| medium | any | \u2014 | .helpOption(false) also disables subcommand help command In this example, I'd like to disable impilcit help **option** and only leave impicit help **command**.
`test.mjs`:
```
#!/usr/bin/env node
import { Command } from 'commander';
const cmd = new Command ();
cmd
.helpOption (false)
.command ('meow')
.option ('-l, [--loud]')
cmd.parse ();
```
If I run `test.mjs`, I get
```
Usage: test [command]
Commands:
meow [options]
help [command] display help for command
```
as expected, but if I run `test.mjs help meow`, I get an error:
`error: unknown option '--help' // what option, I thought I was calling help command?`,
while expected outcome would be
```
Usage: test meow [options]
Options:
-l, [--loud]
``` | fixed | github:1863 |
| medium | any | \u2014 | Exit Code is Zero if Subcommand Killed by Signal If a subcommand child process is killed by a signal (e.g. `SIGKILL`), then commander will exit with exit code zero. I'm seeing this where OOM was killing the subcommand but commander was exiting with zero.
Relevant code looks to be here. The arguments to the `close` event are `(code, signal)` and in the case of killed by signal, `code` will be `null`, so `process.exit` gets called with `null` which leads to exiting with zero. Additionally, should the `exitCallback` case (on line 1036) be using `proc.exitCode` instead of `process.exitCode`? The latter doesn't seem correct.
https://github.com/tj/commander.js/blob/4ef19faac1564743d8c7e3ce89ef8d190e1551b4/lib/command.js#L1032-L1038
Possible fix for the issue could be to bubble up signals, although I'm not sure how to handle the `exitCallback` case then, since AFAIK there's no way to get an exit code for a signal from Node.js (other than mapping it yourself).
```js
proc.on('close', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit.bind(process)(code);
}
});
```
Alternatively a fixed exit code of 1 could be used in the case of a signal, which would work for the `exitCallback` case. However, that's not desirable since it will hide the underlying exit code from the subcommand.
Manually mapping signals to exit codes might be the simplest way to handle this for both cases. | fixed | github:2021 |
| medium | any | \u2014 | Option.fullDescription() does not exist `Option.fullDescription()` is defined in the TypeScript definition file `index.d.ts`, but it does not exist in the implementation (`Option.js`).
Either fix type definition or add implementation. | fixed | github:2190 |
| medium | any | \u2014 | Strange API behaviour for command description When adding description to command declaration, command does not work.
Working code:
```
program.command('analyze')
.description('Do analyze.')
.action(() => console.info("Hello explain!");
```
Execute:
```
> node index.js analyze
> Hello explain!
```
Not working code:
```
program.command('analyze', 'Do analyze.')
.action(() => console.info("Hello explain!");
```
Execute:
```
> node index.js analyze
internal/modules/cjs/loader.js:892
throw err;
^
Error: Cannot find module 'C:\Dev\stuff\npm-dependency-inspector\index-analyze'
?[90m at Function.Module._resolveFilename (internal/modules/cjs/loader.js:889:15)?[39m
?[90m at Function.Module._load (internal/modules/cjs/loader.js:745:27)?[39m
?[90m at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)?[39m
?[90m at internal/main/run_main_module.js:17:47?[39m {
code: ?[32m'MODULE_NOT_FOUND'?[39m,
requireStack: []
}
```
I spent HOURS to find a way to make commander work for simpliest command. Read all docummentation, tried several versions, and only happy accident helped me - I added description for one command, and do not added to another. So I found, that another command working and this give me a tip.
I think, when description specified, or command options specified, commander begin interpretate it as executable command. If it is true, then action() should throw error - it is usless for executable command. WTF? Why simple adding description change behaviour totally? And where in documentation this behaviour is specified? | fixed | github:2290 |
| medium | any | \u2014 | copyInheritedSettings and configureOutput have side-effects Hi - noticed something that maybe isn't desired behaviour with the above two methods. Since `copyInheritedSettings` sets `this._outputConfiguration = sourceCommand._outputConfiguration` and `configureOutput` does `Object.assign(...)` - this means that one command can change another command's settings unexpectedly:
```ts
import {program, Command} from 'commander'
const one = new Command('one')
.description('A very very very very very very very very very very very very very very very very very very very very very very very very long description')
.action(() => console.log('hi i am one'))
.configureOutput({
writeOut: str => console.log(str + '🚀🚀🚀🚀'),
getOutHelpWidth: () => 70,
})
const two = new Command('two')
.copyInheritedSettings(one)
.description('Another very very very very very very very very very very very very very very very very very very very very very very very very long description')
.action(() => console.log('hi i am two'))
.configureOutput({
getOutHelpWidth: () => 200,
})
program
.addCommand(one)
.addCommand(two)
program.parse()
```
When you do `mycommand one --help` it uses 200 for the help width, not 70 as I'd expect. (Note: `mycommand two --help` prints the `🚀🚀🚀🚀` at the bottom, which _is_ correct/expected, IMO).
Suggested solution: use a spread operator in either/both of the methods. | fixed | github:2342 |
API access
Get this data programmatically \u2014 free, no authentication.
curl https://depscope.dev/api/bugs/npm/commander