@@ -5,7 +5,7 @@ import os from 'os';
55import path from 'path' ;
66import { fileURLToPath , pathToFileURL } from 'url' ;
77import yargs from 'yargs-parser' ;
8- import { ZodError } from 'zod' ;
8+ import { ZodCustomIssue , ZodError , ZodIssue } from 'zod' ;
99import Command , { CommandArgs , CommandError } from '../Command.js' ;
1010import GlobalOptions from '../GlobalOptions.js' ;
1111import config from '../config.js' ;
@@ -186,14 +186,34 @@ async function execute(rawArgs: string[]): Promise<void> {
186186 break ;
187187 }
188188 else {
189- const hasNonRequiredErrors = result . error . errors . some ( e => e . code !== 'invalid_type' || e . received !== 'undefined' ) ;
190189 const shouldPrompt = cli . getSettingWithDefaultValue < boolean > ( settingsNames . prompt , true ) ;
191190
192- if ( hasNonRequiredErrors === false &&
193- shouldPrompt ) {
191+ if ( ! shouldPrompt ) {
192+ result . error . errors . forEach ( e => {
193+ if ( e . code === 'invalid_type' &&
194+ e . received === 'undefined' ) {
195+ e . message = `Required option not specified` ;
196+ }
197+ } ) ;
198+ return cli . closeWithError ( result . error , cli . optionsFromArgs , true ) ;
199+ }
200+
201+ const missingRequiredValuesErrors : ZodIssue [ ] = result . error . errors
202+ . filter ( e => ( e . code === 'invalid_type' && e . received === 'undefined' ) ||
203+ ( e . code === 'custom' && e . params ?. customCode === 'required' ) ) ;
204+ const optionSetErrors : ZodCustomIssue [ ] = result . error . errors
205+ . filter ( e => e . code === 'custom' && e . params ?. customCode === 'optionSet' ) as ZodCustomIssue [ ] ;
206+ const otherErrors : ZodIssue [ ] = result . error . errors
207+ . filter ( e => ! missingRequiredValuesErrors . includes ( e ) && ! optionSetErrors . includes ( e as ZodCustomIssue ) ) ;
208+
209+ if ( otherErrors . some ( e => e ) ) {
210+ return cli . closeWithError ( result . error , cli . optionsFromArgs , true ) ;
211+ }
212+
213+ if ( missingRequiredValuesErrors . some ( e => e ) ) {
194214 await cli . error ( '🌶️ Provide values for the following parameters:' ) ;
195215
196- for ( const error of result . error . errors ) {
216+ for ( const error of missingRequiredValuesErrors ) {
197217 const optionName = error . path . join ( '.' ) ;
198218 const optionInfo = cli . commandToExecute . options . find ( o => o . name === optionName ) ;
199219 const answer = await cli . promptForValue ( optionInfo ! ) ;
@@ -206,15 +226,14 @@ async function execute(rawArgs: string[]): Promise<void> {
206226 return cli . closeWithError ( e . message , cli . optionsFromArgs , true ) ;
207227 }
208228 }
229+
230+ continue ;
209231 }
210- else {
211- result . error . errors . forEach ( e => {
212- if ( e . code === 'invalid_type' &&
213- e . received === 'undefined' ) {
214- e . message = `Required option not specified` ;
215- }
216- } ) ;
217- return cli . closeWithError ( result . error , cli . optionsFromArgs , true ) ;
232+
233+ if ( optionSetErrors . some ( e => e ) ) {
234+ for ( const error of optionSetErrors ) {
235+ await promptForOptionSetNameAndValue ( cli . optionsFromArgs , error . params ?. options ) ;
236+ }
218237 }
219238 }
220239 }
@@ -1057,6 +1076,16 @@ function shouldTrimOutput(output: string | undefined): boolean {
10571076 return output === 'text' ;
10581077}
10591078
1079+ async function promptForOptionSetNameAndValue ( args : CommandArgs , options : string [ ] ) : Promise < void > {
1080+ await cli . error ( `🌶️ Please specify one of the following options:` ) ;
1081+
1082+ const selectedOptionName = await prompt . forSelection < string > ( { message : `Option to use:` , choices : options . map ( ( choice : any ) => { return { name : choice , value : choice } ; } ) } ) ;
1083+ const optionValue = await prompt . forInput ( { message : `${ selectedOptionName } :` } ) ;
1084+
1085+ args . options [ selectedOptionName ] = optionValue ;
1086+ await cli . error ( '' ) ;
1087+ }
1088+
10601089export const cli = {
10611090 closeWithError,
10621091 commands,
0 commit comments