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_sizedead_codedocumentationduplicate_codehardcoded_stringslayersmagic_numbersone_class_per_filesecretssource_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 asapp_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_sortingauto-fixes:- Reorders Flutter widget class members to match fCheck sorting rules.
- Reorders
importdirectives with these groups:dart:*- all
package:*imports (includingflutterand 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/topackage:<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.defaultacceptson|offandtrue|false- Opt-in mode:
analyzers:
default: off
enabled:
- magic_numbers
- secrets
- Config precedence: built-in defaults <
.fcheck< CLI flags input.rootis resolved relative to the.fcheckfile location--excludeadds patterns on top of.fcheckinput.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_codesuppresses 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
Layers Folder 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_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