UNPKG

4.42 kBPlain TextView Raw
1import { StrykerOptions, PartialStrykerOptions, strykerCoreSchema } from '@stryker-mutator/api/core';
2import { BaseContext, commonTokens, Injector, tokens } from '@stryker-mutator/api/plugin';
3import { deepFreeze } from '@stryker-mutator/util';
4import { execaCommand } from 'execa';
5
6import { ConfigReader } from '../config/config-reader.js';
7import { LogConfigurator } from '../logging/index.js';
8import { coreTokens, PluginCreator } from '../di/index.js';
9import { TemporaryDirectory } from '../utils/temporary-directory.js';
10import { ConfigError } from '../errors.js';
11import { PluginLoader } from '../di/plugin-loader.js';
12import { reporterPluginsFileUrl } from '../reporters/index.js';
13import { Timer } from '../utils/timer.js';
14import { MetaSchemaBuilder, OptionsValidator } from '../config/index.js';
15import { BroadcastReporter } from '../reporters/broadcast-reporter.js';
16import { UnexpectedExitHandler } from '../unexpected-exit-handler.js';
17
18import { FileSystem, ProjectReader } from '../fs/index.js';
19
20import { MutantInstrumenterContext } from './index.js';
21
22export class PrepareExecutor {
23 public static readonly inject = tokens(commonTokens.injector);
24 constructor(private readonly injector: Injector<BaseContext>) {}
25
26 public async execute(cliOptions: PartialStrykerOptions): Promise<Injector<MutantInstrumenterContext>> {
27 // greedy initialize, so the time starts immediately
28 const timer = new Timer();
29
30 // Already configure the logger, so next classes can use
31 LogConfigurator.configureMainProcess(cliOptions.logLevel, cliOptions.fileLogLevel, cliOptions.allowConsoleColors);
32
33 // Read the config file
34 const configReaderInjector = this.injector
35 .provideValue(coreTokens.validationSchema, strykerCoreSchema)
36 .provideClass(coreTokens.optionsValidator, OptionsValidator);
37 const configReader = configReaderInjector.injectClass(ConfigReader);
38 const options: StrykerOptions = await configReader.readConfig(cliOptions);
39
40 // Load plugins
41 const pluginLoader = configReaderInjector.injectClass(PluginLoader);
42 const pluginDescriptors = [...options.plugins, reporterPluginsFileUrl, ...options.appendPlugins];
43 const loadedPlugins = await pluginLoader.load(pluginDescriptors);
44
45 // Revalidate the options with plugin schema additions
46 const metaSchemaBuilder = configReaderInjector.injectClass(MetaSchemaBuilder);
47 const metaSchema = metaSchemaBuilder.buildMetaSchema(loadedPlugins.schemaContributions);
48 const optionsValidatorInjector = configReaderInjector.provideValue(coreTokens.validationSchema, metaSchema);
49 const validator: OptionsValidator = optionsValidatorInjector.injectClass(OptionsValidator);
50 validator.validate(options, true);
51
52 // Done reading config, deep freeze it so it won't change unexpectedly
53 deepFreeze(options);
54
55 // Final logging configuration, open the logging server
56 const loggingContext = await LogConfigurator.configureLoggingServer(options.logLevel, options.fileLogLevel, options.allowConsoleColors);
57
58 // Resolve input files
59 const projectFileReaderInjector = optionsValidatorInjector
60 .provideValue(commonTokens.options, options)
61 .provideClass(coreTokens.temporaryDirectory, TemporaryDirectory)
62 .provideClass(coreTokens.fs, FileSystem)
63 .provideValue(coreTokens.pluginsByKind, loadedPlugins.pluginsByKind);
64 const project = await projectFileReaderInjector.injectClass(ProjectReader).read();
65
66 if (project.isEmpty) {
67 throw new ConfigError('No input files found.');
68 } else {
69 // Done preparing, finish up and return
70 await projectFileReaderInjector.resolve(coreTokens.temporaryDirectory).initialize();
71 return projectFileReaderInjector
72 .provideValue(coreTokens.project, project)
73 .provideValue(commonTokens.fileDescriptions, project.fileDescriptions)
74 .provideClass(coreTokens.pluginCreator, PluginCreator)
75 .provideClass(coreTokens.reporter, BroadcastReporter)
76 .provideValue(coreTokens.timer, timer)
77 .provideValue(coreTokens.project, project)
78 .provideValue(coreTokens.loggingContext, loggingContext)
79 .provideValue(coreTokens.execa, execaCommand)
80 .provideValue(coreTokens.process, process)
81 .provideClass(coreTokens.unexpectedExitRegistry, UnexpectedExitHandler)
82 .provideValue(coreTokens.pluginModulePaths, loadedPlugins.pluginModulePaths);
83 }
84 }
85}