code_quality_cli 1.0.3 copy "code_quality_cli: ^1.0.3" to clipboard
code_quality_cli: ^1.0.3 copied to clipboard

Installable CLI that audits a Flutter/Dart project's assets, source code, and pubspec dependencies with a shared, colorized report format.

code_quality_cli #

A single, installable CLI that audits a Flutter/Dart project's assets, source code, and pubspec dependencies — one discoverable command, a shared colorized report format, and a --json mode CI can gate on.

Install #

dart pub global activate code_quality_cli
code_quality_cli --help

This puts code_quality_cli on your PATH, usable from any Flutter/Dart project via --path (defaults to the current directory).

From source #

To run a checkout of this repo instead of the published package (e.g. while developing it):

dart pub get
dart run bin/code_quality_cli.dart --help

Or activate that local checkout globally:

dart pub global activate --source path .
code_quality_cli --help

Usage #

code_quality_cli <command> [options]
Command What it checks
assets Unused assets, broken (missing/unregistered) references, dynamic references
code Unused files, comment-heavy files, commented-out dead code, largest files
packages Unused/missing/unpinned dependencies, dev-dep-in-lib and lib-dep-in-test-only miscategorization
all Runs all three and prints a combined scorecard

Run with no arguments in an interactive terminal and it will prompt you for which audit to run (and, for code/all, the comment-density limit) instead of just printing usage:

$ code_quality_cli
? Which audit would you like to run? (Use arrow keys)
❯ All (assets + code + packages)
  Assets
  Code
  Packages

In a non-interactive context (CI, piped output, --json), this fallback never fires — invoking with no subcommand just prints usage and exits 2, so a CI job can never hang waiting on stdin.

Global options #

Flag Default Meaning
-p, --path=<dir> . Project root to audit
--json off Emit machine-readable JSON instead of the report
--no-color (auto) Disable ANSI colors (auto-disabled outside a terminal)
--strict off Exit non-zero on warnings too, not just errors
-v, --verbose off Show full lists instead of truncating to 10 items per section
-h, --help Print usage

code-only options #

Flag Default Meaning
--comment-limit=<percent> 20 Flag files whose comment lines exceed this percent
--top=<n> 10 Largest-files leaderboard size

Examples #

# Audit assets in the current project
code_quality_cli assets

# Audit another repo, failing CI on warnings too
code_quality_cli all --path ../other_app --strict

# Flag files >30% comments, machine-readable output
code_quality_cli code --comment-limit 30 --json

What each audit checks #

assets #

Cross-references the files on disk, the folders registered under flutter: assets: in pubspec.yaml, and every asset path referenced from Dart source in lib/.

  • Broken references (error) — a literal path referenced in lib/ that either doesn't exist on disk at all, or exists but its folder isn't listed under flutter: assets:, so Flutter won't bundle it.
  • Unused assets (warning) — files that live under a registered assets/ folder but are never referenced (by literal path or a FlutterGen-generated accessor) anywhere in lib/.
  • Notes (info) — dynamic/interpolated asset references that can't be resolved statically, and on-disk files outside any registered folder.

