Skip to content

Commit af207c9

Browse files
committed
Add --summary CLI option for diagnostics grouped by rule
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 3570ab9 commit af207c9

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

src/CsLint.Cli/Program.cs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
Description = "Enable semantic analysis for advanced rules",
4646
};
4747

48+
var summaryOption = new Option<bool>("--summary")
49+
{
50+
Description = "Show a summary of diagnostics grouped by rule ID",
51+
};
52+
4853
var versionOption = new Option<bool>("--version")
4954
{
5055
Description = "Show version information and exit",
@@ -59,6 +64,7 @@
5964
listRulesOption,
6065
showConfigOption,
6166
semanticOption,
67+
summaryOption,
6268
versionOption,
6369
};
6470

@@ -116,6 +122,7 @@
116122
string[]? excludePatterns = parseResult.GetValue(excludeOption);
117123

118124
bool semantic = parseResult.GetValue(semanticOption);
125+
bool summary = parseResult.GetValue(summaryOption);
119126
#if !SEMANTIC
120127
if (semantic)
121128
{
@@ -180,11 +187,18 @@
180187
? allDiagnostics.Where(d => d.Severity >= minSeverity).ToList()
181188
: allDiagnostics;
182189

183-
string output = formatter.Format(filteredDiagnostics);
184-
185-
if (!string.IsNullOrEmpty(output))
190+
if (summary)
186191
{
187-
Console.Write(output);
192+
PrintSummary(filteredDiagnostics, registry);
193+
}
194+
else
195+
{
196+
string output = formatter.Format(filteredDiagnostics);
197+
198+
if (!string.IsNullOrEmpty(output))
199+
{
200+
Console.Write(output);
201+
}
188202
}
189203

190204
if (hasError)
@@ -245,6 +259,39 @@ static int PrintRuleList()
245259
return 0;
246260
}
247261

262+
static void PrintSummary(IReadOnlyList<LintDiagnostic> diagnostics, RuleRegistry registry)
263+
{
264+
if (diagnostics.Count == 0)
265+
{
266+
return;
267+
}
268+
269+
Dictionary<string, string> ruleNames = registry.Rules.ToDictionary(r => r.RuleId, r => r.Name);
270+
271+
List<(string RuleId, string Name, int Count)> groups = diagnostics
272+
.GroupBy(d => d.RuleId)
273+
.Select(g => (RuleId: g.Key, Name: ruleNames.GetValueOrDefault(g.Key, ""), Count: g.Count()))
274+
.OrderByDescending(g => g.Count)
275+
.ThenBy(g => g.RuleId, StringComparer.Ordinal)
276+
.ToList();
277+
278+
int maxIdLen = Math.Max("Rule".Length, groups.Max(g => g.RuleId.Length));
279+
int maxNameLen = Math.Max("Name".Length, groups.Max(g => g.Name.Length));
280+
int maxCountLen = Math.Max("Count".Length, diagnostics.Count.ToString().Length);
281+
int lineWidth = maxIdLen + 2 + maxNameLen + 2 + maxCountLen;
282+
283+
Console.WriteLine($"{"Rule".PadRight(maxIdLen)} {"Name".PadRight(maxNameLen)} {"Count".PadLeft(maxCountLen)}");
284+
Console.WriteLine(new string('\u2500', lineWidth));
285+
286+
foreach ((string ruleId, string name, int count) in groups)
287+
{
288+
Console.WriteLine($"{ruleId.PadRight(maxIdLen)} {name.PadRight(maxNameLen)} {count.ToString().PadLeft(maxCountLen)}");
289+
}
290+
291+
Console.WriteLine(new string('\u2500', lineWidth));
292+
Console.WriteLine($"{"Total".PadRight(maxIdLen)} {"".PadRight(maxNameLen)} {diagnostics.Count.ToString().PadLeft(maxCountLen)}");
293+
}
294+
248295
static int PrintConfig(LintConfiguration config)
249296
{
250297
using var stream = new MemoryStream();

0 commit comments

Comments
 (0)