clean_architecture_linter 1.0.0
clean_architecture_linter: ^1.0.0 copied to clipboard
A comprehensive custom lint package that automatically enforces Clean Architecture principles in Flutter projects with specialized rules.
Clean Architecture Linter #
π°π· νκ΅μ΄ README | πΊπΈ English README
A comprehensive custom lint package that automatically enforces Clean Architecture principles in Flutter/Dart projects. Write code naturally while the linter guides you toward perfect Clean Architecture compliance with real-time feedback and actionable corrections.
β¨ Key Features #
- π‘οΈ Automatic Clean Architecture Protection - Write code freely, linter catches violations
- π― 16+ Specialized Rules - Comprehensive coverage of all Clean Architecture layers
- π Flutter-Optimized - Built specifically for Flutter development patterns
- π Educational - Learn Clean Architecture through guided corrections
- β‘ Real-time Feedback - Immediate warnings with actionable solutions
- π§ Zero Configuration - Works out of the box with sensible defaults
- ποΈ Flexible Configuration - Core, Standard, and Strict modes available
- π§ͺ Test-Aware - Smart exceptions for test files and development contexts
π Rules by Clean Architecture Layer #
π― Domain Layer (Core Business Rules) #
The innermost layer containing business logic and rules
Entity & Business Rules (4 rules):
entity_business_rules
- Ensures entities contain only enterprise business rulesentity_stability
- Validates entity stability and immutabilityentity_immutability
- Enforces immutable domain entitiesbusiness_logic_isolation
- Prevents business logic leakage to outer layers
Use Cases & Application Rules (4 rules):
usecase_orchestration
- Validates use case orchestration patternsusecase_application_rules
- Ensures use cases contain application-specific rulesusecase_independence
- Enforces use case independenceusecase_single_responsibility
- Validates single responsibility principle
Domain Interfaces & Validation (3 rules):
repository_interface
- Validates proper repository abstractionsdomain_model_validation
- Ensures proper domain validationdomain_purity
- Prevents external framework dependenciesdependency_inversion
- Validates dependency direction
πΎ Data Layer (Data Access & External Interfaces) #
Repository implementations and data source management
Repository & Data Source Rules (3 rules):
repository_implementation
- Validates repository implementation patternsdatasource_naming
- Enforces proper naming conventionsmodel_structure
- Ensures data models have proper structure
Boundary Data Rules (4 rules):
data_boundary_crossing
- Validates proper data crossing boundariesdatabase_row_boundary
- Prevents database row structures crossing inwarddto_boundary_pattern
- Enforces DTO patterns for boundary crossingentity_boundary_isolation
- Isolates entities from outer layers
π¨ Presentation Layer (UI & Delivery Mechanism) #
User interface and delivery mechanisms
UI & State Management (3 rules):
ui_dependency_injection
- Prevents direct business logic instantiationstate_management
- Validates proper state management patternspresentation_logic_separation
- Enforces UI/business logic separation
π Interface Adapters (Data Format Conversion) #
Controllers, Presenters, and Gateways
Data Conversion & MVC (3 rules):
data_conversion_adapter
- Validates data format conversionsmvc_architecture
- Enforces MVC patterns in adaptersexternal_service_adapter
- Validates external service adapter patterns
βοΈ Framework & Drivers (External Details) #
Web frameworks, databases, and external agencies
Framework Isolation (4 rules):
framework_isolation
- Isolates framework details in outermost layerdatabase_detail
- Keeps database details in framework layerweb_framework_detail
- Isolates web framework specificsglue_code
- Validates glue code patterns
π Architectural Boundaries (Cross-Cutting Concerns) #
Rules that span multiple layers and enforce Uncle Bob's principles
Dependency & Layer Rules (5 rules):
layer_dependency
- Enforces The Dependency Rule (inward only)circular_dependency
- Prevents circular dependenciescore_dependency
- Validates core dependency patternsabstraction_level
- Ensures proper abstraction levelsflexible_layer_detection
- Supports flexible layer architectures
Boundary Crossing Patterns (6 rules):
boundary_crossing
- Validates proper boundary crossingdependency_inversion_boundary
- Enforces dependency inversion at boundariesinterface_boundary
- Validates interface boundary patternspolymorphic_flow_control
- Ensures polymorphic flow control inversionabstraction_progression
- Validates abstraction progression across layersclean_architecture_benefits
- Ensures architecture provides expected benefits
π Detailed Rules Guide: See RULES.md for comprehensive documentation of all 39 rules, including examples, Uncle Bob quotes, and implementation guidance.
π°π· νκΈ κ°μ΄λ: RULES_KO.mdμμ 39κ° κ·μΉμ λν νκ΅μ΄ μ€λͺ κ³Ό μ€μ μ¬μ© μλ리μ€λ₯Ό νμΈνμΈμ.
π Quick Start #
π Requirements #
- Dart SDK: 3.6.0+
- Flutter: 3.0+ (optional, for Flutter projects)
1. Add to your project #
# pubspec.yaml
dev_dependencies:
clean_architecture_linter: ^1.0.0
custom_lint: ^0.7.6
2. Enable custom lint #
# analysis_options.yaml
analyzer:
plugins:
- custom_lint
exclude:
- test/**
- "**/*.test.dart" # Exclude test files
- "**/*.g.dart" # Exclude generated files
- "**/*.freezed.dart" # Exclude Freezed files
- "**/*.mocks.dart" # Exclude mock files
3. Run the linter #
dart pub get
dart pub custom_lint
That's it! The linter will now automatically enforce Clean Architecture principles in your codebase.
ποΈ Configuration Options #
Choose your enforcement level:
π Core Rules Only (Essentials) #
// lib/clean_architecture_linter.dart
import 'package:clean_architecture_linter/clean_architecture_linter_core.dart';
PluginBase createPlugin() => createCorePlugin();
π― Standard Rules (Recommended) #
// lib/clean_architecture_linter.dart
import 'package:clean_architecture_linter/clean_architecture_linter.dart';
// Default - no changes needed
π Strict Rules (Maximum Enforcement) #
// lib/clean_architecture_linter.dart
import 'package:clean_architecture_linter/clean_architecture_linter_strict.dart';
PluginBase createPlugin() => createStrictPlugin();
π¦ Usage #
Folder Structure #
Organize your Flutter project following Clean Architecture:
lib/
βββ domain/
β βββ entities/
β βββ repositories/
β βββ usecases/
βββ data/
β βββ datasources/
β βββ models/
β βββ repositories/
βββ presentation/
βββ providers/
βββ widgets/
βββ pages/
Running the Linter #
# Activate custom_lint if not already done
dart pub global activate custom_lint
# Run the linter
dart pub custom_lint
IDE Integration #
The linter works automatically in:
- VS Code with the Dart/Flutter extensions
- IntelliJ IDEA / Android Studio with Flutter plugin
π Examples #
β Good Examples #
Domain Entity (Immutable)
// lib/domain/entities/user_entity.dart
class UserEntity {
final String id;
final String name;
final String email;
const UserEntity({
required this.id,
required this.name,
required this.email,
});
bool isValidEmail() {
return email.contains('@');
}
}
Repository Interface
// lib/domain/repositories/user_repository.dart
abstract class UserRepository {
Future<UserEntity> getUser(String id);
Future<void> saveUser(UserEntity user);
}
UseCase with Single Responsibility
// lib/domain/usecases/get_user_usecase.dart
class GetUserUseCase {
final UserRepository repository;
GetUserUseCase(this.repository);
Future<UserEntity> call(String userId) {
return repository.getUser(userId);
}
}
β Bad Examples (Will be flagged) #
Mutable Domain Entity
// β This will be flagged by entity_immutability
class UserEntity {
String name; // Non-final field
void setName(String newName) { // Setter in entity
name = newName;
}
}
Domain Layer with External Dependencies
// β This will be flagged by domain_purity
import 'package:http/http.dart'; // External framework import
class UserEntity {
final String name;
}
UI with Direct Business Logic
// β This will be flagged by business_logic_isolation
class UserWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Business logic in UI layer - WRONG!
final isValid = email.contains('@') && email.length > 5;
return Text(isValid ? 'Valid' : 'Invalid');
}
}
Repository Throwing Exceptions
// β This will be flagged by avoid_exception_throwing_in_repository
class UserRepositoryImpl implements UserRepository {
@override
Future<UserEntity> getUser(String id) async {
if (id.isEmpty) {
throw ArgumentError('ID cannot be empty'); // Should return Result instead
}
// ...
}
}
Layer Dependency Violation
// β This will be flagged by avoid_layer_dependency_violation
// In domain layer file:
import 'package:myapp/data/models/user_model.dart'; // Domain importing Data!
class UserEntity extends UserModel { // Wrong dependency direction
// ...
}
Missing Exception Prefix
// β This will be flagged by ensure_exception_prefix
class NetworkException extends Exception { // Should be UserNetworkException
// ...
}
π Common Patterns #
Proper Error Handling with Result Type
// β
Good: Using Result pattern
sealed class Result<T, E> {}
class Success<T, E> extends Result<T, E> {
final T value;
Success(this.value);
}
class Failure<T, E> extends Result<T, E> {
final E error;
Failure(this.error);
}
// Repository implementation
class UserRepositoryImpl implements UserRepository {
@override
Future<Result<UserEntity, UserException>> getUser(String id) async {
try {
final userData = await dataSource.getUser(id);
return Success(userData.toEntity());
} catch (e) {
return Failure(UserDataException(e.toString()));
}
}
}
Proper Exception Naming
// β
Good: Proper exception prefixes
class UserNetworkException extends Exception {
final String message;
UserNetworkException(this.message);
}
class UserValidationException extends Exception {
final String field;
UserValidationException(this.field);
}
For more detailed examples and explanations, see our comprehensive Examples Guide. final user = UserRepository().getUser('123'); return Text(user.name); } }
## π οΈ Development
### Project Structure
clean_architecture_linter/ βββ lib/ β βββ src/ β β βββ rules/ β β βββ domain_rules/ β β βββ data_rules/ β β βββ presentation_rules/ β βββ clean_architecture_linter.dart βββ example/ βββ test/ βββ README.md
### Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for new rules
4. Format your code: `dart format --line-length=120 .`
5. Ensure all tests pass
6. Submit a pull request
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
## π License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## π Support
- β Star this repository if it helped you!
- π [Report bugs](https://github.com/ittae/clean_architecture_linter/issues)
- π‘ [Request features](https://github.com/ittae/clean_architecture_linter/issues)
- π [Read the documentation](https://github.com/ittae/clean_architecture_linter)
## π― Roadmap
- [ ] Configuration system for custom naming patterns
- [ ] Support for multiple state management solutions
- [ ] Integration with CI/CD workflows
- [ ] Custom rule creation guide
- [ ] Performance optimizations
---
**Made with β€οΈ for the Flutter community**