Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit 9ebab5a

Browse files
authored
feat: facelift console reporters (#611)
* feat: facelift lint console reporter * feat: add message for empty report * feat: facelift console reporters * chore: update site screenshots
1 parent 050cf41 commit 9ebab5a

File tree

12 files changed

+181
-91
lines changed

12 files changed

+181
-91
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* chore: disable github_checks annotations from codecov
99
* chore: activate language strict rules
1010
* fix: add missing severity for rules
11+
* feat: facelift console reporters
1112

1213
## 4.8.1
1314

lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter.dart

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ class LintConsoleReporter
2727
Iterable<LintFileReport> records, {
2828
Iterable<SummaryLintReportRecord<Object>> summary = const [],
2929
}) async {
30-
if (records.isEmpty) {
31-
return;
32-
}
30+
var hasReportData = false;
3331

3432
for (final file in records) {
3533
final lines = [
3634
..._reportMetrics('', file.file),
37-
..._reportIssues([...file.issues, ...file.antiPatternCases]),
35+
..._reportIssues(
36+
[...file.issues, ...file.antiPatternCases],
37+
file.relativePath,
38+
),
3839
..._reportEntityMetrics({...file.classes, ...file.functions}),
3940
];
4041

@@ -43,13 +44,21 @@ class LintConsoleReporter
4344
lines.forEach(output.writeln);
4445
output.writeln('');
4546
}
47+
48+
hasReportData |= lines.isNotEmpty;
49+
}
50+
51+
if (!hasReportData) {
52+
output.writeln('${okPen('✔')} no issues found!');
4653
}
4754
}
4855

49-
Iterable<String> _reportIssues(Iterable<Issue> issues) => (issues.toList()
50-
..sort((a, b) =>
51-
a.location.start.offset.compareTo(b.location.start.offset)))
52-
.map(_helper.getIssueMessage);
56+
Iterable<String> _reportIssues(Iterable<Issue> issues, String relativePath) =>
57+
(issues.toList()
58+
..sort((a, b) =>
59+
a.location.start.offset.compareTo(b.location.start.offset)))
60+
.map((issue) => _helper.getIssueMessage(issue, relativePath))
61+
.expand((lines) => lines);
5362

5463
Iterable<String> _reportEntityMetrics(Map<String, Report> reports) =>
5564
(reports.entries.toList()
@@ -66,9 +75,7 @@ class LintConsoleReporter
6675
_helper.getMetricReport(metric),
6776
];
6877

69-
return [
70-
_helper.getMetricMessage(reportLevel, source, violations),
71-
];
78+
return _helper.getMetricMessage(reportLevel, source, violations);
7279
}
7380

7481
return [];

lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper.dart

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,74 @@
11
import 'package:ansicolor/ansicolor.dart';
22

3-
import '../../../../../utils/string_extensions.dart';
43
import '../../../metrics/models/metric_value.dart';
54
import '../../../metrics/models/metric_value_level.dart';
65
import '../../../models/issue.dart';
76
import '../../../models/severity.dart';
87

