clean_arch_lint 1.1.0
clean_arch_lint: ^1.1.0 copied to clipboard
Custom lint rules for enforcing Clean Architecture boundaries in Flutter/Dart projects.
clean_arch_lint #
Custom lint for Flutter Clean Architecture, focused on enforcing layers using static analysis (AST) with custom_lint.
This package acts as an architecture guardian: if a layer depends on something it shouldn't, the error shows up immediately.
🎯 Objective #
Ensure the structure below is automatically respected:
lib/
├─ core/
├─ data/
└─ presentation/
No PR discussions. No "it was unintentional". The lint solves it.
🧱 Layer Concepts #
core #
Pure layer, without Flutter and without infrastructure.
Contains:
- entities
- usecases
- contracts (interfaces)
- business rules
data #
Technical implementations.
Contains:
- datasources
- models / DTOs
- mappers
- repository implementations (
Impl)
presentation #
User interface.
Contains:
- widgets
- pages
- bloc / cubit
- viewmodels / controllers
🚨 Lint Rules #
1️⃣ core_no_flutter (ERROR) #
❌ Prohibits Flutter imports in core.
Blocks:
package:flutter/*dart:uipackage:flutter_test/*
Reason: Core must be completely independent of UI.
2️⃣ core_no_data_or_presentation (ERROR) #
❌ Prohibits core from depending on data or presentation.
Clean Architecture golden rule:
Dependencies always point inward.
3️⃣ data_no_presentation (ERROR) #
❌ data cannot import anything from presentation.
Reason:
- Avoids coupling infrastructure with UI
- Ensures testability
4️⃣ presentation_no_data (WARNING configurable) #
⚠️ By default, presentation should not depend directly on data.
✔️ Usecases and contracts should come from core.
This rule can be configured to ERROR.
📦 Installation #
1) Add dependencies to your Flutter app #
dev_dependencies:
custom_lint: ^0.8.1
clean_arch_lint:
path: ../clean_arch_lint
# Or, when published:
# clean_arch_lint: ^1.0.0
Adjust the
pathaccording to your repository structure.
2) Enable the plugin in analysis_options.yaml #
analyzer:
plugins:
- custom_lint
▶️ How to Run #
# Single execution
dart run custom_lint
# Watch mode (re-executes when saving files)
dart run custom_lint --watch
In VSCode / Android Studio:
- Errors appear automatically in the editor
- Works in real-time as you type
⚙️ Configuration #
Make presentation_no_data an ERROR #
custom_lint:
rules:
- presentation_no_data:
severity: error
Ignore specific paths (example) #
custom_lint:
rules:
- core_no_flutter:
ignore:
- lib/core/di/**
Useful for very specific cases like DI bootstrap.
✅ Examples #
Allowed import #
import 'package:my_app/core/usecases/get_user.dart';
Prohibited import (core → flutter) #
import 'package:flutter/material.dart'; // ❌ error
Prohibited import (presentation → data) #
import 'package:my_app/data/user_repository_impl.dart'; // ⚠️ or ❌
🧠 Recommended Best Practices #
- Interfaces always in
core - Implementations always in
data - UI depends only on abstractions
- Dependency injection resolves the rest
❌ What This Lint Does NOT Do #
- Does not generate code
- Does not automatically fix
- Does not replace code review
It only points out the error before it becomes technical debt.
🧩 Technical Stack #
- Dart SDK >= 3.0
- analyzer
- custom_lint_builder
- path
No build_runner. No source_gen.
🏁 Quick Summary #
| Layer | Can depend on |
|---|---|
| core | core only |
| data | core, data |
| presentation | core, presentation |
If it goes beyond that, the lint alerts.
📁 Supported Structures #
The lint automatically supports two folder structures:
Structure 1: Direct (simple projects) #
lib/
├─ core/
├─ data/
└─ presentation/
Structure 2: With src/ (larger projects) #
lib/
└─ src/
├─ core/
├─ data/
└─ presentation/
No additional configuration needed - the lint automatically detects which structure you're using!
Clean architecture is not an opinion. It's a contract.