Flutter Compositions Lints
Custom lint rules for Flutter Compositions to enforce best practices and prevent common pitfalls.
Rules
1. flutter_compositions_ensure_reactive_props
Severity: Warning
Ensures widget properties are accessed through widget() in setup() to maintain reactivity.
❌ Bad:
@override
Widget Function(BuildContext) setup() {
final name = this.displayName; // Direct access - not reactive!
return (context) => Text(name);
}
✅ Good:
@override
Widget Function(BuildContext) setup() {
final props = widget();
final name = computed(() => props.value.displayName); // Reactive!
return (context) => Text(name.value);
}
2. flutter_compositions_no_async_setup
Severity: Error
Prevents async setup() methods. The setup method must synchronously return a builder function.
❌ Bad:
@override
Future<Widget Function(BuildContext)> setup() async {
await loadData();
return (context) => Text('Loaded');
}
✅ Good:
@override
Widget Function(BuildContext) setup() {
final data = ref<String?>(null);
onMounted(() async {
data.value = await loadData();
});
return (context) => Text(data.value ?? 'Loading...');
}
3. flutter_compositions_controller_lifecycle
Severity: Warning
Ensures Flutter controllers are properly disposed using use* helpers or explicit onUnmounted() calls.
❌ Bad:
@override
Widget Function(BuildContext) setup() {
final controller = ScrollController(); // No disposal!
return (context) => ListView(controller: controller);
}
✅ Good:
@override
Widget Function(BuildContext) setup() {
// Option 1: Use helper (recommended)
final controller = useScrollController();
return (context) => ListView(controller: controller.value);
// Option 2: Manual disposal
final controller = ScrollController();
onUnmounted(() => controller.dispose());
return (context) => ListView(controller: controller);
}
4. flutter_compositions_no_mutable_fields
Severity: Warning
Ensures CompositionWidget fields are final. All mutable state should use ref().
❌ Bad:
class MyWidget extends CompositionWidget {
int count; // Mutable field!
}
✅ Good:
class MyWidget extends CompositionWidget {
final int initialCount; // Immutable prop
@override
Widget Function(BuildContext) setup() {
final count = ref(initialCount); // Mutable via ref
...
}
}
Installation
Add to your pubspec.yaml:
dev_dependencies:
custom_lint: ^0.7.0
flutter_compositions_lints:
path: packages/flutter_compositions_lints
Create analysis_options.yaml in your project root:
analyzer:
plugins:
- custom_lint
custom_lint:
enable_all_lint_rules: true
Running the lints
# Analyze your code
dart run custom_lint
# Watch for changes
dart run custom_lint --watch
# Fix auto-fixable issues
dart run custom_lint --fix
Contributing
Found a false positive or want to suggest a new rule? Please open an issue!
Libraries
- flutter_compositions_lints
- Custom lint rules for Flutter Compositions.