Analyze Widgets
Reports the quality and usage of your widgets.
Shows the number widgets / blocs / context.read / context.watch being used, the number of widgets using a particular widget, similar widgets and a widget quality score (based on code metrics).
This command uses metrics configuration from the analysis_options.yaml
file and uses the following configuration as a fallback configuration:
cyclomatic-complexity: 20
halstead-volume: 300
maintainability-index: 50
maximum-nesting-level: 5
number-of-parameters: 6
source-lines-of-code: 50
To execute the command, run:
$ dcm analyze-widgets lib # or dcm aw lib
Full command description:
Usage: dcm analyze-widgets [arguments] <directories>
-h, --help Print this usage information.
--show-similarity Include similar widgets into the report.
--threshold Set a minimum threshold after which widgets are considered similar.
(defaults to "0.2")
-r, --reporter=<console> Analysis output format.
[console(Pro+) (default), html(Pro+), json(Teams+), codeclimate(Teams+), gitlab(Teams+), checkstyle(Teams+), sonar(Teams+)]
-a, --absolute-path Use absolute path for console reporter output.
-o, --output-directory=<OUTPUT> Write HTML output to OUTPUT.
(defaults to "widgets_report")
--open Automatically open generated HTML report
--json-path=<path/to/file.json> Path to the JSON file with the analysis output.
--report-all Report all widgets (default is to report only medium or low quality widgets).
-c, --print-config Print resolved config.
--root-folder=<./> Root folder.
(defaults to the current directory)
--sdk-path=<directory-path> Dart SDK directory path.
If the project has a `.fvm/flutter_sdk` symlink, it will be used if the SDK is not found.
--exclude=<{**/*.g.dart,**/*.freezed.dart}> File paths in Glob syntax to be exclude.
(defaults to "{**/*.g.dart,**/*.freezed.dart}")
--no-congratulate Don't show output even when there are no issues.
--verbose Show verbose logs.
--ci-key The license key to run on CI server. Can be provided via DCM_CI_KEY env variable.
--email The email used to purchase the license. Can be provided via DCM_EMAIL env variable.
--no-analytics Disable sending anonymous usage statistics.
--fatal-level=<low> Treat given or lower quality level as fatal.
[low, medium]
Detecting Similar Widgets (disabled by default)
To include similar widgets into the report, pass --show-similarity
CLI flag.
Similarity report includes:
- name of the similar widget
- source code of the similar widget with highlighted subtree matches
- similarity percentage of the build method widget tree
- list of the matching widgets subtree
By default, a pair of widgets is considered similar if their subtrees match more than 20%.
You can customize this threshold via the --threshold
CLI option.
Report Example
Highlighted Subtree Example
Showing Statically Resolved Widget Trees
When similarity reporting is enabled, the report will also include the resolved widget tree.
This widget tree includes all found widgets and shows which widgets are rendered conditionally (e.g. via if (condition) MyWidget
) and which are inside multi-child layout widgets (e.g. Column
, Row
, etc.).
Reporting All Widgets
By default only the HTML reporter shows all widgets.
To enable output of all widgets (regardless of their quality level) for other reporters, pass the CLI flag --report-all
.
Output Example
Console (default)
Use --reporter=console
to get output in console format.
HTML
Use --reporter=html
to get output in HTML format.
HTML Report Overview
HTML Single File Report
JSON
Use --reporter=json
to get output as a single JSON object containing metadata and the list of widgets.
Format specification
The root object fields are
formatVersion
- an integer representing the format version (will be incremented each time the serialization format changes)timestamp
- a creation time of the report in YYYY-MM-DD HH:MM:SS formatrecords
- an array of objectssummary
- an array of objects
{
"formatVersion": 2,
"timestamp": "2021-04-11 14:44:42",
"records": [
{
...
},
{
...
},
{
...
}
],
"summary": [
{
...
},
{
...
}
]
}
The record object fields are
path
- a relative path to the target filewidgets
- an array with target file widgets
{
"path": "lib/src/widgets/some_widget_file.dart",
"widgets": {
...
},
}
The summary-record object fields are
title
- a message with information about the recordvalue
- an actual value of this record (is a single value)
{
"title": "Scanned folders",
"value": 50,
}
The widget object fields are
blocs
- an array of used blocs (strings)codeSpan
- a source code span of the target entityfromRead
- an array of classes from context.read (strings)fromWatch
- an array of classes from context.watch (strings)interfaces
- an array of used interfaces (strings)level
- widget quality levelmethodMetrics
an array of method metricsmixins
- an array of used mixins (strings)name
- widget namescore
- quality scoresimilarWidgets
- an array of similar widgetstopLevelMetrics
- an array of top level metricstype
- widget typeusedBy
- an array of used widgets (strings)usedWidgets
- an array of used widgetsstateCodeSpan
- a source code span of the widget's state (optional)stateMixins
- an array of state mixins (strings, optional)stateInterfaces
- an array of state interfaces (strings, optional)
{
"blocs": [],
"codeSpan": {
...
},
"fromRead": ["SomeClass"],
"fromWatch": ["AnotherClass"],
"interfaces": [],
"level": "High",
"methodMetrics": [
...
],
"mixins": [],
"name": "MyWidget",
"score": 0.83,
"topLevelMetrics": [
...
],
"usedBy": ["SomeWidget", "AnotherWidget"],
"usedWidgets": [
...
]
}
The code span object fields are
start
- a start location of an entityend
- an end location of an entitytext
- a source code text of an entity
{
"start": {
...
},
"end": {
...
},
"text": "entity source code"
}
The location object fields are
offset
- a zero-based offset of the location in the sourceline
- a zero-based line of the location in the sourcecolumn
- a zero-based column of the location in the source
{
"offset": 156,
"line": 7,
"column": 1
}
The method metrics object fields are
codeSpan
- a source code span associated with the methodlevel
- method quality levelmetrics
- an array of top level metricsname
- method namescore
- method quality score
{
"codeSpan": {
...
},
"level": "Medium",
"metrics": [
...
],
"name": "build",
"score": 0.80
}
The top level metrics object fields are
isInverted
- whether the level value should be inverted (High
means bad)level
- metric quality levelname
- method namevalue
- method quality score
{
"isInverted": false,
"level": "Medium",
"name": "cyclomatic-complexity",
"value": 20
}
The similar widgets object fields are
widget
- the name of the similar widgetsimilarity
- similarity score
{
"widget": "AnotherWidget",
"similarity": 0.6
}
The used widget object fields are
path
- absolute path to widgetreferences
- number of referencestype
- widget type (local, external, flutter)
{
"path": "/path/to/used/widget.dart",
"references": 5,
"type": "local"
}
GitLab
Use --reporter=gitlab
to get output in a GitLab-compatible format. To learn how to integrate DCM with GitLab, refer to this guide.
Code Climate
Use --reporter=codeclimate
to get output in Code Climate
format.
Output example
{"type":"issue","check_name":"widget-quality-report","description":"SelectorsPage quality score is 67% (medium quality)","categories":["Complexity"],"location":{"path":"example/lib/pages/selectors_page.dart","positions":{"begin":{"column":1,"line":8},"end":{"column":2,"line":13}}},"severity":"info","fingerprint":"de8944aa862a6669a0d37302f326459b"}
{"type":"issue","check_name":"widget-quality-report","description":"TypographyPage quality score is 60% (medium quality)","categories":["Complexity"],"location":{"path":"example/lib/pages/typography_page.dart","positions":{"begin":{"column":1,"line":4},"end":{"column":2,"line":394}}},"severity":"info","fingerprint":"a8862f5dcd972504f9a37e5acd5ba647"}
Checkstyle
Use --reporter=checkstyle
to get output in Checkstyle
format.
Output example
<?xml version="1.0"?>
<checkstyle version="10.0">
<file name="../abstract_class.dart">
<error line="0" severity="warning" message="someWidget quality score is 20% (low quality)" source="widget-quality-report"/>
</file>
<file name="../class_with_factory_constructors.dart">
<error line="0" severity="warning" message="anotherWidget quality score is 20% (low quality)" source="widget-quality-report"/>
</file>
</checkstyle>
Checkstyle
format is supported by Bitbucket. To learn how to integrate DCM with Bitbucket, refer to this guide.
Sonar
Use --reporter=sonar
to get output in SonarQube's generic format for external issues.
Output example
{
"rules": [
{
"cleanCodeAttribute": "CLEAR",
"description": "To learn more, visit the documentation https://dcm.dev/docs/cli/analysis/analyze-widgets/",
"engineId": "dcm",
"id": "widget-quality-report",
"impacts": [
{
"severity": "MEDIUM",
"softwareQuality": "MAINTAINABILITY"
}
],
"name": "widget-quality-report"
}
],
"issues": [
{
"primaryLocation": {
"filePath": "lib/src/buttons/segmented_control.dart",
"message": "MacosSegmentedControl quality score is 73% (medium quality)",
"textRange": {
"endColumn": 2,
"endLine": 37,
"startColumn": 1,
"startLine": 4
}
},
"ruleId": "widget-quality-report"
},
{
"primaryLocation": {
"filePath": "lib/src/buttons/pulldown_button.dart",
"message": "_MacosPulldownMenuItemButton quality score is 78% (medium quality)",
"textRange": {
"endColumn": 2,
"endLine": 48,
"startColumn": 1,
"startLine": 28
}
},
"ruleId": "widget-quality-report"
}
]
}