must_be_handled 0.1.0
must_be_handled: ^0.1.0 copied to clipboard
A Dart analyzer plugin that enforces explicit error-handling contracts at compile time using the @mustBeHandled annotation.
must_be_handled #
A Dart analyzer plugin that enforces explicit error-handling contracts at compile time by introducing a @mustBeHandled annotation.
Functions or methods annotated with @mustBeHandled must be explicitly handled by the caller, otherwise the analyzer reports an error.
This brings checked-exceptionβlike discipline to Dart without changing the language.
Features #
- π― Compile-time enforcement β Errors appear in your IDE and during analysis
- π Sync and async support β Handles both synchronous and asynchronous functions
- β³ Await verification β Ensures async functions are properly awaited
- π‘οΈ try/catch validation β Verifies calls are wrapped in try/catch blocks
- π Precise diagnostics β Clear error messages with correction hints
Getting Started #
1. Add the dependency #
dependencies:
must_be_handled: ^0.1.0
2. Enable the plugin #
Add to your analysis_options.yaml:
plugins:
- must_be_handled
3. Annotate your functions #
import 'package:must_be_handled/must_be_handled.dart';
@mustBeHandled
Future<User> fetchUser() async {
// This function might throw!
}
Usage #
Sync Functions #
Sync functions annotated with @mustBeHandled must be wrapped in a try/catch block:
@mustBeHandled
void dangerousSync() {
throw Exception('Something went wrong!');
}
void main() {
// β Invalid β not in try/catch
dangerousSync();
// β
Valid β wrapped in try/catch
try {
dangerousSync();
} catch (e) {
print('Error: $e');
}
}
Async Functions #
Async functions annotated with @mustBeHandled must be both awaited AND wrapped in try/catch:
@mustBeHandled
Future<String> fetchData() async {
throw Exception('Network error!');
}
void main() async {
// β Invalid β not awaited
fetchData();
// β Invalid β awaited but not in try/catch
await fetchData();
// β Invalid β not awaited (false safety)
try {
fetchData(); // not awaited!
} catch (_) {}
// β
Valid β awaited AND in try/catch
try {
final data = await fetchData();
print(data);
} catch (e) {
print('Error: $e');
}
}
Class Methods #
The annotation works on class methods too:
class ApiService {
@mustBeHandled
Future<Response> post(String url, Map<String, dynamic> body) async {
// ...
}
}
void main() async {
final api = ApiService();
// β
Valid
try {
final response = await api.post('/users', {'name': 'John'});
print(response);
} catch (e) {
print('API error: $e');
}
}
Constructor Annotation #
You can use either the constant or the constructor:
// Using the constant (preferred)
@mustBeHandled
void danger1() {}
// Using the constructor
@MustBeHandled()
void danger2() {}
Enforcement Rules #
| Rule | Description |
|---|---|
| Sync functions | Must be inside try block (not catch/finally) |
| Async functions | Must be awaited AND inside try block |
| Scope | Call must be in try {} body, not in catch or finally |
Explicitly Not Supported (v1) #
The following patterns are not considered valid handling:
// β These don't satisfy @mustBeHandled
fetchUser().catchError(...)
runZonedGuarded(...)
fetchUser().then(...).catchError(...)
Rationale: These patterns are ambiguous and harder to statically verify. Future versions may add opt-in support.
IDE Support #
The plugin works with:
- β VS Code (with Dart extension)
- β IntelliJ IDEA / Android Studio
- β
dart analyzecommand
Example #
See the example directory for a complete working example.
Contributing #
Contributions are welcome! Please feel free to submit issues and pull requests.
License #
BSD-3-Clause β See LICENSE for details.