Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

commander

Package Overview
Dependencies
Maintainers
6
Versions
115
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

commander - npm Package Compare versions

Comparing version 8.1.0 to 8.2.0

lib/suggestSimilar.js

112

lib/command.js

@@ -10,2 +10,3 @@ const EventEmitter = require('events').EventEmitter;

const { Option, splitOptionFlags } = require('./option.js');
const { suggestSimilar } = require('./suggestSimilar');

@@ -39,2 +40,3 @@ // @ts-check

this._optionValues = {};
this._optionValueSources = {}; // default < env < cli
this._storeOptionsAsProperties = false;

@@ -55,2 +57,3 @@ this._actionHandler = null;

this._showHelpAfterError = false;
this._showSuggestionAfterError = false;

@@ -104,2 +107,3 @@ // see .configureOutput() for docs

this._showHelpAfterError = sourceCommand._showHelpAfterError;
this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;

@@ -240,2 +244,13 @@ return this;

/**
* Display suggestion of similar commands for unknown commands, or options for unknown options.
*
* @param {boolean} [displaySuggestion]
* @return {Command} `this` command for chaining
*/
showSuggestionAfterError(displaySuggestion = true) {
this._showSuggestionAfterError = !!displaySuggestion;
return this;
}
/**
* Add a prepared subcommand.

@@ -520,3 +535,3 @@ *

if (defaultValue !== undefined) {
this.setOptionValue(name, defaultValue);
this._setOptionValueWithSource(name, defaultValue, 'default');
}

@@ -528,5 +543,5 @@ }

// when it's passed assign the value
// and conditionally invoke the callback
this.on('option:' + oname, (val) => {
// handler for cli and env supplied values
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
// Note: using closure to access lots of lexical scoped variables.
const oldValue = this.getOptionValue(name);

@@ -540,3 +555,3 @@

if (err.code === 'commander.invalidArgument') {
const message = `error: option '${option.flags}' argument '${val}' is invalid. ${err.message}`;
const message = `${invalidValueMessage} ${err.message}`;
this._displayError(err.exitCode, err.code, message);

@@ -554,14 +569,24 @@ }

if (val == null) {
this.setOptionValue(name, option.negate
? false
: defaultValue || true);
this._setOptionValueWithSource(name, option.negate ? false : defaultValue || true, valueSource);
} else {
this.setOptionValue(name, val);
this._setOptionValueWithSource(name, val, valueSource);
}
} else if (val !== null) {
// reassign
this.setOptionValue(name, option.negate ? false : val);
this._setOptionValueWithSource(name, option.negate ? false : val, valueSource);
}
};
this.on('option:' + oname, (val) => {
const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
handleOptionValue(val, invalidValueMessage, 'cli');
});
if (option.envVar) {
this.on('optionEnv:' + oname, (val) => {
const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
handleOptionValue(val, invalidValueMessage, 'env');
});
}
return this;

@@ -780,2 +805,10 @@ }

/**
* @api private
*/
_setOptionValueWithSource(key, value, source) {
this.setOptionValue(key, value);
this._optionValueSources[key] = source;
}
/**
* Get user arguments implied or explicit arguments.

@@ -1144,2 +1177,3 @@ * Side-effects: set _scriptPath if args included application, and use that to set implicit command name.

const parsed = this.parseOptions(unknown);
this._parseOptionsEnv(); // after cli, so parseArg not called on both cli and env
operands = operands.concat(parsed.operands);

@@ -1207,2 +1241,3 @@ unknown = parsed.unknown;

} else if (this.commands.length) {
checkForUnknownOptions();
// This command has subcommands and nothing hooked up at this level, so display help (and exit).

@@ -1427,2 +1462,26 @@ this.help({ error: true });

/**
* Apply any option related environment variables, if option does
* not have a value from cli or client code.
*
* @api private
*/
_parseOptionsEnv() {
this.options.forEach((option) => {
if (option.envVar && option.envVar in process.env) {
const optionKey = option.attributeName();
// env is second lowest priority source, above default
if (this.getOptionValue(optionKey) === undefined || this._optionValueSources[optionKey] === 'default') {
if (option.required || option.optional) { // option can take a value
// keep very simple, optional always takes value
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
} else { // boolean
// keep very simple, only care that envVar defined and not the value
this.emit(`optionEnv:${option.name()}`);
}
}
}
});
}
/**
* Argument `name` is missing.

@@ -1472,3 +1531,19 @@ *

if (this._allowUnknownOption) return;
const message = `error: unknown option '${flag}'`;
let suggestion = '';
if (flag.startsWith('--') && this._showSuggestionAfterError) {
// Looping to pick up the global options too
let candidateFlags = [];
let command = this;
do {
const moreFlags = command.createHelp().visibleOptions(command)
.filter(option => option.long)
.map(option => option.long);
candidateFlags = candidateFlags.concat(moreFlags);
command = command.parent;
} while (command && !command._enablePositionalOptions);
suggestion = suggestSimilar(flag, candidateFlags);
}
const message = `error: unknown option '${flag}'${suggestion}`;
this._displayError(1, 'commander.unknownOption', message);

@@ -1501,3 +1576,16 @@ };

unknownCommand() {
const message = `error: unknown command '${this.args[0]}'`;
const unknownName = this.args[0];
let suggestion = '';
if (this._showSuggestionAfterError) {
const candidateNames = [];
this.createHelp().visibleCommands(this).forEach((command) => {
candidateNames.push(command.name());
// just visible alias
if (command.alias()) candidateNames.push(command.alias());
});
suggestion = suggestSimilar(unknownName, candidateNames);
}
const message = `error: unknown command '${unknownName}'${suggestion}`;
this._displayError(1, 'commander.unknownCommand', message);

@@ -1504,0 +1592,0 @@ };

13

lib/help.js

@@ -237,7 +237,6 @@ const { humanReadableArgName } = require('./argument.js');

optionDescription(option) {
if (option.negate) {
return option.description;
}
const extraInfo = [];
if (option.argChoices) {
// Some of these do not make sense for negated boolean and suppress for backwards compatibility.
if (option.argChoices && !option.negate) {
extraInfo.push(

@@ -247,8 +246,12 @@ // use stringify to match the display of the default value

}
if (option.defaultValue !== undefined) {
if (option.defaultValue !== undefined && !option.negate) {
extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
}
if (option.envVar !== undefined) {
extraInfo.push(`env: ${option.envVar}`);
}
if (extraInfo.length > 0) {
return `${option.description} (${extraInfo.join(', ')})`;
}
return option.description;

@@ -255,0 +258,0 @@ };

@@ -31,2 +31,3 @@ const { InvalidArgumentError } = require('./error.js');

this.defaultValueDescription = undefined;
this.envVar = undefined;
this.parseArg = undefined;

@@ -52,2 +53,15 @@ this.hidden = false;

/**
* Set environment variable to check for option value.
* Priority order of option values is default < env < cli
*
* @param {string} name
* @return {Option}
*/
env(name) {
this.envVar = name;
return this;
};
/**
* Set the custom handler for processing CLI option arguments into option values.

@@ -54,0 +68,0 @@ *

{
"name": "commander",
"version": "8.1.0",
"version": "8.2.0",
"description": "the complete solution for node.js command-line programs",

@@ -5,0 +5,0 @@ "keywords": [

@@ -96,3 +96,2 @@ # Commander.js

## Options

@@ -312,3 +311,3 @@

Example file: [options-extra.js](./examples/options-extra.js)
Example files: [options-extra.js](./examples/options-extra.js), [options-env.js](./examples/options-env.js)

@@ -319,3 +318,4 @@ ```js

.addOption(new Option('-t, --timeout <delay>', 'timeout in seconds').default(60, 'one minute'))
.addOption(new Option('-d, --drink <size>', 'drink size').choices(['small', 'medium', 'large']));
.addOption(new Option('-d, --drink <size>', 'drink size').choices(['small', 'medium', 'large']))
.addOption(new Option('-p, --port <number>', 'port number').env('PORT'));
```

@@ -330,2 +330,3 @@

-d, --drink <size> drink cup size (choices: "small", "medium", "large")
-p, --port <number> port number (env: PORT)
-h, --help display help for command

@@ -335,2 +336,5 @@

error: option '-d, --drink <size>' argument 'huge' is invalid. Allowed choices are small, medium, large.
$ PORT=80 extra
Options: { timeout: 60, port: '80' }
```

@@ -696,2 +700,14 @@

You can also show suggestions after an error for an unknown command or option.
```js
program.showSuggestionAfterError();
```
```sh
$ pizza --hepl
error: unknown option '--hepl'
(Did you mean --help?)
```
### Display help from code

@@ -912,3 +928,2 @@

```js

@@ -915,0 +930,0 @@ function errorColor(str) {

@@ -47,4 +47,4 @@ // Type definitions for commander

/**
* Return argument name.
*/
* Return argument name.
*/
name(): string;

