file copyright author Vivek M. Chawla <@VivekMChawla>
 *  summary description version license import * as path from 'path' ; import * as Generator from 'yeoman-generator' ; import * as gitHelper from '../sfdx-falcon-util/git' ; import * as listrTasks from '../sfdx-falcon-util/listr-tasks' ; import { SfdxFalconDebug } from '../sfdx-falcon-debug' ; import { SfdxFalconError } from '../sfdx-falcon-error' ; import { SfdxFalconInterview } from '../sfdx-falcon-interview' ; import { SfdxFalconProject } from '../sfdx-falcon-project' ; import { SfdxFalconResult } from '../sfdx-falcon-result' ; import { SfdxFalconKeyValueTable } from '../sfdx-falcon-util/ux' ; import { SfdxFalconTableData } from '../sfdx-falcon-util/ux' ; import { GeneratorStatus } from '../sfdx-falcon-util/yeoman' ; import { GeneratorOptions } from '../sfdx-falcon-yeoman-command' ; import { ListrContextFinalizeGit } from '../sfdx-falcon-types' ; import { SfdxFalconProjectConfig } from '../sfdx-falcon-types' ; const chalk = require ( 'chalk' ) ; const { version } = require ( '../../../package.json' ) ; const { falcon } = require ( '../../../package.json' ) ; const yosay = require ( 'yosay' ) ; const dbgNs = 'GENERATOR:sfdx-falcon-yeoman-generator:' ; class extends Generator summary description public abstract export abstract class SfdxFalconYeomanGenerator < T extends object > extends Generator { protected cliCommandName : string ; protected pluginVersion : string ; protected sfdcApiVersion : string ; protected successMessage : string ; protected failureMessage : string ; protected warningMessage : string ; protected openingMessage : string ; protected generatorStatus : GeneratorStatus ; protected generatorResult : SfdxFalconResult ; protected generatorType : string ; protected installComplete : boolean ; protected falconTable : SfdxFalconKeyValueTable ; protected userInterview : SfdxFalconInterview < T > ; protected defaultAnswers : T ; protected finalAnswers : T ; protected metaAnswers : T ; protected confirmationQuestion : string ; protected sharedData : object ; constructs param { string | string [ ] } args param { GeneratorOptions } opts description public constructor ( args , opts ) { if ( ( opts . generatorResult instanceof SfdxFalconResult ) !== true ) { throw new SfdxFalconError ( `Options provided to SfdxFalconYeomanGenerator must have ` + `a 'generatorResult' key containing an SfdxFalconResult object.` , `InvalidOption` , `${ dbgNs }constructor` ) ; } super ( args , opts ) ; this . cliCommandName = opts . commandName ; this . generatorType = opts . generatorType ; this . generatorResult = opts . generatorResult ; this . generatorStatus = new GeneratorStatus ( ) ; this . pluginVersion = version ; this . sfdcApiVersion = falcon . sfdcApiVersion ; this . installComplete = false ; this . falconTable = new SfdxFalconKeyValueTable ( ) ; this . defaultAnswers = { } as T ; this . finalAnswers = { } as T ; this . metaAnswers = { } as T ; this . sharedData = { } as object ; this . successMessage = `${ this . cliCommandName } completed successfully` ; this . failureMessage = `${ this . cliCommandName } exited without completing the expected tasks` ; this . warningMessage = `${ this . cliCommandName } completed successfully, but with some warnings (see above)` ; this . openingMessage = `SFDX-Falcon Plugin\n${ this . cliCommandName }\nv${ this . pluginVersion }` ; this . generatorStatus . start ( ) ; this . generatorResult . setDetail ( { generatorType : this . generatorType , generatorStatus : this . generatorStatus , userAnswers : null , defaultAnswers : this . defaultAnswers , finalAnswers : this . finalAnswers , interviewQuestions : null } ) ; this . confirmationQuestion = 'Would you like to proceed based on the above settings?' ; SfdxFalconDebug . str ( `${ dbgNs }constructor:` , this . cliCommandName , `this.cliCommandName: ` ) ; SfdxFalconDebug . str ( `${ dbgNs }constructor:` , this . installComplete as unknown as string , `this.installComplete: ` ) ; SfdxFalconDebug . obj ( `${ dbgNs }constructor:` , this . defaultAnswers as unknown as object , `this.defaultAnswers: ` ) ; } protected abstract _buildInterview ( ) ; protected abstract async _buildInterviewAnswersTableData ( userAnswers ) ; method returns { Promise < string > } description protected async protected async _cloneRepository ( ) { const targetDirectory = this . finalAnswers [ 'targetDirectory' ] ; const gitRemoteUri = this [ 'gitRemoteUri' ] ; const gitCloneDirectory = this [ 'gitCloneDirectory' ] || gitHelper . getRepoNameFromUri ( gitRemoteUri ) ; const localProjectPath = path . join ( targetDirectory , gitCloneDirectory ) ; this . log ( chalk `{yellow Cloning Project...}` ) ; return await listrTasks . cloneGitRemote . call ( this , gitRemoteUri , targetDirectory , gitCloneDirectory ) . run ( ) . then ( listrContext => { this . generatorStatus . addMessage ( { type : 'success' , title : `Project Cloned Successfully` , message : `Project cloned to ${ localProjectPath }` } ) ; return localProjectPath ; } ) . catch ( gitCloneError => { this . generatorStatus . abort ( { type : 'error' , title : `Git Clone Error` , message : gitCloneError . cause ? String ( gitCloneError . cause . message ) . trim ( ) : gitCloneError . message } ) ; return '' ; } ) ; } method returns { Promise < void > } description protected async protected async _default_initializing ( ) { this . log ( yosay ( this . openingMessage ) ) ; try { await this . _executeInitializationTasks ( ) ; } catch ( initializationError ) { SfdxFalconDebug . obj ( `${ dbgNs }default_initializing:` , initializationError , `initializationError: ` ) ; this . generatorStatus . abort ( { type : 'error' , title : 'Initialization Error' , message : `${ this . cliCommandName } command aborted because one or more initialization tasks failed` } ) ; throw new SfdxFalconError ( `Command initialization failed. ${ initializationError . message }` , `InitializationError` , `${ dbgNs }default_initializing` , SfdxFalconError . wrap ( initializationError ) ) ; } console . log ( '' ) ; } method returns { Promise < void > } description protected async protected async _default_prompting ( ) { if ( this . generatorStatus . aborted ) { SfdxFalconDebug . msg ( `${ dbgNs }prompting:` , `generatorStatus.aborted found as TRUE inside prompting()` ) ; return ; } this . userInterview = this . _buildInterview ( ) ; this . finalAnswers = await this . userInterview . start ( ) ; ( this . generatorResult . detail as object ) [ 'userAnswers' ] = this . userInterview . userAnswers ; if ( this . userInterview . status . aborted ) { this . generatorStatus . abort ( { type : 'error' , title : 'Command Aborted' , message : `${ this . cliCommandName } canceled by user. ${ this . userInterview . status . reason }` } ) ; } console . log ( '' ) ; return ; } method returns { void } description protected protected _default_configuring ( ) { if ( this . generatorStatus . aborted ) { SfdxFalconDebug . msg ( `${ dbgNs }configuring:` , `generatorStatus.aborted found as TRUE inside configuring()` ) ; return ; } } method returns { void } description protected protected _default_end ( ) { if ( this . generatorStatus . aborted ) { SfdxFalconDebug . msg ( `${ dbgNs }end:` , `generatorStatus.aborted found as TRUE inside end()` ) ; this . generatorStatus . addMessage ( { type : 'error' , title : 'Command Failed' , message : `${ this . failureMessage }\n` } ) ; } else { this . generatorStatus . complete ( [ { type : 'success' , title : 'Command Succeded' , message : this . installComplete ? `${ this . successMessage }\n` : `${ this . warningMessage }\n` } ] ) ; } this . generatorStatus . printStatusMessages ( ) ; return ; } method returns { Promise < void > } description protected async protected async _executeInitializationTasks ( ) { const gitInitTasks = listrTasks . gitInitTasks . call ( this ) ; const sfdxInitTasks = listrTasks . sfdxInitTasks . call ( this ) ; console . log ( chalk `{yellow Initializing ${ this . cliCommandName }...}` ) ; const gitInitResults = await gitInitTasks . run ( ) ; SfdxFalconDebug . obj ( `${ dbgNs }_executeInitializationTasks:` , gitInitResults , `gitInitResults: ` ) ; const sfdxInitResults = await sfdxInitTasks . run ( ) ; SfdxFalconDebug . obj ( `${ dbgNs }_executeInitializationTasks:` , sfdxInitResults , `sfdxInitResults: ` ) ; } method param { string } destinationRoot param { boolean } isInitializingGit param { string } gitRemoteUri param { string } projectAlias returns { Promise < void > } description protected async protected async _finalizeGitActions ( destinationRoot , isInitializingGit , gitRemoteUri , projectAlias ) { if ( isInitializingGit !== true ) { this . generatorStatus . addMessage ( { type : 'success' , title : `Git Initialization` , message : `Skipped - Git initialization skipped at user's request` } ) ; return ; } this . log ( chalk `{yellow Adding project to Git...}` ) ; const finalizeGit = listrTasks . finalizeGit . call ( this , destinationRoot , gitRemoteUri ) ; let finalizeGitCtx = { } as ListrContextFinalizeGit ; try { finalizeGitCtx = await finalizeGit . run ( ) as ListrContextFinalizeGit ; } catch ( listrError ) { SfdxFalconDebug . obj ( `${ dbgNs }_finalizeGitActions:listrError:` , listrError , `listrError: ` ) ; finalizeGitCtx = listrError . context ; } SfdxFalconDebug . obj ( `${ dbgNs }_finalizeGitActions:finalizeGitCtx:` , finalizeGitCtx , `finalizeGitCtx: ` ) ; console . log ( '' ) ; if ( finalizeGitCtx . gitInstalled !== true ) { this . installComplete = false ; this . generatorStatus . addMessage ( { type : 'warning' , title : `Initializing Git` , message : `Warning - git executable not found in your environment - no Git operations attempted` } ) ; return ; } if ( finalizeGitCtx . gitInitialized ) { this . generatorStatus . addMessage ( { type : 'success' , title : `Git Initialization` , message : `Success - Repository created successfully (${ projectAlias })` } ) ; } else { this . installComplete = false ; this . generatorStatus . addMessage ( { type : 'warning' , title : `Git Initialization` , message : `Warning - Git could not be initialized in your project folder` } ) ; return ; } if ( finalizeGitCtx . projectFilesStaged && finalizeGitCtx . projectFilesCommitted ) { this . generatorStatus . addMessage ( { type : 'success' , title : `Git Commit` , message : `Success - Staged all project files and executed the initial commit` } ) ; } else { this . installComplete = false ; this . generatorStatus . addMessage ( { type : 'warning' , title : `Git Commit` , message : `Warning - Attempt to stage and commit project files failed - Nothing to commit` } ) ; } if ( gitRemoteUri ) { if ( finalizeGitCtx . gitRemoteIsValid !== true ) { this . installComplete = false ; this . generatorStatus . addMessage ( { type : 'warning' , title : `Git Remote` , message : `Warning - Could not add Git Remote - ${ gitRemoteUri } is invalid/unreachable` } ) ; } else { if ( finalizeGitCtx . gitRemoteAdded ) { this . generatorStatus . addMessage ( { type : 'success' , title : `Git Remote` , message : `Success - Remote repository ${ gitRemoteUri } added as "origin"` } ) ; } else { this . installComplete = false ; this . generatorStatus . addMessage ( { type : 'warning' , title : `Git Remote` , message : `Warning - Could not add Git Remote - A remote named "origin" already exists` } ) ; } } } return ; } method returns { boolean } description protected protected _finalizeProjectCloning ( ) { if ( this . generatorStatus . aborted ) { SfdxFalconDebug . msg ( `${ dbgNs }_finalizeProjectCloning:` , `generatorStatus.aborted found as TRUE inside install()` ) ; return false ; } if ( ! this . destinationRoot ( ) ) { SfdxFalconDebug . msg ( `${ dbgNs }_finalizeProjectCloning:` , `No value returned by this.destinationRoot(). Skipping finalization tasks.` ) ; return false ; } this . generatorStatus . addMessage ( { type : 'success' , title : `Local Config Created` , message : `.sfdx-falcon/sfdx-falcon-config.json created and customized successfully` } ) ; this . installComplete = true ; console . log ( '' ) ; return true ; } method returns { boolean } description protected protected _finalizeProjectCreation ( ) { if ( this . generatorStatus . aborted ) { SfdxFalconDebug . msg ( `${ dbgNs }_finalizeProjectCreation:` , `generatorStatus.aborted found as TRUE inside install()` ) ; return false ; } if ( ! this . destinationRoot ( ) ) { SfdxFalconDebug . msg ( `${ dbgNs }_finalizeProjectCreation:` , `No value returned by this.destinationRoot(). Skipping finalization tasks.` ) ; return false ; } this . generatorStatus . addMessage ( { type : 'success' , title : `Project Creation` , message : `Success - Project created at ${ this . destinationRoot ( ) }` } ) ; this . installComplete = true ; console . log ( '' ) ; return true ; } method returns { Promise < SfdxFalconProjectConfig > } description protected async protected async _resolveFalconProjectConfig ( projectPath ) { SfdxFalconDebug . obj ( `${ dbgNs }_resolveFalconProjectConfig:arguments:` , arguments , `arguments: ` ) ; const sfdxFalconProjectConfig = await SfdxFalconProject . resolve ( projectPath , { resolveLocalConfig : false } ) . then ( ( sfdxFalconProject ) => { SfdxFalconDebug . obj ( `${ dbgNs }_resolveFalconProjectConfig:sfdxFalconProject:` , sfdxFalconProject , `sfdxFalconProject: ` ) ; return sfdxFalconProject . falconProjectConfig ; } ) . catch ( error => { SfdxFalconDebug . obj ( `${ dbgNs }_resolveFalconProjectConfig:error:` , error , `error: ` ) ; this . generatorStatus . abort ( { type : 'error' , title : `Cloned Project is Invalid` , message : `${ projectPath } does not contain a valid SFDX-Falcon project` } ) ; return null ; } ) as SfdxFalconProjectConfig ; return sfdxFalconProjectConfig ; } }