mz_lints 0.0.1
mz_lints: ^0.0.1 copied to clipboard
Custom Dart lint rules for Flutter apps. Includes rules for proper disposal of ChangeNotifiers, listener cleanup, and Controller lookup patterns.
mz_lints #
Custom Dart lint rules for Flutter applications. Helps catch common mistakes with ChangeNotifier disposal, listener cleanup, and Controller lookup patterns.
Available Rules #
| Rule | Description | Quick Fixes |
|---|---|---|
dispose_notifier |
ChangeNotifier subclasses created in State must be disposed | Add dispose method, Add dispose call |
remove_listener |
Listeners added to Listenables must be removed in dispose | Add removeListener call |
controller_listen_in_callback |
Controller lookups in callbacks should use listen: false |
Add 'listen: false' |
Installation #
Add mz_lints to your pubspec.yaml:
dev_dependencies:
mz_lints: ^0.0.1
Then enable the plugin in your analysis_options.yaml:
# Requires Dart 3.10+ / Flutter 3.38+
plugins:
mz_lints: ^0.0.1
Rule Details #
dispose_notifier #
Ensures ChangeNotifier subclasses created in StatefulWidget State classes are disposed:
TextEditingController,ScrollController,AnimationControllerTabController,PageController,FocusNodeValueNotifier, and any customChangeNotifiersubclass
BAD:
class _MyWidgetState extends State<MyWidget> {
final _controller = TextEditingController(); // LINT: not disposed
@override
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
GOOD:
class _MyWidgetState extends State<MyWidget> {
final _controller = TextEditingController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
remove_listener #
Ensures listeners added in initState, didChangeDependencies, or didUpdateWidget are removed in dispose:
BAD:
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
super.initState();
widget.controller.addListener(_onChanged); // LINT: never removed
}
void _onChanged() {}
}
GOOD:
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
super.initState();
widget.controller.addListener(_onChanged);
}
@override
void dispose() {
widget.controller.removeListener(_onChanged);
super.dispose();
}
void _onChanged() {}
}
controller_listen_in_callback #
Warns when using Controller.ofType() or similar lookup methods inside event handlers without listen: false:
BAD:
void _onButtonPressed() {
// Will cause unnecessary rebuilds
final controller = Controller.ofType<MyController>(context);
controller.doSomething();
}
GOOD:
void _onButtonPressed() {
final controller = Controller.ofType<MyController>(context, listen: false);
controller.doSomething();
}
Suppressing Rules #
You can suppress rules using standard Dart ignore comments:
Suppress for entire file:
// ignore_for_file: dispose_notifier, remove_listener
class MyWidget extends StatefulWidget {
// ...
}
Suppress for a single line:
class _MyWidgetState extends State<MyWidget> {
// ignore: dispose_notifier
final _controller = TextEditingController();
}
Requirements #
- Dart SDK 3.10.0 or later
- Flutter 3.38.0 or later (for Flutter projects)
Related #
This package is part of the mz_utils ecosystem.
License #
MIT License - see the LICENSE file for details.