Dart Code Metrics 4.0: Commands, Monorepo Support, and New Rules
In one of the previous articles, we announced Dart Code Metrics, a static code analysis tool. Today I’ll tell you about the new features available in Dart Code Metrics with the most recent major update. We’ll get into commands, monorepo support, improvements in CI/CD integration, and new rules for the analyzer. Now the tool has a website with documentation.
Commands
The original task of Dart Code Metrics was to collect and present code metrics as well as provide additional analyzer rules with more flexible configuration. We decided to further expand the tool’s capabilities and add commands that help maintain the quality of the codebase.
One of the commands is check-unused-files. Its task is to search for unused Dart files.
You can read more about it in this article.
The previous call to code analysis is now also available as a command, and is called analyze.
You used to call the cli with:
$ dart run dart_code_mertics:metrics lib
now it will look like this:
$ dart run dart_code_mertics:metrics analyze lib
We decided to keep support for $ dart run dart_code_mertics: metrics lib
in version 4.0. It will work at least up to version 5.0, so no changes to CI are required at the moment.
Monorepo support
Starting with version 4.1, we’ve improved monorepo support; the analysis context is now defined correctly for each package in a monorepo. This applies both to the situation when each package has a separate analysis_options.yaml
, and to situations when there’s only one analysis_options.yaml
in the root of the monorepo.
Monorepo support made it possible to use Dart Code Metrics with tools like melos. Now you can add a step to melos.yaml
and it will use the correct analysis_options for each monorepo package.
The melos configuration should look like this:
Improvements in CI/CD integration
We’re also working on improving integration into various CI/CD processes. In this release, we’ve added GitHub Action; it not only makes Dart Code Metrics integration easier, but also contains a more detailed report compared to the cli’s — reporter=github option.
Here’s what the GitHub Action configuration can look like:
For more information on GitHub Action configuration, check out the documentation.
Integration with GitLab wasn’t left out of sight, either. Now the documentation has a description of how you can integrate Dart Code Metrics.
The configuration might look like this:
New rules for Flutter
In this release we focused on rules for Flutter and added four new ones.
Prefer extracting callbacks. Checks that the callbacks used for the arguments of the widget like onPressed are in separate methods and not implemented in place. The main purpose of this rule is to make the widget code inside the build method easier to read.
For example:
In extreme cases, the code in the build method of the widget can consist mostly of the code for such callbacks, making it difficult to understand what parts the widget is made of.
That said, the rule doesn’t work for one-line callbacks, so code like onPressed: () => _handler(…)
or onPressed: _handler
is correct from the rule’s perspective.
See documentation for more information about Prefer extracting callbacks.
Avoid unnecessary setstate. Makes sure setState isn’t called synchronously within initState, didUpdateWidget, and build methods of the widget. Such a call to setState results in unnecessary additional re-renderings of the widget.
Here’s an example where the rule outputs an error:
In this example, setState(() => myString = “Hello”);
will cause additional re-rendering, so the rule will highlight this use of setState.
Consider another example:
Calling setState in this example won’t trigger the rule, since the call comes from an asynchronous method.
See documentation for more information about Avoid unnecessary setState.
Avoid wrapping in padding. Checks that a widget wrapped in a Padding widget doesn’t have a padding setting that can be used instead of wrapping in a Padding widget.
Getting rid of redundant padding allows you to avoid extra Padding widgets in the build method of the widget, making it more readable and allowing you to make the widget tree one level smaller.
See documentation for more information about Avoid wrapping in padding.
Always remove listener. Checks that a subscription added via .addListener(…) is removed in the dispose method of the widget. Failure to remove a subscription leads to memory leaks, which can have a significant performance impact in situations where the widget creating the subscription is initialized a large number of times during the application lifecycle.
In this example, the rule will inform you that the _scrollController.addListener(listener);
subscription in the dispose method wasn’t removed.
See the documentation for more about Always move listener.
Note: This rule doesn’t handle Dart streams, so it’s marked as experimental. If you have any ideas on how to improve it, let us know!
We’d be glad to receive your feedback and ideas on new rules, metrics or commands! You can always find us in the community chat on Telegram or leave us an issue on GitHub. We’re also looking forward to new contributors. If you’re interested in plunging into the world of static analysis, but don’t know where to start, we’d be happy to tell you how the tool works and help you implement your first rule.