Skip to main content
Pro+

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).

info

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

Similarity report example

Highlighted Subtree Example

Highlighted subtree example

Showing Statically Resolved Widget Trees

When similarity reporting is enabled, the report will also include the resolved widget tree.

Resolved tree example

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.

Console

HTML

Use --reporter=html to get output in HTML format.

HTML Report Overview

HTML

HTML Single File Report

HTML

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 format
  • records - an array of objects
  • summary - 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 file
  • widgets - 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 record
  • value - 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 entity
  • fromRead - 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 level
  • methodMetrics an array of method metrics
  • mixins - an array of used mixins (strings)
  • name - widget name
  • score - quality score
  • similarWidgets - an array of similar widgets
  • topLevelMetrics - an array of top level metrics
  • type - widget type
  • usedBy - an array of used widgets (strings)
  • usedWidgets - an array of used widgets
  • stateCodeSpan - 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 entity
  • end - an end location of an entity
  • text - 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 source
  • line - a zero-based line of the location in the source
  • column - 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 method
  • level - method quality level
  • metrics - an array of top level metrics
  • name - method name
  • score - 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 level
  • name - method name
  • value - method quality score
{
"isInverted": false,
"level": "Medium",
"name": "cyclomatic-complexity",
"value": 20
}

The similar widgets object fields are

  • widget - the name of the similar widget
  • similarity - similarity score
{
"widget": "AnotherWidget",
"similarity": 0.6
}

The used widget object fields are

  • path - absolute path to widget
  • references - number of references
  • type - 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>
note

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"
}
]
}