const chalk = require('chalk');
const prompts = require('prompts');
const ansiEscapes = require('ansi-escapes');
const path = require('path');
class JestPluginProjects {
constructor({ config }) {
this._activeProjects = {};
this._projectNames = [];
this._usageInfo = {
key: config.key || 'P',
prompt:
config.prompt ||
function() {
return `select projects ${chalk.italic(
this._getActiveProjectsText(),
)}`;
},
};
}
apply(jestHook) {
jestHook.onFileChange(({ projects }) => this._setProjects(projects));
jestHook.shouldRunTestSuite(({ config }) => {
const name = this._getDisplayName(config) || this._getBasename(config);
return (
this._activeProjects[name] === undefined || this._activeProjects[name]
);
});
}
onKey() {}
_getDisplayName(config) {
const { displayName } = config;
return typeof displayName === 'object' ? displayName.name : displayName;
}
_getBasename(config) {
const { rootDir } = config;
return path.basename(rootDir);
}
_setProjects(projects) {
if (!this._projectNames.length) {
const projectNameSet = projects.reduce((state, p) => {
const displayName = this._getDisplayName(p.config);
const basename = this._getBasename(p.config);
if (state.has(displayName)) {
throw new Error(`
Found multiple projects with the same \`displayName\`: "${displayName}"
Change the \`displayName\` on at least one of them to prevent name collision.
- More info: https://facebook.github.io/jest/docs/en/configuration.html#projects-array-string-projectconfig
`);
}
if (state.has(basename)) {
throw new Error(`
Found multiple projects with the same directory basename: "${basename}"
Add a \`displayName\` to at least one of them to prevent name collision.
- More info: https://facebook.github.io/jest/docs/en/configuration.html#projects-array-string-projectconfig
`);
}
return new Set([...state, displayName || basename]);
}, new Set());
this._projectNames = [...projectNameSet];
this._setActiveProjects(this._projectNames);
}
}
_setActiveProjects(activeProjects) {
this._numActiveProjects = activeProjects.length;
this._activeProjects = this._projectNames.reduce((memo, name) => {
// eslint-disable-next-line no-param-reassign
memo[name] = activeProjects.includes(name);
return memo;
}, {});
}
run() {
console.log(ansiEscapes.clearScreen);
return prompts([
{
type: 'multiselect',
name: 'activeProjects',
message: 'Select projects',
choices: this._projectNames.map(value => ({
value,
selected: this._activeProjects[value],
})),
},
]).then(({ activeProjects }) => {
process.stdin.setRawMode(true);
process.stdin.resume();
if (activeProjects !== undefined) {
this._setActiveProjects(activeProjects);
return true;
}
return Promise.reject();
});
}
_getActiveProjectsText() {
const numProjects = this._projectNames.length;
if (this._numActiveProjects === numProjects) {
return '(all selected)';
}
if (this._numActiveProjects === 0) {
return '(zero selected)';
}
return `(${this._numActiveProjects}/${numProjects} selected)`;
}
getUsageInfo() {
const { key, prompt } = this._usageInfo;
const evaluatedPrompt =
typeof prompt === 'function' ? prompt.call(this) : prompt;
return {
key,
prompt: evaluatedPrompt,
};
}
}
module.exports = JestPluginProjects;