@stryker-mutator/core
Version:
The extendable JavaScript mutation testing framework
106 lines • 4.75 kB
JavaScript
import { promises as fs } from 'fs';
import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
import { childProcessAsPromised } from '@stryker-mutator/util';
import { fileUtils } from '../utils/file-utils.js';
import { CommandTestRunner } from '../test-runner/command-test-runner.js';
import { SUPPORTED_CONFIG_FILE_NAMES, DEFAULT_CONFIG_FILE_NAMES, } from '../config/index.js';
import { initializerTokens } from './index.js';
export class StrykerConfigWriter {
log;
out;
static inject = tokens(commonTokens.logger, initializerTokens.out);
constructor(log, out) {
this.log = log;
this.out = out;
}
async guardForExistingConfig() {
for (const fileName of SUPPORTED_CONFIG_FILE_NAMES) {
await this.checkIfConfigFileExists(fileName);
}
}
async checkIfConfigFileExists(file) {
if (await fileUtils.exists(file)) {
const msg = `Stryker config file "${file}" already exists in the current directory. Please remove it and try again.`;
this.log.error(msg);
throw new Error(msg);
}
}
/**
* Create config based on the chosen framework and test runner
* @function
*/
write(selectedTestRunner, buildCommand, selectedReporters, selectedPackageManager, requiredPlugins, additionalPiecesOfConfig, homepageOfSelectedTestRunner, exportAsJson) {
const configObject = {
_comment: "This config was generated using 'stryker init'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information.",
packageManager: selectedPackageManager.name,
reporters: selectedReporters.map((rep) => rep.name),
testRunner: selectedTestRunner.name,
testRunner_comment: `Take a look at ${homepageOfSelectedTestRunner} for information about the ${selectedTestRunner.name} plugin.`,
coverageAnalysis: CommandTestRunner.is(selectedTestRunner.name)
? 'off'
: 'perTest',
};
// Only write buildCommand to config file if non-empty
if (buildCommand.name) {
configObject.buildCommand = buildCommand.name;
}
// Automatic plugin discovery doesn't work with pnpm, so explicitly specify the required plugins in the config file
if (selectedPackageManager.name === 'pnpm') {
configObject.plugins = requiredPlugins;
}
Object.assign(configObject, ...additionalPiecesOfConfig);
return this.writeStrykerConfig(configObject, exportAsJson);
}
/**
* Create config based on the chosen preset
* @function
*/
async writeCustomInitializer(initializerConfig, exportAsJson) {
const config = {
_comment: `This config was generated using 'stryker init'. Please see the guide for more information: ${initializerConfig.guideUrl}`,
...initializerConfig.config,
};
return this.writeStrykerConfig(config, exportAsJson);
}
writeStrykerConfig(config, exportAsJson) {
if (exportAsJson) {
return this.writeJsonConfig(config);
}
else {
return this.writeJsConfig(config);
}
}
async writeJsConfig(commentedConfig) {
const configFileName = DEFAULT_CONFIG_FILE_NAMES.JAVASCRIPT;
this.out(`Writing & formatting ${configFileName} ...`);
const rawConfig = this.stringify(commentedConfig);
const formattedConfig = `// @ts-check
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
const config = ${rawConfig};
export default config;`;
await fs.writeFile(configFileName, formattedConfig);
try {
await childProcessAsPromised.exec(`npx prettier --write ${configFileName}`);
}
catch (error) {
this.log.debug('Prettier exited with error', error);
this.out(`Unable to format ${configFileName} file for you. This is not a big problem, but it might look a bit messy 🙈.`);
}
return configFileName;
}
async writeJsonConfig(commentedConfig) {
const configFileName = DEFAULT_CONFIG_FILE_NAMES.JSON;
this.out(`Writing & formatting ${configFileName}...`);
const typedConfig = {
$schema: './node_modules/@stryker-mutator/core/schema/stryker-schema.json',
...commentedConfig,
};
const formattedConfig = this.stringify(typedConfig);
await fs.writeFile(configFileName, formattedConfig);
return configFileName;
}
stringify(input) {
return JSON.stringify(input, undefined, 2);
}
}
//# sourceMappingURL=stryker-config-writer.js.map