saropa_lints 4.2.2
saropa_lints: ^4.2.2 copied to clipboard
1650+ custom lint rules with 211 quick fixes for Flutter and Dart. Static analysis for security, accessibility, and performance.
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.
Looking for older changes?
See CHANGELOG_ARCHIVE.md for versions 0.1.0 through 3.4.0.
4.2.2 - 2026-01-19 #
Fixed #
Critical bug fixes for rule execution - Two bugs were causing rules to be silently skipped, resulting in "No issues found" or far fewer issues than expected:
-
Throttle key missing rule name - The analysis throttle used
path:contentHashas a cache key, but didn't include the rule name. When rule A analyzed a file, rules B through Z would see the cache entry and skip the file thinking it was "just analyzed" within the 300ms throttle window. Now usespath:contentHash:ruleNameso each rule has its own throttle. -
Rapid edit mode false triggering - The adaptive tier switching feature (designed to show only essential rules during rapid IDE saves) was incorrectly triggering during CLI batch analysis. When
dart run custom_lintran 268 rules on a file, the edit counter hit 268 in under 2 seconds, triggering "rapid edit mode" and skipping non-essential rules. This check is now disabled for CLI runs.
Impact: These bugs affected all users on all platforms. Windows users were additionally affected by path normalization issues fixed in earlier commits.
4.2.1 - 2026-01-19 #
Changed #
- Rule renamed:
avoid_mutating_parameters→avoid_parameter_reassignment(old name kept as deprecated alias in doc header). Tier changed from Recommended to Stylistic to reflect that reassignment is a style preference, not a correctness issue. - Heuristics improved -
require_android_backup_rulesnow uses word-boundary matching to avoid false positives on keys like "authentication_method" - File reorganization - Consolidated v4.1.7 rules from separate
v417_*.dartfiles into their appropriate category files:- Caching rules →
memory_management_rules.dart - WebSocket reconnection →
api_network_rules.dart - Currency code rule →
money_rules.dart - Lazy singleton rule →
dependency_injection_rules.dart - Performance rules →
performance_rules.dart - Clipboard/encryption security →
security_rules.dart - State management rules →
state_management_rules.dart - Testing rules →
testing_best_practices_rules.dart - Widget rules →
flutter_widget_rules.dart
- Caching rules →
4.2.0 - 2026-01-19 #
Added #
Config key aliases - Rules can now define alternate config keys that users can use in custom_lint.yaml. This helps when rule names have prefixes (like enforce_) that users commonly omit:
rules:
# Both work now:
- enforce_arguments_ordering: false # canonical name
- arguments_ordering: false # alias
Added aliases for:
enforce_arguments_ordering→arguments_orderingenforce_member_ordering→member_orderingenforce_parameters_ordering→parameters_ordering
41 new lint rules covering Android platform, in-app purchases, URL launching, permissions, connectivity, geolocation, SQLite, test file handling, and more:
Android Platform Rules (android_rules.dart) - 6 rules
require_android_permission_request- Runtime permission not requested before using permission-gated APIavoid_android_task_affinity_default- Multiple activities with default taskAffinity cause back stack issuesrequire_android_12_splash- Flutter splash may cause double-splash on Android 12+prefer_pending_intent_flags- PendingIntent without FLAG_IMMUTABLE/FLAG_MUTABLE crashes on Android 12+avoid_android_cleartext_traffic- HTTP URLs blocked by default on Android 9+require_android_backup_rules- Sensitive data in SharedPreferences may be backed up
In-App Purchase Rules (iap_rules.dart) - 3 rules
avoid_purchase_in_sandbox_production- Hardcoded IAP environment URL causes receipt validation failuresrequire_subscription_status_check- Premium content shown without verifying subscription statusrequire_price_localization- Hardcoded prices instead of store-provided localized prices
URL Launcher Rules (url_launcher_rules.dart) - 3 rules
require_url_launcher_can_launch_check- launchUrl without canLaunchUrl checkavoid_url_launcher_simulator_tests- URL launcher tests with tel:/mailto: fail on simulatorprefer_url_launcher_fallback- launchUrl without fallback for unsupported schemes
Permission Rules (permission_rules.dart) - 3 rules
require_location_permission_rationale- Location permission requested without showing rationalerequire_camera_permission_check- Camera initialized without permission checkprefer_image_cropping- Profile image picked without cropping option
Connectivity Rules (connectivity_rules.dart) - 1 rule
require_connectivity_error_handling- Connectivity check without error handling
Geolocator Rules (geolocator_rules.dart) - 1 rule
require_geolocator_battery_awareness- High-accuracy continuous location tracking without battery consideration
SQLite Rules (sqflite_rules.dart) - 1 rule
avoid_sqflite_type_mismatch- SQLite type may not match Dart type (bool vs INTEGER, DateTime vs TEXT)
Rules Added to Existing Files - 19 rules
- firebase_rules.dart:
require_firestore_index- Firestore query requires composite index - notification_rules.dart:
prefer_notification_grouping,avoid_notification_silent_failure - hive_rules.dart:
require_hive_migration_strategy - async_rules.dart:
avoid_stream_sync_events,avoid_sequential_awaits - file_handling_rules.dart:
prefer_streaming_for_large_files,require_file_path_sanitization - error_handling_rules.dart:
require_app_startup_error_handling,avoid_assert_in_production - accessibility_rules.dart:
prefer_focus_traversal_order - ui_ux_rules.dart:
avoid_loading_flash - performance_rules.dart:
avoid_animation_in_large_list,prefer_lazy_loading_images - json_datetime_rules.dart:
require_json_schema_validation,prefer_json_serializable - forms_rules.dart:
prefer_regex_validation - package_specific_rules.dart:
prefer_typed_prefs_wrapper,prefer_freezed_for_data_classes
Test File Length Rules (structure_rules.dart) - 4 rules
Separate file length rules for test files with higher thresholds, allowing comprehensive test suites without triggering production file length warnings:
prefer_small_test_files- Test files over 400 lines (insanity tier)avoid_medium_test_files- Test files over 600 lines (professional tier)avoid_long_test_files- Test files over 1000 lines (comprehensive tier)avoid_very_long_test_files- Test files over 2000 lines (recommended tier)
Production file length rules (prefer_small_files, avoid_medium_files, avoid_long_files, avoid_very_long_files) now skip test files automatically.
Tier Assignments #
- Essential tier: 14 rules (permissions, security, crashes)
- Recommended tier: 10 rules (best practices, UX improvements)
- Professional tier: 13 rules (architecture, performance, maintainability)
Parameter Safety Rules (code_quality_rules.dart) - 1 new rule + 1 renamed
avoid_parameter_mutation(NEW) - Detects when parameter objects are mutated (caller's data modified). Essential tier.avoid_parameter_reassignment- Renamed fromavoid_mutating_parameters. Detects parameter variable reassignment. Moved to Stylistic tier.
Quick fix for prefer_explicit_type_arguments - Adds explicit type arguments to empty collection literals and generic constructor calls.
Conflicting rule detection - Warns at analysis startup when mutually exclusive stylistic rules are both enabled:
avoid_inferrable_type_arguments↔prefer_explicit_type_argumentsprefer_relative_imports↔always_use_package_imports
Stylistic rule tier changes - Removed opposing stylistic rules from Comprehensive tier (now opt-in only):
avoid_inferrable_type_arguments- conflicts withprefer_explicit_type_argumentsprefer_explicit_type_arguments- conflicts withavoid_inferrable_type_arguments
Changed #
- Rule renamed:
avoid_mutating_parameters→avoid_parameter_reassignment(old name kept as deprecated alias in doc header). Tier changed from Recommended to Stylistic to reflect that reassignment is a style preference, not a correctness issue. - Heuristics improved -
require_android_backup_rulesnow uses word-boundary matching to avoid false positives on keys like "authentication_method"
Fixed #
-
function_always_returns_nullfalse positives on void functions - The rule was incorrectly flagging void functions that use barereturn;statements for early exit. Now correctly skips:- Functions with explicit
voidreturn type - Functions with
Future<void>orFutureOr<void>return types (including type aliases via resolved type checking) - Functions with no explicit return type that only use bare
return;statements (inferred void)
- Functions with explicit
-
capitalize_comment_startcode detection overhauled - The previous regex pattern[:\.\(\)\[\]\{\};,=>]was too broad, matching ANY comment containing punctuation (periods, colons, commas). This caused massive false negatives where legitimate prose comments like// this is important.were incorrectly skipped as "code". The new pattern specifically detects:- Identifier followed by code punctuation:
foo.bar,x = 5 - Dart keywords at start:
return,if (,final x - Function calls:
doSomething(),list.add(item) - Statement terminators: ends with
; - Annotations:
@override - Arrow functions:
=> - Block delimiters at boundaries:
{,}
Quick fix added: Capitalizes the first letter of the comment.
- Identifier followed by code punctuation:
-
avoid_commented_out_codecompletely overhauled - Moved fromdebug_rules.darttostylistic_rules.dart. The rule now:- Reports at the actual comment location (previously reported at file start)
- Reports all instances (previously only reported once per file)
- Has a quick fix to delete the commented-out code
- Uses shared
CommentPatternsutility withcapitalize_comment_start - Tier changed: Moved from Insanity tier to Stylistic tier (not enabled by default in any tier)
-
New shared utility:
comment_utils.dart- Extracted common comment detection patterns intoCommentPatternsclass used by bothcapitalize_comment_startandavoid_commented_out_code. This ensures consistent behavior between the two complementary rules.
Improved #
prefer_utc_for_storage rule enhanced:
- Added 6 new serialization patterns:
toJson,toMap,serialize,encode,cache,persist - Removed
toString()from method check (reduces false positives from logging/debugging) - Patterns moved to
static finalclass member (compiled once at class load, not per invocation) - Added comprehensive doc header with multiple BAD/GOOD examples
- Quick fix added: Inserts
.toUtc()before the serialization call
DX message quality for 60+ lint rules - Added clear consequences to problem messages explaining why issues matter. Messages now follow the pattern: "[What's wrong]. [Why it matters]." Extended short messages to meet 180-character minimum for critical/high impact rules.
Security Rules (11 rules)
avoid_sensitive_data_in_clipboard- "Malicious apps can silently read clipboard contents, stealing passwords, tokens, or API keys"require_certificate_pinning- "Attackers on the same network can intercept and modify traffic"avoid_generic_key_in_url- "Exposes credentials in access logs and browser history"avoid_jwt_decode_client- "Attackers can manipulate decoded claims to bypass permissions"require_logout_cleanup- "Next user on shared device could access previous user data"require_deep_link_validation- "Malicious links can inject arbitrary data, leading to crashes or unauthorized access"require_shared_prefs_null_handling- "Common source of production crashes on first launch or after app updates"require_url_validation- "Attackers can make your app request internal network resources"prefer_webview_javascript_disabled- "Malicious scripts can steal data or execute arbitrary code"avoid_unsafe_deserialization- "Attackers can exploit this to corrupt state or trigger unexpected behavior"avoid_notification_payload_sensitive- "Anyone nearby can see passwords, tokens, or PII without unlocking"
Performance Rules (7 rules)
prefer_const_widgets- "Wastes CPU cycles and battery, slowing down UI rendering"avoid_widget_creation_in_loop- "Causes jank and high memory usage for long lists"avoid_calling_of_in_build- "Adds unnecessary overhead that slows down frame rendering"avoid_rebuild_on_scroll- "Memory leaks and duplicate callbacks that compound over time"avoid_shrinkwrap_in_scrollview- "Forces all items to render immediately, causing jank"avoid_text_span_in_build- "Causes visible jank when scrolling or animating"avoid_money_arithmetic_on_double- "Users may be charged incorrect amounts or see wrong totals"
State Management Rules (7 rules)
avoid_bloc_in_bloc- "Makes testing difficult and breaks unidirectional data flow"avoid_static_state- "Causes flaky tests, unexpected state retention, and hard-to-reproduce bugs"require_bloc_manual_dispose- "Memory leaks that accumulate over time, eventually crashing the app"prefer_bloc_listener_for_side_effects- "Causes duplicate navigation, multiple snackbars, or repeated API calls"avoid_bloc_context_dependency- "Makes Bloc untestable and can cause crashes when context is invalid"avoid_provider_value_rebuild- "Loses all state and causes infinite rebuild loops"avoid_ref_watch_outside_build- "Causes missed updates, stale data, and hard-to-debug state inconsistencies"
Notification Rules (3 rules)
avoid_notification_same_id- "Users will miss important alerts and messages without any indication"require_notification_initialize_per_platform- "Users on unsupported platform will never receive notifications"avoid_refresh_without_await- "Spinner dismisses immediately while data is still loading"
Other Rules (7 rules)
avoid_image_picker_without_source- "Users will see an empty dialog and be unable to select images"avoid_unbounded_cache_growth- "Eventually exhausts device memory and crashes the app"require_websocket_reconnection- "Users will see stale data or miss real-time updates"require_sqflite_error_handling- "Operations can fail due to disk full, corruption, or constraint violations"require_avatar_fallback- "Users will see a broken or blank avatar with no indication of the error"require_image_error_fallback- "Users see an ugly error state instead of a graceful fallback"require_google_signin_error_handling/require_supabase_error_handling- "Users will see unexpected crashes instead of friendly error messages"
Disposal & Memory Rules (10 rules)
require_stream_controller_close- "Listeners accumulate in memory, eventually crashing the app"require_video_player_controller_dispose- "Video decoder stays active, audio continues, battery drains"require_change_notifier_dispose- "Disposed widgets remain referenced, crashes on notification"require_receive_port_close- "Isolate port stays open, memory leaks accumulate"require_socket_close- "TCP connection stays occupied, file descriptors leak"require_lifecycle_observer- "Timer drains battery and stale callbacks cause inconsistent state"avoid_closure_memory_leak- "StatefulWidget leaks memory, setState crashes on unmounted"require_dispose_pattern- "Controllers leak memory and crash when accessed after disposal"require_hive_box_close- "File handle stays open, database can't compact"require_getx_permanent_cleanup- "GetxController remains in memory forever"
Additional Security Rules (8 rules)
avoid_dynamic_sql- "Attackers can read, modify, or delete database contents"avoid_ignoring_ssl_errors- "Man-in-the-middle attackers can intercept all HTTPS traffic"avoid_user_controlled_urls- "SSRF vulnerability allows attackers to access internal services"require_apple_signin_nonce- "Replay attacks allow impersonation of the user"require_webview_ssl_error_handling- "Invalid certificates silently accepted, credentials stolen"prefer_secure_random_for_crypto- "Predictable seed allows attackers to guess keys and tokens"require_unique_iv_per_encryption- "Same key+IV breaks confidentiality"avoid_webview_file_access- "Malicious content can read local files, exposing data"
Platform & Context Rules (6 rules)
avoid_mixed_environments- "Debug APIs expose data, development endpoints corrupt production"avoid_storing_context- "Stored context crashes when widget disposed"avoid_web_only_dependencies- "Web-only imports crash on mobile and desktop"avoid_future_tostring- "Logs show useless output, debugging becomes impossible"require_ios_callkit_integration- "Calls fail to show, App Store rejection"avoid_navigator_push_unnamed- "Deep linking fails, users can't share screens"
Widget & State Rules (7 rules)
avoid_obs_outside_controller- "Observables leak memory without lifecycle management"pass_existing_future_to_future_builder- "Duplicate network calls, slow UI with visible loading"require_late_initialization_in_init_state- "Objects recreated on every setState"require_media_loading_state- "Shows black rectangle or crashes"list_all_equatable_fields- "Equality checks fail silently"require_openai_error_handling- "Rate limits crash instead of graceful fallback"prefer_value_listenable_builder- "Full-widget rebuilds cause jank"
4.1.9 - 2026-01-18 #
Changed #
Tier rebalancing - Redistributed rules across tiers to match tier philosophy:
-
Essential: Now strictly crash/security/memory-leak rules. Removed style preferences (
prefer_list_first,enforce_member_ordering,avoid_continue_statement). Added crash-causing rules from Recommended (require_getit_registration_order,require_default_config,avoid_builder_index_out_of_bounds). -
Stylistic: Expanded with ordering/naming rules that were incorrectly in Essential/Recommended. Now 129 rules for formatting, ordering, and naming conventions.
-
Comprehensive: Expanded from 5 to 51 rules. Added optimization hints and strict patterns from Professional (immutability patterns, type strictness, documentation extras, testing extras).
-
Insanity: Expanded from 1 to 10 rules. Added pedantic rules like
avoid_object_creation_in_hot_loops,prefer_feature_folder_structure,avoid_returning_widgets.
Documentation: Updated README tier table with detailed purpose, target user, and examples for each tier.
4.1.8 - 2026-01-18 #
Added #
25 new lint rules focusing on state management, performance, security, caching, testing, and widgets:
State Management Rules (v417_state_rules.dart)
avoid_riverpod_for_network_only-[HEURISTIC]Riverpod just for network access is overkillavoid_large_bloc-[HEURISTIC]Blocs with too many event handlers (>7) need splittingavoid_overengineered_bloc_states-[HEURISTIC]Too many state subclasses; use single stateavoid_getx_static_context- Get.offNamed/Get.dialog use untestable static contextavoid_tight_coupling_with_getx-[HEURISTIC]Heavy GetX usage reduces testability
Performance Rules (v417_performance_rules.dart)
prefer_element_rebuild- Conditional widget returns destroy Elements and staterequire_isolate_for_heavy- Heavy computation blocks UI (jsonDecode, encrypt)avoid_finalizer_misuse- Finalizers add GC overhead; prefer dispose()avoid_json_in_main-[HEURISTIC]jsonDecode in async context should use compute()
Security Rules (v417_security_rules.dart)
avoid_sensitive_data_in_clipboard-[HEURISTIC]Clipboard accessible to other appsrequire_clipboard_paste_validation- Validate clipboard content before usingavoid_encryption_key_in_memory-[HEURISTIC]Keys as fields can be extracted from dumps
Caching Rules (v417_caching_rules.dart)
require_cache_expiration-[HEURISTIC]Caches without TTL serve stale data foreveravoid_unbounded_cache_growth-[HEURISTIC]Caches without limits cause OOMrequire_cache_key_uniqueness- Cache keys need stable hashCode
Testing Rules (v417_testing_rules.dart)
require_dialog_tests- Dialogs need pumpAndSettle after showingprefer_fake_platform- Platform widgets need fakes/mocks in testsrequire_test_documentation-[HEURISTIC]Complex tests (>15 lines) need comments
Widget Rules (v417_widget_rules.dart)
prefer_custom_single_child_layout- Deep positioning nesting should use delegaterequire_locale_for_text- DateFormat/NumberFormat need explicit localerequire_dialog_barrier_consideration-[HEURISTIC]Destructive dialogs need explicit barrierDismissibleprefer_feature_folder_structure-[HEURISTIC]Type-based folders (/blocs/) should be feature-based
Misc Rules (v417_misc_rules.dart)
require_websocket_reconnection-[HEURISTIC]WebSocket needs reconnection logicrequire_currency_code_with_amount-[HEURISTIC]Money amounts need currency fieldprefer_lazy_singleton_registration-[HEURISTIC]Expensive services should be lazy
Tier Assignments #
- Essential tier: 3 rules (websocket, clipboard security, cache limits)
- Recommended tier: 5 rules (dialog tests, clipboard validation, currency, cache TTL, dialog barrier)
- Professional tier: 11 rules (locale, state management, performance, security, caching)
- Comprehensive tier: 5 rules (folder structure, element rebuild, finalizer, platform fakes, test docs)
- Insanity tier: 1 rule (CustomSingleChildLayout preference)
Changed #
- Shared utilities extracted - Added
isInsideIsolate()andisInAsyncContext()toasync_context_utils.dartto reduce code duplication across performance rules - Performance file type filtering - Added
applicableFileTypestoRequireDialogBarrierConsiderationRuleto skip non-widget files - Template updated - Added all 25 new rules to
analysis_options_template.yamlwith proper categorization
4.1.7 - 2026-01-18 #
Fixed #
Critical Windows compatibility bugs that caused rules to not fire on Windows:
-
Cache key incomplete - Rule filtering cache only checked
tierandenableAll, ignoring individual rule overrides like- always_fail_test_case: true. Now includes hash of all rule configurations. -
Windows path normalization - File paths used as map keys without normalizing backslashes. On Windows, analyzer provides
d:\src\file.dartbut caches may stored:/src/file.dart. AddednormalizePath()utility and fixed 15+ locations:IncrementalAnalysisTracker- disk-persisted cacheRuleBatchExecutor- batch execution planBaselineAwareEarlyExit- baseline suppressionFileContentCache- content change detectionFileTypeDetector- file type classificationProjectContext.findProjectRoot()- project detection
Added #
normalizePath()utility function with documentation to prevent future path issues
4.1.6 - 2026-01-18 #
Added #
14 new lint rules focusing on logging, platform safety, JSON/API handling, and configuration:
Logging Rules (debug_rules.dart)
avoid_print_in_release- print() executes in release builds; guard with kDebugModerequire_structured_logging- Use structured logging instead of string concatenationavoid_sensitive_in_logs- Detect passwords, tokens, secrets in log calls
Platform Rules (platform_rules.dart)
require_platform_check- Platform-specific APIs need Platform/kIsWeb guardsprefer_platform_io_conditional- Platform.isX crashes on web; use kIsWeb firstavoid_web_only_dependencies- dart:html and web-only imports crash on mobileprefer_foundation_platform_check- Use defaultTargetPlatform in widget code
JSON/API Rules (json_datetime_rules.dart)
require_date_format_specification- DateTime.parse may fail on server datesprefer_iso8601_dates- Use ISO 8601 format for date serializationavoid_optional_field_crash- JSON field chaining needs null-aware operatorsprefer_explicit_json_keys- Use @JsonKey instead of manual mapping
Configuration Rules (config_rules.dart)
avoid_hardcoded_config- Hardcoded URLs/keys should use environment variablesavoid_mixed_environments- Don't mix production and development config
Lifecycle Rules (lifecycle_rules.dart)
require_late_initialization_in_init_state- Late fields should init in initState(), not build()
Tier Assignments #
- Essential tier: 9 rules for critical safety (print in release, platform crashes, etc.)
- Recommended tier: 2 rules for best practices
- Professional tier: 3 rules for code quality
4.1.5 - 2026-01-18 #
Added #
24 new lint rules focusing on architecture, accessibility, navigation, and internationalization:
Dependency Injection Rules
avoid_di_in_widgets- Widgets shouldn't directly use GetIt/service locatorsprefer_abstraction_injection- Inject abstract types, not concrete implementations
Accessibility Rules
prefer_large_touch_targets- Touch targets should be at least 48dp for WCAG complianceavoid_time_limits- Short durations (< 5s) disadvantage users needing more timerequire_drag_alternatives- Provide button alternatives for drag gestures
Flutter Widget Rules
avoid_global_keys_in_state- GlobalKey fields in StatefulWidget cause issuesavoid_static_route_config- Static final router configs limit testability
State Management Rules
require_flutter_riverpod_not_riverpod- Flutter apps need flutter_riverpod, not base riverpodavoid_riverpod_navigation- Navigation logic belongs in widgets, not providers
Firebase Rules
require_firebase_error_handling- Firebase async calls need try-catchavoid_firebase_realtime_in_build- Don't start Firebase listeners in build method
Security Rules
require_secure_storage_error_handling- Secure storage needs error handlingavoid_secure_storage_large_data- Large data shouldn't use secure storage
Navigation Rules
avoid_navigator_context_issue- Avoid GlobalKey.currentContext in navigationrequire_pop_result_type- Navigator.push should specify result type parameteravoid_push_replacement_misuse- Don't use pushReplacement for detail pagesavoid_nested_navigators_misuse- Nested Navigators need WillPopScope/PopScoperequire_deep_link_testing- Routes should support deep links, not just object params
Internationalization Rules
avoid_string_concatenation_l10n- String concatenation in Text breaks translationsprefer_intl_message_description- Intl.message needs desc parameter for translatorsavoid_hardcoded_locale_strings- Don't hardcode strings that need localization
Async Rules
require_network_status_check- Check connectivity before network requestsavoid_sync_on_every_change- Debounce API calls in onChanged callbacksrequire_pending_changes_indicator- Notify users when changes haven't synced
Tier Assignments #
- Recommended tier: 14 rules for common best practices
- Professional tier: 11 rules for stricter architecture/quality standards
4.1.4 - 2026-01-18 #
Added #
25 new lint rules from ROADMAP star priorities:
Bloc/Cubit Rules
avoid_passing_bloc_to_bloc- Detects Bloc depending on another Bloc (tight coupling)avoid_passing_build_context_to_blocs- Warns when BuildContext is passed to Bloc/Cubitavoid_returning_value_from_cubit_methods- Cubit methods should emit states, not return valuesrequire_bloc_repository_injection- Blocs should receive repositories via constructor injectionprefer_bloc_hydration- Suggests HydratedBloc for persistent state instead of SharedPreferences
GetX Rules
avoid_getx_dialog_snackbar_in_controller- UI dialogs shouldn't be called from controllersrequire_getx_lazy_put- Prefer lazyPut for efficient GetX dependency injection
Hive/SharedPreferences Rules
prefer_hive_lazy_box- Use LazyBox for potentially large collectionsavoid_hive_binary_storage- Don't store large binary data in Hiverequire_shared_prefs_prefix- Set prefix to avoid key conflictsprefer_shared_prefs_async_api- Use SharedPreferencesAsync for new codeavoid_shared_prefs_in_isolate- SharedPreferences doesn't work in isolates
Stream Rules
prefer_stream_distinct- Add .distinct() before .listen() for UI streamsprefer_broadcast_stream- Use broadcast streams when multiple listeners needed
Async/Build Rules
avoid_future_in_build- Don't create Futures inside build() methodrequire_mounted_check_after_await- Check mounted before setState after awaitavoid_async_in_build- Build methods must never be asyncprefer_async_init_state- Use Future field + FutureBuilder pattern
Widget Lifecycle Rules
require_widgets_binding_callback- Wrap showDialog in addPostFrameCallback in initState
Navigation Rules
prefer_route_settings_name- Include RouteSettings with name for debugging
Internationalization Rules
prefer_number_format- Use NumberFormat for locale-aware number formattingprovide_correct_intl_args- Intl.message args must match placeholders
Package-specific Rules
avoid_freezed_for_logic_classes- Freezed is for data classes, not Blocs/Services
Disposal Rules
dispose_class_fields- Classes with disposable fields need dispose/close methods
State Management Rules
prefer_change_notifier_proxy_provider- Use ProxyProvider for dependent notifiers
Tier Assignments #
- Essential tier: avoid_shared_prefs_in_isolate, avoid_future_in_build, require_mounted_check_after_await, provide_correct_intl_args, dispose_class_fields, avoid_async_in_build
- Recommended tier: 17 rules covering best practices
- Professional tier: require_bloc_repository_injection, avoid_freezed_for_logic_classes
4.1.3 - 2026-01-14 #
- Migrated all single/double-word lint rules to three-word convention for clarity and discoverability. Notable migrations include:
arguments_ordering→enforce_arguments_orderingcapitalize_comment→capitalize_comment_startprefer_first_method_usage→prefer_list_firstprefer_last_method_usage→prefer_list_lastprefer_member_ordering→enforce_member_orderingprefer_container_widget→prefer_single_containerprefer_pagination_pattern→prefer_api_paginationprefer_contains_method_usage→prefer_list_containsavoid_dynamic_typing→avoid_dynamic_typeavoid_substring_usage→avoid_string_substringavoid_continue_statement→avoid_continue_statementextend_equatable→require_extend_equatablerequire_dispose_method→require_field_disposedispose_fields→dispose_widget_fieldsparameters_ordering→enforce_parameters_orderingformat_comment→format_comment_stylemax_imports→limit_max_importsavoid_shadowing→avoid_variable_shadowingprefer_selector→prefer_context_selectordispose_providers→dispose_provider_instancesprefer_first→prefer_list_firstprefer_last→prefer_list_lastprefer_contains→prefer_list_containsprefer_container→prefer_single_containerprefer_pagination→prefer_api_paginationavoid_dynamic→avoid_dynamic_typeavoid_substring→avoid_string_substringmember_ordering→enforce_member_orderingparameters_ordering→enforce_parameters_orderingformat_comment→format_comment_stylerequire_dispose→require_field_disposedispose_fields→dispose_widget_fieldsavoid_continue→avoid_continue_statementextend_equatable→require_extend_equatableavoid_shadowing→avoid_variable_shadowing
4.1.1 - 2026-01-13 #
Added #
- New Rule:
avoid_cached_isar_stream([lib/src/rules/isar_rules.dart])- Detects and prevents caching of Isar query streams (must be created inline).
- Tier: Professional
- Quick Fix: Inlines offending Isar stream expressions at usage sites and removes the cached variable.
- Example: [example/lib/isar/avoid_cached_isar_stream_fixture.dart]
Tier Assignment for Previously Unassigned Rules #
The following 6 rules, previously implemented but not assigned to any tier, are now included in the most appropriate tier sets in lib/src/tiers.dart:
- Recommended Tier:
avoid_duplicate_test_assertions(test quality)avoid_real_network_calls_in_tests(test reliability)require_error_case_tests(test completeness)require_test_isolation(test reliability)prefer_where_or_null(idiomatic Dart collections)
- Professional Tier:
prefer_copy_with_for_state(state management, immutability)
This ensures all implemented rules are available through tiered configuration and improves coverage for test and state management best practices.
Rule Tier Assignment Audit #
- Ran
scripts/audit_rules.pyto identify all implemented rules not assigned to any tier. - Assigned the following rules to the most appropriate tier sets in
lib/src/tiers.dart:- Recommended:
avoid_duplicate_test_assertions,avoid_real_network_calls_in_tests,require_error_case_tests,require_test_isolation,prefer_where_or_null - Professional:
prefer_copy_with_for_state
- Recommended:
- All implemented rules are now available through tiered configuration. This ensures no orphaned rules and improves test and state management coverage.
- Updated changelog to document these assignments and maintain full transparency of tier coverage.
Tier Set Maintenance #
- Commented out unimplemented rules in all tier sets in
lib/src/tiers.dartto ensure only implemented rules are active per tier. - Confirmed all unimplemented rules are tracked in
ROADMAP.mdfor future implementation. - This change improves roadmap alignment and prevents accidental activation of unimplemented rules.
- Materially improve the message quality for all Critial rules
4.1.0 - 2026-01-12 #
Tier Assignment Audit #
181 rules previously unassigned to any tier are now properly categorized. These rules existed but were not included in tier configurations, meaning users weren't getting them unless explicitly enabled.
Essential Tier (+50 rules)
Critical and high-impact rules now included in the essential tier:
| Category | Rules Added |
|---|---|
| Security | avoid_deep_link_sensitive_params, avoid_path_traversal, avoid_webview_insecure_content, require_data_encryption, require_secure_password_field, prefer_html_escape |
| JSON/Type Safety | avoid_dynamic_json_access, avoid_dynamic_json_chains, avoid_unrelated_type_casts, require_null_safe_json_access |
| Platform Permissions | avoid_platform_channel_on_web, require_image_picker_permission_android, require_image_picker_permission_ios, require_permission_manifest_android, require_permission_plist_ios, require_url_launcher_queries_android, require_url_launcher_schemes_ios |
| Memory/Resource Leaks | avoid_stream_subscription_in_field, avoid_websocket_memory_leak, prefer_dispose_before_new_instance, require_dispose_implementation, require_video_player_controller_dispose |
| Widget Lifecycle | check_mounted_after_async, avoid_ref_in_build_body, avoid_flashing_content |
| Animation | avoid_animation_rebuild_waste, avoid_overlapping_animations |
| Navigation | prefer_maybe_pop, require_deep_link_fallback, require_stepper_validation |
| Firebase/Backend | prefer_firebase_remote_config_defaults, require_background_message_handler, require_fcm_token_refresh_handler |
| Forms/WebView | require_validator_return_null, avoid_image_picker_large_files, prefer_webview_javascript_disabled, require_webview_error_handling, require_webview_navigation_delegate, require_websocket_message_validation |
| Data/Storage | prefer_utc_for_storage, require_database_migration, require_enum_unknown_value |
| State/UI | require_error_widget, require_feature_flag_default, require_immutable_bloc_state, require_map_idle_callback, require_media_loading_state, prefer_bloc_listener_for_side_effects, require_cors_handling |
Recommended Tier (+83 rules)
Medium-impact rules for better code quality:
| Category | Rules Added |
|---|---|
| Widget Structure | avoid_deep_widget_nesting, avoid_find_child_in_build, avoid_layout_builder_in_scrollable, avoid_nested_providers, avoid_opacity_misuse, avoid_shrink_wrap_in_scroll, avoid_unbounded_constraints, avoid_unconstrained_box_misuse |
| Gesture/Input | avoid_double_tap_submit, avoid_gesture_conflict, avoid_gesture_without_behavior, prefer_actions_and_shortcuts, prefer_cursor_for_buttons, require_disabled_state, require_drag_feedback, require_focus_indicator, require_hover_states, require_long_press_callback |
| Forms/Testing | require_button_loading_state, require_form_validation, avoid_flaky_tests, avoid_real_timer_in_widget_test, avoid_stateful_test_setup, prefer_matcher_over_equals, prefer_mock_http, require_golden_test, require_mock_verification |
| Performance | avoid_hardcoded_layout_values, avoid_hardcoded_text_styles, avoid_large_images_in_memory, avoid_map_markers_in_build, avoid_stack_overflow, prefer_clip_behavior, prefer_deferred_loading_web, prefer_keep_alive, prefer_sliver_app_bar, prefer_sliver_list |
| State Management | avoid_late_context, prefer_cubit_for_simple_state, prefer_selector_over_consumer, require_bloc_consumer_when_both |
| Accessibility | avoid_screenshot_sensitive, avoid_semantics_exclusion, prefer_merge_semantics, avoid_small_text |
| Database/Navigation | require_database_index, prefer_transaction_for_batch, prefer_typed_route_params, require_refresh_indicator, require_scroll_controller, require_scroll_physics |
| Desktop/i18n | require_menu_bar_for_desktop, require_window_close_confirmation, require_intl_locale_initialization, require_notification_timezone_awareness |
Comprehensive Tier (+48 rules)
Low-impact style and pattern rules:
- Code style:
avoid_digit_separators,avoid_nested_try_statements,avoid_type_casts - Documentation:
prefer_doc_comments_over_regular,prefer_error_suffix,prefer_exception_suffix - Patterns:
prefer_class_over_record_return,prefer_record_over_equatable,prefer_guard_clauses - Async:
prefer_async_only_when_awaiting,prefer_await_over_then,prefer_sync_over_async_where_possible - Testing:
prefer_expect_over_assert_in_tests,prefer_single_expectation_per_test - And 33 more...
Intentionally Untiered (81 rules)
Stylistic/opinionated rules remain untiered for team-specific configuration:
- Quote style:
prefer_single_quotesvsprefer_double_quotes - Import style:
prefer_relative_importsvsprefer_absolute_imports - Member ordering:
prefer_fields_before_methodsvsprefer_methods_before_fields - Control flow:
prefer_ternary_over_if_nullvsprefer_if_null_over_ternary - Debug rules:
always_fail,greeting,firebase_custom
4.0.1 - 2026-01-12 #
Testing Best Practices Rules #
Activated 5 previously unregistered testing best practices rules:
| Rule | Tier | Description |
|---|---|---|
prefer_test_find_by_key |
Recommended | Suggests find.byKey() over find.byType() for reliable widget testing |
prefer_setup_teardown |
Recommended | Detects duplicated test setup code (3+ occurrences) |
require_test_description_convention |
Recommended | Ensures test names include descriptive words |
prefer_bloc_test_package |
Professional | Suggests blocTest() when detecting Bloc testing patterns |
prefer_mock_verify |
Professional | Warns when when() is used without verify() |
Note: avoid_test_sleep was already registered.
Code cleanup: Removed redundant test file path checks from these rules (file type filtering is handled by applicableFileTypes).
DX Message Quality Improvements #
Improved problem messages for 7 critical-impact rules to provide specific consequences instead of generic descriptions:
| Rule | Improvement |
|---|---|
require_secure_storage |
Now explains XML storage exposure enables credential extraction |
avoid_storing_sensitive_unencrypted |
Added backup extraction and identity theft consequence |
check_mounted_after_async |
Specifies State disposal during async gap |
avoid_stream_subscription_in_field |
Clarifies callbacks fire after State disposal |
require_stream_subscription_cancel |
Specifies State disposal context |
require_interval_timer_cancel |
Specifies State disposal context |
avoid_dialog_context_after_async |
Clarifies BuildContext deactivation during async gap |
Result: Critical impact rules now at 100% DX compliance (40/40 passing).
Documentation #
- PROFESSIONAL_SERVICES.md: Rewrote professional services documentation with clearer service offerings and contact information
4.0.0 - 2026-01-12 #
OWASP Compliance Mapping #
Security rules are now mapped to OWASP Mobile Top 10 (2024) and OWASP Top 10 (2021) standards, transforming saropa_lints from a developer tool into a security audit tool.
Coverage
| OWASP Mobile | Rules | OWASP Web | Rules |
|---|---|---|---|
| M1 Credential Usage | 5+ | A01 Broken Access Control | 4+ |
| M3 Authentication | 5+ | A02 Cryptographic Failures | 10+ |
| M4 Input Validation | 6+ | A03 Injection | 6+ |
| M5 Communication | 2+ | A05 Misconfiguration | 4+ |
| M6 Privacy Controls | 5+ | A07 Authentication Failures | 8+ |
| M8 Misconfiguration | 4+ | A09 Logging Failures | 2+ |
| M9 Data Storage | 7+ | ||
| M10 Cryptography | 4+ |
Gaps: M2 (Supply Chain), M7 (Binary Protection), and A06 (Outdated Components) require separate tooling — dependency scanners and build-time protections.
New Files
lib/src/owasp/owasp_category.dart-OwaspMobileandOwaspWebenums with category metadatalib/src/owasp/owasp_mapping.dart- Compliance reporting utilitieslib/src/owasp/owasp.dart- Barrel export
API
Rules expose OWASP mappings via the owasp property:
final rule = AvoidHardcodedCredentialsRule();
print(rule.owasp); // Mobile: M1 | Web: A07
// Generate compliance report
final mappings = getAllSecurityRuleMappings();
final report = generateComplianceReport(mappings);
Modified Files
lib/src/saropa_lint_rule.dart- AddedOwaspMapping? get owasptoSaropaLintRulebase classlib/src/rules/security_rules.dart- Added OWASP mappings to 41 security ruleslib/src/rules/crypto_rules.dart- Added OWASP mappings to 4 cryptography ruleslib/saropa_lints.dart- ExportOwaspMapping,OwaspMobile,OwaspWeb
Baseline Feature for Brownfield Projects #
The problem: You want to adopt saropa_lints on an existing project, but running analysis shows 500+ violations in legacy code. You can't fix them all before your next sprint, but you want new code to be clean.
The solution: The baseline feature records existing violations and hides them. Old code is "baselined" (hidden), new code is still checked. You can adopt linting today without fixing legacy code first.
Quick Start
# Generate baseline - hides all current violations
dart run saropa_lints:baseline
This command creates saropa_baseline.json and updates your analysis_options.yaml. Old violations are hidden, new code is still checked.
Three Combinable Baseline Types
| Type | Config | Description |
|---|---|---|
| File-based | baseline.file |
JSON file listing specific violations to ignore |
| Path-based | baseline.paths |
Glob patterns for directories (e.g., lib/legacy/) |
| Date-based | baseline.date |
Git blame - ignore code unchanged since a date |
All three types are combinable - any match suppresses the violation.
Full Configuration
custom_lint:
saropa_lints:
tier: recommended
baseline:
file: "saropa_baseline.json" # Specific violations
date: "2025-01-15" # Code unchanged since this date
paths: # Directories/patterns
- "lib/legacy/"
- "lib/deprecated/"
- "**/generated/"
only_impacts: [low, medium] # Only baseline these severities
CLI Commands
dart run saropa_lints:baseline # Generate new baseline
dart run saropa_lints:baseline --update # Refresh, remove fixed violations
dart run saropa_lints:baseline --dry-run # Preview without changes
dart run saropa_lints:baseline --help # See all options
New Files
lib/src/baseline/baseline_config.dart- Configuration parsinglib/src/baseline/baseline_file.dart- JSON file handlinglib/src/baseline/baseline_paths.dart- Glob pattern matchinglib/src/baseline/baseline_date.dart- Git blame integrationlib/src/baseline/baseline_manager.dart- Central orchestratorbin/baseline.dart- CLI tool
See README.md for full documentation.
New Rules #
OWASP Coverage Gap Rules
Five new rules to fill gaps in OWASP coverage:
| Rule | OWASP | Severity | Description |
|---|---|---|---|
avoid_ignoring_ssl_errors |
M5, A05 | ERROR | Detects badCertificateCallback = (...) => true that bypasses SSL validation |
require_https_only |
M5, A05 | WARNING | Flags http:// URLs (except localhost). Has quick fix to replace with HTTPS |
avoid_unsafe_deserialization |
M4, A08 | WARNING | Detects jsonDecode results used in dangerous operations without type validation |
avoid_user_controlled_urls |
M4, A10 | WARNING | Flags user input (text controllers) passed directly to HTTP methods without URL validation |
require_catch_logging |
M8, A09 | WARNING | Catch blocks that silently swallow exceptions without logging or rethrowing |
3.4.0 and Earlier #
For details on the initial release and versions 0.1.0 through 3.4.0, please refer to CHANGELOG_ARCHIVE.md.