dartrics

pub package GitHub license CI codecov

Dart code-quality metrics and unused public-API detection, designed as the AI-loop counterpart of dart analyze.

AI agents — start here: run dartrics ai-loop (or read doc/ai-loop.md) before driving the tool. It is the operational playbook — the shell commands you actually run, the prompt examples that wire them into Claude / Cursor / Codex / Aider / OpenHands, and the dismiss-comment syntax. dartrics manual is the conceptual companion: lens design, refactor / dismiss / accept / punt decision tree, full flag catalogue, snapshot-cache caveat for verify loops. Both ship in the binary so dart pub global activate dartrics is enough.

What it does

dartrics computes a battery of code-quality metrics — McCabe, Cognitive Complexity (Sonar), Chidamber & Kemerer, Martin, Halstead — on top of package:analyzer, alongside an analyzer-element BFS for unreachable public API à la Periphery. Every report mode is shaped to be consumed: --reporter ai ships a token-efficient YAML-ish bundle, sorted by actionability, with each metric's rationale, refactor hints, and primary-source citation embedded inline.

Designed for the AI loop

  • Auto-explain by default — rationale, refactor hints, and primary-source citation ride alongside every fired metric, so an agent reads the why without a second tool call.
  • Stable IDs across runs — every violation carries a 16-hex-char id (sha256("<file>|<scope>|<metric>")), reappearing across runs so AI loops can detect "my fix didn't take". Surfaces as partialFingerprints.dartrics/v1 in SARIF.
  • Docs in the binarydartrics ai-loop prints the operational playbook (commands, prompts, dismiss syntax) and dartrics manual prints the lens reference; dart pub global activate dartrics is enough, no separate doc download.

Install

dart pub global activate dartrics

dartrics runs on Dart SDK 3.13 or newer, and can analyse projects that target an older SDK.

Quick start

# Token-efficient YAML-ish report optimised for LLM consumption.
dartrics analyze lib/ --reporter ai | claude -p "Refactor the threshold violations"

# After the agent applies a fix: confirm metrics actually improved.
dartrics regression --before HEAD~1 --after HEAD --reporter ai

# Read the operational playbook (start here) or the lens reference in the terminal.
dartrics ai-loop
dartrics manual

Subcommands

Command Purpose
analyze Every metric + the public-API unused detector. Emits signals: (call-graph fan-in / fan-out per declaration) as reference information alongside the thresholded metrics.
unused Public-API reachability only (fast path).
inspect <symbol> [<symbol> ...] Walk the resolved call graph around one or more named declarations in a single analysis pass; --depth / --direction up|down|both configure the walk. Reference-only output; emits ai (default) or json.
report <input.json> Re-emit a previously saved JSON report in another format.
rules Catalogue every metric with rationale, refactor hints, and references.
regression Compare metrics between two git states; classify each delta as improved / regressed / unchanged / added / removed.
ai-loop Operational playbook: commands, prompts, dismiss syntax — start here for agents (mirrors doc/ai-loop.md).
manual Conceptual reference: lens design, decision tree, full flag catalogue (mirrors doc/manual.md).
doctor Validate the dartrics: block in analysis_options.yaml.

Each subcommand only exposes the flags it actually consumes — dartrics <command> --help lists them. Full flag reference, dismissal mechanics, coverage / snapshot / regression details, and the refactor / dismiss decision tree all live in dartrics ai-loop (the playbook) and dartrics manual (the reference).

Provided metrics

dartrics ships a curated set anchored to published sources. For the audit trail — selection principles, deviations from the cited definitions, off-by-default rationale — see doc/calibration.md.

Each metric exposes rationale, refactorHints, references (the primary source — McCabe 1976, Hitz & Montazeri 1995, Martin 1994, …), and polarity (down / neutral). All four surface through dartrics rules and the AI / md / SARIF reporters so an agent can verify a metric against its original paper rather than paraphrasing from training data.

Lenses marked off ship disabled by default; opt in via dartrics: { metrics: { <id>: { enabled: true } } }. A in Default warning means the lens emits a measurement but fires no warning until you set a threshold via dartrics: { metrics: { <id>: { warning: <n> } } }.

Function / method level

Metric Reference Default warning
Cyclomatic Complexity McCabe 1976 10
Cognitive Complexity SonarSource 2017 (rev.) 15
Number Of Parameters Fowler 1999 4
Source Lines Of Code Boehm 1981
Method Length off Beck 1996 opt-in
Halstead Volume off Halstead 1977 opt-in

Class level

Metric Reference Default warning
Number Of Methods Lorenz & Kidd 1994; CK 1994
Weighted Methods Per Class CK 1994
LCOM4 Hitz & Montazeri 1995
Coupling Between Objects CK 1994
Response For a Class CK 1994
Class Length Beck 1996; Fowler 1999; Lippert & Roock 2006

Library / file level (Martin 1994)

Polarity neutral; values rank change-impact rather than fire as Pain/Uselessness verdicts (see doc/calibration.md).

