1616
1717import * as z from 'zod' ;
1818import { commands } from './commands' ;
19+ import { isVariadicArg } from './command' ;
1920
2021import type zodType from 'zod' ;
2122import type { AnyCommandSchema , Category } from './command' ;
2223
23- type CommandArg = { name : string , description : string , optional : boolean } ;
24+ type CommandArg = { name : string , description : string , optional : boolean , variadic : boolean } ;
2425
2526function commandArgs ( command : AnyCommandSchema ) : CommandArg [ ] {
2627 const args : CommandArg [ ] = [ ] ;
2728 const shape = command . args ? ( command . args as zodType . ZodObject < any > ) . shape : { } ;
29+ const names = Object . keys ( shape ) ;
2830 for ( const [ name , schema ] of Object . entries ( shape ) ) {
2931 const zodSchema = schema as zodType . ZodTypeAny ;
3032 const description = zodSchema . description ?? '' ;
31- args . push ( { name, description, optional : zodSchema . safeParse ( undefined ) . success } ) ;
33+ const variadic = name === names [ names . length - 1 ] && isVariadicArg ( zodSchema ) ;
34+ args . push ( { name, description, optional : zodSchema . safeParse ( undefined ) . success , variadic } ) ;
3235 }
3336 return args ;
3437}
3538
39+ function commandArgText ( a : CommandArg ) {
40+ const name = a . variadic ? `${ a . name } ...` : a . name ;
41+ return a . optional ? `[${ name } ]` : `<${ name } >` ;
42+ }
43+
3644function commandArgsText ( args : CommandArg [ ] ) {
37- return args . map ( a => a . optional ? `[ ${ a . name } ]` : `< ${ a . name } >` ) . join ( ' ' ) ;
45+ return args . map ( commandArgText ) . join ( ' ' ) ;
3846}
3947
4048function generateCommandHelp ( command : AnyCommandSchema ) {
@@ -48,7 +56,7 @@ function generateCommandHelp(command: AnyCommandSchema) {
4856
4957 if ( args . length ) {
5058 lines . push ( 'Arguments:' ) ;
51- lines . push ( ...args . map ( a => formatWithGap ( ` ${ a . optional ? `[ ${ a . name } ]` : `< ${ a . name } >` } ` , a . description . toLowerCase ( ) ) ) ) ;
59+ lines . push ( ...args . map ( a => formatWithGap ( ` ${ commandArgText ( a ) } ` , a . description . toLowerCase ( ) ) ) ) ;
5260 }
5361
5462 if ( command . options ) {
@@ -165,7 +173,7 @@ function isBooleanSchema(schema: zodType.ZodTypeAny): boolean {
165173export function generateHelpJSON ( ) {
166174 const booleanOptions = new Set < string > ( ) ;
167175
168- const commandEntries : Record < string , { help : string , flags : Record < string , 'boolean' | 'string' > , args : string [ ] , raw ?: boolean } > = { } ;
176+ const commandEntries : Record < string , { help : string , flags : Record < string , 'boolean' | 'string' > , args : string [ ] , variadicArg ?: boolean , raw ?: boolean } > = { } ;
169177 for ( const [ name , command ] of Object . entries ( commands ) ) {
170178 const flags : Record < string , 'boolean' | 'string' > = { } ;
171179 if ( command . options ) {
@@ -177,8 +185,10 @@ export function generateHelpJSON() {
177185 booleanOptions . add ( flagName ) ;
178186 }
179187 }
180- const args : string [ ] = command . args ? Object . keys ( ( command . args as zodType . ZodObject < any > ) . shape ) : [ ] ;
181- commandEntries [ name ] = { help : generateCommandHelp ( command ) , flags, args } ;
188+ const args = commandArgs ( command ) ;
189+ commandEntries [ name ] = { help : generateCommandHelp ( command ) , flags, args : args . map ( a => a . name ) } ;
190+ if ( args . some ( a => a . variadic ) )
191+ commandEntries [ name ] . variadicArg = true ;
182192 if ( command . raw )
183193 commandEntries [ name ] . raw = true ;
184194 }
0 commit comments