fCheck

fCheck provides fast local quality analysis for Flutter and Dart projects with 0-100% compliance scoring. Single analysis pass covering architecture, maintainability, and safety issues beyond standard linting, with deterministic CLI/JSON reports for CI/CD pipelines and fully private execution: it does not require any AI service, no network calls are needed, and no source code is sent to external services.

Why fCheck

  • Single local run for multiple quality domains
  • Deterministic output for CI and code review
  • 100% private local execution (no AI service, no code sent externally)
  • Console, JSON, and diagram outputs
  • Includes test discovery metrics (hasTests, testDirectories, testFiles, testDartFiles, testCases)
  • Works as a CLI tool
  • Works as a Dart package in your own app/tooling

Checks Included

  • code_size
  • dead_code
  • documentation
  • duplicate_code
  • hardcoded_strings
  • layers
  • magic_numbers
  • one_class_per_file
  • secrets
  • source_sorting

Detailed behavior and edge cases are documented in RULES*.md.

Hardcoded-strings note:

  • If project localization is OFF, hardcoded-strings runs in passive mode ([-]), reports only the total count, and does not affect compliance score/focus area.
  • If project localization is OFF, hardcoded-string findings are also excluded from SVG warning tint/counters (fcheck_files.svg, fcheck_folders.svg, fcheck_loc.svg).
  • If localization is ON, hardcoded-strings is active and reports detailed issue entries.