Metric Notes Default warning
Efferent Coupling (Ce) distinct project-internal + package: dependencies (excludes dart:*)
Afferent Coupling (Ca) incoming internal-import edges
Instability (I) Ce / (Ca + Ce); informational, surfaces drift in change-impact ranking

Configuration

Minimal analysis_options.yaml:

# yaml-language-server: $schema=https://rawgit.flutter-io.cn/koji-1009/dartrics/main/schemas/dartrics-config.schema.json

dartrics:
  metrics:
    cyclomatic-complexity:
      warning: 10
      error: 20
    cognitive-complexity:
      warning: 15
  exclude:
    - "lib/generated/**"

The dartrics: section is read by both the CLI and the analyzer plugin. The # yaml-language-server directive turns on autocomplete + typo detection in editors with yaml-language-server integration. Every key (per-metric thresholds, dismissals, snapshot mode, unused-detector filters) is documented in schemas/dartrics-config.schema.json and explained in dartrics manual.

--config <path> points the CLI at a different file for the dartrics: block only. Which files get analysed — including why that file's analyzer.exclude has no effect — is covered under "Which files are analysed" in the manual.

Analyzer plugin

dartrics ships its own analyzer plugin so the three lightweight function-level rules surface inline in dart analyze and the IDE.

# analysis_options.yaml in your project
plugins:
  dartrics: ^1.0.0

The version constraint is required — a bare dartrics: with no value is rejected as invalid_section_format and the plugin never loads. dartrics does not need to be in your pubspec.yaml; the analysis server resolves the plugin package from this constraint on its own.

After saving, restart the analysis server. Three rules ship by default:

Rule Default threshold
dartrics_cyclomatic_complexity 10
dartrics_cognitive_complexity 15
dartrics_number_of_parameters 4

Heavier metrics (LCOM4, CBO, RFC, library coupling) and the public-API unused detector intentionally stay CLI-only because they need a project-wide index that an analysis-server plugin can't maintain efficiently per file.

Documentation

  • dartrics ai-loop — operational playbook: shell commands, prompt examples, dismiss syntax, four-station walkthrough of one full refactor iteration. Start here when you want to run dartrics.
  • dartrics manual — conceptual reference: lens design (why multiple at once), every flag, dismissal mechanics, refactor / dismiss decision tree, Flutter-aware and test-aware modes, exit codes. Come back here when you need to know why a lens fires.
  • doc/calibration.md — citation audit, selection principles, counting-rule deviations.
  • schemas/ — JSON Schema files: dartrics-config.schema.json for analysis_options.yaml's dartrics: block, dartrics-report.schema.json for the JSON reporter output, dartrics-dismissals.schema.json for the dismissals sidecar. All draft-2020-12.

Output formats

--reporter accepts console (default), json (stable schema, see schemas/dartrics-report.schema.json), md (PR comments / issue bodies), ai (token-efficient YAML-ish bundle starting with # dartrics ai-report v1), and sarif (SARIF 2.1.0 for GitHub Code Scanning / GitLab).

Embedding

lib/dartrics.dart is intentionally tight — it exposes only the function-level metric calculators so a custom CI bot or editor extension can compute one metric on a parsed CompilationUnit without spinning up the full engine.

What you get Names
Function-level metric calculators CyclomaticComplexity, CognitiveComplexity, NumberOfParameters, MethodLength, SourceLinesOfCode, HalsteadCounts / HalsteadVolume
Calculator interface FunctionMetric, FunctionMetricInput, MetricPolarity
Version string dartricsVersion

Anything not in this table is CLI-only and unsupported as a Dart import; reach for dartrics analyze --reporter json instead. example/main.dart shows a minimal standalone embedding against CyclomaticComplexity.

Limitations

  • The analyzer plugin covers only the three function-level rules (CC, Cognitive, Number of parameters). LCOM4 / CBO / RFC / library coupling and the unused detector are CLI-only because they need a project-wide index that the analyzer-plugin API can't maintain efficiently per-file.
  • Built-in metric set is curated. See doc/calibration.md for the selection principles.
  • Per-file Martin granularity. efferent-coupling / afferent-coupling / instability ship as change-impact rankings rather than Pain/Uselessness verdicts (polarity neutral, no default warning). See doc/calibration.md.
  • Not a fit if you need per-line metric thresholds in the IDE for the full metric suite, you don't engage with the dismiss channel at all (a pure-fail-fast linter is a better fit), or you're on Dart < 3.13 / analyzer < 14.

Development

dart pub get
dart format lib test example
dart analyze lib test example   # `dart analyze` (no path) loads the plugin isolate and may flake
dart test
dart pub run coverage:test_with_coverage  # 100% line coverage is required

See AGENTS.md for the contributor / AI-agent workflow notes.

License

MIT.

Libraries

dartrics
Programmatic entry for embedding dartrics — the function-level metric calculators only.
main
Top-level analyzer-plugin entrypoint required by analysis_server_plugin.