Skip to content

Commit 56e129c

Browse files
committed
feat(plugin-eslint): create groups from rules' meta.docs.category (per plugin)
1 parent 0350e49 commit 56e129c

File tree

3 files changed

+138
-4
lines changed

3 files changed

+138
-4
lines changed

packages/plugin-eslint/src/lib/__snapshots__/eslint-plugin.spec.ts.snap

+96
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,102 @@ exports[`eslintPlugin > should initialize ESLint plugin for React application 1`
11661166
"slug": "formatting",
11671167
"title": "Formatting",
11681168
},
1169+
{
1170+
"refs": [
1171+
{
1172+
"slug": "react-prop-types",
1173+
"weight": 1,
1174+
},
1175+
{
1176+
"slug": "react-display-name",
1177+
"weight": 1,
1178+
},
1179+
{
1180+
"slug": "react-jsx-no-target-blank",
1181+
"weight": 1,
1182+
},
1183+
{
1184+
"slug": "react-jsx-uses-react",
1185+
"weight": 1,
1186+
},
1187+
{
1188+
"slug": "react-jsx-uses-vars",
1189+
"weight": 1,
1190+
},
1191+
{
1192+
"slug": "react-no-children-prop",
1193+
"weight": 1,
1194+
},
1195+
{
1196+
"slug": "react-no-deprecated",
1197+
"weight": 1,
1198+
},
1199+
{
1200+
"slug": "react-no-find-dom-node",
1201+
"weight": 1,
1202+
},
1203+
{
1204+
"slug": "react-no-is-mounted",
1205+
"weight": 1,
1206+
},
1207+
{
1208+
"slug": "react-no-render-return-value",
1209+
"weight": 1,
1210+
},
1211+
{
1212+
"slug": "react-no-string-refs",
1213+
"weight": 1,
1214+
},
1215+
],
1216+
"slug": "react-best-practices",
1217+
"title": "Best Practices (react)",
1218+
},
1219+
{
1220+
"refs": [
1221+
{
1222+
"slug": "react-jsx-key",
1223+
"weight": 1,
1224+
},
1225+
{
1226+
"slug": "react-react-in-jsx-scope",
1227+
"weight": 1,
1228+
},
1229+
{
1230+
"slug": "react-jsx-no-comment-textnodes",
1231+
"weight": 1,
1232+
},
1233+
{
1234+
"slug": "react-jsx-no-duplicate-props",
1235+
"weight": 1,
1236+
},
1237+
{
1238+
"slug": "react-jsx-no-undef",
1239+
"weight": 1,
1240+
},
1241+
{
1242+
"slug": "react-no-danger-with-children",
1243+
"weight": 1,
1244+
},
1245+
{
1246+
"slug": "react-no-direct-mutation-state",
1247+
"weight": 1,
1248+
},
1249+
{
1250+
"slug": "react-no-unescaped-entities",
1251+
"weight": 1,
1252+
},
1253+
{
1254+
"slug": "react-no-unknown-property",
1255+
"weight": 1,
1256+
},
1257+
{
1258+
"slug": "react-require-render-return",
1259+
"weight": 1,
1260+
},
1261+
],
1262+
"slug": "react-possible-errors",
1263+
"title": "Possible Errors (react)",
1264+
},
11691265
],
11701266
"icon": "eslint",
11711267
"packageName": "@code-pushup/eslint-plugin",

packages/plugin-eslint/src/lib/meta/groups.ts

+37-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { Rule } from 'eslint';
22
import type { AuditGroup, AuditGroupRef } from '@code-pushup/models';
3-
import { objectToKeys } from '@code-pushup/utils';
3+
import { objectToKeys, slugify } from '@code-pushup/utils';
44
import { ruleIdToSlug } from './hash';
5-
import type { RuleData } from './rules';
5+
import { type RuleData, parseRuleId } from './rules';
66

77
type RuleType = NonNullable<Rule.RuleMetaData['type']>;
88

@@ -50,3 +50,38 @@ export function groupsFromRuleTypes(rules: RuleData[]): AuditGroup[] {
5050
) ?? [],
5151
}));
5252
}
53+
54+
export function groupsFromRuleCategories(rules: RuleData[]): AuditGroup[] {
55+
const categoriesMap = rules.reduce<Record<string, Record<string, string[]>>>(
56+
(acc, { meta: { docs }, ruleId, options }) => {
57+
const category = docs?.category;
58+
if (!category) {
59+
return acc;
60+
}
61+
const { plugin = '' } = parseRuleId(ruleId);
62+
return {
63+
...acc,
64+
[plugin]: {
65+
...acc[plugin],
66+
[category]: [
67+
...(acc[plugin]?.[category] ?? []),
68+
ruleIdToSlug(ruleId, options),
69+
],
70+
},
71+
};
72+
},
73+
{},
74+
);
75+
76+
return Object.entries(categoriesMap)
77+
.flatMap(([plugin, categories]) =>
78+
Object.entries(categories).map(
79+
([category, slugs]): AuditGroup => ({
80+
slug: `${slugify(plugin)}-${slugify(category)}`,
81+
title: `${category} (${plugin})`,
82+
refs: slugs.map(slug => ({ slug, weight: 1 })),
83+
}),
84+
),
85+
)
86+
.sort((a, b) => a.slug.localeCompare(b.slug));
87+
}

packages/plugin-eslint/src/lib/meta/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ESLint } from 'eslint';
22
import type { Audit, AuditGroup } from '@code-pushup/models';
3-
import { groupsFromRuleTypes } from './groups';
3+
import { groupsFromRuleCategories, groupsFromRuleTypes } from './groups';
44
import { listRules } from './rules';
55
import { ruleToAudit } from './transform';
66

@@ -12,7 +12,10 @@ export async function listAuditsAndGroups(
1212

1313
const audits = rules.map(ruleToAudit);
1414

15-
const groups = groupsFromRuleTypes(rules);
15+
const groups = [
16+
...groupsFromRuleTypes(rules),
17+
...groupsFromRuleCategories(rules),
18+
];
1619

1720
return { audits, groups };
1821
}

0 commit comments

Comments
 (0)