@@ -55,3 +55,3 @@

*/
default(value: unknown, description?: string): this;
default(value: unknown, description?: string): this;

@@ -61,3 +61,3 @@ /**

*/
argParser<T>(fn: (value: string, previous: T) => T): this;
argParser<T>(fn: (value: string, previous: T) => T): this;

@@ -67,3 +67,3 @@ /**

*/
choices(values: string[]): this;
choices(values: string[]): this;

@@ -73,3 +73,3 @@ /**

*/
argRequired(): this;
argRequired(): this;

@@ -108,2 +108,8 @@ /**

/**
* Set environment variable to check for option value.
* Priority order of option values is default < env < cli
*/
env(name: string): this;
/**
* Calculate the full description, including defaultValue etc.

@@ -129,8 +135,2 @@ */

/**
* Validation of option argument failed.
* Intended for use from custom argument processing functions.
*/
argumentRejected(messsage: string): never;
/**
* Only allow option value to be one of choices.

@@ -416,3 +416,3 @@ */

*/
copyInheritedSettings(sourceCommand: Command): this;
copyInheritedSettings(sourceCommand: Command): this;

@@ -425,2 +425,7 @@ /**

/**
* Display suggestion of similar commands for unknown commands, or options for unknown options.
*/
showSuggestionAfterError(displaySuggestion?: boolean): this;
/**
* Register callback `fn` for the command.

@@ -427,0 +432,0 @@ *

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc