@@ -9,6 +9,7 @@ import {LogEventListener, LogEventLogger} from '../listeners/LogEventListener';
99import { ProgressEventListener } from '../listeners/ProgressEventListener' ;
1010import { ConfigActionSummaryViewer } from '../viewers/ActionSummaryViewer' ;
1111import { AnnotatedConfigModel , ConfigModel } from '../models/ConfigModel' ;
12+ import { EnginePlugin } from "@salesforce/code-analyzer-engine-api" ;
1213
1314export type ConfigDependencies = {
1415 configFactory : CodeAnalyzerConfigFactory ;
@@ -35,47 +36,70 @@ export class ConfigAction {
3536 }
3637
3738 public async execute ( input : ConfigInput ) : Promise < void > {
38- // We need the user's Config and the default Config.
39+
40+ // ==== PREPARE USER's CONFIG AND USER's CODE ANALYZER =========================================================
3941 const userConfig : CodeAnalyzerConfig = this . dependencies . configFactory . create ( input [ 'config-file' ] ) ;
40- const defaultConfig : CodeAnalyzerConfig = CodeAnalyzerConfig . withDefaults ( ) ;
4142
4243 // We always add a Logger Listener to the appropriate listeners list, because we should always be logging.
4344 const logFileWriter : LogFileWriter = await LogFileWriter . fromConfig ( userConfig ) ;
4445 this . dependencies . actionSummaryViewer . viewPreExecutionSummary ( logFileWriter . getLogDestination ( ) ) ;
4546 const logEventLogger : LogEventLogger = new LogEventLogger ( logFileWriter ) ;
4647 this . dependencies . logEventListeners . push ( logEventLogger ) ;
4748
48- // The User's config produces one Core.
4949 const userCore : CodeAnalyzer = new CodeAnalyzer ( userConfig ) ;
50- // The Default config produces two Cores, since we have to run two selections.
51- const defaultCoreForAllRules : CodeAnalyzer = new CodeAnalyzer ( defaultConfig ) ;
52- const defaultCoreForSelectRules : CodeAnalyzer = new CodeAnalyzer ( defaultConfig ) ;
5350
5451 // LogEventListeners should start listening as soon as the User Core is instantiated, since it can start emitting
5552 // relevant events basically immediately.
5653 this . dependencies . logEventListeners . forEach ( listener => listener . listen ( userCore ) ) ;
54+
55+ const enginePlugins : EnginePlugin [ ] = this . dependencies . pluginsFactory . create ( ) ;
56+ const enginePluginModules : string [ ] = userConfig . getCustomEnginePluginModules ( ) ;
57+
58+ const userEnginePromises : Promise < void > [ ] = [
59+ ...enginePlugins . map ( enginePlugin => userCore . addEnginePlugin ( enginePlugin ) ) ,
60+ ...enginePluginModules . map ( pluginModule => userCore . dynamicallyAddEnginePlugin ( pluginModule ) ) ,
61+ ] ;
62+ await Promise . all ( userEnginePromises ) ;
63+
64+
65+ // ==== PREPARE DEFAULT CONFIG (with disable_engine settings kept) AND DEFAULT CODE ANALYZER ===================
66+
67+ // TODO: We are currently only passing in the enginePlugins here which are not all plugins. We need to
68+ // include the dynamically loaded plugins... but dynamicallyAddEnginePlugin loads and adds and so we never get
69+ // access to the plugins. We need to update core to separate the concerns so that we just have a
70+ // dynamicallyLoadEnginePlugin to just return the plugin so that we can add these plugins to this list.
71+ // And/Or we could just have the Code Analyzer class return a list of the engines that were disabled so that
72+ // we don't need this helper function here.
73+ const disabledEngines : string [ ] = getDisabledEngineNames ( enginePlugins , new Set ( userCore . getEngineNames ( ) ) ) ;
74+
75+ type engineDisableInfo = { engines : { [ key : string ] : { disable_engine : boolean } } } ;
76+ const rawConfigOnlyWithEnginesDisabled : engineDisableInfo = { engines : { } } ;
77+ for ( const engineName of disabledEngines ) {
78+ rawConfigOnlyWithEnginesDisabled . engines [ engineName ] = { disable_engine : true } ;
79+ }
80+ const defaultConfigWithEnginesDisabled : CodeAnalyzerConfig = CodeAnalyzerConfig . fromObject ( rawConfigOnlyWithEnginesDisabled ) ;
81+
82+ // The Default config produces two Cores, since we have to run two selections.
83+ const defaultCoreForAllRules : CodeAnalyzer = new CodeAnalyzer ( defaultConfigWithEnginesDisabled ) ;
84+ const defaultCoreForSelectRules : CodeAnalyzer = new CodeAnalyzer ( defaultConfigWithEnginesDisabled ) ;
85+
5786 // Only the File Logger should listen to the Default Cores, since we don't want to bother the user with redundant
5887 // logs printed to the console.
5988 logEventLogger . listen ( defaultCoreForAllRules ) ;
6089 logEventLogger . listen ( defaultCoreForSelectRules ) ;
6190
62- const enginePlugins = this . dependencies . pluginsFactory . create ( ) ;
63- const enginePluginModules = userConfig . getCustomEnginePluginModules ( ) ;
64-
65- const addEnginePromises : Promise < void > [ ] = [
66- // Assumption: It's safe for the different cores to share the same plugins, because all currently existent
67- // plugins return unique engines every time. This code may fail or behave unexpectedly if a plugin reuses engines.
68- ...enginePlugins . map ( enginePlugin => userCore . addEnginePlugin ( enginePlugin ) ) ,
91+ const defaultEnginePromises : Promise < void > [ ] = [
6992 ...enginePlugins . map ( enginePlugin => defaultCoreForAllRules . addEnginePlugin ( enginePlugin ) ) ,
7093 ...enginePlugins . map ( enginePlugin => defaultCoreForSelectRules . addEnginePlugin ( enginePlugin ) ) ,
71- ...enginePluginModules . map ( pluginModule => userCore . dynamicallyAddEnginePlugin ( pluginModule ) ) ,
7294 // Assumption: Every engine's default configuration is sufficient to allow that engine to be instantiated,
7395 // or throw a clear error indicating the problem.
7496 ...enginePluginModules . map ( pluginModule => defaultCoreForAllRules . dynamicallyAddEnginePlugin ( pluginModule ) ) ,
7597 ...enginePluginModules . map ( pluginModule => defaultCoreForSelectRules . dynamicallyAddEnginePlugin ( pluginModule ) ) ,
7698 ] ;
77- await Promise . all ( addEnginePromises ) ;
99+ await Promise . all ( defaultEnginePromises ) ;
78100
101+
102+ // ==== PERFORM RULE SELECTIONS ================================================================================
79103 const userSelectOptions = input . workspace
80104 ? { workspace : await createWorkspace ( userCore , input . workspace ) }
81105 : undefined ;
@@ -106,8 +130,15 @@ export class ConfigAction {
106130 this . dependencies . progressEventListeners . forEach ( listener => listener . stopListening ( ) ) ;
107131 this . dependencies . logEventListeners . forEach ( listener => listener . stopListening ( ) ) ;
108132
109- // We need the Set of all Engines that returned rules for the user's selection on both the Default and User Cores.
110- const relevantEngines : Set < string > = new Set ( [ ...userRules . getEngineNames ( ) , ...selectedDefaultRules . getEngineNames ( ) ] ) ;
133+
134+ // ==== CREATE AND WRITE CONFIG YAML ===========================================================================
135+
136+ // We need the Set of disabled engines plus all engines that returned rules for the user's selection on both the
137+ // Default and User Cores.
138+ const relevantEngines : Set < string > = new Set ( [
139+ ...disabledEngines ,
140+ ...userRules . getEngineNames ( ) ,
141+ ...selectedDefaultRules . getEngineNames ( ) ] ) ;
111142
112143 const configModel : ConfigModel = new AnnotatedConfigModel ( userCore , userRules , allDefaultRules , relevantEngines ) ;
113144
@@ -126,3 +157,9 @@ export class ConfigAction {
126157 return new ConfigAction ( dependencies )
127158 }
128159}
160+
161+ function getDisabledEngineNames ( allEnginePlugins : EnginePlugin [ ] , enabledEngineNames : Set < string > ) : string [ ] {
162+ return allEnginePlugins . flatMap ( enginePlugin =>
163+ enginePlugin . getAvailableEngineNames ( ) . filter ( engineName => ! enabledEngineNames . has ( engineName ) )
164+ ) ;
165+ }
0 commit comments