UNPKG

@code-pushup/eslint-plugin

Version:

Code PushUp plugin for detecting problems in source code using ESLint.📋

112 lines • 4.44 kB
import { objectToKeys, slugify, ui } from '@code-pushup/utils'; import { ruleToSlug } from './hash.js'; import { parseRuleId } from './parse.js'; import { expandWildcardRules } from './rules.js'; // docs on meta.type: https://eslint.org/docs/latest/extend/custom-rules#rule-structure const typeGroups = { problem: { slug: 'problems', title: 'Problems', description: 'Code that either will cause an error or may cause confusing behavior. Developers should consider this a high priority to resolve.', }, suggestion: { slug: 'suggestions', title: 'Suggestions', description: "Something that could be done in a better way but no errors will occur if the code isn't changed.", }, layout: { slug: 'formatting', title: 'Formatting', description: 'Primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes.', }, }; export function groupsFromRuleTypes(rules) { const allTypes = objectToKeys(typeGroups); const auditSlugsMap = rules.reduce((acc, rule) => rule.meta.type == null ? acc : { ...acc, [rule.meta.type]: [ ...(acc[rule.meta.type] ?? []), ruleToSlug(rule), ], }, {}); return allTypes .map(type => ({ ...typeGroups[type], refs: auditSlugsMap[type]?.map((slug) => ({ slug, weight: 1 })) ?? [], })) .filter(group => group.refs.length); } export function groupsFromRuleCategories(rules) { const categoriesMap = rules.reduce((acc, rule) => { // meta.docs.category still used by some popular plugins (e.g. import, react, functional) const category = rule.meta.docs?.category; if (!category) { return acc; } const { plugin = '' } = parseRuleId(rule.id); return { ...acc, [plugin]: { ...acc[plugin], [category]: [...(acc[plugin]?.[category] ?? []), ruleToSlug(rule)], }, }; }, {}); const groups = Object.entries(categoriesMap).flatMap(([plugin, categories]) => Object.entries(categories).map(([category, slugs]) => ({ slug: `${slugify(plugin)}-${slugify(category)}`, title: `${category} (${plugin})`, refs: slugs.map(slug => ({ slug, weight: 1 })), }))); return groups.toSorted((a, b) => a.slug.localeCompare(b.slug)); } export function groupsFromCustomConfig(rules, groups) { const rulesMap = createRulesMap(rules); return groups.map(group => { const groupRules = Array.isArray(group.rules) ? Object.fromEntries(group.rules.map(rule => [rule, 1])) : group.rules; const { refs, invalidRules } = resolveGroupRefs(groupRules, rulesMap); if (invalidRules.length > 0 && Object.entries(groupRules).length > 0) { if (refs.length === 0) { throw new Error(`Invalid rule configuration in group ${group.slug}. All rules are invalid.`); } ui().logger.warning(`Some rules in group ${group.slug} are invalid: ${invalidRules.join(', ')}`); } return { slug: group.slug, title: group.title, refs, }; }); } export function createRulesMap(rules) { return rules.reduce((acc, rule) => ({ ...acc, [rule.id]: [...(acc[rule.id] || []), rule], }), {}); } export function resolveGroupRefs(groupRules, rulesMap) { return Object.entries(groupRules).reduce((acc, [rule, weight]) => { const matchedRuleIds = rule.endsWith('*') ? expandWildcardRules(rule, Object.keys(rulesMap)) : [rule]; const matchedRefs = matchedRuleIds.flatMap(ruleId => { const matchingRules = rulesMap[ruleId] || []; const weightPerRule = weight / matchingRules.length; return matchingRules.map(ruleData => ({ slug: ruleToSlug(ruleData), weight: weightPerRule, })); }); return { refs: [...acc.refs, ...matchedRefs], invalidRules: matchedRefs.length > 0 ? acc.invalidRules : [...acc.invalidRules, rule], }; }, { refs: [], invalidRules: [] }); } //# sourceMappingURL=groups.js.map