Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into release/12.x
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowspawn committed Nov 12, 2023
1 parent 1e72dc3 commit 04e7db5
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 57 deletions.
28 changes: 26 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,32 @@ The version numbering does not follow semantic versioning but instead aligns wit
<!-- markdownlint-disable MD024 -->
<!-- markdownlint-disable MD004 -->

## [12.0.0-0] (2023-11-11)
## [12.0.0-0] (2023-11-12)

### Changed

- update `peerDependencies` to `[email protected]`, which requires Node.js v18 or higher

## [11.1.0] (2023-10-15)

### Added

- `Option` properties: `envVar`, `presetArg` ([#48])
- `Argument` properties: `argChoices`, `defaultValue`, `defaultValueDescription` ([#48])
- `Command` properties: `options`, `registeredArguments` ([#50])

### Changed

- `commands` property of `Command` is now readonly ([#48])
- update `peerDependencies` to `[email protected]` ([#48])

### Fixed

- remove unused `Option.optionFlags` property ([#48])
- add that `Command.version()` can also be used as getter ([#48])
- add null return type to `Commands.executableDir()`, for when not configured ([#48])
- preserve option typings when adding arguments to `Command` ([#49])

## [11.0.0] (2023-06-16)

### Changed
Expand Down Expand Up @@ -119,7 +139,8 @@ The version numbering does not follow semantic versioning but instead aligns wit
- inferred types for `.action()`
- inferred types for `.opts()`

[12.0.0-0]: https://github.com/commander-js/extra-typings/compare/v11.0.0...v12.0.0-0
[12.0.0-0]: https://github.com/commander-js/extra-typings/compare/v11.1.0...v12.0.0-0
[11.1.0]: https://github.com/commander-js/extra-typings/compare/v11.0.0...v11.1.0
[11.0.0]: https://github.com/commander-js/extra-typings/compare/v10.0.3...v11.0.0
[10.0.3]: https://github.com/commander-js/extra-typings/compare/v10.0.2...v10.0.3
[10.0.2]: https://github.com/commander-js/extra-typings/compare/v10.0.1...v10.0.2
Expand All @@ -139,3 +160,6 @@ The version numbering does not follow semantic versioning but instead aligns wit
[#29]: https://github.com/commander-js/extra-typings/pull/29
[#31]: https://github.com/commander-js/extra-typings/pull/31
[#33]: https://github.com/commander-js/extra-typings/pull/33
[#48]: https://github.com/commander-js/extra-typings/pull/48
[#49]: https://github.com/commander-js/extra-typings/pull/49
[#50]: https://github.com/commander-js/extra-typings/pull/50
86 changes: 34 additions & 52 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,10 @@ export class CommanderError extends Error {
description: string;
required: boolean;
variadic: boolean;

defaultValue?: any;
defaultValueDescription?: string;
argChoices?: string[];

/**
* Initialize a new command argument with the given name and description.
* The default is that the argument is required, and you can explicitly
Expand Down Expand Up @@ -259,12 +262,13 @@ export class CommanderError extends Error {
optional: boolean; // A value is optional when the option is specified.
variadic: boolean;
mandatory: boolean; // The option must have a value after parsing, which usually means it must be specified on command line.
optionFlags: string;
short?: string;
long?: string;
negate: boolean;
defaultValue?: any;
defaultValueDescription?: string;
presetArg?: unknown;
envVar?: string;
parseArg?: <T>(value: string, previous: T) => T;
hidden: boolean;
argChoices?: string[];
Expand Down Expand Up @@ -446,15 +450,14 @@ export class CommanderError extends Error {
// The source is a string so author can define their own too.
export type OptionValueSource = LiteralUnion<'default' | 'config' | 'env' | 'cli' | 'implied', string> | undefined;

export interface OptionValues {
[key: string]: unknown;
}
export type OptionValues = Record<string, unknown>;

export class Command<Args extends any[] = [], Opts extends OptionValues = {}> {
args: string[];
processedArgs: Args;
readonly commands: readonly CommandUnknownOpts[];
readonly options: readonly Option[];
readonly registeredArguments: readonly Argument[];
parent: CommandUnknownOpts | null;

constructor(name?: string);
Expand All @@ -468,7 +471,10 @@ export class CommanderError extends Error {
* You can optionally supply the flags and description to override the defaults.
*/
version(str: string, flags?: string, description?: string): this;

/**
* Get the program version.
*/
version(): string | undefined;
/**
* Define a command, implemented using an action handler.
*
Expand Down Expand Up @@ -550,21 +556,21 @@ export class CommanderError extends Error {
* @returns `this` command for chaining
*/
argument<S extends string, T>(
flags: S, description: string, fn: (value: string, previous: T) => T): Command<[...Args, InferArgument<S, undefined, T>]>;
flags: S, description: string, fn: (value: string, previous: T) => T): Command<[...Args, InferArgument<S, undefined, T>], Opts>;
argument<S extends string, T>(
flags: S, description: string, fn: (value: string, previous: T) => T, defaultValue: T): Command<[...Args, InferArgument<S, T, T>]>;
flags: S, description: string, fn: (value: string, previous: T) => T, defaultValue: T): Command<[...Args, InferArgument<S, T, T>], Opts>;
argument<S extends string>(
usage: S, description?: string): Command<[...Args, InferArgument<S, undefined>]>;
usage: S, description?: string): Command<[...Args, InferArgument<S, undefined>], Opts>;
argument<S extends string, DefaultT>(
usage: S, description: string, defaultValue: DefaultT): Command<[...Args, InferArgument<S, DefaultT>]>;
usage: S, description: string, defaultValue: DefaultT): Command<[...Args, InferArgument<S, DefaultT>], Opts>;

/**
* Define argument syntax for command, adding a prepared argument.
*
* @returns `this` command for chaining
*/
addArgument<Usage extends string, DefaultT, CoerceT, ArgRequired extends boolean|undefined, ChoicesT>(
arg: Argument<Usage, DefaultT, CoerceT, ArgRequired, ChoicesT>): Command<[...Args, InferArgument<Usage, DefaultT, CoerceT, ArgRequired, ChoicesT>]>;
arg: Argument<Usage, DefaultT, CoerceT, ArgRequired, ChoicesT>): Command<[...Args, InferArgument<Usage, DefaultT, CoerceT, ArgRequired, ChoicesT>], Opts>;


/**
Expand All @@ -579,7 +585,7 @@ export class CommanderError extends Error {
*
* @returns `this` command for chaining
*/
arguments<Names extends string>(args: Names): Command<[...Args, ...InferArguments<Names>]>;
arguments<Names extends string>(args: Names): Command<[...Args, ...InferArguments<Names>], Opts>;


/**
Expand Down Expand Up @@ -680,45 +686,21 @@ export class CommanderError extends Error {
action(fn: (...args: [...Args, Opts, this]) => void | Promise<void>): this;

/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
* Define option with `flags`, `description`, and optional argument parsing function or `defaultValue` or both.
*
* The `flags` string contains the short and/or long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space. A required
* option-argument is indicated by `<>` and an optional option-argument by `[]`.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
* See the README for more details, and see also addOption() and requiredOption().
*
* @example
* ```
* // simple boolean defaulting to false
* program.option('-p, --pepper', 'add pepper');
*
* --pepper
* program.pepper
* // => Boolean
*
* // simple boolean defaulting to true
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => false
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
* ```js
* program
* .option('-p, --pepper', 'add pepper')
* .option('-p, --pizza-type <TYPE>', 'type of pizza') // required option-argument
* .option('-c, --cheese [CHEESE]', 'add extra cheese', 'mozzarella') // optional option-argument with default
* .option('-t, --tip <VALUE>', 'add tip to purchase cost', parseFloat) // custom parse function
* ```
*
* @returns `this` command for chaining
Expand All @@ -728,9 +710,9 @@ export class CommanderError extends Error {
option<S extends string, DefaultT extends string | boolean | string[] | []>(
usage: S, description?: string, defaultValue?: DefaultT): Command<Args, InferOptions<Opts, S, DefaultT, undefined, false>>;
option<S extends string, T>(
usage: S, description: string, fn: (value: string, previous: T) => T): Command<Args, InferOptions<Opts, S, undefined, T, false>>;
usage: S, description: string, parseArg: (value: string, previous: T) => T): Command<Args, InferOptions<Opts, S, undefined, T, false>>;
option<S extends string, T>(
usage: S, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): Command<Args, InferOptions<Opts, S, T, T, false>>;
usage: S, description: string, parseArg: (value: string, previous: T) => T, defaultValue?: T): Command<Args, InferOptions<Opts, S, T, T, false>>;

/**
* Define a required option, which must have a value after parsing. This usually means
Expand All @@ -743,9 +725,9 @@ export class CommanderError extends Error {
requiredOption<S extends string, DefaultT extends string | boolean | string[]>(
usage: S, description?: string, defaultValue?: DefaultT): Command<Args, InferOptions<Opts, S, DefaultT, undefined, true>>;
requiredOption<S extends string, T>(
usage: S, description: string, fn: (value: string, previous: T) => T): Command<Args, InferOptions<Opts, S, undefined, T, true>>;
usage: S, description: string, parseArg: (value: string, previous: T) => T): Command<Args, InferOptions<Opts, S, undefined, T, true>>;
requiredOption<S extends string, T, D extends T>(
usage: S, description: string, fn: (value: string, previous: T) => T, defaultValue?: D): Command<Args, InferOptions<Opts, S, D, T, true>>;
usage: S, description: string, parseArg: (value: string, previous: T) => T, defaultValue?: D): Command<Args, InferOptions<Opts, S, D, T, true>>;

/**
* Factory routine to create a new unattached option.
Expand Down Expand Up @@ -919,7 +901,7 @@ export class CommanderError extends Error {

description(str: string): this;
/** @deprecated since v8, instead use .argument to add command argument with description */
description(str: string, argsDescription: {[argName: string]: string}): this;
description(str: string, argsDescription: Record<string, string>): this;
/**
* Get the description.
*/
Expand Down Expand Up @@ -1016,7 +998,7 @@ export class CommanderError extends Error {
/**
* Get the executable search directory.
*/
executableDir(): string;
executableDir(): string | null;

/**
* Output help information for this command.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions tests/arguments.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,28 @@ expectType<('C')>(
.parse()
.processedArgs[0]
)

// adding argument preserves options
expectType<({ example?: true })>(
program
.option('--example')
.argument('<arg>', 'arg description')
.parse()
.opts()
)

expectType<({ example?: true })>(
program
.option('--example')
.arguments('<arg1> [arg2]')
.parse()
.opts()
)

expectType<({ example?: true })>(
program
.option('--example')
.addArgument(new Argument('<arg>'))
.parse()
.opts()
)
26 changes: 24 additions & 2 deletions tests/commander.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ expectType<string[]>(program.args);
expectType<[]>(program.processedArgs);
expectType<readonly commander.CommandUnknownOpts[]>(program.commands);
expectType<readonly commander.Option[]>(program.options);
expectType<readonly commander.Argument[]>(program.registeredArguments);
expectType<commander.CommandUnknownOpts | null>(program.parent);

// version
expectChainedCommand(program.version('1.2.3'));
expectChainedCommand(program.version('1.2.3', '-r,--revision'));
expectChainedCommand(program.version('1.2.3', '-r,--revision', 'show revision information'));
expectType<string | undefined>(program.version());

// command (and CommandOptions)
expectChainedCommand(program.command('action'));
Expand Down Expand Up @@ -293,7 +295,7 @@ expectChainedCommand(program.nameFromFilename(__filename));

// executableDir
expectChainedCommand(program.executableDir(__dirname));
expectType<string>(program.executableDir());
expectType<string | null>(program.executableDir());

// outputHelp
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
Expand Down Expand Up @@ -415,9 +417,26 @@ expectType<string>(helper.wrap('a b c', 50, 3));

expectType<string>(helper.formatHelp(helperCommand, helper));

// Option methods
// Option properties

const baseOption = new commander.Option('-f,--foo', 'foo description');
expectType<string>(baseOption.flags);
expectType<string>(baseOption.description);
expectType<boolean>(baseOption.required);
expectType<boolean>(baseOption.optional);
expectType<boolean>(baseOption.variadic);
expectType<boolean>(baseOption.mandatory);
expectType<string | undefined>(baseOption.short);
expectType<string | undefined>(baseOption.long);
expectType<boolean>(baseOption.negate);
expectType<any>(baseOption.defaultValue);
expectType<string | undefined>(baseOption.defaultValueDescription);
expectType<unknown>(baseOption.presetArg);
expectType<string | undefined>(baseOption.envVar);
expectType<boolean>(baseOption.hidden);
expectType<string[] | undefined>(baseOption.argChoices);

// Option methods

// default
expectType<commander.Option>(baseOption.default(3));
Expand Down Expand Up @@ -471,6 +490,9 @@ const baseArgument = new commander.Argument('<foo');
expectType<string>(baseArgument.description);
expectType<boolean>(baseArgument.required);
expectType<boolean>(baseArgument.variadic);
expectType<any>(baseArgument.defaultValue);
expectType<string | undefined>(baseArgument.defaultValueDescription);
expectType<string[] | undefined>(baseArgument.argChoices);

// Argument methods

Expand Down

0 comments on commit 04e7db5

Please sign in to comment.