From a6f71e5ee5bca6109ee2adca10cdfad35d486016 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 15 Oct 2023 13:37:41 +1300 Subject: [PATCH 1/4] Preserve option typings when adding arguments to Command (#49) --- index.d.ts | 12 ++++++------ tests/arguments.test-d.ts | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0d7b487..3ab4186 100644 --- a/index.d.ts +++ b/index.d.ts @@ -549,13 +549,13 @@ export class CommanderError extends Error { * @returns `this` command for chaining */ argument( - flags: S, description: string, fn: (value: string, previous: T) => T): Command<[...Args, InferArgument]>; + flags: S, description: string, fn: (value: string, previous: T) => T): Command<[...Args, InferArgument], Opts>; argument( - flags: S, description: string, fn: (value: string, previous: T) => T, defaultValue: T): Command<[...Args, InferArgument]>; + flags: S, description: string, fn: (value: string, previous: T) => T, defaultValue: T): Command<[...Args, InferArgument], Opts>; argument( - usage: S, description?: string): Command<[...Args, InferArgument]>; + usage: S, description?: string): Command<[...Args, InferArgument], Opts>; argument( - usage: S, description: string, defaultValue: DefaultT): Command<[...Args, InferArgument]>; + usage: S, description: string, defaultValue: DefaultT): Command<[...Args, InferArgument], Opts>; /** * Define argument syntax for command, adding a prepared argument. @@ -563,7 +563,7 @@ export class CommanderError extends Error { * @returns `this` command for chaining */ addArgument( - arg: Argument): Command<[...Args, InferArgument]>; + arg: Argument): Command<[...Args, InferArgument], Opts>; /** @@ -578,7 +578,7 @@ export class CommanderError extends Error { * * @returns `this` command for chaining */ - arguments(args: Names): Command<[...Args, ...InferArguments]>; + arguments(args: Names): Command<[...Args, ...InferArguments], Opts>; /** diff --git a/tests/arguments.test-d.ts b/tests/arguments.test-d.ts index d3efffb..76d7aed 100644 --- a/tests/arguments.test-d.ts +++ b/tests/arguments.test-d.ts @@ -385,3 +385,28 @@ expectType<('C')>( .parse() .processedArgs[0] ) + +// adding argument preserves options +expectType<({ example?: true })>( + program + .option('--example') + .argument('', 'arg description') + .parse() + .opts() +) + +expectType<({ example?: true })>( + program + .option('--example') + .arguments(' [arg2]') + .parse() + .opts() +) + +expectType<({ example?: true })>( + program + .option('--example') + .addArgument(new Argument('')) + .parse() + .opts() +) From 8559a139f873d9d03e38ed2e337adf0dea854948 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 15 Oct 2023 13:38:25 +1300 Subject: [PATCH 2/4] Add options and registeredArguments properties to Command (#50) --- index.d.ts | 2 ++ tests/commander.test-d.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/index.d.ts b/index.d.ts index 3ab4186..fd791a5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -454,6 +454,8 @@ export class CommanderError extends Error { args: string[]; processedArgs: Args; commands: CommandUnknownOpts[]; + readonly options: readonly Option[]; + readonly registeredArguments: readonly Argument[]; parent: CommandUnknownOpts | null; constructor(name?: string); diff --git a/tests/commander.test-d.ts b/tests/commander.test-d.ts index d9a0e73..0fde6ec 100644 --- a/tests/commander.test-d.ts +++ b/tests/commander.test-d.ts @@ -41,6 +41,8 @@ expectType(program.args); // eslint-disable-next-line @typescript-eslint/no-explicit-any expectType<[]>(program.processedArgs); expectType(program.commands); +expectType(program.options); +expectType(program.registeredArguments); expectType(program.parent); // version From 264aa11eebf70e92110d11709c3064b384625f3b Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 15 Oct 2023 13:49:19 +1300 Subject: [PATCH 3/4] Update for Commander v11.1.0 (#48) --- CHANGELOG.md | 24 +++++++++++++ index.d.ts | 75 +++++++++++++++------------------------ package-lock.json | 8 ++--- package.json | 4 +-- tests/commander.test-d.ts | 27 ++++++++++++-- 5 files changed, 82 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7fece..d8b5a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,26 @@ The version numbering does not follow semantic versioning but instead aligns wit +## [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 `commander@11.1.x` ([#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 @@ -113,6 +133,7 @@ The version numbering does not follow semantic versioning but instead aligns wit - inferred types for `.action()` - inferred types for `.opts()` +[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 @@ -132,3 +153,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 diff --git a/index.d.ts b/index.d.ts index fd791a5..c250d17 100644 --- a/index.d.ts +++ b/index.d.ts @@ -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 @@ -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?: (value: string, previous: T) => T; hidden: boolean; argChoices?: string[]; @@ -446,14 +450,12 @@ 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; export class Command { args: string[]; processedArgs: Args; - commands: CommandUnknownOpts[]; + readonly commands: readonly CommandUnknownOpts[]; readonly options: readonly Option[]; readonly registeredArguments: readonly Argument[]; parent: CommandUnknownOpts | null; @@ -469,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. * @@ -681,45 +686,21 @@ export class CommanderError extends Error { action(fn: (...args: [...Args, Opts, this]) => void | Promise): 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 ', '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 of pizza') // required option-argument + * .option('-c, --cheese [CHEESE]', 'add extra cheese', 'mozzarella') // optional option-argument with default + * .option('-t, --tip ', 'add tip to purchase cost', parseFloat) // custom parse function * ``` * * @returns `this` command for chaining @@ -729,9 +710,9 @@ export class CommanderError extends Error { option( usage: S, description?: string, defaultValue?: DefaultT): Command>; option( - usage: S, description: string, fn: (value: string, previous: T) => T): Command>; + usage: S, description: string, parseArg: (value: string, previous: T) => T): Command>; option( - usage: S, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): Command>; + usage: S, description: string, parseArg: (value: string, previous: T) => T, defaultValue?: T): Command>; /** * Define a required option, which must have a value after parsing. This usually means @@ -744,9 +725,9 @@ export class CommanderError extends Error { requiredOption( usage: S, description?: string, defaultValue?: DefaultT): Command>; requiredOption( - usage: S, description: string, fn: (value: string, previous: T) => T): Command>; + usage: S, description: string, parseArg: (value: string, previous: T) => T): Command>; requiredOption( - usage: S, description: string, fn: (value: string, previous: T) => T, defaultValue?: D): Command>; + usage: S, description: string, parseArg: (value: string, previous: T) => T, defaultValue?: D): Command>; /** * Factory routine to create a new unattached option. @@ -920,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): this; /** * Get the description. */ @@ -1017,7 +998,7 @@ export class CommanderError extends Error { /** * Get the executable search directory. */ - executableDir(): string; + executableDir(): string | null; /** * Output help information for this command. diff --git a/package-lock.json b/package-lock.json index 167916f..17ba8d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,24 @@ { "name": "@commander-js/extra-typings", - "version": "11.0.0", + "version": "11.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@commander-js/extra-typings", - "version": "11.0.0", + "version": "11.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.2.6", "@types/node": "^18.7.16", - "commander": "~11.0.0", + "commander": "~11.1.0", "jest": "^29.3.1", "ts-jest": "^29.0.5", "tsd": "^0.22.0", "typescript": "^4.7.4" }, "peerDependencies": { - "commander": "11.0.x" + "commander": "11.1.x" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index 1709d84..97a8062 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@commander-js/extra-typings", - "version": "11.0.0", + "version": "11.1.0", "description": "Infer strong typings for commander options and action handlers", "main": "index.js", "scripts": { @@ -45,7 +45,7 @@ ] }, "peerDependencies": { - "commander": "11.0.x" + "commander": "11.1.x" }, "devDependencies": { "@types/jest": "^29.2.6", diff --git a/tests/commander.test-d.ts b/tests/commander.test-d.ts index 0fde6ec..c9f2e41 100644 --- a/tests/commander.test-d.ts +++ b/tests/commander.test-d.ts @@ -40,7 +40,7 @@ expectType(commander.createArgument('')); expectType(program.args); // eslint-disable-next-line @typescript-eslint/no-explicit-any expectType<[]>(program.processedArgs); -expectType(program.commands); +expectType(program.commands); expectType(program.options); expectType(program.registeredArguments); expectType(program.parent); @@ -49,6 +49,7 @@ expectType(program.parent); 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(program.version()); // command (and CommandOptions) expectChainedCommand(program.command('action')); @@ -294,7 +295,7 @@ expectChainedCommand(program.nameFromFilename(__filename)); // executableDir expectChainedCommand(program.executableDir(__dirname)); -expectType(program.executableDir()); +expectType(program.executableDir()); // outputHelp // eslint-disable-next-line @typescript-eslint/no-invalid-void-type @@ -416,9 +417,26 @@ expectType(helper.wrap('a b c', 50, 3)); expectType(helper.formatHelp(helperCommand, helper)); -// Option methods +// Option properties const baseOption = new commander.Option('-f,--foo', 'foo description'); +expectType(baseOption.flags); +expectType(baseOption.description); +expectType(baseOption.required); +expectType(baseOption.optional); +expectType(baseOption.variadic); +expectType(baseOption.mandatory); +expectType(baseOption.short); +expectType(baseOption.long); +expectType(baseOption.negate); +expectType(baseOption.defaultValue); +expectType(baseOption.defaultValueDescription); +expectType(baseOption.presetArg); +expectType(baseOption.envVar); +expectType(baseOption.hidden); +expectType(baseOption.argChoices); + +// Option methods // default expectType(baseOption.default(3)); @@ -472,6 +490,9 @@ const baseArgument = new commander.Argument('(baseArgument.description); expectType(baseArgument.required); expectType(baseArgument.variadic); +expectType(baseArgument.defaultValue); +expectType(baseArgument.defaultValueDescription); +expectType(baseArgument.argChoices); // Argument methods From 78391da7109319c5df7a438d44f6576b8b1496e7 Mon Sep 17 00:00:00 2001 From: John Gee Date: Sun, 15 Oct 2023 14:08:59 +1300 Subject: [PATCH 4/4] Bump version for developer Commander too --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17ba8d1..7140d10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1575,9 +1575,9 @@ "dev": true }, "node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" @@ -5570,9 +5570,9 @@ "dev": true }, "commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true }, "concat-map": { diff --git a/package.json b/package.json index 97a8062..66ac8dc 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "devDependencies": { "@types/jest": "^29.2.6", "@types/node": "^18.7.16", - "commander": "~11.0.0", + "commander": "~11.1.0", "jest": "^29.3.1", "ts-jest": "^29.0.5", "tsd": "^0.22.0",