@@ -39,11 +39,30 @@ export class Kernel {
3939 * The concept is similar to Javascript function arguments, you cannot have a
4040 * required argument after an optional argument.
4141 */
42- private _validateArgs ( command : CommandConstructorContract ) {
42+ private _validateCommand ( command : CommandConstructorContract ) {
43+ /**
44+ * Ensure command has a name
45+ */
46+ if ( ! command . commandName ) {
47+ throw new Error ( `missing command name for ${ command . name } class` )
48+ }
49+
4350 let optionalArg : CommandArg
44- command . args . forEach ( ( arg ) => {
51+
52+ command . args . forEach ( ( arg , index ) => {
53+ /**
54+ * Ensure optional arguments comes after required
55+ * arguments
56+ */
4557 if ( optionalArg && arg . required ) {
46- throw new Error ( `Required argument {${ arg . name } } cannot come after optional argument {${ optionalArg . name } }` )
58+ throw new Error ( `option argument {${ optionalArg . name } } must be after required argument {${ arg . name } }` )
59+ }
60+
61+ /**
62+ * Ensure spread arg is the last arg
63+ */
64+ if ( arg . type === 'spread' && command . args . length > index + 1 ) {
65+ throw new Error ( 'spread arguments must be last' )
4766 }
4867
4968 if ( ! arg . required ) {
@@ -52,26 +71,6 @@ export class Kernel {
5271 } )
5372 }
5473
55- /**
56- * Casting runtime flag value to the expected flag value of
57- * the command. Currently, we just need to normalize
58- * arrays.
59- */
60- private _castFlagValue ( flag : CommandFlag , value : any ) : any {
61- return flag . type === 'array' && ! Array . isArray ( value ) ? [ value ] : value
62- }
63-
64- /**
65- * Validates the runtime command line arguments to ensure they satisfy
66- * the length of required arguments for a given command.
67- */
68- private _validateRuntimeArgs ( args : string [ ] , command : CommandConstructorContract ) {
69- const requiredArgs = command ! . args . filter ( ( arg ) => arg . required )
70- if ( args . length < requiredArgs . length ) {
71- throw new Error ( `Missing value for ${ requiredArgs [ args . length ] . name } argument` )
72- }
73- }
74-
7574 /**
7675 * Executing global flag handlers. The global flag handlers are
7776 * not async as of now, but later we can look into making them
@@ -84,10 +83,16 @@ export class Kernel {
8483 const globalFlags = Object . keys ( this . flags )
8584
8685 globalFlags . forEach ( ( name ) => {
87- if ( options [ name ] || options [ name ] === false ) {
88- const value = this . _castFlagValue ( this . flags [ name ] , options [ name ] )
89- this . flags [ name ] . handler ( value , options , command )
86+ const value = options [ name ]
87+ if ( value === undefined ) {
88+ return
89+ }
90+
91+ if ( ( typeof ( value ) === 'string' || Array . isArray ( value ) ) && ! value . length ) {
92+ return
9093 }
94+
95+ this . flags [ name ] . handler ( options [ name ] , options , command )
9196 } )
9297 }
9398
@@ -96,7 +101,7 @@ export class Kernel {
96101 */
97102 public register ( commands : CommandConstructorContract [ ] ) : this {
98103 commands . forEach ( ( command ) => {
99- this . _validateArgs ( command )
104+ this . _validateCommand ( command )
100105 this . commands [ command . commandName ] = command
101106 } )
102107
@@ -181,12 +186,6 @@ export class Kernel {
181186 const parsedOptions = parser . parse ( argv . splice ( 1 ) , command )
182187 this . _executeGlobalFlagsHandlers ( parsedOptions , command )
183188
184- /**
185- * Ensure that the runtime arguments satisfies the command
186- * arguments requirements.
187- */
188- this . _validateRuntimeArgs ( parsedOptions . _ , command )
189-
190189 /**
191190 * Creating a new command instance and setting
192191 * parsed options on it.
@@ -198,12 +197,21 @@ export class Kernel {
198197 * Setup command instance argument and flag
199198 * properties.
200199 */
201- command . args . forEach ( ( arg , index ) => {
202- commandInstance [ arg . name ] = parsedOptions . _ [ index ]
203- } )
200+ for ( let i = 0 ; i < command . args . length ; i ++ ) {
201+ const arg = command . args [ i ]
202+ if ( arg . type === 'spread' ) {
203+ commandInstance [ arg . name ] = parsedOptions . _ . slice ( i )
204+ break
205+ } else {
206+ commandInstance [ arg . name ] = parsedOptions . _ [ i ]
207+ }
208+ }
204209
210+ /**
211+ * Set flag value on the command instance
212+ */
205213 command . flags . forEach ( ( flag ) => {
206- commandInstance [ flag . name ] = this . _castFlagValue ( flag , parsedOptions [ flag . name ] )
214+ commandInstance [ flag . name ] = parsedOptions [ flag . name ]
207215 } )
208216
209217 /**
0 commit comments