import { Plugin , PluginPreparer , WorkingDirectoryInfo , CreateQuestionsOptions , RegSuitConfiguration , KeyGeneratorPluginHolder , PublisherPluginHolder , NotifierPlugin , NotifierPluginHolder , } from "reg-suit-interface" ; import { RegLogger , fsUtil } from "reg-suit-util" ; export interface PluginMetadata { moduleId : string ; [ key ] : any ; } function isPublisher ( pluginHolder ) { return ! ! pluginHolder [ "publisher" ] ; } function isKeyGenerator ( pluginHolder ) { return ! ! pluginHolder [ "keyGenerator" ] ; } function isNotifier ( pluginHolder ) { return ! ! pluginHolder [ "notifier" ] ; } export class PluginManager { internal _pluginHolders : PluginMetadata [ ] = [ ] ; constructor ( private _logger , private _noEmit , private _config , private _workingDirs ) { } loadPlugins ( ) { if ( ! this . _config . plugins ) return ; const pluginNames = Object . keys ( this . _config . plugins ) ; pluginNames . forEach ( pluginName => this . _loadPlugin ( pluginName ) ) ; } createQuestions ( opt ) { const noConfigurablePlugins = [ ] ; const preparerHolders = [ ] ; opt . pluginNames . forEach ( name => this . _loadPlugin ( name ) ) ; this . _pluginHolders . forEach ( h => { if ( h [ "preparer" ] ) { preparerHolders . push ( { name : h . moduleId , preparer : h [ "preparer" ] } ) ; } else { noConfigurablePlugins . push ( h . moduleId ) ; } } ) ; return [ ... noConfigurablePlugins . map ( pluginName => { return { name : pluginName , questions : [ ] as any [ ] , prepare : ( ) => Promise . resolve < any > ( true ) , configured : null , } ; } ) , ... preparerHolders . map ( holder => { const questions = holder . preparer . inquire ( ) ; const boundPrepare = ( inquireResult ) => holder . preparer . prepare ( { coreConfig : this . _config . core , workingDirs : this . _workingDirs , logger : this . _logger . fork ( holder . name ) , options : inquireResult , noEmit : this . _noEmit , } ) ; const configured = this . _config . plugins && typeof this . _config . plugins [ holder . name ] === "object" ? this . _config . plugins [ holder . name ] : null ; return { name : holder . name , questions : questions as any [ ] , prepare : boundPrepare , configured , } ; } ) , ] ; } initKeyGenerator ( ) { const metadata = this . _pluginHolders . filter ( holder => isKeyGenerator ( holder ) ) ; if ( metadata . length === 0 ) { this . _logger . verbose ( "No key generator plugin." ) ; return ; } else if ( metadata . length > 1 ) { const pluginNames = metadata . map ( p => p . moduleId ) . join ( ", " ) ; this . _logger . warn ( `2 or more key generator plugins are found. Select one of ${ pluginNames }.` ) ; return ; } const ph = metadata [ 0 ] ; if ( isKeyGenerator ( ph ) ) { return this . _initPlugin ( ph . keyGenerator , ph ) ; } } initPublisher ( ) { const metadata = this . _pluginHolders . filter ( holder => isPublisher ( holder ) ) ; if ( metadata . length === 0 ) { this . _logger . verbose ( "No publisher plugin." ) ; return ; } else if ( metadata . length > 1 ) { const pluginNames = metadata . map ( p => p . moduleId ) . join ( ", " ) ; this . _logger . warn ( `2 or more publisher plugins are found. Select one of ${ pluginNames }.` ) ; return ; } const ph = metadata [ 0 ] ; if ( isPublisher ( ph ) ) { return this . _initPlugin ( ph . publisher , ph ) ; } } initNotifiers ( ) { const notifiers = [ ] ; const metadata = this . _pluginHolders . filter ( holder => isNotifier ( holder ) ) ; if ( metadata . length === 0 ) { this . _logger . verbose ( "No notifier plugin." ) ; } else { metadata . forEach ( ph => { if ( isNotifier ( ph ) ) { const np = this . _initPlugin ( ph . notifier , ph ) ; np && notifiers . push ( np ) ; } } ) ; } return notifiers ; } internal _loadPlugin ( name ) { let pluginFileName = null ; const basedir = fsUtil . prjRootDir ( ) ; try { pluginFileName = require . resolve ( name , { paths : [ basedir ] } ) ; this . _logger . verbose ( `Loaded plugin from ${ this . _logger . colors . magenta ( pluginFileName ) }` ) ; } catch ( e ) { this . _logger . error ( `Failed to load plugin '${ name }'` ) ; throw e ; } if ( pluginFileName ) { const factory = require ( pluginFileName ) ; const pluginHolder = typeof factory ?. default === "function" ? factory . default ( ) : factory ( ) ; this . _pluginHolders . push ( { ... pluginHolder , moduleId : name } ) ; } } private _initPlugin < S extends { disabled ? : boolean ; } , P extends Plugin < S > > ( targetPlugin , metadata ) { let pluginSpecifiedOption ; if ( this . _config . plugins && this . _config . plugins [ metadata . moduleId ] ) { pluginSpecifiedOption = this . _config . plugins [ metadata . moduleId ] ; } else { pluginSpecifiedOption = { disabled : true } as S ; } if ( pluginSpecifiedOption . disabled === true ) { this . _logger . verbose ( `${ metadata . moduleId } is disabled.` ) ; return ; } targetPlugin . init ( { coreConfig : this . _config . core , workingDirs : this . _workingDirs , logger : this . _logger . fork ( metadata . moduleId ) , options : pluginSpecifiedOption , noEmit : this . _noEmit , } ) ; this . _logger . verbose ( `${ metadata . moduleId } is inialized with: ` , pluginSpecifiedOption ) ; return targetPlugin ; } }