@code-pushup/cli
Version:
A CLI to run all kinds of code quality measurements to align your team with company goals
119 lines • 6.11 kB
JavaScript
import { capitalize, filterItemRefsBy, isVerbose, pluralize, ui, } from '@code-pushup/utils';
export class OptionValidationError extends Error {
}
// eslint-disable-next-line max-lines-per-function
export function validateFilterOption(option, { plugins, categories = [] }, { itemsToFilter, skippedItems, }) {
const validItems = isCategoryOption(option)
? categories.map(({ slug }) => slug)
: isPluginOption(option)
? plugins.map(({ slug }) => slug)
: [];
const itemsToFilterSet = new Set(itemsToFilter);
const skippedItemsSet = new Set(skippedItems);
const validItemsSet = new Set(validItems);
const nonExistentItems = itemsToFilter.filter(item => !validItemsSet.has(item) && !skippedItemsSet.has(item));
const skippedValidItems = itemsToFilter.filter(item => skippedItemsSet.has(item));
if (nonExistentItems.length > 0) {
const message = createValidationMessage(option, nonExistentItems, validItemsSet);
if (isOnlyOption(option) &&
itemsToFilterSet.size > 0 &&
itemsToFilterSet.size === nonExistentItems.length) {
throw new OptionValidationError(message);
}
ui().logger.warning(message);
}
if (skippedValidItems.length > 0 && isVerbose()) {
const item = getItemType(option, skippedValidItems.length);
const prefix = skippedValidItems.length === 1 ? `a skipped` : `skipped`;
ui().logger.warning(`The --${option} argument references ${prefix} ${item}: ${skippedValidItems.join(', ')}.`);
}
if (isPluginOption(option) && categories.length > 0 && isVerbose()) {
const removedCategories = filterItemRefsBy(categories, ({ plugin }) => isOnlyOption(option)
? !itemsToFilterSet.has(plugin)
: itemsToFilterSet.has(plugin)).map(({ slug }) => slug);
if (removedCategories.length > 0) {
ui().logger.info(`The --${option} argument removed the following categories: ${removedCategories.join(', ')}.`);
}
}
}
export function validateSkippedCategories(originalCategories, filteredCategories) {
const skippedCategories = originalCategories.filter(original => !filteredCategories.some(({ slug }) => slug === original.slug));
if (skippedCategories.length > 0 && isVerbose()) {
skippedCategories.forEach(category => {
ui().logger.info(`Category ${category.slug} was removed because all its refs were skipped. Affected refs: ${category.refs
.map(ref => `${ref.slug} (${ref.type})`)
.join(', ')}`);
});
}
if (filteredCategories.length === 0) {
throw new OptionValidationError(`No categories remain after filtering. Removed categories: ${skippedCategories
.map(({ slug }) => slug)
.join(', ')}`);
}
}
export function validateFinalState(filteredItems, originalItems) {
const { categories: filteredCategories = [], plugins: filteredPlugins } = filteredItems;
const { categories: originalCategories = [], plugins: originalPlugins } = originalItems;
if (filteredCategories.length === 0 &&
filteredPlugins.length === 0 &&
(originalPlugins.length > 0 || originalCategories.length > 0)) {
const availablePlugins = originalPlugins.map(p => p.slug).join(', ') || 'none';
const availableCategories = originalCategories.map(c => c.slug).join(', ') || 'none';
throw new OptionValidationError(`Nothing to report. No plugins or categories are available after filtering. Available plugins: ${availablePlugins}. Available categories: ${availableCategories}.`);
}
if (filteredPlugins.some(pluginHasZeroWeightRefs)) {
throw new OptionValidationError('Some groups in the filtered plugins have only zero-weight references. Please adjust your filters or weights.');
}
}
export function pluginHasZeroWeightRefs(plugin) {
if (!plugin.groups || plugin.groups.length === 0) {
return false;
}
return plugin.groups.some(group => group.refs.reduce((sum, ref) => sum + ref.weight, 0) === 0);
}
function isCategoryOption(option) {
return option.endsWith('Categories');
}
function isPluginOption(option) {
return option.endsWith('Plugins');
}
export function isOnlyOption(option) {
return option.startsWith('only');
}
export function getItemType(option, count) {
const itemType = isCategoryOption(option)
? 'category'
: isPluginOption(option)
? 'plugin'
: 'item';
return pluralize(itemType, count);
}
export function createValidationMessage(option, invalidItems, validItems) {
const invalidItem = getItemType(option, invalidItems.length);
const invalidItemText = invalidItems.length === 1
? `a ${invalidItem} that does not exist:`
: `${invalidItem} that do not exist:`;
const invalidSlugs = invalidItems.join(', ');
const validItem = getItemType(option, validItems.size);
const validItemText = validItems.size === 1
? `The only valid ${validItem} is`
: `Valid ${validItem} are`;
const validSlugs = [...validItems].join(', ');
return `The --${option} argument references ${invalidItemText} ${invalidSlugs}. ${validItemText} ${validSlugs}.`;
}
export function handleConflictingOptions(type, onlyItems, skipItems) {
const conflictingItems = onlyItems.filter(item => skipItems.includes(item));
if (conflictingItems.length > 0) {
const conflictSubject = () => {
switch (type) {
case 'categories':
return conflictingItems.length > 1 ? 'categories are' : 'category is';
case 'plugins':
return conflictingItems.length > 1 ? 'plugins are' : 'plugin is';
}
};
const conflictingSlugs = conflictingItems.join(', ');
throw new OptionValidationError(`The following ${conflictSubject()} specified in both --only${capitalize(type)} and --skip${capitalize(type)}: ${conflictingSlugs}. Please choose one option.`);
}
}
//# sourceMappingURL=validate-filter-options.utils.js.map