8+
final _alarmPen = AnsiPen()..rgb(r: 0.88, g: 0.32, b: 0.36);
9+
final _warnigPen = AnsiPen()..rgb(r: 0.98, g: 0.68, b: 0.4);
10+
final _bluePen = AnsiPen()..rgb(r: 0.08, g: 0.11, b: 0.81);
11+
final _whitePen = AnsiPen()..white();
12+
13+
final _linkPen = AnsiPen()..rgb(r: 0.0, g: 0.78, b: 1.0);
14+
915
/// Helper for building lint console reports
1016
class LintConsoleReporterHelper {
1117
static final _colorPens = {
12-
MetricValueLevel.alarm: AnsiPen()..red(bold: true),
13-
MetricValueLevel.warning: AnsiPen()..yellow(bold: true),
14-
MetricValueLevel.noted: AnsiPen()..blue(),
15-
MetricValueLevel.none: AnsiPen()..white(),
18+
MetricValueLevel.alarm: _alarmPen,
19+
MetricValueLevel.warning: _warnigPen,
20+
MetricValueLevel.noted: _bluePen,
21+
MetricValueLevel.none: _whitePen,
1622
};
1723

1824
final _severityPens = {
19-
Severity.error: AnsiPen()..red(bold: true),
20-
Severity.warning: AnsiPen()..yellow(bold: true),
21-
Severity.performance: AnsiPen()..cyan(),
22-
Severity.style: AnsiPen()..blue(),
23-
Severity.none: AnsiPen()..white(),
25+
Severity.error: _alarmPen,
26+
Severity.warning: _warnigPen,
27+
Severity.performance: _bluePen,
28+
Severity.style: _bluePen,
29+
Severity.none: _whitePen,
2430
};
2531

2632
/// Converts an [issue] to the issue message string.
27-
String getIssueMessage(Issue issue) {
33+
Iterable<String> getIssueMessage(Issue issue, String relativePath) {
2834
final severity = _getSeverity(issue.severity);
29-
final location =
30-
'${issue.location.start.line}:${issue.location.start.column}';
31-
32-
return '$severity${[issue.message, location, issue.ruleId].join(' : ')}';
35+
final location = _linkPen(
36+
'$relativePath:${issue.location.start.line}:${issue.location.start.column}',
37+
);
38+
final tabulation = _normalize('');
39+
40+
return [
41+
'$severity${issue.message}',
42+
'$tabulation$location',
43+
'$tabulation${issue.ruleId} : ${issue.documentation}',
44+
'',
45+
];
3346
}
3447

3548
/// Creates a message for [violations] based on given [violationLevel].
36-
String getMetricMessage(
49+
Iterable<String> getMetricMessage(
3750
MetricValueLevel violationLevel,
3851
String source,
3952
Iterable<String> violations,
4053
) {
54+
if (violations.isEmpty) {
55+
return [];
56+
}
57+
4158
final color = _colorPens[violationLevel];
4259
if (color != null) {
43-
final normalizedLabel = color(_normalize(
44-
violationLevel != MetricValueLevel.none
45-
? violationLevel.toString().capitalize()
46-
: '',
47-
));
48-
49-
return '$normalizedLabel${source.isNotEmpty ? '$source - ' : ''}${violations.join(', ')}';
60+
final normalizedLabel =
61+
color(_normalize(violationLevel.toString().toUpperCase()));
62+
63+
final firstLine = source.isNotEmpty ? source : violations.first;
64+
final records = source.isNotEmpty ? violations : violations.skip(1);
65+
final tabulation = _normalize('');
66+
67+
return [
68+
'$normalizedLabel$firstLine',
69+
for (final record in records) '$tabulation$record',
70+
'',
71+
];
5072
}
5173

5274
throw StateError('Unexpected violation level.');
@@ -70,7 +92,7 @@ class LintConsoleReporterHelper {
7092

7193
if (color != null) {
7294
return color(_normalize(
73-
severity != Severity.none ? severity.toString().capitalize() : '',
95+
severity != Severity.none ? severity.toString().toUpperCase() : '',
7496
));
7597
}
7698

lib/src/analyzers/unused_files_analyzer/reporters/reporters_list/console/unused_files_console_reporter.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import 'dart:io';
22

3-
import 'package:ansicolor/ansicolor.dart';
4-
53
import '../../../../../reporters/models/console_reporter.dart';
64
import '../../../models/unused_files_file_report.dart';
75

@@ -18,7 +16,7 @@ class UnusedFilesConsoleReporter
1816
Iterable<void> summary = const [],
1917
}) async {
2018
if (records.isEmpty) {
21-
output.writeln('No unused files found!');
19+
output.writeln('${okPen('✔')} no unused files found!');
2220

2321
return;
2422
}
@@ -27,13 +25,15 @@ class UnusedFilesConsoleReporter
2725
..sort((a, b) => a.relativePath.compareTo(b.relativePath));
2826

2927
for (final analysisRecord in sortedRecords) {
30-
output.writeln('Unused file: ${analysisRecord.relativePath}');
28+
output.writeln(
29+
'${warnigPen('⚠')} unused file: ${analysisRecord.relativePath}',
30+
);
3131
}
3232

33-
final color = AnsiPen()..yellow();
34-
3533
output
3634
..writeln('')
37-
..writeln('Total unused files - ${color(sortedRecords.length)}');
35+
..writeln(
36+
'${alarmPen('✖')} total unused files - ${alarmPen(sortedRecords.length)}',
37+
);
3838
}
3939
}

lib/src/analyzers/unused_l10n_analyzer/reporters/reporters_list/console/unused_l10n_console_reporter.dart

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import 'dart:io';
22

3-
import 'package:ansicolor/ansicolor.dart';
4-
53
import '../../../../../reporters/models/console_reporter.dart';
64
import '../../../models/unused_l10n_file_report.dart';
75

@@ -10,10 +8,6 @@ import '../../../models/unused_l10n_file_report.dart';
108
/// Use it to create reports in console format.
119
class UnusedL10nConsoleReporter
1210
extends ConsoleReporter<UnusedL10nFileReport, void> {
13-
final _errorColor = AnsiPen()..red(bold: true);
14-
final _warningColor = AnsiPen()..yellow(bold: true);
15-
final _successColor = AnsiPen()..green();
16-
1711
UnusedL10nConsoleReporter(IOSink output) : super(output);
1812

1913
@override
@@ -22,7 +16,7 @@ class UnusedL10nConsoleReporter
2216
Iterable<void> summary = const [],
2317
}) async {
2418
if (records.isEmpty) {
25-
output.writeln('${_successColor('✔')} no unused localization found!');
19+
output.writeln('${okPen('✔')} no unused localization found!');
2620

2721
return;
2822
}
@@ -44,7 +38,7 @@ class UnusedL10nConsoleReporter
4438
final pathOffset = offset.padRight(5);
4539

4640
output
47-
..writeln('$offset ${_warningColor('⚠')} unused ${issue.memberName}')
41+
..writeln('$offset ${warnigPen('⚠')} unused ${issue.memberName}')
4842
..writeln('$pathOffset at $path:$line:$column');
4943
}
5044

@@ -54,7 +48,7 @@ class UnusedL10nConsoleReporter
5448
}
5549

