From 24dba48df76878db521105bd9646aaa87ef160d9 Mon Sep 17 00:00:00 2001 From: Dmitry Krutskikh Date: Wed, 1 Dec 2021 15:19:24 +0300 Subject: [PATCH] feat: add metric value unit type --- CHANGELOG.md | 1 + .../metrics/metrics_list/lines_of_code_metric.dart | 3 +++ .../metrics_list/number_of_methods_metric.dart | 3 +++ .../source_lines_of_code_metric.dart | 3 +++ .../lint_analyzer/metrics/models/metric.dart | 5 +++++ .../lint_analyzer/metrics/models/metric_value.dart | 4 ++++ .../console/lint_console_reporter_helper.dart | 4 ++-- .../html/components/report_details_tooltip.dart | 3 ++- .../reporters_list/json/lint_json_reporter.dart | 2 ++ .../metrics_list/lines_of_code_metric_test.dart | 3 +++ .../source_lines_of_code_metric_test.dart | 3 +++ .../console/lint_console_reporter_helper_test.dart | 8 ++++++-- .../console/lint_console_reporter_test.dart | 8 ++++---- .../components/report_details_tooltip_test.dart | 14 ++++++++++++++ .../json/lint_json_reporter_test.dart | 1 + .../reporters/reporters_list/report_example.dart | 2 ++ test/stubs_builders.dart | 2 ++ website/docs/cli/analyze.md | 2 ++ 18 files changed, 62 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c74e9d23ef..542b1a2817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * feat: add support mixins, extensions and enums for `prefer-match-file-name` rule. * fix: prefer conditional expressions rule breaks code with increment / decrement operators. * fix: improve file metrics. +* feat: add metric value unit type. * chore: restrict `analyzer` version to `>=2.4.0 <2.9.0`. * chore: tune GitHub workflows. diff --git a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric.dart b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric.dart index 5884f2507e..53cb539c4c 100644 --- a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric.dart +++ b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric.dart @@ -62,4 +62,7 @@ class LinesOfCodeMetric extends FunctionMetric { (threshold != null && value > threshold) ? 'Consider breaking this $nodeType up into smaller parts.' : null; + + @override + String? unitType(int value) => value == 1 ? 'line' : 'lines'; } diff --git a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/number_of_methods_metric.dart b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/number_of_methods_metric.dart index e9373d16fe..67c5cac8d2 100644 --- a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/number_of_methods_metric.dart +++ b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/number_of_methods_metric.dart @@ -77,4 +77,7 @@ class NumberOfMethodsMetric extends ClassMetric { location: nodeLocation(node: func.declaration, source: source), )) .toList(growable: false); + + @override + String? unitType(int value) => value == 1 ? 'method' : 'methods'; } diff --git a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric.dart b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric.dart index 2f37bd38a7..718bfa5675 100644 --- a/lib/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric.dart +++ b/lib/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric.dart @@ -71,6 +71,9 @@ class SourceLinesOfCodeMetric extends FunctionMetric { ? 'Consider breaking this $nodeType up into smaller parts.' : null; + @override + String? unitType(int value) => value == 1 ? 'line' : 'lines'; + Iterable _context( Iterable linesWithCode, InternalResolvedUnitResult source, diff --git a/lib/src/analyzers/lint_analyzer/metrics/models/metric.dart b/lib/src/analyzers/lint_analyzer/metrics/models/metric.dart index b2ddf8c75c..b7a3c7808b 100644 --- a/lib/src/analyzers/lint_analyzer/metrics/models/metric.dart +++ b/lib/src/analyzers/lint_analyzer/metrics/models/metric.dart @@ -65,6 +65,7 @@ abstract class Metric { metricsId: id, documentation: documentation, value: result.value, + unitType: unitType(result.value), level: _levelComputer(result.value, threshold), comment: commentMessage(type, result.value, threshold), recommendation: recommendationMessage(type, result.value, threshold), @@ -98,4 +99,8 @@ abstract class Metric { Iterable classDeclarations, Iterable functionDeclarations, ); + + /// Returns the human readable unit type. + @protected + String? unitType(T value) => null; } diff --git a/lib/src/analyzers/lint_analyzer/metrics/models/metric_value.dart b/lib/src/analyzers/lint_analyzer/metrics/models/metric_value.dart index 9f4f7193dc..5bef437496 100644 --- a/lib/src/analyzers/lint_analyzer/metrics/models/metric_value.dart +++ b/lib/src/analyzers/lint_analyzer/metrics/models/metric_value.dart @@ -16,6 +16,9 @@ class MetricValue { /// The actual value computed by the metric. final T value; + /// The human readable unit type. + final String? unitType; + /// The level of this value computed by the metric. final MetricValueLevel level; @@ -41,6 +44,7 @@ class MetricValue { required this.metricsId, required this.documentation, required this.value, + this.unitType, required this.level, required this.comment, this.recommendation, diff --git a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper.dart b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper.dart index 2de930c0e8..0908266f05 100644 --- a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper.dart +++ b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper.dart @@ -57,9 +57,9 @@ class LintConsoleReporterHelper { final color = _colorPens[metric.level]; if (color != null) { - final value = metric.value.toInt(); + final value = '${metric.value.toInt()} ${metric.unitType ?? ''}'.trim(); - return '${metric.documentation.name.toLowerCase()}: ${color('$value')}'; + return '${metric.documentation.name.toLowerCase()}: ${color(value)}'; } throw StateError('Unexpected violation level.'); diff --git a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip.dart b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip.dart index a1c71931c1..80bee00547 100644 --- a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip.dart +++ b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip.dart @@ -38,7 +38,8 @@ Element renderDetailsTooltipMetric(MetricValue metric) { ..attributes['rel'] = 'noopener noreferrer' ..attributes['title'] = metricName ..text = '$metricName: ') - ..append(Element.tag('span')..text = metric.value.round().toString())) + ..append(Element.tag('span') + ..text = '${metric.value.round()} ${metric.unitType ?? ''}'.trim())) ..append(Element.tag('p') ..classes.add('metrics-source-code__tooltip-text') ..append(Element.tag('span') diff --git a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter.dart b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter.dart index 76f7566432..d3f823b44f 100644 --- a/lib/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter.dart +++ b/lib/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter.dart @@ -100,11 +100,13 @@ class LintJsonReporter Iterable> metrics, ) => metrics.map((metric) { + final unitType = metric.unitType; final recommendation = metric.recommendation; return { 'metricsId': metric.metricsId, 'value': metric.value, + if (unitType != null) 'unitType': unitType, 'level': metric.level.toString(), 'comment': metric.comment, if (recommendation != null) 'recommendation': recommendation, diff --git a/test/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric_test.dart b/test/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric_test.dart index 4f29a28093..d6a0428378 100644 --- a/test/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric_test.dart +++ b/test/src/analyzers/lint_analyzer/metrics/metrics_list/lines_of_code_metric_test.dart @@ -30,6 +30,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(5)); + expect(metricValue.unitType, equals('lines')); expect(metricValue.level, equals(MetricValueLevel.noted)); expect( metricValue.comment, @@ -50,6 +51,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(2)); + expect(metricValue.unitType, equals('lines')); expect(metricValue.level, equals(MetricValueLevel.none)); expect( metricValue.comment, @@ -70,6 +72,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(12)); + expect(metricValue.unitType, equals('lines')); expect(metricValue.level, equals(MetricValueLevel.warning)); expect( metricValue.comment, diff --git a/test/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric_test.dart b/test/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric_test.dart index b04436104d..e16bd6dd90 100644 --- a/test/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric_test.dart +++ b/test/src/analyzers/lint_analyzer/metrics/metrics_list/source_lines_of_code/source_lines_of_code_metric_test.dart @@ -31,6 +31,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(1)); + expect(metricValue.unitType, equals('line')); expect(metricValue.level, equals(MetricValueLevel.none)); expect( metricValue.comment, @@ -56,6 +57,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(6)); + expect(metricValue.unitType, equals('lines')); expect(metricValue.level, equals(MetricValueLevel.warning)); expect( metricValue.comment, @@ -81,6 +83,7 @@ Future main() async { expect(metricValue.metricsId, equals(metric.id)); expect(metricValue.value, equals(4)); + expect(metricValue.unitType, equals('lines')); expect(metricValue.level, equals(MetricValueLevel.none)); expect( metricValue.comment, diff --git a/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper_test.dart b/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper_test.dart index c1b4ae43e4..2d5ee778dc 100644 --- a/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper_test.dart +++ b/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_helper_test.dart @@ -81,8 +81,12 @@ void main() { test('getMetricReport returns formatted message', () { expect( - helper.getMetricReport(buildMetricValueStub(id: 'metricId', value: 12)), - equals('metricid: \x1B[38;5;7m12\x1B[0m'), + helper.getMetricReport(buildMetricValueStub( + id: 'metricId', + value: 12, + unitType: 'units', + )), + equals('metricid: \x1B[38;5;7m12 units\x1B[0m'), ); }); }); diff --git a/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_test.dart b/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_test.dart index d75e8b9c93..12652eee79 100644 --- a/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_test.dart +++ b/test/src/analyzers/lint_analyzer/reporters/reporters_list/console/lint_console_reporter_test.dart @@ -52,13 +52,13 @@ void main() { equals( [ 'test/resources/abstract_class.dart:', - '\x1B[38;5;11mWarning \x1B[0mmetric1: \x1B[38;5;11m100\x1B[0m', + '\x1B[38;5;11mWarning \x1B[0mmetric1: \x1B[38;5;11m100 units\x1B[0m', '\x1B[38;5;9mAlarm \x1B[0mclass.constructor - metric2: \x1B[38;5;9m10\x1B[0m', '', 'test/resources/class_with_factory_constructors.dart:', '\x1B[38;5;11mWarning \x1B[0msimple message : 0:0 : id', '\x1B[38;5;4mStyle \x1B[0msimple design message : 0:0 : designId', - '\x1B[38;5;11mWarning \x1B[0mfunction - metric4: \x1B[38;5;11m5\x1B[0m', + '\x1B[38;5;11mWarning \x1B[0mfunction - metric4: \x1B[38;5;11m5 units\x1B[0m', '', ], ), @@ -68,7 +68,7 @@ void main() { equals( [ 'test/resources/abstract_class.dart:', - '\x1B[38;5;11mWarning \x1B[0mmetric1: \x1B[38;5;11m100\x1B[0m', + '\x1B[38;5;11mWarning \x1B[0mmetric1: \x1B[38;5;11m100 units\x1B[0m', '\x1B[38;5;7m \x1B[0mclass - metric1: \x1B[38;5;7m0\x1B[0m', '\x1B[38;5;9mAlarm \x1B[0mclass.constructor - metric2: \x1B[38;5;9m10\x1B[0m', '\x1B[38;5;7m \x1B[0mclass.method - metric3: \x1B[38;5;7m1\x1B[0m', @@ -77,7 +77,7 @@ void main() { '\x1B[38;5;7m \x1B[0mmetric1: \x1B[38;5;7m0\x1B[0m, metric2: \x1B[38;5;7m1\x1B[0m', '\x1B[38;5;11mWarning \x1B[0msimple message : 0:0 : id', '\x1B[38;5;4mStyle \x1B[0msimple design message : 0:0 : designId', - '\x1B[38;5;11mWarning \x1B[0mfunction - metric4: \x1B[38;5;11m5\x1B[0m', + '\x1B[38;5;11mWarning \x1B[0mfunction - metric4: \x1B[38;5;11m5 units\x1B[0m', '', ], ), diff --git a/test/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip_test.dart b/test/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip_test.dart index 6801c6b6a4..d8a9962dc2 100644 --- a/test/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip_test.dart +++ b/test/src/analyzers/lint_analyzer/reporters/reporters_list/html/components/report_details_tooltip_test.dart @@ -50,6 +50,20 @@ void main() { '

metric:&nbsp;10

metric violation level:&nbsp;warning

', ), ); + + expect( + renderDetailsTooltipMetric( + buildMetricValueStub( + id: 'metric', + value: 10, + unitType: 'units', + level: MetricValueLevel.warning, + ), + ).outerHtml, + equals( + '

metric:&nbsp;10 units

metric violation level:&nbsp;warning

', + ), + ); }, ); }); diff --git a/test/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter_test.dart b/test/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter_test.dart index c43804e7f6..c64a925eeb 100644 --- a/test/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter_test.dart +++ b/test/src/analyzers/lint_analyzer/reporters/reporters_list/json/lint_json_reporter_test.dart @@ -44,6 +44,7 @@ void main() { { 'metricsId': 'file-metric-id', 'value': 100, + 'unitType': 'units', 'level': 'warning', 'comment': 'metric comment', 'context': [], diff --git a/test/src/analyzers/lint_analyzer/reporters/reporters_list/report_example.dart b/test/src/analyzers/lint_analyzer/reporters/reporters_list/report_example.dart index 008d646640..8099563efa 100644 --- a/test/src/analyzers/lint_analyzer/reporters/reporters_list/report_example.dart +++ b/test/src/analyzers/lint_analyzer/reporters/reporters_list/report_example.dart @@ -34,6 +34,7 @@ final _file1Report = Report( recomendedThreshold: 0, ), value: 100, + unitType: 'units', level: MetricValueLevel.warning, comment: 'metric comment', ), @@ -119,6 +120,7 @@ final _function3Report = Report( recomendedThreshold: 0, ), value: 5, + unitType: 'units', level: MetricValueLevel.warning, comment: 'metric comment', ), diff --git a/test/stubs_builders.dart b/test/stubs_builders.dart index 6ed2bc6da9..c7c8bec51e 100644 --- a/test/stubs_builders.dart +++ b/test/stubs_builders.dart @@ -18,6 +18,7 @@ class _DeclarationMock extends Mock implements Declaration {} MetricValue buildMetricValueStub({ required String id, required T value, + String? unitType, EntityType type = EntityType.methodEntity, MetricValueLevel level = MetricValueLevel.none, }) => @@ -30,6 +31,7 @@ MetricValue buildMetricValueStub({ recomendedThreshold: 0, ), value: value, + unitType: unitType, level: level, comment: '', ); diff --git a/website/docs/cli/analyze.md b/website/docs/cli/analyze.md index d696ba1c45..92b3d27b62 100644 --- a/website/docs/cli/analyze.md +++ b/website/docs/cli/analyze.md @@ -206,6 +206,7 @@ The reporter prints a single JSON object containing meta information and the vio - `metricsId` - an id of the computed metric - `value` - an actual value computed by the metric +- `unitType` - a human readable unit type _(optional)_ - `level` - a level of the value computed by the metric - `comment` - a message with information about the value - `recommendation` - a message with information about how the user can improve the value _(optional)_ @@ -215,6 +216,7 @@ The reporter prints a single JSON object containing meta information and the vio { "metricsId": "number-of-methods", "value": 14, + "unitType": "methods", "level": "warning", "comment": "This class has 14 methods, which exceeds the maximum of 10 allowed.", "recommendation": "Consider breaking this class up into smaller parts.",