From 7e5f15a18d75cd6c3874756009fd604b95ee3fc4 Mon Sep 17 00:00:00 2001 From: Chen Asraf Date: Mon, 29 Jan 2024 00:22:07 +0200 Subject: [PATCH] feat: default value in help --- pnpm-lock.yaml | 6 ++ src/help.ts | 150 ++++++++++++++++++++++++++++--------------------- src/sample.ts | 1 + 3 files changed, 92 insertions(+), 65 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3af9a4b..afd583b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,6 +43,12 @@ devDependencies: ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.11.10)(typescript@5.3.3) + typedoc: + specifier: ^0.25.7 + version: 0.25.7(typescript@5.3.3) + typedoc-plugin-zod: + specifier: ^1.1.2 + version: 1.1.2(typedoc@0.25.7) typescript: specifier: ^5.3.3 version: 5.3.3 diff --git a/src/help.ts b/src/help.ts index 4b0734a..e83d8d2 100644 --- a/src/help.ts +++ b/src/help.ts @@ -24,6 +24,10 @@ export const GenerateTableOptionConfig = GenerateTableCommandConfig.merge( z.object({ /** Whether to display negations with each option name */ displayNegations: z.boolean().optional(), + /** Whether to display the default value with each option (if it has one) */ + displayDefaultValue: z.boolean().optional(), + /** Style of the default value */ + defaultValueStyle: StringStyle.optional(), }), ) export type GenerateTableOptionConfig = z.infer @@ -46,7 +50,11 @@ export const HelpConfig = z.object({ useGlobalTableColumns: z.boolean().default(true).optional(), /** Options for generating the table of commands */ - commandOptions: GenerateTableCommandConfig.omit({ lineLength: true }).optional(), + commandOptions: GenerateTableCommandConfig.omit({ + lineLength: true, + dislayDefaultValue: true, + defaultValueStyle: true, + }).optional(), /** Options for generating the table of options */ optionOptions: GenerateTableOptionConfig.omit({ lineLength: true }).optional(), /** Style of the help title */ @@ -121,12 +129,16 @@ export const defaultHelpConfig: DeepRequired = { namePrefix: DEFAULT_OPT_FULL_PREFIX, aliasPrefix: DEFAULT_OPT_SHORT_PREFIX, displayNegations: false, + displayDefaultValue: true, nameStyle: { color: 'yellow', }, descriptionStyle: { color: 'gray', }, + defaultValueStyle: { + color: 'brightWhite', + }, }, descriptionStyle: {}, exampleOptions: { @@ -188,6 +200,7 @@ export type HelpItem = { description: string hidden?: boolean negatable?: boolean + defaultValue?: any } export class HelpGenerator { @@ -215,9 +228,9 @@ export class HelpGenerator { } const maxNameLength = this.config.useGlobalTableColumns ? Math.max( - getMaxNameLength(entry.options.map((e) => getItemDetails(e, optionOptions))), - getMaxNameLength(entry.commands.map((e) => getItemDetails(e, commandOptions))), - ) + getMaxNameLength(entry.options.map((e) => getItemDetails(e, optionOptions))), + getMaxNameLength(entry.commands.map((e) => getItemDetails(e, commandOptions))), + ) : undefined const options = generateHelpTable(entry.options, optionOptions, maxNameLength).trimEnd() const commands = generateHelpTable(entry.commands, commandOptions, maxNameLength).trimEnd() @@ -230,39 +243,39 @@ export class HelpGenerator { ], ...(description && input && this.config.exampleOptions.compact ? [] : ['']), input && - _subindent( - _wrap( - [ - this.config.exampleOptions.inputPrefix && - format( - this.config.exampleOptions.inputPrefix, - this.config.exampleOptions.prefixStyle, - ), - format(input, this.config.exampleOptions.inputStyle), - ] - .filter(Boolean) - .join(' '), - 4, - ), - (this.config.exampleOptions.inputPrefix ?? '').length + 1, + _subindent( + _wrap( + [ + this.config.exampleOptions.inputPrefix && + format( + this.config.exampleOptions.inputPrefix, + this.config.exampleOptions.prefixStyle, + ), + format(input, this.config.exampleOptions.inputStyle), + ] + .filter(Boolean) + .join(' '), + 4, ), + (this.config.exampleOptions.inputPrefix ?? '').length + 1, + ), output && - _subindent( - _wrap( - [ - this.config.exampleOptions.outputPrefix && - format( - this.config.exampleOptions.outputPrefix, - this.config.exampleOptions.prefixStyle, - ), - format(output, this.config.exampleOptions.outputStyle), - ] - .filter(Boolean) - .join(' '), - 4, - ), - (this.config.exampleOptions.outputPrefix ?? '').length + 1, + _subindent( + _wrap( + [ + this.config.exampleOptions.outputPrefix && + format( + this.config.exampleOptions.outputPrefix, + this.config.exampleOptions.prefixStyle, + ), + format(output, this.config.exampleOptions.outputStyle), + ] + .filter(Boolean) + .join(' '), + 4, ), + (this.config.exampleOptions.outputPrefix ?? '').length + 1, + ), '', ) }) @@ -274,17 +287,17 @@ export class HelpGenerator { _wrap( usageText ? strConcat( - format('Usage:', this.config.usageStyle.prefix), - format(usageText, this.config.usageStyle.main), - ) + format('Usage:', this.config.usageStyle.prefix), + format(usageText, this.config.usageStyle.main), + ) : [ - format(`Usage:`, this.config.usageStyle.prefix), - format(entry.name, this.config.usageStyle.main), - commands.length && format('[command]', this.config.usageStyle.command), - options.length && format('[options]', this.config.usageStyle.options), - ] - .filter(Boolean) - .join(' '), + format(`Usage:`, this.config.usageStyle.prefix), + format(entry.name, this.config.usageStyle.main), + commands.length && format('[command]', this.config.usageStyle.command), + options.length && format('[options]', this.config.usageStyle.options), + ] + .filter(Boolean) + .join(' '), ), headerText.length && ['', format(headerText, this.config.descriptionStyle)], entry.description.length && [ @@ -292,27 +305,27 @@ export class HelpGenerator { _wrap(format(entry.description, this.config.descriptionStyle)), ], commands.length && - indent([ - '', - format( - entry.parent ? `Commands for ${entry.name}:` : 'Commands:', - this.config.subtitleStyle, - ), - '', - indent(commands), - ]), + indent([ + '', + format( + entry.parent ? `Commands for ${entry.name}:` : 'Commands:', + this.config.subtitleStyle, + ), + '', + indent(commands), + ]), options.length && - indent([ - '', - format( - entry.parent ? `Options for ${entry.name}:` : 'Options:', - this.config.subtitleStyle, - ), - '', - indent(options), - ]), + indent([ + '', + format( + entry.parent ? `Options for ${entry.name}:` : 'Options:', + this.config.subtitleStyle, + ), + '', + indent(options), + ]), examples.length && - indent(['', format('Examples:', this.config.subtitleStyle), '', indent(examples)]), + indent(['', format('Examples:', this.config.subtitleStyle), '', indent(examples)]), footerText.length && ['', format(footerText, this.config.descriptionStyle)], ) + '\n' ) @@ -349,6 +362,8 @@ type ParsedHelpItem = { description: string hidden: boolean negatable: boolean + displayNegations: boolean + defaultValue: any } const getMaxNameLength = (items: ParsedHelpItem[]): number => @@ -365,6 +380,7 @@ function getItemDetails( const description = o.description const hidden = o.hidden || false const negatable = (displayNegations && o.negatable) || false + const defaultValue = o.defaultValue ?? null const cmdNames = { full: `${namePrefix}${o.name}`, @@ -380,7 +396,7 @@ function getItemDetails( ] .filter(Boolean) .join(' | ') - return { name, description, hidden, negatable } + return { name, description, hidden, negatable, displayNegations, defaultValue } } function generateHelpTable( @@ -393,6 +409,7 @@ function generateHelpTable format(desc, config.descriptionStyle) const table = rows.map((row) => { const name = nameStyle(row.name.padEnd(maxNameLength! + 2)) - const description = descStyle(row.description) + let description = descStyle(row.description) + if (displayDefaultValue && row.defaultValue != null) { + description += ` ${format(`(default: ${row.defaultValue})`, config.defaultValueStyle)}` + } const length = stripStyle(name).length + stripStyle(description).length if (length <= lineLength) { const line = `${name}${description}` diff --git a/src/sample.ts b/src/sample.ts index ce3bd5e..5e381c8 100644 --- a/src/sample.ts +++ b/src/sample.ts @@ -104,6 +104,7 @@ const main = massarg({ description: 'Example boolean option', aliases: ['b'], negatable: true, + defaultValue: false, }) .option({ name: 'string',