From 681a7e417a4cd29062ab01d350163ecfef95767b Mon Sep 17 00:00:00 2001 From: Wee Bit Date: Sat, 5 Aug 2023 02:20:56 +0300 Subject: [PATCH 01/28] Add missing checks for passThroughOptions --- lib/command.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/command.js b/lib/command.js index 590a271dd..ac8189866 100644 --- a/lib/command.js +++ b/lib/command.js @@ -272,6 +272,8 @@ class Command extends EventEmitter { this.commands.push(cmd); cmd.parent = this; + this._checkForIllegalPassThroughOptions(cmd, this); + return this; } @@ -721,6 +723,9 @@ Expecting one of '${allowedValues.join("', '")}'`); */ enablePositionalOptions(positional = true) { this._enablePositionalOptions = !!positional; + this.commands.forEach((command) => { + this._checkForIllegalPassThroughOptions(command, this); + }); return this; } @@ -735,12 +740,22 @@ Expecting one of '${allowedValues.join("', '")}'`); */ passThroughOptions(passThrough = true) { this._passThroughOptions = !!passThrough; - if (!!this.parent && passThrough && !this.parent._enablePositionalOptions) { - throw new Error('passThroughOptions can not be used without turning on enablePositionalOptions for parent command(s)'); - } + this._checkForIllegalPassThroughOptions(this, this.parent); return this; } + /** + * @param {Command} command + * @param {Command | null} parent + * @api private + */ + + _checkForIllegalPassThroughOptions(command, parent) { + if (parent && command._passThroughOptions && !parent._enablePositionalOptions) { + throw new Error(`passThroughOptions cannot be used for '${command._name}' without turning on enablePositionalOptions for parent command${parent._name ? ` '${parent._name}'` : ''}`); + } + } + /** * Whether to store option values as properties on command object, * or store separately (specify false). In both cases the option values can be accessed using .opts(). From af67d1113aae66af1bbbe2d10b2667aa670a8e02 Mon Sep 17 00:00:00 2001 From: Wee Bit Date: Sat, 5 Aug 2023 02:35:29 +0300 Subject: [PATCH 02/28] Add tests for illegal passThroughOptions --- tests/command.positionalOptions.test.js | 35 ++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/tests/command.positionalOptions.test.js b/tests/command.positionalOptions.test.js index d130b7835..169866d20 100644 --- a/tests/command.positionalOptions.test.js +++ b/tests/command.positionalOptions.test.js @@ -362,13 +362,36 @@ describe('program with action handler and positionalOptions and subcommand', () // ------------------------------------------------------------------------------ -test('when program not positional and turn on passthrough in subcommand then error', () => { - const program = new commander.Command(); - const sub = program.command('sub'); +describe('illegal passThroughOptions', () => { + test('when program not positional and turn on passThroughOptions in subcommand then error', () => { + const program = new commander.Command(); + const sub = program.command('sub'); + + expect(() => { + sub.passThroughOptions(); + }).toThrow(); + }); + + test('when program not positional and add subcommand with passThroughOptions then error', () => { + const program = new commander.Command(); + const sub = new commander.Command('sub') + .passThroughOptions(); - expect(() => { - sub.passThroughOptions(); - }).toThrow(); + expect(() => { + program.addCommand(sub); + }).toThrow(); + }); + + test('when program has subcommand with passThroughOptions and reset to non-positional then error', () => { + const program = new commander.Command() + .enablePositionalOptions(); + program.command('sub') + .passThroughOptions(); + + expect(() => { + program.enablePositionalOptions(false); + }).toThrow(); + }); }); // ------------------------------------------------------------------------------ From 1453bdf53a930b04875c0c44a7e53397b934b8ae Mon Sep 17 00:00:00 2001 From: Wee Bit Date: Sat, 5 Aug 2023 03:14:33 +0300 Subject: [PATCH 03/28] Remove illegal passThroughOptions check deemed unnecessary --- lib/command.js | 3 --- tests/command.positionalOptions.test.js | 11 ----------- 2 files changed, 14 deletions(-) diff --git a/lib/command.js b/lib/command.js index ac8189866..e01586a1d 100644 --- a/lib/command.js +++ b/lib/command.js @@ -723,9 +723,6 @@ Expecting one of '${allowedValues.join("', '")}'`); */ enablePositionalOptions(positional = true) { this._enablePositionalOptions = !!positional; - this.commands.forEach((command) => { - this._checkForIllegalPassThroughOptions(command, this); - }); return this; } diff --git a/tests/command.positionalOptions.test.js b/tests/command.positionalOptions.test.js index 169866d20..73dd7a877 100644 --- a/tests/command.positionalOptions.test.js +++ b/tests/command.positionalOptions.test.js @@ -381,17 +381,6 @@ describe('illegal passThroughOptions', () => { program.addCommand(sub); }).toThrow(); }); - - test('when program has subcommand with passThroughOptions and reset to non-positional then error', () => { - const program = new commander.Command() - .enablePositionalOptions(); - program.command('sub') - .passThroughOptions(); - - expect(() => { - program.enablePositionalOptions(false); - }).toThrow(); - }); }); // ------------------------------------------------------------------------------ From c60ce9daa308fc19ddfb7126565ae6e8c5b18451 Mon Sep 17 00:00:00 2001 From: Wee Bit Date: Sat, 5 Aug 2023 03:15:42 +0300 Subject: [PATCH 04/28] Use weaker wording: "broken" instead of "illegal" --- lib/command.js | 6 +++--- tests/command.positionalOptions.test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/command.js b/lib/command.js index e01586a1d..d190512ed 100644 --- a/lib/command.js +++ b/lib/command.js @@ -272,7 +272,7 @@ class Command extends EventEmitter { this.commands.push(cmd); cmd.parent = this; - this._checkForIllegalPassThroughOptions(cmd, this); + this._checkForBrokenPassThrough(cmd, this); return this; } @@ -737,7 +737,7 @@ Expecting one of '${allowedValues.join("', '")}'`); */ passThroughOptions(passThrough = true) { this._passThroughOptions = !!passThrough; - this._checkForIllegalPassThroughOptions(this, this.parent); + this._checkForBrokenPassThrough(this, this.parent); return this; } @@ -747,7 +747,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @api private */ - _checkForIllegalPassThroughOptions(command, parent) { + _checkForBrokenPassThrough(command, parent) { if (parent && command._passThroughOptions && !parent._enablePositionalOptions) { throw new Error(`passThroughOptions cannot be used for '${command._name}' without turning on enablePositionalOptions for parent command${parent._name ? ` '${parent._name}'` : ''}`); } diff --git a/tests/command.positionalOptions.test.js b/tests/command.positionalOptions.test.js index 73dd7a877..82011e136 100644 --- a/tests/command.positionalOptions.test.js +++ b/tests/command.positionalOptions.test.js @@ -362,7 +362,7 @@ describe('program with action handler and positionalOptions and subcommand', () // ------------------------------------------------------------------------------ -describe('illegal passThroughOptions', () => { +describe('broken passThrough', () => { test('when program not positional and turn on passThroughOptions in subcommand then error', () => { const program = new commander.Command(); const sub = program.command('sub'); From ec1942ddcc404adbe9cea3e11d87ed4043782b6c Mon Sep 17 00:00:00 2001 From: aweebit Date: Sat, 5 Aug 2023 03:42:38 +0300 Subject: [PATCH 05/28] Unclutter error message in broken passThrough checks Co-authored-by: John Gee --- lib/command.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command.js b/lib/command.js index d190512ed..65559112a 100644 --- a/lib/command.js +++ b/lib/command.js @@ -749,7 +749,7 @@ Expecting one of '${allowedValues.join("', '")}'`); _checkForBrokenPassThrough(command, parent) { if (parent && command._passThroughOptions && !parent._enablePositionalOptions) { - throw new Error(`passThroughOptions cannot be used for '${command._name}' without turning on enablePositionalOptions for parent command${parent._name ? ` '${parent._name}'` : ''}`); + throw new Error(`passThroughOptions cannot be used for '${command._name}' without turning on enablePositionalOptions for parent command(s)`); } } From ac8db3a6f1d1025ea9a9b11d3cf4483a71610666 Mon Sep 17 00:00:00 2001 From: Wee Bit Date: Sat, 5 Aug 2023 04:01:21 +0300 Subject: [PATCH 06/28] Refactor _checkForBrokenPassThrough() to make it instance-aware --- lib/command.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/command.js b/lib/command.js index 65559112a..e4b5d1699 100644 --- a/lib/command.js +++ b/lib/command.js @@ -272,7 +272,7 @@ class Command extends EventEmitter { this.commands.push(cmd); cmd.parent = this; - this._checkForBrokenPassThrough(cmd, this); + cmd._checkForBrokenPassThrough(); return this; } @@ -737,19 +737,17 @@ Expecting one of '${allowedValues.join("', '")}'`); */ passThroughOptions(passThrough = true) { this._passThroughOptions = !!passThrough; - this._checkForBrokenPassThrough(this, this.parent); + this._checkForBrokenPassThrough(); return this; } /** - * @param {Command} command - * @param {Command | null} parent * @api private */ - _checkForBrokenPassThrough(command, parent) { - if (parent && command._passThroughOptions && !parent._enablePositionalOptions) { - throw new Error(`passThroughOptions cannot be used for '${command._name}' without turning on enablePositionalOptions for parent command(s)`); + _checkForBrokenPassThrough() { + if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) { + throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`); } } From c876dee8a5ac71598dd8f252a3a29d71942e3c73 Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 15 Sep 2023 20:35:25 +1200 Subject: [PATCH 07/28] Remove default export of global program (#2017) --- docs/deprecated.md | 1 + index.js | 10 ++--- tests/fixtures-extensions/pm.js | 2 +- tests/fixtures/inspect.js | 2 +- tests/fixtures/pm | 2 +- tests/fixtures/pm-cache.js | 2 +- tests/program.test.js | 71 +++++++++++++++++++++++++++------ tests/ts-imports.test.ts | 6 --- 8 files changed, 68 insertions(+), 28 deletions(-) diff --git a/docs/deprecated.md b/docs/deprecated.md index 2ead1ab81..6bbd87a86 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -58,6 +58,7 @@ const program = new Command() - Removed from README in Commander v5. - Deprecated from Commander v7. - Removed from TypeScript declarations in Commander v8. +- Removed from CommonJS in Commander v12. Deprecated and gone! ## Callback to .help() and .outputHelp() diff --git a/index.js b/index.js index 7563b1bac..ab63c35d9 100644 --- a/index.js +++ b/index.js @@ -6,13 +6,11 @@ const { Option } = require('./lib/option.js'); // @ts-check -/** - * Expose the root command. - */ +exports.program = new Command(); -exports = module.exports = new Command(); -exports.program = exports; // More explicit access to global command. -// Implicit export of createArgument, createCommand, and createOption. +exports.createCommand = (name) => new Command(name); +exports.createOption = (flags, description) => new Option(flags, description); +exports.createArgument = (name, description) => new Argument(name, description); /** * Expose classes diff --git a/tests/fixtures-extensions/pm.js b/tests/fixtures-extensions/pm.js index 8aff56027..d05bb2a82 100644 --- a/tests/fixtures-extensions/pm.js +++ b/tests/fixtures-extensions/pm.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const program = require('../../'); +const { program } = require('../../'); program .command('try-ts', 'test file extension lookup') diff --git a/tests/fixtures/inspect.js b/tests/fixtures/inspect.js index 46b99b06d..2ad93ba8a 100644 --- a/tests/fixtures/inspect.js +++ b/tests/fixtures/inspect.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const program = require('../../'); +const { program } = require('../../'); program .command('sub', 'install one or more packages') diff --git a/tests/fixtures/pm b/tests/fixtures/pm index 40fbd396d..a897597e0 100755 --- a/tests/fixtures/pm +++ b/tests/fixtures/pm @@ -1,6 +1,6 @@ #!/usr/bin/env node -var program = require('../../'); +var { program } = require('../../'); program .version('0.0.1') diff --git a/tests/fixtures/pm-cache.js b/tests/fixtures/pm-cache.js index 121eca247..58346dcf2 100644 --- a/tests/fixtures/pm-cache.js +++ b/tests/fixtures/pm-cache.js @@ -1,4 +1,4 @@ -const program = require('../../'); +const { program } = require('../../'); program .command('clear', 'clear the cache') diff --git a/tests/program.test.js b/tests/program.test.js index 3d5faaf82..51c1b0ee8 100644 --- a/tests/program.test.js +++ b/tests/program.test.js @@ -1,20 +1,67 @@ -const commander = require('../'); +const { + program, + Command, + Option, + Argument, + Help, + CommanderError, + InvalidArgumentError, + InvalidOptionArgumentError, + createCommand, + createOption, + createArgument +} = require('../index.js'); // Do some testing of the default export(s). +// Similar tests to ts-imports.test.ts and esm-imports-test.js. -test('when require commander then is a Command (default export of global)', () => { - // Deprecated global command - const program = commander; - expect(program.constructor.name).toBe('Command'); +/* eslint jest/expect-expect: ["error", { "assertFunctionNames": ["expect", "checkClass"] }] */ + +function checkClass(obj, name) { + expect(typeof obj).toEqual('object'); + expect(obj.constructor.name).toEqual(name); +} + +test('program', () => { + checkClass(program, 'Command'); +}); + +test('Command', () => { + checkClass(new Command('name'), 'Command'); +}); + +test('Option', () => { + checkClass(new Option('-e, --example', 'description'), 'Option'); +}); + +test('Argument', () => { + checkClass(new Argument('', 'description'), 'Argument'); +}); + +test('Help', () => { + checkClass(new Help(), 'Help'); +}); + +test('CommanderError', () => { + checkClass(new CommanderError(1, 'code', 'failed'), 'CommanderError'); +}); + +test('InvalidArgumentError', () => { + checkClass(new InvalidArgumentError('failed'), 'InvalidArgumentError'); +}); + +test('InvalidOptionArgumentError', () => { // Deprecated + checkClass(new InvalidOptionArgumentError('failed'), 'InvalidArgumentError'); +}); + +test('createCommand', () => { + checkClass(createCommand('foo'), 'Command'); }); -test('when require commander then has program (named export of global)', () => { - // program added in v5 - const program = commander.program; - expect(program.constructor.name).toBe('Command'); +test('createOption', () => { + checkClass(createOption('-e, --example', 'description'), 'Option'); }); -test('when require commander then has newable Command', () => { - const cmd = new commander.Command(); - expect(cmd.constructor.name).toBe('Command'); +test('createArgument', () => { + checkClass(createArgument('', 'description'), 'Argument'); }); diff --git a/tests/ts-imports.test.ts b/tests/ts-imports.test.ts index 5f6704e2d..e766bcb5f 100644 --- a/tests/ts-imports.test.ts +++ b/tests/ts-imports.test.ts @@ -1,7 +1,5 @@ import { program, Command, Option, CommanderError, InvalidArgumentError, InvalidOptionArgumentError, Help, createCommand } from '../'; -import * as commander from '../'; - // Do some simple checks that expected imports are available at runtime. // Similar tests to esm-imports-test.js @@ -11,10 +9,6 @@ function checkClass(obj: object, name: string): void { expect(obj.constructor.name).toEqual(name); } -test('legacy default export of global Command', () => { - checkClass(commander, 'Command'); -}); - test('program', () => { checkClass(program, 'Command'); }); From 37c939818493f5189c47daa5e62f99edda74caae Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 16 Sep 2023 16:39:40 +1200 Subject: [PATCH 08/28] Switch @api private to official JSDoc (#2018) --- lib/argument.js | 4 +-- lib/command.js | 95 ++++++++++++++++++++++++------------------------- lib/option.js | 11 +++--- 3 files changed, 54 insertions(+), 56 deletions(-) diff --git a/lib/argument.js b/lib/argument.js index c16430250..bcdba6de3 100644 --- a/lib/argument.js +++ b/lib/argument.js @@ -52,7 +52,7 @@ class Argument { } /** - * @api private + * @package internal use only */ _concatValue(value, previous) { @@ -132,7 +132,7 @@ class Argument { * * @param {Argument} arg * @return {string} - * @api private + * @private */ function humanReadableArgName(arg) { diff --git a/lib/command.js b/lib/command.js index a6291bcf7..544f8c353 100644 --- a/lib/command.js +++ b/lib/command.js @@ -111,7 +111,7 @@ class Command extends EventEmitter { /** * @returns {Command[]} - * @api private + * @private */ _getCommandAndAncestors() { @@ -395,7 +395,7 @@ class Command extends EventEmitter { /** * @return {boolean} - * @api private + * @package internal use only */ _hasImplicitHelpCommand() { @@ -456,7 +456,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {string} code an id string representing the error * @param {string} message human-readable description of the error * @return never - * @api private + * @private */ _exit(exitCode, code, message) { @@ -522,7 +522,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {string} value * @param {any} previous * @param {string} invalidArgumentMessage - * @api private + * @private */ _callParseArg(target, value, previous, invalidArgumentMessage) { @@ -608,7 +608,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Internal implementation shared by .option() and .requiredOption() * - * @api private + * @private */ _optionEx(config, flags, description, fn, defaultValue) { if (typeof flags === 'object' && flags instanceof Option) { @@ -769,7 +769,7 @@ Expecting one of '${allowedValues.join("', '")}'`); } /** - * @api private + * @private */ _checkForBrokenPassThrough() { @@ -877,7 +877,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Get user arguments from implied or explicit arguments. * Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches. * - * @api private + * @private */ _prepareUserArgs(argv, parseOptions) { @@ -980,7 +980,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Execute a sub-command executable. * - * @api private + * @private */ _executeSubCommand(subcommand, args) { @@ -1105,7 +1105,7 @@ Expecting one of '${allowedValues.join("', '")}'`); } /** - * @api private + * @private */ _dispatchSubcommand(commandName, operands, unknown) { @@ -1128,7 +1128,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Invoke help directly if possible, or dispatch if necessary. * e.g. help foo * - * @api private + * @private */ _dispatchHelpCommand(subcommandName) { @@ -1149,7 +1149,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Check this.args against expected this._args. * - * @api private + * @private */ _checkNumberOfArguments() { @@ -1171,7 +1171,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Process this.args using this._args and save as this.processedArgs! * - * @api private + * @private */ _processArguments() { @@ -1219,7 +1219,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {Promise|undefined} promise * @param {Function} fn * @return {Promise|undefined} - * @api private + * @private */ _chainOrCall(promise, fn) { @@ -1237,7 +1237,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {Promise|undefined} promise * @param {string} event * @return {Promise|undefined} - * @api private + * @private */ _chainOrCallHooks(promise, event) { @@ -1269,7 +1269,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {Command} subCommand * @param {string} event * @return {Promise|undefined} - * @api private + * @private */ _chainOrCallSubCommandHook(promise, subCommand, event) { @@ -1288,7 +1288,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Process arguments in context of this command. * Returns action result, in case it is a promise. * - * @api private + * @private */ _parseCommand(operands, unknown) { @@ -1306,7 +1306,7 @@ Expecting one of '${allowedValues.join("', '")}'`); return this._dispatchHelpCommand(operands[1]); } if (this._defaultCommandName) { - outputHelpIfRequested(this, unknown); // Run the help for default command from parent rather than passing to default command + this._outputHelpIfRequested(unknown); // Run the help for default command from parent rather than passing to default command return this._dispatchSubcommand(this._defaultCommandName, operands, unknown); } if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) { @@ -1314,7 +1314,7 @@ Expecting one of '${allowedValues.join("', '")}'`); this.help({ error: true }); } - outputHelpIfRequested(this, parsed.unknown); + this._outputHelpIfRequested(parsed.unknown); this._checkForMissingMandatoryOptions(); this._checkForConflictingOptions(); @@ -1372,7 +1372,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Find matching command. * - * @api private + * @private */ _findCommand(name) { if (!name) return undefined; @@ -1384,7 +1384,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * * @param {string} arg * @return {Option} - * @api private + * @package internal use only */ _findOption(arg) { @@ -1395,7 +1395,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Display an error message if a mandatory option does not have a value. * Called after checking for help flags in leaf subcommand. * - * @api private + * @private */ _checkForMissingMandatoryOptions() { @@ -1412,7 +1412,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Display an error message if conflicting options are used together in this. * - * @api private + * @private */ _checkForConflictingLocalOptions() { const definedNonDefaultOptions = this.options.filter( @@ -1443,7 +1443,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Display an error message if conflicting options are used together. * Called after checking for help flags in leaf subcommand. * - * @api private + * @private */ _checkForConflictingOptions() { // Walk up hierarchy so can call in subcommand after checking for displaying help. @@ -1647,7 +1647,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Apply any option related environment variables, if option does * not have a value from cli or client code. * - * @api private + * @private */ _parseOptionsEnv() { this.options.forEach((option) => { @@ -1670,7 +1670,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Apply any implied option values, if option is undefined or default value. * - * @api private + * @private */ _parseOptionsImplied() { const dualHelper = new DualOptions(this.options); @@ -1694,7 +1694,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Argument `name` is missing. * * @param {string} name - * @api private + * @private */ missingArgument(name) { @@ -1706,7 +1706,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * `Option` is missing an argument. * * @param {Option} option - * @api private + * @private */ optionMissingArgument(option) { @@ -1718,7 +1718,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * `Option` does not have a value, and is a mandatory option. * * @param {Option} option - * @api private + * @private */ missingMandatoryOptionValue(option) { @@ -1731,7 +1731,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * * @param {Option} option * @param {Option} conflictingOption - * @api private + * @private */ _conflictingOption(option, conflictingOption) { // The calling code does not know whether a negated option is the source of the @@ -1768,7 +1768,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Unknown option `flag`. * * @param {string} flag - * @api private + * @private */ unknownOption(flag) { @@ -1797,7 +1797,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Excess arguments, more than expected. * * @param {string[]} receivedArgs - * @api private + * @private */ _excessArguments(receivedArgs) { @@ -1813,7 +1813,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Unknown command. * - * @api private + * @private */ unknownCommand() { @@ -2023,7 +2023,7 @@ Expecting one of '${allowedValues.join("', '")}'`); } /** - * @api private + * @private */ _getHelpContext(contextOptions) { @@ -2149,22 +2149,21 @@ Expecting one of '${allowedValues.join("', '")}'`); }); return this; } -} -/** - * Output help information if help flags specified - * - * @param {Command} cmd - command to output help for - * @param {Array} args - array of options to search for help flags - * @api private - */ + /** + * Output help information if help flags specified + * + * @param {Array} args - array of options to search for help flags + * @private + */ -function outputHelpIfRequested(cmd, args) { - const helpOption = cmd._hasHelpOption && args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag); - if (helpOption) { - cmd.outputHelp(); - // (Do not have all displayed text available so only passing placeholder.) - cmd._exit(0, 'commander.helpDisplayed', '(outputHelp)'); + _outputHelpIfRequested(args) { + const helpOption = this._hasHelpOption && args.find(arg => arg === this._helpLongFlag || arg === this._helpShortFlag); + if (helpOption) { + this.outputHelp(); + // (Do not have all displayed text available so only passing placeholder.) + this._exit(0, 'commander.helpDisplayed', '(outputHelp)'); + } } } @@ -2173,7 +2172,7 @@ function outputHelpIfRequested(cmd, args) { * * @param {string[]} args - array of arguments from node.execArgv * @returns {string[]} - * @api private + * @private */ function incrementNodeInspectorPort(args) { diff --git a/lib/option.js b/lib/option.js index d61fc5f2f..42f38826d 100644 --- a/lib/option.js +++ b/lib/option.js @@ -160,7 +160,7 @@ class Option { } /** - * @api private + * @package internal use only */ _concatValue(value, previous) { @@ -210,7 +210,6 @@ class Option { * as a object attribute key. * * @return {string} - * @api private */ attributeName() { @@ -222,7 +221,7 @@ class Option { * * @param {string} arg * @return {boolean} - * @api private + * @package internal use only */ is(arg) { @@ -235,7 +234,7 @@ class Option { * Options are one of boolean, negated, required argument, or optional argument. * * @return {boolean} - * @api private + * @package internal use only */ isBoolean() { @@ -295,7 +294,7 @@ class DualOptions { * * @param {string} str * @return {string} - * @api private + * @private */ function camelcase(str) { @@ -307,7 +306,7 @@ function camelcase(str) { /** * Split the short and long flag out of something like '-m,--mixed ' * - * @api private + * @private */ function splitOptionFlags(flags) { From a0ca1bd4722b8459c7d6bab426c283c63c39bb68 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 8 Oct 2023 01:09:03 +1300 Subject: [PATCH 09/28] Drop Node.js 16 (#2027) --- .github/workflows/tests.yml | 2 +- Readme.md | 2 +- Readme_zh-CN.md | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6bfe72b18..3f240df1a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x] os: [ubuntu-latest, windows-latest, macos-latest] steps: diff --git a/Readme.md b/Readme.md index f92667d7a..3d38b1323 100644 --- a/Readme.md +++ b/Readme.md @@ -1136,7 +1136,7 @@ There is more information available about: ## Support -The current version of Commander is fully supported on Long Term Support versions of Node.js, and requires at least v16. +The current version of Commander is fully supported on Long Term Support versions of Node.js, and requires at least v18. (For older versions of Node.js, use an older version of Commander.) The main forum for free and community support is the project [Issues](https://github.com/tj/commander.js/issues) on GitHub. diff --git a/Readme_zh-CN.md b/Readme_zh-CN.md index b6c6ff238..fc3bd0c41 100644 --- a/Readme_zh-CN.md +++ b/Readme_zh-CN.md @@ -1059,7 +1059,7 @@ program ## 支持 -当前版本的 Commander 在 LTS 版本的 Node.js 上完全支持。并且至少需要 v16。 +当前版本的 Commander 在 LTS 版本的 Node.js 上完全支持。并且至少需要 v18。 (使用更低版本 Node.js 的用户建议安装更低版本的 Commander) 社区支持请访问项目的 [Issues](https://github.com/tj/commander.js/issues)。 diff --git a/package.json b/package.json index 9382be627..36af5dbbb 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ }, "types": "typings/index.d.ts", "engines": { - "node": ">=16" + "node": ">=18" }, "support": true } From 5aaca0d666271f56fcc79044391765db527123f2 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 8 Oct 2023 10:26:48 +1300 Subject: [PATCH 10/28] Exit with non-zero code when subprocess terminated by signal (#2023) --- lib/command.js | 16 ++--- ...mmand.executableSubcommand.signals.test.js | 61 +++++++++++-------- tests/fixtures/pm | 13 +++- tests/fixtures/pm-fail.js | 1 + tests/fixtures/pm-terminate.js | 1 + 5 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 tests/fixtures/pm-fail.js create mode 100644 tests/fixtures/pm-terminate.js diff --git a/lib/command.js b/lib/command.js index 93b9d0192..9484a5e46 100644 --- a/lib/command.js +++ b/lib/command.js @@ -1040,15 +1040,15 @@ Expecting one of '${allowedValues.join("', '")}'`); } // By default terminate process when spawned process terminates. - // Suppressing the exit if exitCallback defined is a bit messy and of limited use, but does allow process to stay running! const exitCallback = this._exitCallback; - if (!exitCallback) { - proc.on('close', process.exit.bind(process)); - } else { - proc.on('close', () => { - exitCallback(new CommanderError(process.exitCode || 0, 'commander.executeSubCommandAsync', '(close)')); - }); - } + proc.on('close', (code, _signal) => { + code = code ?? 1; // code is null if spawned process terminated due to a signal + if (!exitCallback) { + process.exit(code); + } else { + exitCallback(new CommanderError(code, 'commander.executeSubCommandAsync', '(close)')); + } + }); proc.on('error', (err) => { // @ts-ignore if (err.code === 'ENOENT') { diff --git a/tests/command.executableSubcommand.signals.test.js b/tests/command.executableSubcommand.signals.test.js index a5eb23081..d97ebb2bf 100644 --- a/tests/command.executableSubcommand.signals.test.js +++ b/tests/command.executableSubcommand.signals.test.js @@ -1,39 +1,46 @@ const childProcess = require('child_process'); const path = require('path'); -// Test that a signal sent to the parent process is received by the executable subcommand process (which is listening). +const pmPath = path.join(__dirname, 'fixtures', 'pm'); -// Disabling tests on Windows as: +// Disabling some tests on Windows as: // "Windows does not support sending signals" // https://nodejs.org/api/process.html#process_signal_events const describeOrSkipOnWindows = (process.platform === 'win32') ? describe.skip : describe; -// Note: the previous (sinon) test had custom code for SIGUSR1, revisit if required: -// As described at https://nodejs.org/api/process.html#process_signal_events -// this signal will start a debugger and thus the process might output an -// additional error message: -// "Failed to open socket on port 5858, waiting 1000 ms before retrying". +describeOrSkipOnWindows('signals', () => { + test.each(['SIGINT', 'SIGHUP', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'])('when program sent %s then executableSubcommand sent signal too', (signal, done) => { + // Spawn program. The listen subcommand waits for a signal and writes the name of the signal to stdout. + const proc = childProcess.spawn(pmPath, ['listen'], {}); -describeOrSkipOnWindows.each([['SIGINT'], ['SIGHUP'], ['SIGTERM'], ['SIGUSR1'], ['SIGUSR2']])( - 'test signal handling in executableSubcommand', (value) => { - // Slightly tricky test, stick with callback and disable lint warning. - // eslint-disable-next-line jest/no-done-callback - test(`when command killed with ${value} then executableSubcommand receives ${value}`, (done) => { - const pmPath = path.join(__dirname, './fixtures/pm'); + let processOutput = ''; + proc.stdout.on('data', (data) => { + if (processOutput.length === 0) { + // Send signal to program. + proc.kill(`${signal}`); + } + processOutput += data.toString(); + }); + proc.on('close', (code) => { + // Check the child subcommand received the signal too. + expect(processOutput).toBe(`Listening for signal...${signal}`); + done(); + }); + }); - // The child process writes to stdout. - const proc = childProcess.spawn(pmPath, ['listen'], {}); + test('when executable subcommand sent signal then program exit code is non-zero', () => { + const { status } = childProcess.spawnSync(pmPath, ['terminate'], {}); + expect(status).toBeGreaterThan(0); + }); - let processOutput = ''; - proc.stdout.on('data', (data) => { - if (processOutput.length === 0) { - proc.kill(`${value}`); - } - processOutput += data.toString(); - }); - proc.on('close', (code) => { - expect(processOutput).toBe(`Listening for signal...${value}`); - done(); - }); - }); + test('when command has exitOverride and executable subcommand sent signal then exit code is non-zero', () => { + const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'terminate'], {}); + expect(status).toBeGreaterThan(0); + }); + + // Not a signal test, but closely related code so adding here. + test('when command has exitOverride and executable subcommand fails then program exit code is subcommand exit code', () => { + const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'fail'], {}); + expect(status).toEqual(42); }); +}); diff --git a/tests/fixtures/pm b/tests/fixtures/pm index 1eb341899..1e7cd302e 100755 --- a/tests/fixtures/pm +++ b/tests/fixtures/pm @@ -1,6 +1,7 @@ #!/usr/bin/env node -var { program } = require('../../'); +const path = require('node:path'); +const { program } = require('../../'); process.env.FORCE_COLOR = 0; // work-around bug in Jest: https://github.com/jestjs/jest/issues/14391 @@ -17,4 +18,14 @@ program .command('specifyInstall', 'specify install subcommand', { executableFile: 'pm-install' }) .command('specifyPublish', 'specify publish subcommand', { executableFile: 'pm-publish' }) .command('silent', 'silently succeed') + .command('fail', 'exit with non-zero status code') + .command('terminate', 'terminate due to signal'); + +program + .command('exit-override') + .exitOverride((err) => { process.exit(err.exitCode); }) + .command('fail', 'exit with non-zero status code', { executableFile: path.join(__dirname, 'pm-fail.js') }) + .command('terminate', 'terminate due to signal', { executableFile: path.join(__dirname, 'pm-terminate.js') }); + +program .parse(process.argv); diff --git a/tests/fixtures/pm-fail.js b/tests/fixtures/pm-fail.js new file mode 100644 index 000000000..6427ca060 --- /dev/null +++ b/tests/fixtures/pm-fail.js @@ -0,0 +1 @@ +process.exit(42); diff --git a/tests/fixtures/pm-terminate.js b/tests/fixtures/pm-terminate.js new file mode 100644 index 000000000..70066ae49 --- /dev/null +++ b/tests/fixtures/pm-terminate.js @@ -0,0 +1 @@ +process.kill(process.pid, 'SIGINT'); From d90c59c959505c0d49d549fd4ba18c518ffe81bc Mon Sep 17 00:00:00 2001 From: John Gee Date: Fri, 13 Oct 2023 19:53:37 +1300 Subject: [PATCH 11/28] Restore extra sanity check when enabling storeOptionsAsProperties (#2029) --- lib/command.js | 6 +++--- tests/commander.configureCommand.test.js | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/command.js b/lib/command.js index 16c390065..8cca02598 100644 --- a/lib/command.js +++ b/lib/command.js @@ -761,9 +761,9 @@ Expecting one of '${allowedValues.join("', '")}'`); if (this.options.length) { throw new Error('call .storeOptionsAsProperties() before adding options'); } - // if (Object.keys(this._optionValues).length) { - // throw new Error('call .storeOptionsAsProperties() before setting option values'); - // } + if (Object.keys(this._optionValues).length) { + throw new Error('call .storeOptionsAsProperties() before setting option values'); + } this._storeOptionsAsProperties = !!storeAsProperties; return this; } diff --git a/tests/commander.configureCommand.test.js b/tests/commander.configureCommand.test.js index 9c5a72d03..60940ec18 100644 --- a/tests/commander.configureCommand.test.js +++ b/tests/commander.configureCommand.test.js @@ -85,10 +85,10 @@ test('when storeOptionsAsProperties() after adding option then throw', () => { }).toThrow(); }); -// test('when storeOptionsAsProperties() after setting option value then throw', () => { -// const program = new commander.Command(); -// program.setOptionValue('foo', 'bar'); -// expect(() => { -// program.storeOptionsAsProperties(); -// }).toThrow(); -// }); +test('when storeOptionsAsProperties() after setting option value then throw', () => { + const program = new commander.Command(); + program.setOptionValue('foo', 'bar'); + expect(() => { + program.storeOptionsAsProperties(); + }).toThrow(); +}); From d90e81eddf9fbef9f265c3f05be93836b809f629 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 15 Oct 2023 19:12:30 +1300 Subject: [PATCH 12/28] Add migration tips for default import --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b8c949b7..b4feedbb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. +## [Unreleased] (date goes here) + +### Changed + +- *Breaking:* Commander 12 requires Node.js v18 or higher + +### Removed + +- *Breaking:* removed default export of a global Command instance from CommonJS + +### Migration Tips + +If you are using the [deprecated](./docs/deprecated.md#default-import-of-global-command-object) default import of the global Command object, you need to switch to using a named import (or create a new `Command`). + +```js +// const program = require('commander'); +const { program } = require('commander'); +``` + ## [11.0.0] (2023-06-16) ### Fixed From b96af407cd7980aa9cd6d0a08c793a8c09122cee Mon Sep 17 00:00:00 2001 From: John Gee Date: Wed, 1 Nov 2023 20:45:53 +1300 Subject: [PATCH 13/28] Throw error when add option with clashing flags (#2055) --- lib/command.js | 29 +++++++++++--- tests/options.registerClash.test.js | 59 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 tests/options.registerClash.test.js diff --git a/lib/command.js b/lib/command.js index 8cca02598..bc7d8dbcb 100644 --- a/lib/command.js +++ b/lib/command.js @@ -535,6 +535,25 @@ Expecting one of '${allowedValues.join("', '")}'`); throw err; } } + /** + * Check for option flag conflicts. + * Register option if no conflicts found. + * Throw otherwise. + * + * @param {Option} option + * @api private + */ + + _registerOption(option) { + const matchingOption = (option.short && this._findOption(option.short)) || + (option.long && this._findOption(option.long)); + if (matchingOption) { + const matchingFlag = (option.long && this._findOption(option.long)) ? option.long : option.short; + throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}' +- already used by option '${matchingOption.flags}'`); + } + this.options.push(option); + } /** * Add an option. @@ -543,6 +562,8 @@ Expecting one of '${allowedValues.join("', '")}'`); * @return {Command} `this` command for chaining */ addOption(option) { + this._registerOption(option); + const oname = option.name(); const name = option.attributeName(); @@ -557,9 +578,6 @@ Expecting one of '${allowedValues.join("', '")}'`); this.setOptionValueWithSource(name, option.defaultValue, 'default'); } - // register the option - this.options.push(option); - // handler for cli and env supplied values const handleOptionValue = (val, invalidValueMessage, valueSource) => { // val is null for optional option used without an optional-argument. @@ -1824,8 +1842,9 @@ Expecting one of '${allowedValues.join("', '")}'`); flags = flags || '-V, --version'; description = description || 'output the version number'; const versionOption = this.createOption(flags, description); - this._versionOptionName = versionOption.attributeName(); // [sic] not defined in constructor, partly legacy, partly only needed at root - this.options.push(versionOption); + this._versionOptionName = versionOption.attributeName(); + this._registerOption(versionOption); + this.on('option:' + versionOption.name(), () => { this._outputConfiguration.writeOut(`${str}\n`); this._exit(0, 'commander.version', str); diff --git a/tests/options.registerClash.test.js b/tests/options.registerClash.test.js new file mode 100644 index 000000000..b5d531379 --- /dev/null +++ b/tests/options.registerClash.test.js @@ -0,0 +1,59 @@ +const { Command, Option } = require('../'); + +describe('.option()', () => { + test('when short option flag conflicts then throws', () => { + expect(() => { + const program = new Command(); + program + .option('-c, --cheese ', 'cheese type') + .option('-c, --conflict'); + }).toThrow('Cannot add option'); + }); + + test('when long option flag conflicts then throws', () => { + expect(() => { + const program = new Command(); + program + .option('-c, --cheese ', 'cheese type') + .option('-H, --cheese'); + }).toThrow('Cannot add option'); + }); + + test('when use help options separately then does not throw', () => { + expect(() => { + const program = new Command(); + program + .option('-h, --help', 'display help'); + }).not.toThrow(); + }); + + test('when reuse flags in subcommand then does not throw', () => { + expect(() => { + const program = new Command(); + program + .option('e, --example'); + program.command('sub') + .option('e, --example'); + }).not.toThrow(); + }); +}); + +describe('.addOption()', () => { + test('when short option flags conflicts then throws', () => { + expect(() => { + const program = new Command(); + program + .option('-c, --cheese ', 'cheese type') + .addOption(new Option('-c, --conflict')); + }).toThrow('Cannot add option'); + }); + + test('when long option flags conflicts then throws', () => { + expect(() => { + const program = new Command(); + program + .option('-c, --cheese ', 'cheese type') + .addOption(new Option('-H, --cheese')); + }).toThrow('Cannot add option'); + }); +}); From 1d3dd47d76375c9f5595a3510db65c8c2fa1e035 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 5 Nov 2023 10:50:24 +1300 Subject: [PATCH 14/28] Add check for overlapping command names or aliases (#2059) Co-authored-by: aweebit --- lib/command.js | 38 +++++++++++++++++++--- tests/command.registerClash.test.js | 49 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 tests/command.registerClash.test.js diff --git a/lib/command.js b/lib/command.js index bc7d8dbcb..d8bfc9a3f 100644 --- a/lib/command.js +++ b/lib/command.js @@ -165,7 +165,7 @@ class Command extends EventEmitter { cmd._hidden = !!(opts.noHelp || opts.hidden); // noHelp is deprecated old name for hidden cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor if (args) cmd.arguments(args); - this.commands.push(cmd); + this._registerCommand(cmd); cmd.parent = this; cmd.copyInheritedSettings(this); @@ -282,7 +282,7 @@ class Command extends EventEmitter { if (opts.isDefault) this._defaultCommandName = cmd._name; if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation - this.commands.push(cmd); + this._registerCommand(cmd); cmd.parent = this; cmd._checkForBrokenPassThrough(); @@ -535,10 +535,10 @@ Expecting one of '${allowedValues.join("', '")}'`); throw err; } } + /** * Check for option flag conflicts. - * Register option if no conflicts found. - * Throw otherwise. + * Register option if no conflicts found, or throw on conflict. * * @param {Option} option * @api private @@ -552,9 +552,33 @@ Expecting one of '${allowedValues.join("', '")}'`); throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}' - already used by option '${matchingOption.flags}'`); } + this.options.push(option); } + /** + * Check for command name and alias conflicts with existing commands. + * Register command if no conflicts found, or throw on conflict. + * + * @param {Command} command + * @api private + */ + + _registerCommand(command) { + const knownBy = (cmd) => { + return [cmd.name()].concat(cmd.aliases()); + }; + + const alreadyUsed = knownBy(command).find((name) => this._findCommand(name)); + if (alreadyUsed) { + const existingCmd = knownBy(this._findCommand(alreadyUsed)).join('|'); + const newCmd = knownBy(command).join('|'); + throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`); + } + + this.commands.push(command); + } + /** * Add an option. * @@ -1900,6 +1924,12 @@ Expecting one of '${allowedValues.join("', '")}'`); } if (alias === command._name) throw new Error('Command alias can\'t be the same as its name'); + const matchingCommand = this.parent?._findCommand(alias); + if (matchingCommand) { + // c.f. _registerCommand + const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join('|'); + throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`); + } command._aliases.push(alias); return this; diff --git a/tests/command.registerClash.test.js b/tests/command.registerClash.test.js new file mode 100644 index 000000000..4930ecccc --- /dev/null +++ b/tests/command.registerClash.test.js @@ -0,0 +1,49 @@ +const { Command } = require('../'); + +test('when command name conflicts with existing name then throw', () => { + expect(() => { + const program = new Command(); + program.command('one'); + program.command('one'); + }).toThrow('cannot add command'); +}); + +test('when command name conflicts with existing alias then throw', () => { + expect(() => { + const program = new Command(); + program.command('one').alias('1'); + program.command('1'); + }).toThrow('cannot add command'); +}); + +test('when command alias conflicts with existing name then throw', () => { + expect(() => { + const program = new Command(); + program.command('one'); + program.command('1').alias('one'); + }).toThrow('cannot add alias'); +}); + +test('when command alias conflicts with existing alias then throw', () => { + expect(() => { + const program = new Command(); + program.command('one').alias('1'); + program.command('unity').alias('1'); + }).toThrow('cannot add alias'); +}); + +test('when .addCommand name conflicts with existing name then throw', () => { + expect(() => { + const program = new Command(); + program.command('one'); + program.addCommand(new Command('one')); + }).toThrow('cannot add command'); +}); + +test('when .addCommand alias conflicts with existing name then throw', () => { + expect(() => { + const program = new Command(); + program.command('one'); + program.addCommand(new Command('unity').alias('one')); + }).toThrow('cannot add command'); +}); From c6820a588717d931276068a84aa8469c373cc3b2 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 11 Nov 2023 09:42:57 +1300 Subject: [PATCH 15/28] Update CHANGELOG for 12.0.0 (#2066) --- CHANGELOG.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b999e3d2..520dfad22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,24 +8,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. -## [Unreleased] (date goes here) +## [12.0.0] (date goes here) + +### Fixed + +- *Breaking:* use non-zero exit code when spawned executable subcommand terminates due to a signal ([#2023]) +- *Breaking:* check `passThroughOptions` constraints when using `.addCommand` and throw if parent command does not have `.enablePositionalOptions()` enabled ([#1937]) ### Changed -- *Breaking:* Commander 12 requires Node.js v18 or higher +- *Breaking:* Commander 12 requires Node.js v18 or higher ([#2027]) +- *Breaking:* throw an error if add an option with a flag which is already in use ([#2055]) +- *Breaking:* throw an error if add a command with name or alias which is already in use ([#2059]) +- *Breaking:* throw error when calling `.storeOptionsAsProperties()` after setting an option value ([#1928]) +- replace non-standard JSDoc of `@api private` with documented `@private` ([#1949]) ### Removed -- *Breaking:* removed default export of a global Command instance from CommonJS +- *Breaking:* removed default export of a global Command instance from CommonJS (use the named `program` export instead) ([#2017]) ### Migration Tips +**global program** + If you are using the [deprecated](./docs/deprecated.md#default-import-of-global-command-object) default import of the global Command object, you need to switch to using a named import (or create a new `Command`). ```js // const program = require('commander'); const { program } = require('commander'); ``` + +**option and command clashes** + +A couple of configuration problems now throw an error, which will pick up issues in existing programs: + +- adding an option which uses the same flag as a previous option +- adding a command which uses the same name or alias as a previous command + ## [11.1.0] (2023-10-13) ### Fixed @@ -1206,13 +1225,21 @@ program [#1874]: https://github.com/tj/commander.js/pull/1874 [#1886]: https://github.com/tj/commander.js/pull/1886 [#1896]: https://github.com/tj/commander.js/pull/1896 +[#1928]: https://github.com/tj/commander.js/pull/1928 [#1930]: https://github.com/tj/commander.js/pull/1930 +[#1937]: https://github.com/tj/commander.js/pull/1937 +[#1949]: https://github.com/tj/commander.js/pull/1949 [#1965]: https://github.com/tj/commander.js/pull/1965 [#1969]: https://github.com/tj/commander.js/pull/1969 [#1982]: https://github.com/tj/commander.js/pull/1982 [#1983]: https://github.com/tj/commander.js/pull/1983 [#2010]: https://github.com/tj/commander.js/pull/2010 +[#2017]: https://github.com/tj/commander.js/pull/2017 [#2019]: https://github.com/tj/commander.js/pull/2019 +[#2023]: https://github.com/tj/commander.js/pull/2023 +[#2027]: https://github.com/tj/commander.js/pull/2027 +[#2055]: https://github.com/tj/commander.js/pull/2055 +[#2059]: https://github.com/tj/commander.js/pull/2059 [#1]: https://github.com/tj/commander.js/issues/1 @@ -1292,6 +1319,7 @@ program [#1028]: https://github.com/tj/commander.js/pull/1028 [Unreleased]: https://github.com/tj/commander.js/compare/master...develop +[12.0.0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0 [11.1.0]: https://github.com/tj/commander.js/compare/v11.0.0...v11.1.0 [11.0.0]: https://github.com/tj/commander.js/compare/v10.0.1...v11.0.0 [10.0.1]: https://github.com/tj/commander.js/compare/v10.0.0...v10.0.1 From 4085ac7449d9a13c571e76fb21e4e69bb1271d19 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 11 Nov 2023 18:24:47 +1300 Subject: [PATCH 16/28] Prepare for prerelease 12.0.0-0 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 520dfad22..71141dadd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. -## [12.0.0] (date goes here) +## [12.0.0-0] (2023-11-11) ### Fixed @@ -1319,7 +1319,7 @@ program [#1028]: https://github.com/tj/commander.js/pull/1028 [Unreleased]: https://github.com/tj/commander.js/compare/master...develop -[12.0.0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0 +[12.0.0-0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0-0 [11.1.0]: https://github.com/tj/commander.js/compare/v11.0.0...v11.1.0 [11.0.0]: https://github.com/tj/commander.js/compare/v10.0.1...v11.0.0 [10.0.1]: https://github.com/tj/commander.js/compare/v10.0.0...v10.0.1 From db6b4d5912068ce7ec9134ca81428dde9f6333fb Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 11 Nov 2023 18:26:11 +1300 Subject: [PATCH 17/28] Bump required version in package-lock --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 30f7b5f89..e397a3dce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "typescript": "^5.0.4" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@aashutoshrathi/word-wrap": { From 18f921d9778ebd1578ad98aba9b873f51786fbe4 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 11 Nov 2023 18:28:12 +1300 Subject: [PATCH 18/28] 12.0.0-0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e397a3dce..a29166316 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "commander", - "version": "11.1.0", + "version": "12.0.0-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "commander", - "version": "11.1.0", + "version": "12.0.0-0", "license": "MIT", "devDependencies": { "@types/jest": "^29.2.4", diff --git a/package.json b/package.json index 3dcdfbf57..ba618eba5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commander", - "version": "11.1.0", + "version": "12.0.0-0", "description": "the complete solution for node.js command-line programs", "keywords": [ "commander", From 9821f3a7529b57bb3b7b5079ee695f93ca7acb25 Mon Sep 17 00:00:00 2001 From: John Gee Date: Wed, 15 Nov 2023 19:25:21 +1300 Subject: [PATCH 19/28] Update url per npm advice (#2077) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ba618eba5..f60bd9546 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/tj/commander.js.git" + "url": "git+https://github.com/tj/commander.js.git" }, "scripts": { "lint": "npm run lint:javascript && npm run lint:typescript", From 066e38110a594b6cfe4ce41a0beca089953d891f Mon Sep 17 00:00:00 2001 From: John Gee Date: Wed, 15 Nov 2023 19:26:08 +1300 Subject: [PATCH 20/28] Add Removed section to Deprecated (#2078) --- docs/deprecated.md | 95 ++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/docs/deprecated.md b/docs/deprecated.md index 610709b9d..74ffb16d6 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -4,20 +4,21 @@ These features are deprecated, which means they may go away in a future major ve They are currently still available for backwards compatibility, but should not be used in new code. - [Deprecated](#deprecated) - - [RegExp .option() parameter](#regexp-option-parameter) - - [noHelp](#nohelp) - - [Default import of global Command object](#default-import-of-global-command-object) - - [Callback to .help() and .outputHelp()](#callback-to-help-and-outputhelp) - - [.on('--help')](#on--help) - - [.on('command:\*')](#oncommand) - - [.command('\*')](#command) - - [cmd.description(cmdDescription, argDescriptions)](#cmddescriptioncmddescription-argdescriptions) - - [InvalidOptionArgumentError](#invalidoptionargumenterror) - - [Short option flag longer than a single character](#short-option-flag-longer-than-a-single-character) - - [Import from `commander/esm.mjs`](#import-from-commanderesmmjs) - - [cmd.\_args](#cmd_args) - -## RegExp .option() parameter + - [RegExp .option() parameter](#regexp-option-parameter) + - [noHelp](#nohelp) + - [Callback to .help() and .outputHelp()](#callback-to-help-and-outputhelp) + - [.on('--help')](#on--help) + - [.on('command:\*')](#oncommand) + - [.command('\*')](#command) + - [cmd.description(cmdDescription, argDescriptions)](#cmddescriptioncmddescription-argdescriptions) + - [InvalidOptionArgumentError](#invalidoptionargumenterror) + - [Short option flag longer than a single character](#short-option-flag-longer-than-a-single-character) + - [Import from `commander/esm.mjs`](#import-from-commanderesmmjs) + - [cmd.\_args](#cmd_args) + - [Removed](#removed) + - [Default import of global Command object](#default-import-of-global-command-object) + +### RegExp .option() parameter The `.option()` method allowed a RegExp as the third parameter to restrict what values were accepted. @@ -29,7 +30,7 @@ Removed from README in Commander v3. Deprecated from Commander v7. The newer functionality is the Option `.choices()` method, or using a custom option processing function. -## noHelp +### noHelp This was an option passed to `.command()` to hide the command from the built-in help: @@ -39,29 +40,7 @@ program.command('example', 'example command', { noHelp: true }); The option was renamed `hidden` in Commander v5.1. Deprecated from Commander v7. -## Default import of global Command object - -The default import was a global Command object. - -```js -const program = require('commander'); -``` - -The global Command object is exported as `program` from Commander v5, or import the Command object. - -```js -const { program } = require('commander'); -// or -const { Command } = require('commander'); -const program = new Command() -``` - -- Removed from README in Commander v5. -- Deprecated from Commander v7. -- Removed from TypeScript declarations in Commander v8. -- Removed from CommonJS in Commander v12. Deprecated and gone! - -## Callback to .help() and .outputHelp() +### Callback to .help() and .outputHelp() These routines allowed a callback parameter to process the built-in help before display. @@ -79,7 +58,7 @@ console.error(colors.red(program.helpInformation())); Deprecated from Commander v7. -## .on('--help') +### .on('--help') This was the way to add custom help after the built-in help. From Commander v3.0.0 this used the custom long help option flags, if changed. @@ -104,7 +83,7 @@ Examples: Deprecated from Commander v7. -## .on('command:*') +### .on('command:*') This was emitted when the command argument did not match a known subcommand (as part of the implementation of `.command('*')`). @@ -115,7 +94,7 @@ or for custom behaviour catch the `commander.unknownCommand` error. Deprecated from Commander v8.3. -## .command('*') +### .command('*') This was used to add a default command to the program. @@ -135,7 +114,7 @@ program Removed from README in Commander v5. Deprecated from Commander v8.3. -## cmd.description(cmdDescription, argDescriptions) +### cmd.description(cmdDescription, argDescriptions) This was used to add command argument descriptions for the help. @@ -158,7 +137,7 @@ program Deprecated from Commander v8. -## InvalidOptionArgumentError +### InvalidOptionArgumentError This was used for throwing an error from custom option processing, for a nice error message. @@ -188,13 +167,13 @@ function myParseInt(value, dummyPrevious) { Deprecated from Commander v8. -## Short option flag longer than a single character +### Short option flag longer than a single character Short option flags like `-ws` were never supported, but the old README did not make this clear. The README now states that short options are a single character. README updated in Commander v3. Deprecated from Commander v9. -## Import from `commander/esm.mjs` +### Import from `commander/esm.mjs` The first support for named imports required an explicit entry file. @@ -210,7 +189,7 @@ import { Command } from 'commander'; README updated in Commander v9. Deprecated from Commander v9. -## cmd._args +### cmd._args This was always private, but was previously the only way to access the command `Argument` array. @@ -225,3 +204,27 @@ const registeredArguments = program.registeredArguments; ``` Deprecated from Commander v11. + +## Removed + +### Default import of global Command object + +The default import was a global Command object. + +```js +const program = require('commander'); +``` + +The global Command object is exported as `program` from Commander v5, or import the Command object. + +```js +const { program } = require('commander'); +// or +const { Command } = require('commander'); +const program = new Command() +``` + +- Removed from README in Commander v5. +- Deprecated from Commander v7. +- Removed from TypeScript declarations in Commander v8. +- Removed from CommonJS in Commander v12. Deprecated and gone! From 32c05a8c0aba991031a44036b139c1350b39226f Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 17 Dec 2023 12:50:50 +1300 Subject: [PATCH 21/28] Improve JSDoc (#2103) --- lib/command.js | 64 +++++++++++++++++++++++++------------------------- lib/option.js | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/command.js b/lib/command.js index d8bfc9a3f..8f2d30071 100644 --- a/lib/command.js +++ b/lib/command.js @@ -52,7 +52,7 @@ class Command extends EventEmitter { this._enablePositionalOptions = false; this._passThroughOptions = false; this._lifeCycleHooks = {}; // a hash of arrays - /** @type {boolean | string} */ + /** @type {(boolean | string)} */ this._showHelpAfterError = false; this._showSuggestionAfterError = true; @@ -141,7 +141,7 @@ class Command extends EventEmitter { * .command('stop [service]', 'stop named service, or all if no name supplied'); * * @param {string} nameAndArgs - command name and arguments, args are `` or `[optional]` and last may also be `variadic...` - * @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable) + * @param {(Object|string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable) * @param {Object} [execOpts] - configuration options (for executable) * @return {Command} returns new command for action handler, or `this` for executable command */ @@ -203,7 +203,7 @@ class Command extends EventEmitter { * or with a subclass of Help by overriding createHelp(). * * @param {Object} [configuration] - configuration options - * @return {Command|Object} `this` command for chaining, or stored configuration + * @return {(Command|Object)} `this` command for chaining, or stored configuration */ configureHelp(configuration) { @@ -229,7 +229,7 @@ class Command extends EventEmitter { * outputError(str, write) // used for displaying errors, and not used for displaying help * * @param {Object} [configuration] - configuration options - * @return {Command|Object} `this` command for chaining, or stored configuration + * @return {(Command|Object)} `this` command for chaining, or stored configuration */ configureOutput(configuration) { @@ -242,7 +242,7 @@ class Command extends EventEmitter { /** * Display the help or a custom message after an error occurs. * - * @param {boolean|string} [displayHelp] + * @param {(boolean|string)} [displayHelp] * @return {Command} `this` command for chaining */ showHelpAfterError(displayHelp = true) { @@ -316,7 +316,7 @@ class Command extends EventEmitter { * * @param {string} name * @param {string} [description] - * @param {Function|*} [fn] - custom argument processing function + * @param {(Function|*)} [fn] - custom argument processing function * @param {*} [defaultValue] * @return {Command} `this` command for chaining */ @@ -517,7 +517,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Wrap parseArgs to catch 'commander.invalidArgument'. * - * @param {Option | Argument} target + * @param {(Option | Argument)} target * @param {string} value * @param {*} previous * @param {string} invalidArgumentMessage @@ -691,7 +691,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * * @param {string} flags * @param {string} [description] - * @param {Function|*} [parseArg] - custom option processing function or default value + * @param {(Function|*)} [parseArg] - custom option processing function or default value * @param {*} [defaultValue] * @return {Command} `this` command for chaining */ @@ -708,7 +708,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * * @param {string} flags * @param {string} [description] - * @param {Function|*} [parseArg] - custom option processing function or default value + * @param {(Function|*)} [parseArg] - custom option processing function or default value * @param {*} [defaultValue] * @return {Command} `this` command for chaining */ @@ -725,7 +725,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour * program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b` * - * @param {Boolean} [combine=true] - if `true` or omitted, an optional value can be specified directly after the flag. + * @param {boolean} [combine=true] - if `true` or omitted, an optional value can be specified directly after the flag. */ combineFlagAndOptionalValue(combine = true) { this._combineFlagAndOptionalValue = !!combine; @@ -735,7 +735,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Allow unknown options on the command line. * - * @param {Boolean} [allowUnknown=true] - if `true` or omitted, no error will be thrown + * @param {boolean} [allowUnknown=true] - if `true` or omitted, no error will be thrown * for unknown options. */ allowUnknownOption(allowUnknown = true) { @@ -746,7 +746,7 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * 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 + * @param {boolean} [allowExcess=true] - if `true` or omitted, no error will be thrown * for excess arguments. */ allowExcessArguments(allowExcess = true) { @@ -759,7 +759,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions. * The default behaviour is non-positional and global options may appear anywhere on the command line. * - * @param {Boolean} [positional=true] + * @param {boolean} [positional=true] */ enablePositionalOptions(positional = true) { this._enablePositionalOptions = !!positional; @@ -772,7 +772,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * positional options to have been enabled on the program (parent commands). * The default behaviour is non-positional and options may appear before or after command-arguments. * - * @param {Boolean} [passThrough=true] + * @param {boolean} [passThrough=true] * for unknown options. */ passThroughOptions(passThrough = true) { @@ -1229,9 +1229,9 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * Once we have a promise we chain, but call synchronously until then. * - * @param {Promise|undefined} promise + * @param {(Promise|undefined)} promise * @param {Function} fn - * @return {Promise|undefined} + * @return {(Promise|undefined)} * @private */ @@ -1247,9 +1247,9 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * - * @param {Promise|undefined} promise + * @param {(Promise|undefined)} promise * @param {string} event - * @return {Promise|undefined} + * @return {(Promise|undefined)} * @private */ @@ -1278,10 +1278,10 @@ Expecting one of '${allowedValues.join("', '")}'`); /** * - * @param {Promise|undefined} promise + * @param {(Promise|undefined)} promise * @param {Command} subCommand * @param {string} event - * @return {Promise|undefined} + * @return {(Promise|undefined)} * @private */ @@ -1477,8 +1477,8 @@ Expecting one of '${allowedValues.join("', '")}'`); * sub --unknown uuu op => [sub], [--unknown uuu op] * sub -- --unknown uuu op => [sub --unknown uuu op], [] * - * @param {String[]} argv - * @return {{operands: String[], unknown: String[]}} + * @param {string[]} argv + * @return {{operands: string[], unknown: string[]}} */ parseOptions(argv) { @@ -1857,7 +1857,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * @param {string} [str] * @param {string} [flags] * @param {string} [description] - * @return {this | string | undefined} `this` command for chaining, or version string if no arguments + * @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments */ version(str, flags, description) { @@ -1881,7 +1881,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * * @param {string} [str] * @param {Object} [argsDescription] - * @return {string|Command} + * @return {(string|Command)} */ description(str, argsDescription) { if (str === undefined && argsDescription === undefined) return this._description; @@ -1896,7 +1896,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Set the summary. Used when listed as subcommand of parent. * * @param {string} [str] - * @return {string|Command} + * @return {(string|Command)} */ summary(str) { if (str === undefined) return this._summary; @@ -1910,7 +1910,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help. * * @param {string} [alias] - * @return {string|Command} + * @return {(string|Command)} */ alias(alias) { @@ -1941,7 +1941,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Only the first alias is shown in the auto-generated help. * * @param {string[]} [aliases] - * @return {string[]|Command} + * @return {(string[]|Command)} */ aliases(aliases) { @@ -1956,7 +1956,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Set / get the command usage `str`. * * @param {string} [str] - * @return {String|Command} + * @return {(string|Command)} */ usage(str) { @@ -1981,7 +1981,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * Get or set the name of the command. * * @param {string} [str] - * @return {string|Command} + * @return {(string|Command)} */ name(str) { @@ -2018,7 +2018,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * program.executableDir('subcommands'); * * @param {string} [path] - * @return {string|null|Command} + * @return {(string|null|Command)} */ executableDir(path) { @@ -2100,7 +2100,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * flags and help description for your command. Pass in false to * disable the built-in help option. * - * @param {string | boolean} [flags] + * @param {(string | boolean)} [flags] * @param {string} [description] * @return {Command} `this` command for chaining */ @@ -2145,7 +2145,7 @@ Expecting one of '${allowedValues.join("', '")}'`); * and 'beforeAll' or 'afterAll' to affect this command and all its subcommands. * * @param {string} position - before or after built-in help - * @param {string | Function} text - string to add, or a function returning a string + * @param {(string | Function)} text - string to add, or a function returning a string * @return {Command} `this` command for chaining */ addHelpText(position, text) { diff --git a/lib/option.js b/lib/option.js index 456b918bd..f06190168 100644 --- a/lib/option.js +++ b/lib/option.js @@ -74,7 +74,7 @@ class Option { * new Option('--rgb').conflicts('cmyk'); * new Option('--js').conflicts(['ts', 'jsx']); * - * @param {string | string[]} names + * @param {(string | string[])} names * @return {Option} */ From ff08a02866d5431a9702edb43915b448c3002f82 Mon Sep 17 00:00:00 2001 From: John Gee Date: Thu, 11 Jan 2024 17:33:59 +1300 Subject: [PATCH 22/28] Refactor help command implementation to hold actual Command (#2087) --- Readme.md | 10 +- docs/deprecated.md | 22 ++++ lib/command.js | 92 +++++++++----- lib/help.js | 9 +- package-lock.json | 198 ++++++++++++++++------------- tests/command.chain.test.js | 46 ++++++- tests/command.copySettings.test.js | 23 +++- typings/index.d.ts | 25 ++-- typings/index.test-d.ts | 12 +- 9 files changed, 295 insertions(+), 142 deletions(-) diff --git a/Readme.md b/Readme.md index 14dba192a..c3241a476 100644 --- a/Readme.md +++ b/Readme.md @@ -37,7 +37,7 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md) - [.usage](#usage) - [.description and .summary](#description-and-summary) - [.helpOption(flags, description)](#helpoptionflags-description) - - [.addHelpCommand()](#addhelpcommand) + - [.helpCommand()](#helpcommand) - [More configuration](#more-configuration-2) - [Custom event listeners](#custom-event-listeners) - [Bits and pieces](#bits-and-pieces) @@ -904,16 +904,18 @@ program .helpOption('-e, --HELP', 'read more information'); ``` -### .addHelpCommand() +### .helpCommand() -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)`. +A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.helpCommand(true)` and `.helpCommand(false)`. You can both turn on and customise the help command by supplying the name and description: ```js -program.addHelpCommand('assist [command]', 'show assistance'); +program.helpCommand('assist [command]', 'show assistance'); ``` +(Or use `.addHelpCommand()` to add a command you construct yourself.) + ### More configuration The built-in help is formatted using the Help class. diff --git a/docs/deprecated.md b/docs/deprecated.md index 74ffb16d6..7dc5bad23 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -15,6 +15,7 @@ They are currently still available for backwards compatibility, but should not b - [Short option flag longer than a single character](#short-option-flag-longer-than-a-single-character) - [Import from `commander/esm.mjs`](#import-from-commanderesmmjs) - [cmd.\_args](#cmd_args) + - [.addHelpCommand(string|boolean|undefined)](#addhelpcommandstringbooleanundefined) - [Removed](#removed) - [Default import of global Command object](#default-import-of-global-command-object) @@ -205,6 +206,27 @@ const registeredArguments = program.registeredArguments; Deprecated from Commander v11. +### .addHelpCommand(string|boolean|undefined) + +This was originally used with a variety of parameters, but not by passing a Command object despite the "add" name. + +```js +program.addHelpCommand('assist [command]'); +program.addHelpCommand('assist', 'show assistance'); +program.addHelpCommand(false); + +``` + +In new code you configure the help command with `.helpCommand()`. Or use `.addHelpCommand()` which now takes a Command object, like `.addCommand()`. + +```js +program.helpCommand('assist [command]'); +program.helpCommand('assist', 'show assistance'); +program.helpCommand(false); + +program.addHelpCommand(new Command('assist').argument('[command]').description('show assistance')); + +``` ## Removed ### Default import of global Command object diff --git a/lib/command.js b/lib/command.js index 8f2d30071..7e568df38 100644 --- a/lib/command.js +++ b/lib/command.js @@ -71,10 +71,9 @@ class Command extends EventEmitter { this._helpDescription = 'display help for command'; this._helpShortFlag = '-h'; this._helpLongFlag = '--help'; - this._addImplicitHelpCommand = undefined; // Deliberately undefined, not decided whether true or false - this._helpCommandName = 'help'; - this._helpCommandnameAndArgs = 'help [command]'; - this._helpCommandDescription = 'display help for command'; + this._addImplicitHelpCommand = undefined; // undecided whether true or false yet, not inherited + /** @type {Command} */ + this._helpCommand = undefined; // lazy initialised, inherited this._helpConfiguration = {}; } @@ -93,9 +92,7 @@ class Command extends EventEmitter { this._helpDescription = sourceCommand._helpDescription; this._helpShortFlag = sourceCommand._helpShortFlag; this._helpLongFlag = sourceCommand._helpLongFlag; - this._helpCommandName = sourceCommand._helpCommandName; - this._helpCommandnameAndArgs = sourceCommand._helpCommandnameAndArgs; - this._helpCommandDescription = sourceCommand._helpCommandDescription; + this._helpCommand = sourceCommand._helpCommand; this._helpConfiguration = sourceCommand._helpConfiguration; this._exitCallback = sourceCommand._exitCallback; this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties; @@ -369,39 +366,76 @@ class Command extends EventEmitter { } /** - * Override default decision whether to add implicit help command. + * Customise or override default help command. By default a help command is automatically added if your command has subcommands. * - * addHelpCommand() // force on - * addHelpCommand(false); // force off - * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details + * program.helpCommand('help [cmd]'); + * program.helpCommand('help [cmd]', 'show help'); + * program.helpCommand(false); // suppress default help command + * program.helpCommand(true); // add help command even if no subcommands * + * @param {string|boolean} enableOrNameAndArgs - enable with custom name and/or arguments, or boolean to override whether added + * @param {string} [description] - custom description * @return {Command} `this` command for chaining */ - addHelpCommand(enableOrNameAndArgs, description) { - if (enableOrNameAndArgs === false) { - this._addImplicitHelpCommand = false; - } else { - this._addImplicitHelpCommand = true; - if (typeof enableOrNameAndArgs === 'string') { - this._helpCommandName = enableOrNameAndArgs.split(' ')[0]; - this._helpCommandnameAndArgs = enableOrNameAndArgs; - } - this._helpCommandDescription = description || this._helpCommandDescription; + helpCommand(enableOrNameAndArgs, description) { + if (typeof enableOrNameAndArgs === 'boolean') { + this._addImplicitHelpCommand = enableOrNameAndArgs; + return this; } + + enableOrNameAndArgs = enableOrNameAndArgs ?? 'help [command]'; + const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/); + const helpDescription = description ?? 'display help for command'; + + const helpCommand = this.createCommand(helpName); + helpCommand.helpOption(false); + if (helpArgs) helpCommand.arguments(helpArgs); + if (helpDescription) helpCommand.description(helpDescription); + + this._addImplicitHelpCommand = true; + this._helpCommand = helpCommand; + return this; } /** - * @return {boolean} - * @package internal use only + * Add prepared custom help command. + * + * @param {(Command|string|boolean)} helpCommand - custom help command, or deprecated enableOrNameAndArgs as for `.helpCommand()` + * @param {string} [deprecatedDescription] - deprecated custom description used with custom name only + * @return {Command} `this` command for chaining */ + addHelpCommand(helpCommand, deprecatedDescription) { + // If not passed an object, call through to helpCommand for backwards compatibility, + // as addHelpCommand was originally used like helpCommand is now. + if (typeof helpCommand !== 'object') { + this.helpCommand(helpCommand, deprecatedDescription); + return this; + } + + this._addImplicitHelpCommand = true; + this._helpCommand = helpCommand; + return this; + } - _hasImplicitHelpCommand() { - if (this._addImplicitHelpCommand === undefined) { - return this.commands.length && !this._actionHandler && !this._findCommand('help'); + /** + * Lazy create help command. + * + * @return {(Command|null)} + * @package + */ + _getHelpCommand() { + const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? + (this.commands.length && !this._actionHandler && !this._findCommand('help')); + + if (hasImplicitHelpCommand) { + if (this._helpCommand === undefined) { + this.helpCommand(undefined, undefined); // use default name and description + } + return this._helpCommand; } - return this._addImplicitHelpCommand; + return null; } /** @@ -1315,7 +1349,7 @@ Expecting one of '${allowedValues.join("', '")}'`); if (operands && this._findCommand(operands[0])) { return this._dispatchSubcommand(operands[0], operands.slice(1), unknown); } - if (this._hasImplicitHelpCommand() && operands[0] === this._helpCommandName) { + if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) { return this._dispatchHelpCommand(operands[1]); } if (this._defaultCommandName) { @@ -1572,7 +1606,7 @@ Expecting one of '${allowedValues.join("', '")}'`); operands.push(arg); if (args.length > 0) unknown.push(...args); break; - } else if (arg === this._helpCommandName && this._hasImplicitHelpCommand()) { + } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) { operands.push(arg); if (args.length > 0) operands.push(...args); break; diff --git a/lib/help.js b/lib/help.js index e2441ed87..586bad8d2 100644 --- a/lib/help.js +++ b/lib/help.js @@ -26,13 +26,8 @@ class Help { visibleCommands(cmd) { const visibleCommands = cmd.commands.filter(cmd => !cmd._hidden); - if (cmd._hasImplicitHelpCommand()) { - // Create a command matching the implicit help command. - const [, helpName, helpArgs] = cmd._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/); - const helpCommand = cmd.createCommand(helpName) - .helpOption(false); - helpCommand.description(cmd._helpCommandDescription); - if (helpArgs) helpCommand.arguments(helpArgs); + const helpCommand = cmd._getHelpCommand(); + if (helpCommand && !helpCommand._hidden) { visibleCommands.push(helpCommand); } if (this.sortSubcommands) { diff --git a/package-lock.json b/package-lock.json index a29166316..94e1aa3fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -725,9 +725,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -748,9 +748,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", + "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1382,9 +1382,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", - "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", + "version": "29.5.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz", + "integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1410,9 +1410,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", - "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1452,16 +1452,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz", + "integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/type-utils": "6.10.0", + "@typescript-eslint/utils": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1487,15 +1487,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", - "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz", + "integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4" }, "engines": { @@ -1515,13 +1515,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1532,9 +1532,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1545,13 +1545,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1572,12 +1572,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1589,13 +1589,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1606,13 +1606,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz", + "integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/utils": "6.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1633,9 +1633,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1646,13 +1646,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1673,17 +1673,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz", + "integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", "semver": "^7.5.4" }, "engines": { @@ -1698,12 +1698,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1721,9 +1721,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2168,6 +2168,18 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -2687,15 +2699,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", + "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.53.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3084,9 +3096,9 @@ } }, "node_modules/eslint-plugin-n": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.2.0.tgz", - "integrity": "sha512-AQER2jEyQOt1LG6JkGJCCIFotzmlcCZFur2wdKrp1JX2cNotC7Ae0BcD/4lLv3lUAArM9uNS8z/fsvXTd0L71g==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.3.1.tgz", + "integrity": "sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", @@ -3094,6 +3106,7 @@ "eslint-plugin-es-x": "^7.1.0", "get-tsconfig": "^4.7.0", "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", "is-core-module": "^2.12.1", "minimatch": "^3.1.2", "resolve": "^1.22.2", @@ -3945,6 +3958,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -5611,9 +5639,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" diff --git a/tests/command.chain.test.js b/tests/command.chain.test.js index 3f907c869..58d8c4af2 100644 --- a/tests/command.chain.test.js +++ b/tests/command.chain.test.js @@ -34,12 +34,54 @@ describe('Command methods that should return this for chaining', () => { expect(result).toBe(program); }); - test('when call .addHelpCommand() then returns this', () => { + test('when call .addHelpCommand(cmd) then returns this', () => { const program = new Command(); - const result = program.addHelpCommand(false); + const result = program.addHelpCommand(new Command('assist')); expect(result).toBe(program); }); + test('when call deprecated .addHelpCommand() then returns this', () => { + const program = new Command(); + const result = program.addHelpCommand(); + expect(result).toBe(program); + }); + + test('when call deprecated .addHelpCommand(boolean) then returns this', () => { + const program = new Command(); + const result1 = program.addHelpCommand(true); + expect(result1).toBe(program); + const result2 = program.addHelpCommand(false); + expect(result2).toBe(program); + }); + + test('when call deprecated .addHelpCommand(string[, string]) then returns this', () => { + const program = new Command(); + const result1 = program.addHelpCommand('assist'); + expect(result1).toBe(program); + const result2 = program.addHelpCommand('assist', 'assist description'); + expect(result2).toBe(program); + }); + + test('when call .helpCommand(name) then returns this', () => { + const program = new Command(); + const result = program.helpCommand(); + expect(result).toBe(program); + }); + + test('when call .helpCommand(name, description) then returns this', () => { + const program = new Command(); + const result1 = program.helpCommand('assist', 'assist description'); + expect(result1).toBe(program); + }); + + test('when call .helpCommand(boolean) then returns this', () => { + const program = new Command(); + const result1 = program.helpCommand(true); + expect(result1).toBe(program); + const result2 = program.helpCommand(false); + expect(result2).toBe(program); + }); + test('when call .exitOverride() then returns this', () => { const program = new Command(); const result = program.exitOverride(() => { }); diff --git a/tests/command.copySettings.test.js b/tests/command.copySettings.test.js index 79722d78b..de06914d7 100644 --- a/tests/command.copySettings.test.js +++ b/tests/command.copySettings.test.js @@ -50,15 +50,28 @@ describe('copyInheritedSettings property tests', () => { expect(cmd._helpLongFlag).toBe('--zz'); }); - test('when copyInheritedSettings then copies addHelpCommand(name, description)', () => { + test('when copyInheritedSettings then copies custom help command', () => { const source = new commander.Command(); const cmd = new commander.Command(); - source.addHelpCommand('HELP [cmd]', 'ddd'); + source.helpCommand('HELP [cmd]', 'ddd'); cmd.copyInheritedSettings(source); - expect(cmd._helpCommandName).toBe('HELP'); - expect(cmd._helpCommandnameAndArgs).toBe('HELP [cmd]'); - expect(cmd._helpCommandDescription).toBe('ddd'); + cmd.helpCommand(true); // force enable + const helpCommand = cmd._getHelpCommand(); + expect(helpCommand).toBeTruthy(); + expect(helpCommand.name()).toBe('HELP'); + expect(helpCommand.description()).toBe('ddd'); + }); + + test('when copyInheritedSettings then does not copy help enable override', () => { + const source = new commander.Command(); + const cmd = new commander.Command(); + + // Existing behaviour, force enable/disable does not inherit, + // largely so (probably redundant) program.helpCommand(true) does not inherit to leaf subcommands. + source.helpCommand(true); + cmd.copyInheritedSettings(source); + expect(cmd._addHelpOption).toBeUndefined(); }); test('when copyInheritedSettings then copies configureHelp(config)', () => { diff --git a/typings/index.d.ts b/typings/index.d.ts index e77cb1bf3..7ca2c49c9 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -419,18 +419,27 @@ export class Command { arguments(names: string): this; /** - * Override default decision whether to add implicit help command. + * Customise or override default help command. By default a help command is automatically added if your command has subcommands. * * @example + * ```ts + * program.helpCommand('help [cmd]'); + * program.helpCommand('help [cmd]', 'show help'); + * program.helpCommand(false); // suppress default help command + * program.helpCommand(true); // add help command even if no subcommands * ``` - * addHelpCommand() // force on - * addHelpCommand(false); // force off - * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details - * ``` - * - * @returns `this` command for chaining */ - addHelpCommand(enableOrNameAndArgs?: string | boolean, description?: string): this; + helpCommand(nameAndArgs: string, description?: string): this; + helpCommand(enable: boolean): this; + + /** + * Add prepared custom help command. + */ + addHelpCommand(cmd: Command): this; + /** @deprecated since v12, instead use helpCommand */ + addHelpCommand(nameAndArgs: string, description?: string): this; + /** @deprecated since v12, instead use helpCommand */ + addHelpCommand(enable?: boolean): this; /** * Add hook for life cycle event. diff --git a/typings/index.test-d.ts b/typings/index.test-d.ts index 22706982b..2a4864ad7 100644 --- a/typings/index.test-d.ts +++ b/typings/index.test-d.ts @@ -59,11 +59,19 @@ expectType(program.argument('[value]', 'description', parseFl expectType(program.arguments(' [env]')); // addHelpCommand +expectType(program.addHelpCommand(new commander.Command('assist'))); +// Deprecated uses expectType(program.addHelpCommand()); expectType(program.addHelpCommand(false)); expectType(program.addHelpCommand(true)); -expectType(program.addHelpCommand('compress ')); -expectType(program.addHelpCommand('compress ', 'compress target file')); +expectType(program.addHelpCommand('assist [cmd]')); +expectType(program.addHelpCommand('assist [file]', 'display help')); + +// helpCommand +expectType(program.helpCommand(false)); +expectType(program.helpCommand(true)); +expectType(program.helpCommand('assist [cmd]')); +expectType(program.helpCommand('assist [file]', 'display help')); // exitOverride expectType(program.exitOverride()); From 09244af7ab71d4241bb9566380db7fd56eceb969 Mon Sep 17 00:00:00 2001 From: John Gee Date: Wed, 17 Jan 2024 22:19:44 +1300 Subject: [PATCH 23/28] Refactor help option implementation to hold actual Option (#2006) --- Readme.md | 2 + lib/command.js | 82 +++++++++++++++++++---------- lib/help.js | 24 ++++----- lib/option.js | 1 - package-lock.json | 70 ++++++++++++------------ package.json | 2 +- tests/command.addHelpOption.test.js | 54 +++++++++++++++++++ tests/command.chain.test.js | 11 +++- tests/command.copySettings.test.js | 13 ++--- typings/index.d.ts | 6 +++ typings/index.test-d.ts | 3 ++ 11 files changed, 184 insertions(+), 84 deletions(-) create mode 100644 tests/command.addHelpOption.test.js diff --git a/Readme.md b/Readme.md index c3241a476..769f4577b 100644 --- a/Readme.md +++ b/Readme.md @@ -904,6 +904,8 @@ program .helpOption('-e, --HELP', 'read more information'); ``` +(Or use `.addHelpOption()` to add an option you construct yourself.) + ### .helpCommand() A help command is added by default if your command has subcommands. You can explicitly turn on or off the implicit help command with `.helpCommand(true)` and `.helpCommand(false)`. diff --git a/lib/command.js b/lib/command.js index 7e568df38..5b16e6031 100644 --- a/lib/command.js +++ b/lib/command.js @@ -7,7 +7,7 @@ const process = require('process'); const { Argument, humanReadableArgName } = require('./argument.js'); const { CommanderError } = require('./error.js'); const { Help } = require('./help.js'); -const { Option, splitOptionFlags, DualOptions } = require('./option.js'); +const { Option, DualOptions } = require('./option.js'); const { suggestSimilar } = require('./suggestSimilar'); class Command extends EventEmitter { @@ -66,11 +66,8 @@ class Command extends EventEmitter { }; this._hidden = false; - this._hasHelpOption = true; - this._helpFlags = '-h, --help'; - this._helpDescription = 'display help for command'; - this._helpShortFlag = '-h'; - this._helpLongFlag = '--help'; + /** @type {(Option | null | undefined)} */ + this._helpOption = undefined; // Lazy created on demand. May be null if help option is disabled. this._addImplicitHelpCommand = undefined; // undecided whether true or false yet, not inherited /** @type {Command} */ this._helpCommand = undefined; // lazy initialised, inherited @@ -87,11 +84,7 @@ class Command extends EventEmitter { */ copyInheritedSettings(sourceCommand) { this._outputConfiguration = sourceCommand._outputConfiguration; - this._hasHelpOption = sourceCommand._hasHelpOption; - this._helpFlags = sourceCommand._helpFlags; - this._helpDescription = sourceCommand._helpDescription; - this._helpShortFlag = sourceCommand._helpShortFlag; - this._helpLongFlag = sourceCommand._helpLongFlag; + this._helpOption = sourceCommand._helpOption; this._helpCommand = sourceCommand._helpCommand; this._helpConfiguration = sourceCommand._helpConfiguration; this._exitCallback = sourceCommand._exitCallback; @@ -1189,7 +1182,7 @@ Expecting one of '${allowedValues.join("', '")}'`); // Fallback to parsing the help flag to invoke the help. return this._dispatchSubcommand(subcommandName, [], [ - this._helpLongFlag || this._helpShortFlag + this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help' ]); } @@ -2001,7 +1994,7 @@ Expecting one of '${allowedValues.join("', '")}'`); return humanReadableArgName(arg); }); return [].concat( - (this.options.length || this._hasHelpOption ? '[options]' : []), + (this.options.length || (this._helpOption !== null) ? '[options]' : []), (this.commands.length ? '[command]' : []), (this.registeredArguments.length ? args : []) ).join(' '); @@ -2122,35 +2115,69 @@ Expecting one of '${allowedValues.join("', '")}'`); } context.write(helpInformation); - if (this._helpLongFlag) { - this.emit(this._helpLongFlag); // deprecated + if (this._getHelpOption()?.long) { + this.emit(this._getHelpOption().long); // deprecated } this.emit('afterHelp', context); this._getCommandAndAncestors().forEach(command => command.emit('afterAllHelp', context)); } /** - * You can pass in flags and a description to override the help - * flags and help description for your command. Pass in false to - * disable the built-in help option. + * You can pass in flags and a description to customise the built-in help option. + * Pass in false to disable the built-in help option. * - * @param {(string | boolean)} [flags] + * @example + * program.helpOption('-?, --help' 'show help'); // customise + * program.helpOption(false); // disable + * + * @param {(string | boolean)} flags * @param {string} [description] * @return {Command} `this` command for chaining */ helpOption(flags, description) { + // Support disabling built-in help option. if (typeof flags === 'boolean') { - this._hasHelpOption = flags; + if (flags) { + this._helpOption = this._helpOption ?? undefined; // preserve existing option + } else { + this._helpOption = null; // disable + } return this; } - this._helpFlags = flags || this._helpFlags; - this._helpDescription = description || this._helpDescription; - const helpFlags = splitOptionFlags(this._helpFlags); - this._helpShortFlag = helpFlags.shortFlag; - this._helpLongFlag = helpFlags.longFlag; + // Customise flags and description. + flags = flags ?? '-h, --help'; + description = description ?? 'display help for command'; + this._helpOption = this.createOption(flags, description); + + return this; + } + /** + * Lazy create help option. + * Returns null if has been disabled with .helpOption(false). + * + * @returns {(Option | null)} the help option + * @package internal use only + */ + _getHelpOption() { + // Lazy create help option on demand. + if (this._helpOption === undefined) { + this.helpOption(undefined, undefined); + } + return this._helpOption; + } + + /** + * Supply your own option to use for the built-in help option. + * This is an alternative to using helpOption() to customise the flags and description etc. + * + * @param {Option} option + * @return {Command} `this` command for chaining + */ + addHelpOption(option) { + this._helpOption = option; return this; } @@ -2212,8 +2239,9 @@ Expecting one of '${allowedValues.join("', '")}'`); */ _outputHelpIfRequested(args) { - const helpOption = this._hasHelpOption && args.find(arg => arg === this._helpLongFlag || arg === this._helpShortFlag); - if (helpOption) { + const helpOption = this._getHelpOption(); + const helpRequested = helpOption && args.find(arg => helpOption.is(arg)); + if (helpRequested) { this.outputHelp(); // (Do not have all displayed text available so only passing placeholder.) this._exit(0, 'commander.helpDisplayed', '(outputHelp)'); diff --git a/lib/help.js b/lib/help.js index 586bad8d2..64e358a0b 100644 --- a/lib/help.js +++ b/lib/help.js @@ -63,19 +63,19 @@ class Help { visibleOptions(cmd) { const visibleOptions = cmd.options.filter((option) => !option.hidden); - // Implicit help - const showShortHelpFlag = cmd._hasHelpOption && cmd._helpShortFlag && !cmd._findOption(cmd._helpShortFlag); - const showLongHelpFlag = cmd._hasHelpOption && !cmd._findOption(cmd._helpLongFlag); - if (showShortHelpFlag || showLongHelpFlag) { - let helpOption; - if (!showShortHelpFlag) { - helpOption = cmd.createOption(cmd._helpLongFlag, cmd._helpDescription); - } else if (!showLongHelpFlag) { - helpOption = cmd.createOption(cmd._helpShortFlag, cmd._helpDescription); - } else { - helpOption = cmd.createOption(cmd._helpFlags, cmd._helpDescription); + // Built-in help option. + const helpOption = cmd._getHelpOption(); + if (helpOption && !helpOption.hidden) { + // Automatically hide conflicting flags. Bit dubious but a historical behaviour that is convenient for single-command programs. + const removeShort = helpOption.short && cmd._findOption(helpOption.short); + const removeLong = helpOption.long && cmd._findOption(helpOption.long); + if (!removeShort && !removeLong) { + visibleOptions.push(helpOption); // no changes needed + } else if (helpOption.long && !removeLong) { + visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description)); + } else if (helpOption.short && !removeShort) { + visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description)); } - visibleOptions.push(helpOption); } if (this.sortOptions) { visibleOptions.sort(this.compareOptions); diff --git a/lib/option.js b/lib/option.js index f06190168..4e047041e 100644 --- a/lib/option.js +++ b/lib/option.js @@ -324,5 +324,4 @@ function splitOptionFlags(flags) { } exports.Option = Option; -exports.splitOptionFlags = splitOptionFlags; exports.DualOptions = DualOptions; diff --git a/package-lock.json b/package-lock.json index 94e1aa3fd..eaa103a17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@typescript-eslint/parser": "^6.7.5", "eslint": "^8.30.0", "eslint-config-standard": "^17.0.0", - "eslint-config-standard-with-typescript": "^39.1.1", + "eslint-config-standard-with-typescript": "^40.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest": "^27.1.7", "eslint-plugin-n": "^16.2.0", @@ -748,9 +748,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", - "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", + "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1487,15 +1487,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz", - "integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", + "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.10.0", - "@typescript-eslint/types": "6.10.0", - "@typescript-eslint/typescript-estree": "6.10.0", - "@typescript-eslint/visitor-keys": "6.10.0", + "@typescript-eslint/scope-manager": "6.13.1", + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/typescript-estree": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", "debug": "^4.3.4" }, "engines": { @@ -1515,13 +1515,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", - "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", + "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.10.0", - "@typescript-eslint/visitor-keys": "6.10.0" + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1532,9 +1532,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", - "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", + "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1545,13 +1545,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", - "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", + "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.10.0", - "@typescript-eslint/visitor-keys": "6.10.0", + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1572,12 +1572,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", - "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", + "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/types": "6.13.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2699,15 +2699,15 @@ } }, "node_modules/eslint": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", - "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", + "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.53.0", + "@eslint/js": "8.54.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2783,9 +2783,9 @@ } }, "node_modules/eslint-config-standard-with-typescript": { - "version": "39.1.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-39.1.1.tgz", - "integrity": "sha512-t6B5Ep8E4I18uuoYeYxINyqcXb2UbC0SOOTxRtBSt2JUs+EzeXbfe2oaiPs71AIdnoWhXDO2fYOHz8df3kV84A==", + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-40.0.0.tgz", + "integrity": "sha512-GXUJcwIXiTQaS3H4etv8a1lejVVdZYaxZNz3g7vt6GoJosQqMTurbmSC4FVGyHiGT/d1TjFr3+47A3xsHhsG+Q==", "dev": true, "dependencies": { "@typescript-eslint/parser": "^6.4.0", diff --git a/package.json b/package.json index f60bd9546..d58797979 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@typescript-eslint/parser": "^6.7.5", "eslint": "^8.30.0", "eslint-config-standard": "^17.0.0", - "eslint-config-standard-with-typescript": "^39.1.1", + "eslint-config-standard-with-typescript": "^40.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest": "^27.1.7", "eslint-plugin-n": "^16.2.0", diff --git a/tests/command.addHelpOption.test.js b/tests/command.addHelpOption.test.js new file mode 100644 index 000000000..48c8e9932 --- /dev/null +++ b/tests/command.addHelpOption.test.js @@ -0,0 +1,54 @@ +const { Command, Option } = require('../'); + +// More complete tests are in command.helpOption.test.js. + +describe('addHelpOption', () => { + let writeSpy; + let writeErrorSpy; + + beforeAll(() => { + // Optional. Suppress expected output to keep test output clean. + writeSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => { }); + writeErrorSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => { }); + }); + + afterEach(() => { + writeSpy.mockClear(); + writeErrorSpy.mockClear(); + }); + + afterAll(() => { + writeSpy.mockRestore(); + writeErrorSpy.mockRestore(); + }); + + test('when addHelpOption has custom flags then custom short flag invokes help', () => { + const program = new Command(); + program + .exitOverride() + .addHelpOption(new Option('-c,--custom-help')); + + expect(() => { + program.parse(['-c'], { from: 'user' }); + }).toThrow('(outputHelp)'); + }); + + test('when addHelpOption has custom flags then custom long flag invokes help', () => { + const program = new Command(); + program + .exitOverride() + .addHelpOption(new Option('-c,--custom-help')); + + expect(() => { + program.parse(['--custom-help'], { from: 'user' }); + }).toThrow('(outputHelp)'); + }); + + test('when addHelpOption with hidden help option then help does not include help option', () => { + const program = new Command(); + program + .addHelpOption(new Option('-c,--custom-help', 'help help help').hideHelp()); + const helpInfo = program.helpInformation(); + expect(helpInfo).not.toMatch(/help/); + }); +}); diff --git a/tests/command.chain.test.js b/tests/command.chain.test.js index 58d8c4af2..b3872f66b 100644 --- a/tests/command.chain.test.js +++ b/tests/command.chain.test.js @@ -172,9 +172,16 @@ describe('Command methods that should return this for chaining', () => { expect(result).toBe(program); }); - test('when call .helpOption() then returns this', () => { + test('when call .helpOption(flags) then returns this', () => { const program = new Command(); - const result = program.helpOption(false); + const flags = '-h, --help'; + const result = program.helpOption(flags); + expect(result).toBe(program); + }); + + test('when call .addHelpOption() then returns this', () => { + const program = new Command(); + const result = program.addHelpOption(new Option('-h, --help')); expect(result).toBe(program); }); diff --git a/tests/command.copySettings.test.js b/tests/command.copySettings.test.js index de06914d7..1127b3c60 100644 --- a/tests/command.copySettings.test.js +++ b/tests/command.copySettings.test.js @@ -31,11 +31,10 @@ describe('copyInheritedSettings property tests', () => { test('when copyInheritedSettings then copies helpOption(false)', () => { const source = new commander.Command(); const cmd = new commander.Command(); - expect(cmd._hasHelpOption).toBeTruthy(); source.helpOption(false); cmd.copyInheritedSettings(source); - expect(cmd._hasHelpOption).toBeFalsy(); + expect(cmd._getHelpOption()).toBe(null); }); test('when copyInheritedSettings then copies helpOption(flags, description)', () => { @@ -44,10 +43,12 @@ describe('copyInheritedSettings property tests', () => { source.helpOption('-Z, --zz', 'ddd'); cmd.copyInheritedSettings(source); - expect(cmd._helpFlags).toBe('-Z, --zz'); - expect(cmd._helpDescription).toBe('ddd'); - expect(cmd._helpShortFlag).toBe('-Z'); - expect(cmd._helpLongFlag).toBe('--zz'); + expect(cmd._getHelpOption()).toBe(source._getHelpOption()); + // const helpOption = cmd._getHelpOption(); + // expect(helpOption.flags).toBe('-Z, --zz'); + // expect(helpOption.description).toBe('ddd'); + // expect(helpOption.short).toBe('-Z'); + // expect(helpOption.long).toBe('--zz'); }); test('when copyInheritedSettings then copies custom help command', () => { diff --git a/typings/index.d.ts b/typings/index.d.ts index 7ca2c49c9..632511c18 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -847,6 +847,12 @@ export class Command { */ helpOption(flags?: string | boolean, description?: string): this; + /** + * Supply your own option to use for the built-in help option. + * This is an alternative to using helpOption() to customise the flags and description etc. + */ + addHelpOption(option: Option): this; + /** * Output help information and exit. * diff --git a/typings/index.test-d.ts b/typings/index.test-d.ts index 2a4864ad7..12d621ea5 100644 --- a/typings/index.test-d.ts +++ b/typings/index.test-d.ts @@ -310,6 +310,9 @@ expectType(program.helpOption('-h,--help', 'custom descriptio expectType(program.helpOption(undefined, 'custom description')); expectType(program.helpOption(false)); +// addHelpOption +expectType(program.addHelpOption(new commander.Option('-h,--help'))); + // addHelpText expectType(program.addHelpText('after', 'text')); expectType(program.addHelpText('afterAll', 'text')); From eed665d5b1b9f0902494462dff120c0db50f72fa Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 20 Jan 2024 09:05:26 +1300 Subject: [PATCH 24/28] Add 12.0.0-1 changes to CHANGELOG --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71141dadd..97c159a8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. +## [12.0.0-1] (2024-01-20) + +### Added + +- `.addHelpOption()` as another way of configuring built-in help option +- `.helpCommand()` for configuring built-in help command + +### Changed + +- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) +- refactor internal implementation of built-in help option +- refactor internal implementation of built-in help command + +### Deprecated + +- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) + + ## [12.0.0-0] (2023-11-11) ### Fixed From 90f3c8a4c99bd03e641ab23210fce8a3c989df8a Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 20 Jan 2024 09:07:40 +1300 Subject: [PATCH 25/28] 12.0.0-1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index eaa103a17..5291dcb0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "commander", - "version": "12.0.0-0", + "version": "12.0.0-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "commander", - "version": "12.0.0-0", + "version": "12.0.0-1", "license": "MIT", "devDependencies": { "@types/jest": "^29.2.4", diff --git a/package.json b/package.json index d58797979..2558d13f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commander", - "version": "12.0.0-0", + "version": "12.0.0-1", "description": "the complete solution for node.js command-line programs", "keywords": [ "commander", From b53109b64644d98acc3e2aaed6c945306941d247 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 20 Jan 2024 09:15:08 +1300 Subject: [PATCH 26/28] Add links in CHANGELOG --- CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97c159a8d..32f2b2baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,18 +12,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added -- `.addHelpOption()` as another way of configuring built-in help option -- `.helpCommand()` for configuring built-in help command +- `.addHelpOption()` as another way of configuring built-in help option ([#2006]) +- `.helpCommand()` for configuring built-in help command ([#2087]) ### Changed -- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) -- refactor internal implementation of built-in help option -- refactor internal implementation of built-in help command +- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) ([#2087]) +- refactor internal implementation of built-in help option ([#2006]) +- refactor internal implementation of built-in help command ([#2087]) ### Deprecated -- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) +- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) ([#2087]) ## [12.0.0-0] (2023-11-11) @@ -1251,6 +1251,7 @@ program [#1969]: https://github.com/tj/commander.js/pull/1969 [#1982]: https://github.com/tj/commander.js/pull/1982 [#1983]: https://github.com/tj/commander.js/pull/1983 +[#2006]: https://github.com/tj/commander.js/pull/2006 [#2010]: https://github.com/tj/commander.js/pull/2010 [#2017]: https://github.com/tj/commander.js/pull/2017 [#2019]: https://github.com/tj/commander.js/pull/2019 @@ -1258,6 +1259,7 @@ program [#2027]: https://github.com/tj/commander.js/pull/2027 [#2055]: https://github.com/tj/commander.js/pull/2055 [#2059]: https://github.com/tj/commander.js/pull/2059 +[#2087]: https://github.com/tj/commander.js/pull/2087 [#1]: https://github.com/tj/commander.js/issues/1 @@ -1337,6 +1339,7 @@ program [#1028]: https://github.com/tj/commander.js/pull/1028 [Unreleased]: https://github.com/tj/commander.js/compare/master...develop +[12.0.0-1]: https://github.com/tj/commander.js/compare/v12.0.0-0...v12.0.0-1 [12.0.0-0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0-0 [11.1.0]: https://github.com/tj/commander.js/compare/v11.0.0...v11.1.0 [11.0.0]: https://github.com/tj/commander.js/compare/v10.0.1...v11.0.0 From 3f44d29975f60f73d9612b4cb3a2826d6dcbdc47 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 27 Jan 2024 13:46:29 +1300 Subject: [PATCH 27/28] Update dependencies preparing for release (#2132) --- package-lock.json | 939 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 512 insertions(+), 429 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b49b479c..cebb7b769 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "eslint-plugin-promise": "^6.1.1", "jest": "^29.3.1", "ts-jest": "^29.0.3", - "tsd": "^0.29.0", + "tsd": "^0.30.4", "typescript": "^5.0.4" }, "engines": { @@ -52,12 +52,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -136,30 +136,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -184,12 +184,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -199,14 +199,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -270,9 +270,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -322,9 +322,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -340,32 +340,32 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", @@ -448,9 +448,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -520,9 +520,9 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", - "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -622,9 +622,9 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", - "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.22.5" @@ -637,34 +637,34 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -681,12 +681,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, @@ -716,9 +716,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -747,6 +747,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "8.56.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", @@ -757,19 +779,41 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -784,9 +828,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -1214,9 +1258,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1265,9 +1309,9 @@ "dev": true }, "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -1283,18 +1327,18 @@ } }, "node_modules/@tsd/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-VtjHPAKJqLJoHHKBDNofzvQB2+ZVxjXU/Gw6INAS9aINLQYVsxfzrQ2s84huCeYWZRTtrr7R0J7XgpZHjNwBCw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==", "dev": true, "engines": { "node": ">=14.17" } }, "node_modules/@types/babel__core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", - "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1305,18 +1349,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.5", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", - "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", - "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1324,9 +1368,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", - "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -1343,39 +1387,39 @@ } }, "node_modules/@types/estree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/graceful-fs": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz", - "integrity": "sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-gPQuzaPR5h/djlAv2apEG1HVOyj1IUs7GpfMZixU0/0KXT3pm64ylHuMUI1/Akh+sq/iikxg6Z2j+fcMDXaaTQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-kv43F9eb3Lhj+lr/Hn6OcLCs/sSM8bt+fIaP11rCYngfV6NVjzWXJ17owQtDQTL9tQ8WSLUrGsSJ6rJz0F1w1A==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" @@ -1392,9 +1436,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -1404,64 +1448,64 @@ "dev": true }, "node_modules/@types/minimist": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz", - "integrity": "sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, "node_modules/@types/node": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", - "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "version": "20.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.7.tgz", + "integrity": "sha512-GPmeN1C3XAyV5uybAf4cMLWT9fDWcmQhZVtMFu7OR32WjrqGG+Wnk2V1d0bmtUyE/Zy1QJ9BxyiTih9z8Oks8A==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.28", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", - "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", - "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", + "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/type-utils": "6.18.0", - "@typescript-eslint/utils": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/type-utils": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1487,15 +1531,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", - "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", + "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4" }, "engines": { @@ -1514,88 +1558,14 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", - "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", - "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", - "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", - "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.1", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", - "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0" + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1606,13 +1576,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", - "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", + "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.18.0", - "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/utils": "6.19.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1633,9 +1603,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", - "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1646,13 +1616,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", - "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/visitor-keys": "6.18.0", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1673,42 +1643,18 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", - "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", + "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.18.0", - "@typescript-eslint/types": "6.18.0", - "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", "semver": "^7.5.4" }, "engines": { @@ -1723,12 +1669,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", - "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/types": "6.19.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2113,13 +2059,12 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2135,9 +2080,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", + "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", "dev": true, "funding": [ { @@ -2154,9 +2099,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", + "caniuse-lite": "^1.0.30001580", + "electron-to-chromium": "^1.4.648", + "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, "bin": { @@ -2215,13 +2160,14 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2263,9 +2209,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001549", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz", - "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==", + "version": "1.0.30001580", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", + "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", "dev": true, "funding": [ { @@ -2577,9 +2523,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.554", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz", - "integrity": "sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ==", + "version": "1.4.648", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz", + "integrity": "sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==", "dev": true }, "node_modules/emittery": { @@ -2610,26 +2556,26 @@ } }, "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -2639,7 +2585,7 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", @@ -2653,7 +2599,7 @@ "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -2663,26 +2609,26 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -2778,6 +2724,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-compat-utils": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", + "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/eslint-config-standard": { "version": "17.1.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", @@ -2894,13 +2852,14 @@ } }, "node_modules/eslint-plugin-es-x": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.2.0.tgz", - "integrity": "sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz", + "integrity": "sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.6.0" + "@eslint-community/regexpp": "^4.6.0", + "eslint-compat-utils": "^0.1.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -2913,9 +2872,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { "array-includes": "^3.1.7", @@ -2934,7 +2893,7 @@ "object.groupby": "^1.0.1", "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -2943,6 +2902,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -2964,6 +2933,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2974,9 +2955,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz", - "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==", + "version": "27.6.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.3.tgz", + "integrity": "sha512-+YsJFVH6R+tOiO3gCJon5oqn4KWc+mDq2leudk8mrp8RFubLOo9CVyi3cib4L7XMpxExmkmBZQTPDYVBzgpgOA==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -3121,15 +3102,16 @@ } }, "node_modules/eslint-plugin-n": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.3.1.tgz", - "integrity": "sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==", + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.1.0", + "eslint-plugin-es-x": "^7.5.0", "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", "ignore": "^5.2.4", "is-builtin-module": "^3.2.1", "is-core-module": "^2.12.1", @@ -3147,6 +3129,28 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-plugin-n/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-n/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", @@ -3193,6 +3197,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -3320,9 +3346,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3360,9 +3386,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", + "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -3418,9 +3444,9 @@ } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { "flatted": "^3.2.9", @@ -3428,7 +3454,7 @@ "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { @@ -3521,15 +3547,15 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3616,6 +3642,28 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -3699,15 +3747,6 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3727,12 +3766,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3835,9 +3874,9 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -3913,13 +3952,13 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -4252,9 +4291,9 @@ "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -5181,15 +5220,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -5234,9 +5276,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-package-data": { @@ -5276,9 +5318,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", - "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5294,13 +5336,13 @@ } }, "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -6005,13 +6047,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -6023,15 +6065,18 @@ } }, "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", "is-regex": "^1.1.4" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6069,6 +6114,22 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -6169,9 +6230,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -6394,6 +6455,28 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6449,9 +6532,9 @@ } }, "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", + "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -6467,7 +6550,7 @@ "ts-jest": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", @@ -6492,9 +6575,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -6525,12 +6608,12 @@ } }, "node_modules/tsd": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.29.0.tgz", - "integrity": "sha512-5B7jbTj+XLMg6rb9sXRBGwzv7h8KJlGOkTHxY63eWpZJiQ5vJbXEjL0u7JkIxwi5EsrRE1kRVUWmy6buK/ii8A==", + "version": "0.30.4", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.4.tgz", + "integrity": "sha512-ncC4SwAeUk0OTcXt5h8l0/gOLHJSp9ogosvOADT6QYzrl0ITm398B3wkz8YESqefIsEEwvYAU8bvo7/rcN/M0Q==", "dev": true, "dependencies": { - "@tsd/typescript": "~5.2.2", + "@tsd/typescript": "~5.3.3", "eslint-formatter-pretty": "^4.1.0", "globby": "^11.0.1", "jest-diff": "^29.0.3", @@ -6738,9 +6821,9 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -6802,13 +6885,13 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" diff --git a/package.json b/package.json index 2558d13f5..f2e583f66 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "eslint-plugin-promise": "^6.1.1", "jest": "^29.3.1", "ts-jest": "^29.0.3", - "tsd": "^0.29.0", + "tsd": "^0.30.4", "typescript": "^5.0.4" }, "types": "typings/index.d.ts", From 608eaf0b8b550a34c7c5a2045e6d2d9b82add442 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sat, 3 Feb 2024 14:44:25 +1300 Subject: [PATCH 28/28] Update CHANGELOG for v12 (#2133) --- CHANGELOG.md | 31 +++++++++++++++++-------------- SECURITY.md | 4 ++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f2b2baf..ab9955aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,26 +8,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. -## [12.0.0-1] (2024-01-20) +## [12.0.0] (2024-02-03) ### Added - `.addHelpOption()` as another way of configuring built-in help option ([#2006]) - `.helpCommand()` for configuring built-in help command ([#2087]) -### Changed - -- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) ([#2087]) -- refactor internal implementation of built-in help option ([#2006]) -- refactor internal implementation of built-in help command ([#2087]) - -### Deprecated - -- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) ([#2087]) - - -## [12.0.0-0] (2023-11-11) - ### Fixed - *Breaking:* use non-zero exit code when spawned executable subcommand terminates due to a signal ([#2023]) @@ -40,6 +27,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - *Breaking:* throw an error if add a command with name or alias which is already in use ([#2059]) - *Breaking:* throw error when calling `.storeOptionsAsProperties()` after setting an option value ([#1928]) - replace non-standard JSDoc of `@api private` with documented `@private` ([#1949]) +- `.addHelpCommand()` now takes a Command (passing string or boolean still works as before but deprecated) ([#2087]) +- refactor internal implementation of built-in help option ([#2006]) +- refactor internal implementation of built-in help command ([#2087]) + +### Deprecated + +- `.addHelpCommand()` passing string or boolean (use `.helpCommand()` or pass a Command) ([#2087]) ### Removed @@ -63,6 +57,14 @@ A couple of configuration problems now throw an error, which will pick up issues - adding an option which uses the same flag as a previous option - adding a command which uses the same name or alias as a previous command +## [12.0.0-1] (2024-01-20) + +(Released in 12.0.0) + +## [12.0.0-0] (2023-11-11) + +(Released in 12.0.0) + ## [11.1.0] (2023-10-13) ### Fixed @@ -1339,6 +1341,7 @@ program [#1028]: https://github.com/tj/commander.js/pull/1028 [Unreleased]: https://github.com/tj/commander.js/compare/master...develop +[12.0.0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0 [12.0.0-1]: https://github.com/tj/commander.js/compare/v12.0.0-0...v12.0.0-1 [12.0.0-0]: https://github.com/tj/commander.js/compare/v11.1.0...v12.0.0-0 [11.1.0]: https://github.com/tj/commander.js/compare/v11.0.0...v11.1.0 diff --git a/SECURITY.md b/SECURITY.md index 206825ea1..d0cadc185 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,8 +6,8 @@ Old versions receive security updates for six months. | Version | Supported | | ------- | ------------------------------------------ | -| 10.x | :white_check_mark: support ends 2024-01-16 | -| < 10 | :x: | +| 11.x | :white_check_mark: support ends 2024-07-03 | +| < 11 | :x: | Pull Requests for security issues will be considered for older versions back to 2.x.