This is a heuristic, grep-based scan, not a full static analyzer — see the doc comment at the top of lib/src/audits/asset_audit.dart for the exact rules and their limitations (e.g. paths built via string concatenation aren't recognized).

code #

  • Unused files (warning) — files under lib/ with zero incoming import/export references from lib/ or test/ (excluding lib/main.dart, the entry point).
  • Comment hygiene (info) — files whose comment-line percentage exceeds --comment-limit, and runs of 3+ consecutive // lines that look like dead code rather than prose. /// documentation comments are not counted toward the density limit — they're documentation, not clutter.
  • Largest files (info) — the biggest files by line count, up to --top.

"Unused" means zero incoming references, not "unreachable from main.dart" — a full transitive-reachability analysis would catch more but risks false positives on real files (conditional imports, etc.), so this scan deliberately under-reports rather than over-reports.

packages #

Cross-references dependencies:/dev_dependencies: in pubspec.yaml against every package: import found in the codebase.

  • Missing dependencies (error) — imported somewhere but not declared directly (only resolvable today because something else pulls it in transitively — one version bump upstream and the build breaks).
  • Dependency hygiene (warning):
    • Unused — declared under dependencies: but never imported. dev_dependencies: is exempt from this check: build tools and codegen (build_runner, lints, flutter_launcher_icons, ...) are legitimately consumed via CLI/build.yaml, never a Dart import, and would otherwise always show up as false positives.
    • Unpinned — no version constraint at all.
    • A dev_dependencies: entry imported from lib/ (miscategorized — it's shipping in the app, not just used for building/testing).
    • A dependencies: entry only ever imported from test/ (candidate to move to dev_dependencies:).

Sample output #

📋 Combined audit — my_app

  ┌───────────────────────┬───────┐
  │ Broken references     │  2 ❌ │
  │ Unused assets         │ 12 ⚠️ │
  │ Notes                 │  1 ℹ️ │
  │ Unused files          │  3 ⚠️ │
  │ Comment hygiene       │  4 ℹ️ │
  │ Largest files         │ 10 ℹ️ │
  │ Missing dependencies  │  1 ❌ │
  │ Dependency hygiene    │  6 ⚠️ │
  │ Reclaimable           │ 484 KB │
  └───────────────────────┴───────┘

📦 Asset
❌ Broken references (2)
   assets/images/store.png
     └─ lib/src/checkout/receipt_page.dart:65

...

❌ Issues found — see errors above.

--json output #

Every command accepts --json for machine-readable output instead of the colorized report — useful for CI gating or piping into another tool:

$ code_quality_cli assets --path . --json
{
  "tool": "assets",
  "summary": { "Reclaimable": "484.1 KB" },
  "sections": [
    {
      "title": "Broken references",
      "findings": [
        {
          "severity": "error",
          "message": "assets/images/store.png",
          "location": "lib/src/checkout/receipt_page.dart:65",
          "detail": "file doesn't exist"
        }
      ]
    }
  ],
  "hasErrors": true,
  "hasWarnings": false
}

all --json wraps the same shape as {"reports": [...], "hasErrors": ..., "hasWarnings": ...}, one entry per audit.

Exit codes #

Code Meaning
0 No errors (warnings are fine unless --strict)
1 At least one error-level finding (or any finding, under --strict)
2 Tool failure — bad arguments, unreadable/missing project

CI usage #

A GitHub Actions recipe is included at .github/workflows/code_quality.yml: it runs dart analyze/dart test on this repo, then runs code_quality_cli all --json --strict and uploads the JSON report as a build artifact, failing the job on any finding. Point --path at a different checkout to audit another repo instead of this one.

Programmatic use #

Each audit is a pure, injectable function (auditAssets, auditCode, auditPackages) that only touches the filesystem under a given repoRoot, independent of the CLI:

import 'package:code_quality_cli/code_quality_cli.dart';

final result = auditAssets(repoRoot: '/path/to/project');
print(result.unusedAssets);

// Or work with the same shared report model the CLI renders:
final report = result.toReport();
print(report.hasErrors);

Architecture #

lib/src/
  audits/    auditAssets / auditCode / auditPackages — pure functions, one
             result class + a toReport() mapper per audit. No CLI/rendering
             concerns; each is independently testable against a repoRoot.
  report/    Finding / AuditSection / AuditReport — the shared vocabulary
             every audit's toReport() translates into, plus Renderer, the
             one place terminal/JSON formatting lives.
  cli/       CodeQualityCommandRunner (package:args CommandRunner), the four
             Command subclasses, and command_support.dart's shared
             run → render → exit-code pipeline.

The audits know nothing about the CLI or the report model; the CLI knows nothing about how an audit works, only that it produces an AuditReport. Adding a new audit means: write a pure auditX({required repoRoot}) function, add a toReport() extension, and wire up one Command — the renderer, JSON output, exit-code semantics, and all scorecard all come for free.

Development #

dart pub get
dart analyze
dart test

test/fixtures/sample_project/ is a small, hand-built Dart project with deliberate issues (a broken asset reference, an unused file, a missing dependency, ...) that the test suite runs the real audits against — see test/audits/*_test.dart and test/cli/*_test.dart. It's excluded from the published package via .pubignore since its imports are intentionally fake.

Generate API docs locally with:

dart doc .
2
likes
130
points
251
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Installable CLI that audits a Flutter/Dart project's assets, source code, and pubspec dependencies with a shared, colorized report format.

Topics

#cli #linter #static-analysis #flutter #tools

License

MIT (license)

Dependencies

args, mason_logger

More

Packages that depend on code_quality_cli