5650
output.writeln(
57-
'${_errorColor('✖')} total unused localization class fields, getters and methods - ${_errorColor(warnings)}',
51+
'${alarmPen('✖')} total unused localization class fields, getters and methods - ${alarmPen(warnings)}',
5852
);
5953
}
6054
}

lib/src/reporters/models/console_reporter.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:io';
22

3+
import 'package:ansicolor/ansicolor.dart';
34
import 'package:meta/meta.dart';
45

56
import 'file_report.dart';
@@ -10,8 +11,12 @@ abstract class ConsoleReporter<T extends FileReport, S> extends Reporter<T, S> {
1011
static const String id = 'console';
1112
static const String verboseId = 'console-verbose';
1213

14+
final AnsiPen alarmPen = AnsiPen()..rgb(r: 0.88, g: 0.32, b: 0.36);
15+
final AnsiPen warnigPen = AnsiPen()..rgb(r: 0.98, g: 0.68, b: 0.4);
16+
final AnsiPen okPen = AnsiPen()..rgb(r: 0.08, g: 0.11, b: 0.81);
17+
1318
@protected
1419
final IOSink output;
1520

16-
const ConsoleReporter(this.output);
21+
ConsoleReporter(this.output);
1722
}

test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper_test.dart

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,14 @@ void main() {
3636
message: 'Issue message',
3737
verboseMessage: 'Issue verbose message',
3838
),
39+
'lib/src/my_source.dart',
3940
),
40-
equals('\x1B[38;5;11mWarning \x1B[0mIssue message : 1:2 : rule'),
41+
equals([
42+
'\x1B[38;5;180mWARNING \x1B[0mIssue message',
43+
' \x1B[38;5;39mlib/src/my_source.dart:1:2\x1B[0m',
44+
' rule : https://dartcodemetrics/rules/rule',
45+
'',
46+
]),
4147
);
4248

4349
expect(
@@ -50,8 +56,14 @@ void main() {
5056
message: 'Issue message',
5157
verboseMessage: 'Issue verbose message',
5258
),
59+
'lib/src/my_source.dart',
5360
),
54-
equals('\x1B[38;5;7m \x1B[0mIssue message : 1:2 : rule'),
61+
equals([
62+
'\x1B[38;5;7m \x1B[0mIssue message',
63+
' \x1B[38;5;39mlib/src/my_source.dart:1:2\x1B[0m',
64+
' rule : https://dartcodemetrics/rules/rule',
65+
'',
66+
]),
5567
);
5668
});
5769

@@ -62,9 +74,12 @@ void main() {
6274
'Class.method',
6375
['violation1', 'violation2'],
6476
),
65-
equals(
66-
'\x1B[38;5;9mAlarm \x1B[0mClass.method - violation1, violation2',
67-
),
77+
equals([
78+
'\x1B[38;5;167mALARM \x1B[0mClass.method',
79+
' violation1',
80+
' violation2',
81+
'',
82+
]),
6883
);
6984

7085
expect(
@@ -73,9 +88,12 @@ void main() {
7388
'Class.method',
7489
['violation1', 'violation2'],
7590
),
76-
equals(
77-
'\x1B[38;5;7m \x1B[0mClass.method - violation1, violation2',
78-
),
91+
equals([
92+
'\x1B[38;5;7mNONE \x1B[0mClass.method',
93+
' violation1',
94+
' violation2',
95+
'',
96+
]),
7997
);
8098
});
8199

0 commit comments

Comments
 (0)