diff --git a/typings/commander-tests.ts b/typings/commander-tests.ts index 21fcb0ac7..568c6fa7a 100644 --- a/typings/commander-tests.ts +++ b/typings/commander-tests.ts @@ -1,161 +1,187 @@ -import * as program from './index'; - -interface ExtendedOptions extends program.CommandOptions { - isNew: any; -} - -const commandInstance = new program.Command('-f'); -const optionsInstance = new program.Option('-f'); -const errorInstance = new program.CommanderError(1, 'code', 'message'); - -const name = program.name(); +import * as commander from './index'; +import { Script } from 'vm'; + +// Test Commander usage with TypeScript. +// This is NOT a usable program, just used to test for compile errors! + +// Defined stricter type, as the options as properties `[key: string]: any` +// makes the type checking very weak. +// https://github.com/Microsoft/TypeScript/issues/25987#issuecomment-441224690 +type KnownKeys = { + [K in keyof T]: string extends K ? never : number extends K ? never : K +} extends {[_ in keyof T]: infer U} ? ({} extends U ? never : U) : never; +type CommandWithoutOptionsAsProperties = Pick>; + +const program: CommandWithoutOptionsAsProperties = commander.program; +const programWithOptions = commander.program; +// program.silly; // <-- Error, hurrah! + +// Check for exported global Command objects +const importedDefaultProgram: commander.Command = commander; +const importedExplicitProgram: commander.Command = commander.program; + +// Check export classes exist +const commandInstance1 = new commander.Command(); +const commandInstance2 = new commander.Command('name'); +const optionsInstance = new commander.Option('-f'); +const errorInstance = new commander.CommanderError(1, 'code', 'message'); + +// Command properties +console.log(programWithOptions.someOption); +console.log(programWithOptions['someOption']); +const theArgs = program.args; +const theCommands: commander.Command[] = program.commands; + +// version +const versionThis1: commander.Command = program.version('1.2.3'); +const versionThis2: commander.Command = program.version('1.2.3', '-r,--revision'); +const versionThis3: commander.Command = program.version('1.2.3', '-r,--revision', 'show revision information'); + +// command (and CommandOptions) +const commandNew1: commander.Command = program.command('action'); +const commandNew2: commander.Command = program.command('action', { isDefault: true, noHelp: true }); +const commandThis1: commander.Command = program.command('exec', 'exec description'); +const commandThis2: commander.Command = program.command('exec', 'exec description', { isDefault: true, noHelp: true, executableFile: 'foo' }); + +// addCommand +const addCommandThis: commander.Command = program.addCommand(new commander.Command('abc')); + +// arguments +const argumentsThis: commander.Command = program.arguments(' [env]') + +// exitOverride +const exitThis1: commander.Command = program.exitOverride(); +const exitThis2: commander.Command = program.exitOverride((err):never => { + return process.exit(err.exitCode); +}); +const exitThis3: commander.Command = program.exitOverride((err):void => { + if (err.code !== 'commander.executeSubCommandAsync') { + throw err; + } else { + // Async callback from spawn events, not useful to throw. + } +}); -program.storeOptionsAsProperties(true); -program.passCommandToAction(true); +// action +const actionThis1: commander.Command = program.action(() => { }); +const actionThis2: commander.Command = program.action(async () => { }); -program - .name('set name') - .version('0.0.1') - .option('-p, --peppers', 'Add peppers') - .option('-P, --pineapple', 'Add pineapple') - .option('-b, --bbq', 'Add bbq sauce') - .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') - .parse(process.argv); +// option +const optionThis1: commander.Command = program.option('-a,--alpha'); +const optionThis2: commander.Command = program.option('-p, --peppers', 'Add peppers') +const optionThis3: commander.Command = program.option('-s, --string [value]', 'default string', 'value') +const optionThis4: commander.Command = program.option('-b, --boolean', 'default boolean', false); -console.log('you ordered a pizza with:'); -if (program['peppers']) console.log(' - peppers'); -if (program['pineapple']) console.log(' - pineapple'); -if (program['bbq']) console.log(' - bbq'); -console.log(' - %s cheese', program['cheese']); +// example coercion functions from README function range(val: string) { - return val.split('..').map(Number); + return val.split('..').map(Number); } -function list(val: string) { - return val.split(','); +function myParseInt(value: string, dummyPrevious: number) { + return parseInt(value); } -function collect(val: string, memo: string[]) { - memo.push(val); - return memo; +function increaseVerbosity(dummyValue: string, previous: number) { + return previous + 1; } -function increaseVerbosity(v: any, total: number) { - return total + 1; +function collect(value: string, previous: string[]) { + return previous.concat([value]); } -function syncCall() { - console.log("Sync success!"); +function commaSeparatedList(value: string, dummyPrevious: string[]) { + return value.split(','); } -async function asyncCall() { - return; -} - -program - .version('0.0.1') - .usage('[options] ') - .option('-i, --integer ', 'An integer argument', parseInt) - .option('-f, --float ', 'A float argument', parseFloat) - .option('-r, --range ..', 'A range', range) - .option('-l, --list ', 'A list', list) - .option('-o, --optional [value]', 'An optional value') - .option('-c, --collect [value]', 'A repeatable value', collect, []) - .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0) - .parse(process.argv); - -console.log(' int: %j', program['integer']); -console.log(' float: %j', program['float']); -console.log(' optional: %j', program['optional']); -program['range'] = program['range'] || []; -console.log(' range: %j..%j', program['range'][0], program['range'][1]); -console.log(' list: %j', program['list']); -console.log(' collect: %j', program['collect']); -console.log(' verbosity: %j', program['verbose']); -console.log(' args: %j', program['args']); - -program - .version('0.0.1') - .option('-f, --foo', 'enable some foo') - .option('-b, --bar', 'enable some bar') - .option('-B, --baz', 'enable some baz'); - -// must be before .parse() -program.on('--help', () => { - console.log(' Examples:'); - console.log(''); - console.log(' $ custom-help --help'); - console.log(' $ custom-help -h'); - console.log(''); -}); - -program - .command('allow-unknown-option') - .description("description") - .allowUnknownOption() - .action(() => { - console.log('unknown option is allowed'); - }); - -program - .requiredOption('-a,--aaa', 'description') - .requiredOption('-b,--bbb ', 'description') - .requiredOption('-c,--ccc [value]', 'description') - .requiredOption('-d,--ddd ', 'description', 'default value') - .requiredOption('-e,--eee ', 'description', (value, memo) => { return value; }) - .requiredOption('-f,--fff ', 'description', (value, memo) => { return value; }, 'starting value') - .requiredOption('-g,--ggg ', 'description') - .requiredOption('-G,--no-ggg ', 'description for negation'); - -program - .version('0.0.1') - .arguments(' [env]') - .action((cmd, env) => { - console.log(cmd, env); - }); - -program - .command("name1", "description") - .command("name2", "description", { isDefault:true }); - -program - .command("name3").action(syncCall) - .command("name4").action(asyncCall); - -const preparedCommand = new program.Command('prepared'); -program.addCommand(preparedCommand); - -program - .exitOverride(); - -program.exitOverride((err):never => { - console.log(err.code); - console.log(err.message); - console.log(err.nestedError); - return process.exit(err.exitCode); -}); +const optionThis5: commander.Command = program.option('-f, --float ', 'float argument', parseFloat) +const optionThis6: commander.Command = program.option('-f, --float ', 'float argument', parseFloat, 3.2) +const optionThis7: commander.Command = program.option('-i, --integer ', 'integer argument', myParseInt) +const optionThis8: commander.Command = program.option('-i, --integer ', 'integer argument', myParseInt, 5) +const optionThis9: commander.Command = program.option('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0) +const optionThis10: commander.Command = program.option('-c, --collect ', 'repeatable value', collect, []) +const optionThis11: commander.Command = program.option('-l, --list ', 'comma separated list', commaSeparatedList); + +// requiredOption, same tests as option +const requiredOptionThis1: commander.Command = program.requiredOption('-a,--alpha'); +const requiredOptionThis2: commander.Command = program.requiredOption('-p, --peppers', 'Add peppers') +const requiredOptionThis3: commander.Command = program.requiredOption('-s, --string [value]', 'default string', 'value') +const requiredOptionThis4: commander.Command = program.requiredOption('-b, --boolean', 'default boolean', false); + +const requiredOptionThis5: commander.Command = program.requiredOption('-f, --float ', 'float argument', parseFloat) +const requiredOptionThis6: commander.Command = program.requiredOption('-f, --float ', 'float argument', parseFloat, 3.2) +const requiredOptionThis7: commander.Command = program.requiredOption('-i, --integer ', 'integer argument', myParseInt) +const requiredOptionThis8: commander.Command = program.requiredOption('-i, --integer ', 'integer argument', myParseInt, 5) +const requiredOptionThis9: commander.Command = program.requiredOption('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0) +const requiredOptionThis10: commander.Command = program.requiredOption('-c, --collect ', 'repeatable value', collect, []) +const requiredOptionThis11: commander.Command = program.requiredOption('-l, --list ', 'comma separated list', commaSeparatedList); + +// storeOptionsAsProperties +const storeOptionsAsPropertiesThis1: commander.Command = program.storeOptionsAsProperties(); +const storeOptionsAsPropertiesThis2: commander.Command = program.storeOptionsAsProperties(false); + +// passCommandToAction +const passCommandToActionThis1: commander.Command = program.passCommandToAction(); +const passCommandToActionThis2: commander.Command = program.passCommandToAction(false); + +// allowUnknownOption +const allowUnknownOptionThis1: commander.Command = program.allowUnknownOption(); +const allowUnknownOptionThis2: commander.Command = program.allowUnknownOption(false); + +// parse +const parseThis1: commander.Command = program.parse(); +const parseThis2: commander.Command = program.parse(process.argv); +const parseThis3: commander.Command = program.parse(['node', 'script.js'], { from: 'node' }); +const parseThis4: commander.Command = program.parse(['node', 'script.js'], { from: 'electron' }); +const parseThis5: commander.Command = program.parse(['--option'], { from: "user" }); + +// parseAsync, same tests as parse +const parseAsyncThis1: Promise = program.parseAsync(); +const parseAsyncThis2: Promise = program.parseAsync(process.argv); +const parseAsyncThis3: Promise = program.parseAsync(['node', 'script.js'], { from: 'node' }); +const parseAsyncThis4: Promise = program.parseAsync(['node', 'script.js'], { from: 'electron' }); +const parseAsyncThis5: Promise = program.parseAsync(['--option'], { from: "user" }); + +// parseOptions (and ParseOptionsResult) +const { operands, unknown } = program.parseOptions(['node', 'script.js', 'hello']); + +// opts +const opts = program.opts(); +const optsVal1 = opts.foo; +const opstVale2 = opts['bar']; + +// description +const descriptionThis: commander.Command = program.description("my description"); +const descriptionValue: string = program.description(); + +// alias +const aliasThis: commander.Command = program.alias("my alias"); +const aliasValue: string = program.alias(); + +// usage +const usageThis: commander.Command = program.usage("my usage"); +const usageValue: string = program.usage(); + +// name +const nameThis: commander.Command = program.name("my-name"); +const nameValue: string = program.name(); + +// outputHelp +program.outputHelp(); +program.outputHelp((str: string) => { return str }); -program.exitOverride((err):void => { - if (err.code !== 'commander.executeSubCommandAsync') { - throw err; - } else { - // Async callback from spawn events, not useful to throw. - } -}); +// help +program.help(); +program.help((str: string) => { return str }); -program.parse(process.argv); -program.parse(); -program.parse(["foo"], { from: "user" }); -program.parseAsync(process.argv).then(() => { - console.log('parseAsync success'); -}).catch(err => { - console.log('parseAsync failed'); -}); +// helpInformation +const helpInformnationValue: string = program.helpInformation(); -program.help(); -program.outputHelp(); -const info = program.helpInformation(); +// helpOption +const helpOptionThis1: commander.Command = program.helpOption('-h,--help'); +const helpOptionThis2: commander.Command = program.helpOption('-h,--help', 'custom description'); +const helpOptionThis3: commander.Command = program.helpOption(undefined, 'custom description'); -console.log('stuff'); +// on +const onThis: commander.Command = program.on('--help', () => { }) diff --git a/typings/index.d.ts b/typings/index.d.ts index 39b4076e8..ffd7e8c97 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -346,6 +346,7 @@ declare namespace commander { } interface CommanderStatic extends Command { + program: Command; Command: CommandConstructor; Option: OptionConstructor; CommanderError:CommanderErrorConstructor;