Code-size LOC note:

  • Localization Dart files are excluded from LOC code-size evaluation (lib/l10n/**, app_localization.dart, app_localizations.dart, and generated locale variants such as app_localizations_<locale>.dart).

Install

Option 1: Global CLI

dart pub global activate fcheck
fcheck .

Option 2: Project Dev Dependency

dart pub add fcheck -d
dart run fcheck .

Option 3: Use as a Dart package in your app/tool

dart pub add fcheck
import 'dart:io';
import 'package:fcheck/fcheck.dart';

void main() {
  final metrics = AnalyzeFolder(Directory('.')).analyze();
  print('Score: ${metrics.complianceScore}%');
}

Quick Start (CLI)

# Analyze current folder
fcheck .

# Analyze another folder
fcheck ../my_app
fcheck --input ../my_app

# JSON output
fcheck --json

# Full list output
fcheck --list full

# Generate diagrams
fcheck --svg --mermaid --plantuml

# Auto-fix source sorting issues (class members + import directives)
fcheck --fix

What --fix does

  • Rewrites Dart source files in place.
  • Applies only source_sorting auto-fixes:
    • Reorders Flutter widget class members to match fCheck sorting rules.
    • Reorders import directives with these groups:
      • dart:*
      • all package:* imports (including flutter and your own package), alphabetical
      • other absolute URIs (for example http:)
      • relative imports
    • Inserts one blank line between import groups.
    • Rewrites relative imports that resolve under lib/ to package:<this-package>/....
  • Does not auto-fix other analyzers; it only reports their issues.

Sample Bash Output

$ fcheck .
↓------------------------------ fCheck 1.0.8 -------------------------------↓
Input              : /path/to/project
Dart Project       : my-cool-app (version: 9.0.0)
Platforms          : [✓Android] [✓iOS]  [✓MacOS] [✓Windows] [✓Linux]   [✓Web]
--------------------------------- Dashboard ---------------------------------
Dependencies       :               5  |  DevDependencies    :               2
Folders            :              21  |  Classes            :              66
Files              :             120  |  Widgets: Stateful  :              26
Excluded Files     :              39  |  Widgets: Stateless :              40
Dart Files         :              91  |  Methods            :             357
Lines of Code      :       15.0 KLoC  |  Functions          :             179
Comments           :     2,145 (14%)  |
----------------------------------- Tests -----------------------------------
Test Dart Files    :              35  |  Touched Dart Files :         41 (45%)
Test Cases         :             392  |  Touched Classes    :         31 (47%)
                                      |  Touched Methods    :        144 (40%)
                                      |  Touched Functions  :         73 (41%)
--------------------------------- Literals ----------------------------------
Localization       : ON
Strings            : 1,203 (64% dupe)
Numbers            :   842 (74 hardcoded)
--------------------------------- Analyzers ---------------------------------
[✓] Checks bypassed
[✓] Code size
[✓] Dead code
[✓] Documentation
[✓] Duplicate code
[✓] Layers architecture
[✓] Magic numbers
[✓] One class per file
[✓] Secrets
[✓] Source sorting
[✓] Hardcoded strings
--------------------------------- Scorecard ---------------------------------
Total Score        : 100%
Invest Next        : Maintain this level by enforcing fcheck in CI on every pull request.
↑------------------------ fCheck completed (1.73s) -------------------------↑

The Touched ... rows are a static inventory derived from test-file imports plus transitive project-local Dart dependencies. They indicate source reached by test dependency graphs, not code coverage.

Configuration (.fcheck)

Create .fcheck in the input directory (--input) or current directory.

input:
  root: app
  exclude:
    - "**/generated/**"
    - "**/*.g.dart"

analyzers:
  default: on
  disabled:
    - hardcoded_strings
    - source_sorting
  options:
    duplicate_code:
      similarity_threshold: 0.85 # 0.0..1.0
      min_tokens: 20
      min_non_empty_lines: 10
    code_size:
      max_file_loc: 900
      max_class_loc: 800
      max_function_loc: 700
      max_method_loc: 500

Notes:

  • analyzers.default accepts on|off and true|false
  • Opt-in mode:
analyzers:
  default: off
  enabled:
    - magic_numbers
    - secrets
  • Config precedence: built-in defaults < .fcheck < CLI flags
  • input.root is resolved relative to the .fcheck file location
  • --exclude adds patterns on top of .fcheck input.exclude

Ignore Directives

Use top-of-file or line-level ignore directives:

// ignore: fcheck_dead_code
// ignore: fcheck_documentation
// ignore: fcheck_duplicate_code
// ignore: fcheck_hardcoded_strings
// ignore_for_file: avoid_hardcoded_strings_in_widgets
// ignore: fcheck_layers
// ignore: fcheck_magic_numbers
// ignore: fcheck_one_class_per_file
// ignore: fcheck_secrets

CLI help to guide you on how to exclude some of checks

fcheck --help-ignore

Dead-code note:

  • // ignore: fcheck_dead_code suppresses dead-code findings for that file's declarations, while keeping its dependencies/usages in global dead-code analysis.
  • Dead-code usage tracking includes property-style getter/setter access and operator usage (+, -, [], etc.) inferred from expression syntax.
  • Functions/methods annotated with @Preview (including prefixed forms such as @ui.Preview) are treated as externally used and are not reported as dead functions.

Visual Outputs

fcheck --svg          # shortcut: fcheck_files.svg + fcheck_folders.svg + fcheck_loc.svg
fcheck --svg-files    # fcheck_files.svg
fcheck --svg-folders  # fcheck_folders.svg
fcheck --svg-loc      # fcheck_loc.svg
fcheck --mermaid      # fcheck.mmd
fcheck --plantuml     # fcheck.puml

# Custom output base directory
fcheck --svg --mermaid --plantuml --output ./reports/fcheck

# Per-artifact file overrides
fcheck --svg --output-svg-files ./artifacts/graph/files.svg
fcheck --svg-folders --output-svg-folders ./artifacts/graph/folders.svg
fcheck --svg-loc --output-svg-loc ./artifacts/graph/loc.svg
fcheck --mermaid --output-mermaid ./artifacts/graph/fcheck.mmd
fcheck --plantuml --output-plantuml ./artifacts/graph/fcheck.puml

Layers Files diagram

fcheck layers files diagram

Layers Folder diagram

fcheck Layer folders diagram

Orange upward folder dependencies in fcheck_folders.svg are also emitted in CLI report output as layers warnings (wrongFolderLayer) with the source Dart file path.

Warning/error-highlighted file and folder nodes in layers SVGs now use a softer transparent gradient tint (instead of opaque flat fills) to preserve node text/details readability.

Code size diagram

fcheck code size diagram

fcheck_loc.svg uses a unified treemap hierarchy: Folders > Files > Classes > Functions.

Warning highlighting in fcheck_loc.svg:

  • Artifacts with analyzer findings are tinted on a red transparency spectrum (low warnings => light pink, high warnings => stronger red).
  • Dead artifacts are treated as maximum severity tint.
  • SVG tooltips include warning counts and sampled issue details for each affected file/class/function tile.

Exclusions

# Add custom excludes
fcheck --exclude "**/generated/**" --exclude "**/*.g.dart"

# Inspect excluded items
fcheck --excluded
fcheck --excluded --json

# Inspect ignore/suppression inventory (.fcheck + Dart directives)
fcheck --ignores
fcheck --ignores --json

# Inspect literals inventory only
fcheck --literals
fcheck --literals --json

--ignores groups results by suppression type (exclude, analyzer skips, and Dart comment directive type) so cleanup work can be prioritized. --literals full list text output od all the literals in your project.

Default exclusion behavior includes hidden folders and common non-analysis directories (.git, .dart_tool, build, example, test, integration_test, platform folders, etc.).

Generated Dart files ending with *.g.dart are analyzed for dependency/usage flow, but non-actionable checks are suppressed (for example code size, one-class-per-file, dead-code declarations, hardcoded strings, magic numbers, sorting, duplicate code, and documentation).

CI Example (GitHub Actions)

name: CI
on:
  pull_request:
  push:
    branches: [main]

jobs:
  quality:
    name: Build, test, and self-check (100%)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          channel: stable
      - run: flutter pub get
      - run: ./tool/generate_version.sh
      - run: dart format --output=none --set-exit-if-changed .
      - run: flutter analyze lib test --no-pub
      - run: dart test --reporter=compact
      - run: dart run ./bin/fcheck.dart --json --exclude "**/example" . > fcheck-report.json
      - run: |
          score="$(grep -oE '"complianceScore"[[:space:]]*:[[:space:]]*[0-9]+([.][0-9]+)?' fcheck-report.json | head -n1 | sed -E 's/.*:[[:space:]]*//')"
          score_int="$(awk "BEGIN { printf \"%d\", ${score} }")"
          test "$score_int" -eq 100
      - uses: actions/upload-artifact@v4
        with:
          name: fcheck-report
          path: fcheck-report.json

This repository already includes this workflow at .github/workflows/ci.yml. The CI gate fails unless fcheck's self-analysis score is exactly 100%.

License

MIT

Libraries

fcheck