clean_architecture_linter 1.2.0
clean_architecture_linter: ^1.2.0 copied to clipboard
A comprehensive custom lint package that automatically enforces Clean Architecture principles in Flutter projects with Riverpod state management.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.2.0 - 2026-01-19 #
โจ Added (2 new rules) #
-
ref_mounted_usage - Detects
ref.mountedusage in Riverpod providers- Using
ref.mountedto guard async operations masks design problems - Encourages proper patterns: AsyncValue, ref.listen, or completing async work before navigation
- Only checks in
/presentation/and/providers/directories - Severity: WARNING
- Using
-
riverpod_keep_alive - Warns against unnecessary
@Riverpod(keepAlive: true)keepAlive: trueshould only be used for truly global state (auth, settings, cache)- Warns when used on feature-specific providers (e.g., TodoListNotifier)
- Skips infrastructure providers (DataSource, Repository, UseCase, Service, Client, API)
- Valid patterns: auth, user, session, settings, preferences, config, theme, locale, cache, analytics, notification, connectivity, permission
- Severity: WARNING
๐ Statistics #
- Total rules: 33 (was 31 in v1.1.0)
- Presentation layer rules: 13 (was 11)
1.1.0 - 2026-01-09 #
๐ Breaking Changes #
- Pass-through Repository Pattern - Result ํจํด ์ ๊ฑฐ, pass-through ํจํด์ผ๋ก ์ ํ
- Repository๋ ์ด์
Future<Entity>๋ฅผ ์ง์ ๋ฐํ (๊ถ์ฅ) Future<Result<Entity, Failure>>์ฌ์ฉ ์ ๊ฒฝ๊ณ ํ์- ์๋ฌ๋ DataSource์์ ๋ฐ์ํ์ฌ Presentation๊น์ง pass-through
AsyncValue.guard()๋ก ์๋ฌ ์๋ ์บ์น
- Repository๋ ์ด์
โจ Added #
-
AppException ํ์ ์ธ์ -
exception_validation_mixin์ AppException ํ์ ์ธํธ ์ถ๊ฐ- ํ์ค AppException ํ์
:
AppException,NetworkException,TimeoutException,ServerException,UnauthorizedException,ForbiddenException,NotFoundException,InvalidInputException,ConflictException,CacheException,UnknownException isAppExceptionType()๋ฉ์๋ ์ถ๊ฐisAllowedWithoutPrefix()๊ฐ AppException ํ์ ์ธ์
- ํ์ค AppException ํ์
:
-
Loading ํ๋ ๊ฐ์ง -
presentation_use_async_value๊ท์น ๊ฐํisLoading,loading,isSubmitting,submitting,isFetching,fetching,isProcessing,processingํ๋ ๊ฐ์ง- Freezed State์์ ์๋ ๋ก๋ฉ ์ํ ๊ด๋ฆฌ ๊ธ์ง (AsyncValue๊ฐ ์๋ ๊ด๋ฆฌ)
๐ Changed #
-
repository_must_return_result - Result ํจํด ์ฌ์ฉ ์ ๊ฒฝ๊ณ
- ์ด์ :
Future<Entity>๋๋Future<Result<Entity, Failure>>๋ชจ๋ ํ์ฉ - ์ดํ:
Future<Entity>๊ถ์ฅ, Result ์ฌ์ฉ ์ WARNING
- ์ด์ :
-
repository_must_return_result โ repository_pass_through (์ด๋ฆ ๋ณ๊ฒฝ)
- ๊ท์น ์ด๋ฆ์ด pass-through ํจํด์ ๋ ๋ช ํํ๊ฒ ๋ฐ์
-
repository_no_throw - ๋ฌธ์ ์ ๋ฐ์ดํธ
- Pass-through ํจํด ์ค์ฌ์ผ๋ก ๋ฌธ์ ์ฌ์์ฑ
- AppException ํ์ throw ํ์ฉ
- ๋นํ์ค ์์ธ throw ์ INFO ๋ ๋ฒจ ๊ฒฝ๊ณ
-
datasource_exception_types - AppException ํ์ ์ฒดํฌ ์ถ๊ฐ
isAppExceptionType()์ฒดํฌ ์ถ๊ฐ- DataSource์์ AppException ํ์ ๋ง throw ํ์ฉ
โ ๏ธ Deprecated #
-
usecase_must_convert_failure - Pass-through ํจํด์ผ๋ก ์ธํด ๋ ์ด์ ํ์ ์์
- UseCase์์ FailureโException ๋ณํ ๋ถํ์
- ์๋ฌ๊ฐ DataSource์์ Presentation๊น์ง ์ง์ ์ ๋ฌ๋จ
- ๊ท์น์ ์ ์ง๋์ง๋ง no-op (์๋ฌด ๋์ ์ํจ)
-
failure_naming_convention - Failure ํด๋์ค ์ฌ์ฉ ์์ฒด๋ฅผ ๊ฒฝ๊ณ
- Result ํจํด ์ ๊ฑฐ๋ก Failure ํด๋์ค ๋ถํ์
- ๊ท์น์ด Failure ํด๋์ค ์ ์ ์ ๊ฒฝ๊ณ ํ์
- AppException ์ฌ์ฉ ๊ถ์ฅ
๐ Documentation #
-
CLAUDE.md - Pass-through ํจํด ์ค์ฌ์ผ๋ก ์ ๋ฐ์ดํธ
- Result ํจํด ์์ ์ ๊ฑฐ
- STATE_MANAGEMENT_GUIDE.md ์ฐธ์กฐ ์ถ๊ฐ
-
doc/UNIFIED_ERROR_GUIDE.md - ํตํฉ ์๋ฌ ํธ๋ค๋ง ๊ฐ์ด๋ ์ถ๊ฐ
-
doc/STATE_MANAGEMENT_GUIDE.md - ์ํ ๊ด๋ฆฌ ๊ฐ์ด๋ ์ถ๊ฐ
๐งช Tests #
- ๋ชจ๋ ํ
์คํธ ์
๋ฐ์ดํธ (568๊ฐ ํ
์คํธ ํต๊ณผ)
exception_validation_mixin_test.dart- AppException ํ์ ํ ์คํธ ์ถ๊ฐrepository_no_throw_rule_test.dart- Pass-through ํจํด ํ ์คํธ๋ก ๋ณ๊ฒฝexception_handling_integration_test.dart- ์ ์ฒด ๋ฆฌํฉํ ๋ง
1.0.11 - 2025-12-31 #
๐ง Fixed #
- layer_dependency_rule - DI Provider ํ์ผ์์ Data Models import ๊ธ์ง ์ถ๊ฐ
- DI/Provider ํ์ผ(
*_providers.dart,providers.dart)์์ DataSource/Repository ๊ตฌํ์ฒด import๋ ํ์ฉ - ํ์ง๋ง Data Models(
/data/models/) import๋ DI ํ์ผ์์๋ ๊ธ์ง - Data Models๋ Data ๋ ์ด์ด ๋ด๋ถ์ฉ์ด๋ฉฐ, Presentation ๋ ์ด์ด(DI ํฌํจ)์์ ์ฌ์ฉํ๋ฉด ์๋จ
- ์๋ก์ด
_isDataModelImport()ํฌํผ ๋ฉ์๋ ์ถ๊ฐ
- DI/Provider ํ์ผ(
1.0.10 - 2025-12-10 #
โจ Added #
- allowed_instance_variables_rule - Extended infrastructure SDK type support
- Google Mobile Ads SDK:
BannerAd,InterstitialAd,RewardedAd,NativeAd,AppOpenAd,AdWidget - In-App Purchase SDK:
InAppPurchase,ProductDetails,PurchaseDetails Subscriptiontype (StreamSubscription, etc.)- These SDK types require mutable state for lifecycle management
- Google Mobile Ads SDK:
๐จ Improved #
- Correction messages - Made all rule correction messages more concise for better VS Code PROBLEMS panel display
- Removed verbose examples from correction messages
- Focused on brief, actionable fix instructions
- Affected rules:
failure_naming_convention,model_naming_convention,exception_message_localization,presentation_no_data_exceptions,presentation_use_async_value,riverpod_provider_naming,riverpod_ref_usage,widget_no_usecase_call,widget_ref_read_then_when
1.0.9 - 2025-11-12 #
โจ Added (1 new rule) #
- allowed_instance_variables_rule - Enforce stateless architecture in UseCase, Repository, and DataSource classes
- UseCase: Only
final/constRepository and Service dependencies allowed - Repository: Only
final/constDataSource and infrastructure dependencies (primitives, Stream, HTTP, Firebase, Database) allowed - DataSource: Only
final/constprimitives and infrastructure dependencies allowed - Mock/Fake classes can have mutable state for testing purposes
- Prevents hidden state bugs and enables testability
- Comprehensive validation with clear error messages
- Total rules: 34 (was 33)
- Cross-layer rules: 3 (was 2)
- UseCase: Only
๐ง Fixed #
-
Domain Layer dart:io Support - Fixed false positive for
dart:ioimports in domain layerdomain_purity_rule: Now allowsdart:ioimports for type references (File, Directory) in domain layer method signatures- Actual I/O operations should still be implemented in data layer
- Addresses legitimate use cases where domain repositories need File type parameters
-
Database Library Support - Added proper exceptions for database libraries (ObjectBox, Realm, Isar, Drift)
layer_dependency_rule: Data layer can now importpackage:objectbox/,package:realm/,package:isar/,package:drift/datasource_abstraction_rule:- Private methods/getters (starting with
_) are now skipped from validation - Database entity types (Box<*Entity>, *ObjectBoxEntity, *RealmEntity, etc.) are allowed in return types
- Private methods/getters (starting with
model_structure_rule: Models with database annotations (@Entity, @RealmModel, @collection, etc.) are exempt from @freezed requirement- These libraries require mutable classes with their own code generation, incompatible with Freezed
๐ Documentation #
-
CLAUDE.md
- Added "Instance Variables & Stateless Architecture" section with comprehensive examples
- Added "Domain Layer with dart:io Types" example showing allowed usage of File type in repository signatures
- Updated Layer Dependencies section to clarify dart:io is allowed for type references
- Documented allowed infrastructure types for each layer
- Explained Mock/Fake exception for testing
- Added "Database Library Exceptions" section with comprehensive examples
- Explained why database Models don't use @freezed (mutability requirement)
- Listed all allowed database imports and annotations
-
README.md
- Updated rule count from 33 to 34
- Added allowed_instance_variables_rule to Core Clean Architecture Principles section
- Added ObjectBox example in "Good Examples" section
- Documented database library exceptions with clear note
-
README_KO.md
- Updated rule count from 29 to 34
- Synchronized with English README structure
๐จ Improved #
- exception_naming_convention_rule - More concise error messages for better VS Code PROBLEMS panel display
1.0.8 - 2025-10-30 #
๐ง Changed #
- Minimum Dart SDK updated to 3.7.0
- Updated from ^3.6.0 to ^3.7.0 for better compatibility
- Downgraded lints from ^6.0.0 to ^5.1.1 for Dart 3.7.0 compatibility
- All existing features and tests remain compatible
- No breaking changes to API or functionality
1.0.6 - 2025-10-28 #
๐ง Fixed #
- Fixed package dependencies structure
- Moved
analyzer,custom_lint_builder, andpathback todependencies - These packages are used in
lib/code and must be runtime dependencies custom_lint,lints, andtestremain indev_dependencies- Note: End users still add this package to
dev_dependenciesin their projects
- Moved
๐ฆ Dependencies #
- Runtime dependencies (used in lib/):
analyzer,custom_lint_builder,path - Dev dependencies (development only):
custom_lint,lints,test
1.0.5 - 2025-10-28 #
๐ง Changed #
- Upgraded custom_lint_builder from
0.7.6to0.8.0- Ensures compatibility with riverpod_generator 3.0.0
- Upgraded custom_lint dev dependency to
0.8.0 - All 527 tests pass successfully
- No breaking API changes required
- Maintains backward compatibility
๐ฆ Dependencies #
custom_lint_builder: ^0.7.6 โ ^0.8.0custom_lint: ^0.7.6 โ ^0.8.0 (dev dependency)
1.0.4 - 2025-10-22 #
โจ Added (2 new rules) #
-
widget_no_usecase_call rule - Enforce proper Riverpod architecture: Widget โ Provider โ UseCase
- Prevents widgets from directly importing or calling UseCases
- Enforces proper separation: Widgets should only interact with Providers
- Detects UseCase imports in widget/page files
- Detects direct UseCase provider calls via
ref.read()orref.watch() - Provides comprehensive correction messages with proper Riverpod patterns
- Severity: WARNING
-
widget_ref_read_then_when rule - Prevent anti-pattern of using
.when()afterref.read()- Detects
ref.read()followed by.when()in the same function - Enforces proper patterns:
ref.watch()+.when()for UI,ref.listen()for side effects - Prevents misuse of AsyncValue state management
- Explains why this pattern is incorrect (state is already settled after operation)
- Provides three correct alternatives based on use case
- Severity: WARNING
- Detects
๐ Changed #
-
presentation_no_throw rule - Enhanced detection capabilities
- Now checks
/providers/directory in addition to/states/and/state/ - Improved State/Notifier class detection with three methods:
- Detects
@riverpodannotation (Riverpod Generator pattern) - Detects
extends AsyncNotifier/Notifier/StateNotifier/ChangeNotifier - Detects generated classes with
_$prefix
- Detects
- More robust validation of Riverpod-based state management classes
- Better coverage of modern Riverpod code generation patterns
- Now checks
-
Total rules: 31 (was 29 in v1.0.3)
- Added: 2 new presentation layer rules
- Modified: 1 rule (presentation_no_throw)
๐ Documentation #
- Enhanced CLAUDE.md with comprehensive Riverpod state management patterns
- Added 3-tier provider architecture documentation
- Documented Entity Providers (AsyncNotifier), UI State Providers (Notifier), and Computed Logic Providers
- Added detailed examples of AsyncValue.when() pattern usage
- Included common violations and their solutions
- Comprehensive Widget usage examples with proper error handling
๐ Statistics #
- Files changed: 5 files
- 2 new rule implementations
- 1 rule enhancement
- 1 test file
- 1 main registration file
- Lines added: ~600+ lines
- widget_no_usecase_call_rule.dart: 265 lines
- widget_ref_read_then_when_rule.dart: 301 lines
- Enhanced presentation_no_throw_rule.dart
- Test coverage: Comprehensive unit tests for widget_no_usecase_call rule
1.0.3 - 2025-10-17 #
โจ Added (3 new rules) #
-
model_entity_direct_access rule - Enforce
.toEntity()method usage instead of direct.entityproperty access in Data layer- Prevents direct
.entityaccess in Repository and DataSource implementations - Allows direct access inside extension methods (where conversion logic is implemented)
- Allows direct access in test files
- Provides clear architectural boundaries for Model โ Entity conversion
- Prevents direct
-
model_naming_convention rule - Enforce naming conventions for Models in Data layer
- Models must end with
Modelsuffix - Validates proper naming in
data/models/directories - Helps maintain consistent codebase structure
- Models must end with
-
presentation_no_throw rule - Enforce no exception throwing in Presentation layer
- Presentation layer should use AsyncValue for error handling
- No direct exception throws in widgets, states, or notifiers
- Aligns with Riverpod best practices
๐ Changed #
-
model_conversion_methods rule - Updated to align with Dart/Freezed best practices
- Now only requires
toEntity()method in extensions (mandatory) fromEntity()implementation is optional and should use factory constructors in the Model class- Removed extension static method pattern (not idiomatic in Dart)
- Updated error messages to guide users toward factory constructor pattern
- Now only requires
-
Total rules: 29 (was 26 in v1.0.2)
- Added: 3 new rules
- Modified: 1 rule (model_conversion_methods)
๐ Bug Fixes #
- Fixed
exception_naming_conventionrule to skipcore/directory (framework-level exceptions) - Fixed
failure_naming_conventionrule to skipcore/directory - Fixed data file detection to correctly exclude
domain/repositories/from data layer - Fixed
model_conversion_methodsrule incorrectly requiring extension static methods - Improved error severity levels across multiple rules
๐ Documentation #
- Updated CLAUDE.md with comprehensive
.entityaccess control guidelines - Updated Data Layer rules README with all 3 new rules documentation
- Enhanced Model conversion pattern examples with factory constructor approach
- Added 48 new lines of documentation in CLAUDE.md
- Added 55 new lines in Data Layer README
- Updated README.md with accurate rule count
๐ Statistics #
- Files changed: 23 files
- Lines added: ~1,237 lines
- New test coverage: 398+ lines of new tests for new rules
- Documentation improvements: 100+ lines across multiple files
1.0.2 - 2025-10-09 #
๐๏ธ Removed #
- entity_business_logic rule - Removed overly strict rule requiring all entities to have business logic methods
- Not all entities need business logic (e.g., events, DTOs, value objects)
- Users reported this as too restrictive for practical use cases
- Total rules: 27 โ 26
๐ Documentation #
- Fixed incomplete code snippet in README.md examples section
- Synchronized README_KO.md structure with README.md (removed inconsistent sections)
- Updated rule count from 27 to 26 in both English and Korean READMEs
1.0.1 - 2025-10-09 #
๐ Documentation #
- Updated README.md with accurate rule count (27 rules instead of 16+)
- Updated README_KO.md with accurate rule count and simplified structure
- Simplified configuration section, removed non-existent Core/Strict modes
- Reorganized rules documentation with clear categorization
- Removed unnecessary documentation files (VALIDATION_REPORT.md, ERROR_HANDLING_RULES_TODO.md)
๐ง CI/CD #
- Improved publish workflow to use official OIDC-based authentication
- Added quality checks (tests, analyzer, format) before publishing
- Aligned publish workflow with CI workflow for consistency
1.0.0 - 2025-10-09 #
๐ Initial Release #
A comprehensive custom lint package that automatically enforces Clean Architecture principles in Flutter/Dart projects.
โจ Added #
New Utility Infrastructure
- CleanArchitectureUtils - Centralized utility class for common Clean Architecture validations
- File path detection (isDomainFile, isDataFile, isPresentationFile)
- Component detection (isUseCaseFile, isDataSourceFile, isRepositoryFile)
- Class name validation (isUseCaseClass, isDataSourceClass, isRepositoryClass)
- Type checking (isVoidType, isResultType)
- Exception pattern recognition (isDataException, isDomainException)
- AST utilities (findParentClass, isPrivateMethod, isRethrow)
- Feature extraction (extractFeatureName)
New Mixin System
- ExceptionValidationMixin - Exception naming and validation logic
- ReturnTypeValidationMixin - Return type validation for methods
- RepositoryRuleVisitor - Repository-specific validation
๐ Changed #
Code Organization
- 170 lines removed (13.6% code reduction) through deduplication
- Consolidated 13 rules to use shared mixins and utilities
- Improved consistency across all validation logic
- Enhanced test coverage with 76 comprehensive tests
Refactored All 24 Rules
All lint rules were refactored to leverage the new utility and mixin infrastructure:
Cross-Layer Rules (4)
- LayerDependencyRule
- CircularDependencyRule
- BoundaryCrossingRule
- TestCoverageRule
Domain Layer Rules (4)
- DomainPurityRule
- DependencyInversionRule
- RepositoryInterfaceRule
- UseCaseNoResultReturnRule
- UseCaseMustConvertFailureRule
- ExceptionNamingConventionRule
- ExceptionMessageLocalizationRule
Data Layer Rules (7)
- ModelStructureRule
- DataSourceAbstractionRule
- DataSourceNoResultReturnRule
- RepositoryMustReturnResultRule
- RepositoryNoThrowRule
- DataSourceExceptionTypesRule
- FailureNamingConventionRule
Presentation Layer Rules (6)
- NoPresentationModelsRule
- ExtensionLocationRule
- FreezedUsageRule
- RiverpodGeneratorRule
- PresentationNoDataExceptionsRule
- PresentationUseAsyncValueRule
๐ Improved #
Documentation
- Added comprehensive ARCHITECTURE.md with system overview
- Created CONTRIBUTING.md with development guidelines
- Added RULE_DEVELOPMENT_GUIDE.md for contributors
- Enhanced inline documentation across all files
Testing
- 76 comprehensive tests covering all utilities and mixins
- 100% coverage of utility methods
- Extensive mixin behavior validation
Code Quality
- Eliminated 170 lines of duplicate code
- Consistent validation patterns across all rules
- Improved error messages with better context
- Enhanced maintainability through shared components
๐ง Technical Details #
Dependencies
- Dart SDK: ^3.6.0
- analyzer: ^7.6.0
- custom_lint_builder: ^0.7.6
- path: ^1.9.1