all_observer_lint 0.5.0
all_observer_lint: ^0.5.0 copied to clipboard
Official lint rules and automated fixes for safe, predictable, and efficient development with all_observer.
all_observer_lint #
[all_observer_lint banner]
Official lint rules for building safer Flutter and Dart apps with
all_observer.
Leia em português
all_observer_lint helps catch common reactive mistakes directly in your IDE:
state created inside build, effects registered on every rebuild, invalid
watch(context) usage, impure Computed callbacks, and reactive resources that
were not disposed.
It is a development-only package. It does not change your app runtime.
Install #
Add both packages as development dependencies:
dart pub add --dev custom_lint all_observer_lint
For Flutter projects:
flutter pub add --dev custom_lint all_observer_lint
Your pubspec.yaml should contain:
dev_dependencies:
custom_lint: ^0.8.0
all_observer_lint: ^0.5.0
custom_lint is required because it is the analyzer runner that loads custom
lint plugins. all_observer_lint provides the rules.
Configure #
In analysis_options.yaml, use the recommended preset:
include: package:all_observer_lint/recommended.yaml
That preset enables the custom_lint analyzer plugin and the recommended rule
set.
To show diagnostics in Brazilian Portuguese:
include: package:all_observer_lint/recommended.yaml
custom_lint:
rules:
- all_observer:
language: pt-BR
Migrating from 0.3.x #
The package installation command did not change, but custom options now use
the custom_lint.rules configuration shape. If you previously configured
Portuguese diagnostics with a top-level all_observer: key, move that option
under custom_lint.rules as shown above.
Run #
Use your normal analyzer workflow:
dart analyze
Or run the custom lint runner directly:
dart run custom_lint
In Flutter projects:
flutter analyze
dart run custom_lint
Most IDEs show the diagnostics automatically after pub get.
Example #
This code creates reactive state every time the widget rebuilds:
Widget build(BuildContext context) {
final count = 0.obs;
return Text('${count.value}');
}
all_observer_lint reports:
warning: Avoid creating reactive state inside build. The resource will be
recreated whenever the widget rebuilds. Move it to a State field, initState,
controller, view model, or another lifecycle-managed object.
Move the state to a lifecycle-managed place:
class _CounterPageState extends State<CounterPage> {
final count = 0.obs;
@override
Widget build(BuildContext context) {
return Observer(() => Text('${count.value}'));
}
}
Quick Fixes #
Some rules provide IDE quick fixes. dispose_reactive_resources selects the
call from the field's resolved type. In particular, an effect() disposer is
invoked as a callback:
class _SearchPageState extends State<SearchPage> {
late final disposeEffect = effect(() => query.value);
@override
void dispose() {
disposeEffect();
super.dispose();
}
}
Assists #
Select a resolved Widget expression containing an immediate reactive read and
choose Wrap with Observer. It generates the public
Observer(() => widget) constructor, reuses prefixed imports, and adds an
import when safe. It stays unavailable in callbacks, tracked contexts,
watch(context), constant contexts, and unresolved code.
Presets #
| Preset | Use when |
|---|---|
recommended.yaml |
You want the default rule set for everyday projects. |
strict.yaml |
You also want experimental suggestions for cleaner reactive design. |
all.yaml |
You want to try every available rule. |
Rules #
| Rule | What it catches |
|---|---|
avoid_reactive_creation_in_build |
Observable, .obs, Computed, ObservableFuture, or ObservableStream created inside rebuild scopes. |
avoid_effect_creation_in_build |
effect, ever, once, debounce, or interval registered inside rebuild scopes. |
watch_only_inside_build |
watch(context) used outside widget build contexts. |
dispose_reactive_resources |
Workers/effects/streams stored in fields but not disposed. |
avoid_reactive_write_in_computed |
Reactive writes inside Computed callbacks. |
avoid_set_state_in_computed |
setState inside Computed callbacks. |
avoid_worker_creation_in_computed |
Workers/effects created inside Computed callbacks. |
avoid_io_in_computed |
await or obvious dart:io work inside Computed callbacks. |
avoid_observable_write_during_observer_build |
Reactive writes while an Observer is building. |
self_referencing_computed |
A Computed value directly reading its own .value. |
prefer_computed_for_derived_state |
Manual derived state that could be a Computed. |
prefer_batch_for_multiple_related_writes |
Related reactive writes that may benefit from batch. |
prefer_assign_all_for_reactive_list_replace |
ObservableList.clear() followed by add/addAll; prefer assign/assignAll. |
unused_reactive_state |
Private reactive fields or top-level variables that are never used in the same file. |
unobserved_reactive_read_in_build |
Reactive .value reads rendered in build without Observer or watch(context). |
invalid_history_limit |
Known non-positive ObservableHistory limits. |
async_inside_batch |
Directly async callbacks passed to Observable.batch. |
observer_without_reactive_read |
Observer builders with no proven tracked read (strict/all). |
computed_without_reactive_read |
Computed callbacks with no proven tracked read (strict/all). |
effect_without_reactive_read |
effect callbacks with no proven tracked read (strict/all). |
More Documentation #
- Example app
- Architecture and why
custom_lintis required - Known limitations and future rules
- False positive policy
License #
MIT. See LICENSE.