diff --git a/CHANGELOG.md b/CHANGELOG.md index 51ae1db85..ab24e9607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added -- *Breaking:* error message if there are too many command-arguments on command line for the action handler ([#1409]) - - if should be allowed then declare extra arguments, or use `.allowExcessArguments()` +- `.allowExcessArguments(false)` to show an error message if there are too many command-arguments on command line for the action handler ([#1409]) - `.configureOutput()` to modify use of stdout and stderr or customise display of errors ([#1387]) - use `.addHelpText()` to add text before or after the built-in help, for just current command or also for all subcommands ([#1296]) - enhance Option class ([#1331]) @@ -120,32 +119,6 @@ program }); ``` -**excess command-arguments** - -There is now an error if there are too many command-arguments on the command line (only checked if there is an action handler). -If the extra arguments are supported by your command then you can either declare the expected arguments, or allow excess arguments. - -```js -// Old code before Commander 7 -program - .action(() => {}); -program.parse(['a', 'b', 'c'], { from: 'user' }); // now causes an error -``` - -```js -// New code, declare arguments -program - .arguments('[args...]') - .action(() => {}); -``` - -```js -// New code, allow excess arguments -program - .allowExcessArguments() - .action(() => {}); -``` - ## [7.0.0-2] (2020-12-14) (Released in 7.0.0) diff --git a/Readme.md b/Readme.md index 4d2d98177..94c3d8e47 100644 --- a/Readme.md +++ b/Readme.md @@ -483,7 +483,8 @@ async function main() { } ``` -A command's options and arguments on the command line are validated when the command is used. Any unknown options or unexpected command-arguments will be reported as an error, or you can suppress these checks with `.allowUnknownOption()` and `.allowExcessArguments()`. +A command's options and arguments on the command line are validated when the command is used. Any unknown options or missing arguments will be reported as an error. You can suppress the unknown option checks with `.allowUnknownOption()`. By default it is not an error to +pass more arguments than declared, but you can make this an error with `.allowExcessArguments(false)`. ### Stand-alone executable (sub)commands @@ -715,9 +716,11 @@ program --port=80 arg program arg --port=80 ``` - By default the option processing shows an error for an unknown option. To have an unknown option treated as an ordinary command-argument and continue looking for options, use `.allowUnknownOption()`. This lets you mix known and unknown options. +By default the argument processing does not display an error for more command-arguments than expected. +To display an error for excess arguments, use`.allowExcessArguments(false)`. + ### Legacy options as properties Before Commander 7, the option values were stored as properties on the command. diff --git a/examples/custom-command-class.js b/examples/custom-command-class.js index dc2cd6c3d..a5e40b00b 100755 --- a/examples/custom-command-class.js +++ b/examples/custom-command-class.js @@ -4,47 +4,47 @@ const commander = require('../'); // include commander in git clone of commander repo // Use a class override to customise the command and its subcommands. -// -// Configuring the command for compatibility with Commander v6 defaults behaviours. - -class Command6 extends commander.Command { - constructor(name) { - super(name); - - // Revert to Commander v6 behaviours. - this.storeOptionsAsProperties(); - this.allowExcessArguments(); - } +class CommandWithTrace extends commander.Command { createCommand(name) { - return new Command6(name); + const cmd = new CommandWithTrace(name); + // Add an option to subcommands created using `.command()` + cmd.option('-t, --trace', 'display extra information when run command'); + return cmd; } }; -function inspectCommand(command, optionName) { +function inpectCommand(command) { // The option value is stored as property on command because we called .storeOptionsAsProperties() - console.log(`Inspecting '${command.name()}'`); - console.log(`option '${optionName}': ${command[optionName]}`); + console.log(`Called '${command.name()}'`); console.log(`args: ${command.args}`); + console.log('opts: %o', command.opts()); }; -const program = new Command6('program') - .option('-p, --port ') - .action(() => { - inspectCommand(program, 'port'); +const program = new CommandWithTrace('program') + .option('-v, ---verbose') + .action((options, command) => { + inpectCommand(command); + }); + +program + .command('serve [params...]') + .option('-p, --port ', 'port number') + .action((params, options, command) => { + inpectCommand(command); }); program - .command('sub') - .option('-d, --debug') - .action((options, command) => { - inspectCommand(command, 'debug'); + .command('build ') + .action((buildTarget, options, command) => { + inpectCommand(command); }); program.parse(); -// We can pass excess arguments without an error as we called .allowExcessArguments() -// // Try the following: -// node custom-command-class.js --port 80 extra arguments -// node custom-command-class.js sub --debug extra arguments +// node custom-command-class.js --help +// node custom-command-class.js serve --help +// node custom-command-class.js serve -t -p 80 a b c +// node custom-command-class.js build --help +// node custom-command-class.js build --trace foo diff --git a/index.js b/index.js index 3b3fc664c..cc840cd81 100644 --- a/index.js +++ b/index.js @@ -535,7 +535,7 @@ class Command extends EventEmitter { this.options = []; this.parent = null; this._allowUnknownOption = false; - this._allowExcessArguments = false; + this._allowExcessArguments = true; this._args = []; this.rawArgs = null; this._scriptPath = null; @@ -635,6 +635,7 @@ class Command extends EventEmitter { cmd._exitCallback = this._exitCallback; cmd._storeOptionsAsProperties = this._storeOptionsAsProperties; cmd._combineFlagAndOptionalValue = this._combineFlagAndOptionalValue; + cmd._allowExcessArguments = this._allowExcessArguments; cmd._enablePositionalOptions = this._enablePositionalOptions; cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor @@ -1126,7 +1127,7 @@ class Command extends EventEmitter { }; /** - * Allow excess arguments on the command line. + * Allow excess command-arguments on the command line. Pass false to make excess arguments an error. * * @param {Boolean} [allowExcess=true] - if `true` or omitted, no error will be thrown * for excess arguments. @@ -1724,10 +1725,9 @@ class Command extends EventEmitter { }; /** - * `Option` is missing an argument, but received `flag` or nothing. + * `Option` is missing an argument. * * @param {Option} option - * @param {string} [flag] * @api private */ diff --git a/tests/command.allowExcessArguments.test.js b/tests/command.allowExcessArguments.test.js index fae40384a..9431a1888 100644 --- a/tests/command.allowExcessArguments.test.js +++ b/tests/command.allowExcessArguments.test.js @@ -18,7 +18,7 @@ describe('allowUnknownOption', () => { writeErrorSpy.mockRestore(); }); - test('when specify excess program argument then error by default', () => { + test('when specify excess program argument then no error by default', () => { const program = new commander.Command(); program .exitOverride() @@ -26,7 +26,7 @@ describe('allowUnknownOption', () => { expect(() => { program.parse(['excess'], { from: 'user' }); - }).toThrow(); + }).not.toThrow(); }); test('when specify excess program argument and allowExcessArguments(false) then error', () => { @@ -65,7 +65,7 @@ describe('allowUnknownOption', () => { }).not.toThrow(); }); - test('when specify excess command argument then error (by default)', () => { + test('when specify excess command argument then no error (by default)', () => { const program = new commander.Command(); program .exitOverride() @@ -74,7 +74,7 @@ describe('allowUnknownOption', () => { expect(() => { program.parse(['sub', 'excess'], { from: 'user' }); - }).toThrow(); + }).not.toThrow(); }); test('when specify excess command argument and allowExcessArguments(false) then error', () => { diff --git a/typings/index.d.ts b/typings/index.d.ts index 64f030b82..d2c383459 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -402,7 +402,7 @@ declare namespace commander { allowUnknownOption(allowUnknown?: boolean): this; /** - * Allow excess arguments on the command line. + * Allow excess command-arguments on the command line. Pass false to make excess arguments an error. * * @returns `this` command for chaining */