file copyright author Vivek M. Chawla <@VivekMChawla>
 *  summary description version license import { SfdxFalconDebug } from '../sfdx-falcon-debug' ; import { SfdxFalconPrompt } from '../sfdx-falcon-prompt' ; import { SfdxFalconKeyValueTable } from '../sfdx-falcon-util/ux' ; import { AbortInterview } from '../sfdx-falcon-types' ; import { AnswersDisplay } from '../sfdx-falcon-types' ; import { ConfirmationAnswers } from '../sfdx-falcon-types' ; import { InterviewGroupOptions } from '../sfdx-falcon-types' ; import { InterviewOptions } from '../sfdx-falcon-types' ; import { InterviewStatus } from '../sfdx-falcon-types' ; import { Questions } from '../sfdx-falcon-types' ; import { QuestionsBuilder } from '../sfdx-falcon-types' ; import { ShowInterviewGroup } from '../sfdx-falcon-types' ; const dbgNs = 'MODULE:sfdx-falcon-interview:' ; class summary description public export class InterviewGroup < T extends object > { public readonly title : string ; public readonly abort : AbortInterview ; public when : ShowInterviewGroup ; private readonly falconPrompt : SfdxFalconPrompt < T > ; constructs param { SfdxFalconPrompt < T > } falconPrompt param { AbortInterview } abort param { ShowInterviewGroup } when description public constructor ( falconPrompt , abort ? , when ? , title ? ) { this . falconPrompt = falconPrompt ; this . abort = abort ; this . when = when ; this . title = title ; } method returns { Promise < T > } description public async public async prompt ( ) { if ( this . title ) { console . log ( this . title ) ; } return this . falconPrompt . prompt ( ) ; } } class summary description public export class SfdxFalconInterview < T extends object > { public readonly context : object ; public readonly sharedData : object ; public readonly defaultAnswers : T ; public status : InterviewStatus ; public userAnswers : T ; public when : ShowInterviewGroup ; private readonly _interviewGroups : Array < InterviewGroup < T > > ; private readonly _confirmation : Questions | QuestionsBuilder ; private readonly _confirmationHeader : string ; private readonly _display : AnswersDisplay < T > ; private readonly _displayHeader : string ; private readonly _invertConfirmation : boolean ; public get finalAnswers ( ) : T { return { ... this . defaultAnswers as object , ... this . userAnswers as object } as T ; } constructs param { InterviewOptions < T > } opts description public constructor ( opts ) { this . defaultAnswers = opts . defaultAnswers as T ; this . _confirmation = opts . confirmation ; this . _confirmationHeader = opts . confirmationHeader || '' ; this . _display = opts . display ; this . _displayHeader = opts . displayHeader || '' ; this . _invertConfirmation = opts . invertConfirmation || false ; this . context = opts . context || { } as object ; this . sharedData = opts . sharedData || { } as object ; this . userAnswers = { } as T ; this . _interviewGroups = new Array < InterviewGroup < T > > ( ) ; this . status = { aborted : false , completed : false } ; } method param { InterviewGroupOptions } opts returns { void } description public public createGroup ( opts ) { SfdxFalconDebug . obj ( `${ dbgNs }createGroup:` , arguments , `arguments: ` ) ; const falconPrompt = new SfdxFalconPrompt < T > ( { questions : opts . questions , confirmation : opts . confirmation , invertConfirmation : opts . invertConfirmation , defaultAnswers : this . defaultAnswers , context : this } ) ; const interviewGroup = new InterviewGroup < T > ( falconPrompt , opts . abort , opts . when , opts . title ) ; SfdxFalconDebug . obj ( `${ dbgNs }createGroup:` , interviewGroup , `interviewGroup: ` ) ; this . _interviewGroups . push ( interviewGroup ) ; } method returns { Promise < T > } description public async public async start ( ) { for ( const interviewGroup of this . _interviewGroups ) { if ( await this . skipInterviewGroup ( interviewGroup ) ) { SfdxFalconDebug . msg ( `${ dbgNs }start:` , `Interview Group Skipped! ` ) ; continue ; } SfdxFalconDebug . obj ( `${ dbgNs }start:userAnswers:` , this . userAnswers , `this.userAnswers (PRE-PROMPT): ` ) ; const groupAnswers = await interviewGroup . prompt ( ) ; SfdxFalconDebug . obj ( `${ dbgNs }start:groupAnswers:` , groupAnswers , `groupAnswers: ` ) ; this . userAnswers = { ... this . userAnswers as object , ... groupAnswers as object } as T ; SfdxFalconDebug . obj ( `${ dbgNs }start:userAnswers:` , this . userAnswers , `this.userAnswers (POST-PROMPT): ` ) ; if ( typeof interviewGroup . abort === 'function' ) { const abort = interviewGroup . abort ( groupAnswers , this . userAnswers ) ; if ( abort ) { return this . abortInterview ( abort as string ) ; } } } return await this . proceedRestartAbort ( ) ; } method param { string } returns { T } description private private abortInterview ( message ) { console . log ( `\n${ message }` ) ; this . status . aborted = true ; this . status . completed = false ; this . status . reason = message ; return this . finalAnswers ; } method returns { Promise < void > } description private async private async displayAnswers ( ) { if ( typeof this . _display === 'function' ) { const displayResults = await this . _display ( this . userAnswers ) ; if ( Array . isArray ( displayResults ) ) { const falconTable = new SfdxFalconKeyValueTable ( ) ; if ( this . _displayHeader ) { console . log ( this . _displayHeader ) ; } else { console . log ( '' ) ; } falconTable . render ( displayResults ) ; console . log ( '' ) ; } } } method returns { Promise description private async private async proceedRestartAbort ( ) { SfdxFalconDebug . obj ( `${ dbgNs }proceedRestartAbort:` , this . finalAnswers , `this.finalAnswers: ` ) ; if ( typeof this . _confirmation === 'undefined' ) { SfdxFalconDebug . msg ( `${ dbgNs }proceedRestartAbort:` , `No Confirmation Questions Found. PROCEED by default. ` ) ; return this . finalAnswers ; } await this . displayAnswers ( ) ; if ( this . _confirmationHeader ) { console . log ( this . _confirmationHeader ) ; } const confirmationDefaults = { proceed : false , restart : false } as ConfirmationAnswers ; const confirmationPrompt = new SfdxFalconPrompt < ConfirmationAnswers > ( { questions : this . _confirmation , defaultAnswers : confirmationDefaults , context : this } ) ; const confirmationAnswers = await confirmationPrompt . prompt ( ) ; const invertConfirmation = this . _invertConfirmation ? 1 : 0 ; const proceed = ( invertConfirmation ^ ( confirmationAnswers . proceed ? 1 : 0 ) ) === 1 ? true : false ; const restart = ( invertConfirmation ^ ( confirmationAnswers . restart ? 1 : 0 ) ) === 1 ? true : false ; if ( proceed !== true && restart !== true ) { SfdxFalconDebug . obj ( `${ dbgNs }proceedRestartAbort:` , { confirmationAnswers : confirmationAnswers , invertConfirmation : invertConfirmation , proceed : proceed , restart : restart } , `ABORT DETECTED. Relevant Variables: ` ) ; return this . abortInterview ( 'Command Aborted' ) ; } if ( proceed === true ) { SfdxFalconDebug . obj ( `${ dbgNs }proceedRestartAbort:` , { confirmationAnswers : confirmationAnswers , invertConfirmation : invertConfirmation , proceed : proceed , restart : restart } , `PROCEED DETECTED. Relevant Variables: ` ) ; return this . finalAnswers ; } SfdxFalconDebug . obj ( `${ dbgNs }proceedRestartAbort:` , { confirmationAnswers : confirmationAnswers , invertConfirmation : invertConfirmation , proceed : proceed , restart : restart } , `RESTART DETECTED. Relevant Variables: ` ) ; console . log ( '' ) ; return this . start ( ) ; } method param { InterviewGroup < T > } interviewGroup returns { Promise < boolean > } description private async private async skipInterviewGroup ( interviewGroup ) { if ( typeof interviewGroup . when === 'boolean' ) { return ! interviewGroup . when ; } if ( typeof interviewGroup . when === 'function' ) { return ! interviewGroup . when ( this . userAnswers ) ; } return false ; } }