Skip to content

Commit dbf1364

Browse files
committed
Release v9.1.1: Rename filter and add GlobalErrorFilter
Improvements: - Renamed FirstLocalThenGlobalErrorFilter to GlobalIfNoLocalErrorFilter for better clarity - Name now clearly indicates "global if no local handler" behavior New Features: - Added GlobalErrorFilter that routes errors ONLY to global handler - Returns ErrorReaction.globalHandler (not firstLocalThenGlobal) - Useful when you want all errors to go global regardless of local listeners Fixes: - Removed incorrectly deprecated GlobalErrorFilter from v9.1.0 - Replaced with correct implementation Tests: - Added test for GlobalErrorFilter behavior - All 38 tests passing
1 parent d58de85 commit dbf1364

17 files changed

+4411
-19
lines changed

API_PROPOSAL_v8.1_v9.0.md

Lines changed: 532 additions & 0 deletions
Large diffs are not rendered by default.

BREAKING_CHANGE_ANNOUNCEMENT.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<div align="center">
2+
3+
<img src="https://github.com/flutter-it/command_it/blob/main/command_it.png?raw=true" alt="command_it logo" width="200"/>
4+
5+
# 🔮 Upcoming Breaking Change: v9.0.0
6+
7+
# `execute``run`
8+
9+
## Making Commands More Natural
10+
11+
**Status: Proposal****Your Feedback Needed!**
12+
13+
</div>
14+
15+
---
16+
17+
## 📢 The Change
18+
19+
<table>
20+
<tr>
21+
<th>Before (v8.x)</th>
22+
<th>After (v9.0.0+)</th>
23+
</tr>
24+
<tr>
25+
<td>
26+
27+
```dart
28+
// Methods
29+
command.execute(param);
30+
await command.executeWithFuture(param);
31+
32+
// Properties
33+
command.isExecuting.value;
34+
command.canExecute.value;
35+
36+
// Widgets
37+
FloatingActionButton(
38+
onPressed: command.execute,
39+
child: Icon(Icons.play),
40+
)
41+
```
42+
43+
</td>
44+
<td>
45+
46+
```dart
47+
// Methods
48+
command.run(param);
49+
await command.runWithFuture(param);
50+
51+
// Properties
52+
command.isRunning.value;
53+
command.canRun.value;
54+
55+
// Widgets
56+
FloatingActionButton(
57+
onPressed: command.run,
58+
child: Icon(Icons.play),
59+
)
60+
```
61+
62+
</td>
63+
</tr>
64+
</table>
65+
66+
---
67+
68+
## 🎯 Why This Change?
69+
70+
### The Problem
71+
The callable class syntax (`command()`) triggers linter warnings due to **implicit call tear-offs**:
72+
73+
```dart
74+
// ⚠️ Triggers implicit_call_tearoffs warning
75+
onPressed: command
76+
```
77+
78+
This forces developers to use `.execute()` as the primary API, not the callable syntax.
79+
80+
### The Solution
81+
Since `.execute()` is now the primary API surface, let's make it **natural and Flutter-idiomatic**:
82+
83+
**`run`** feels lighter and more action-oriented
84+
✨ Aligns with Flutter's "run the app" terminology
85+
✨ Shorter and easier to type (`isRunning` vs `isExecuting`)
86+
✨ More approachable than formal "execute" terminology
87+
88+
---
89+
90+
## 📅 Timeline
91+
92+
| Version | Date | What Happens |
93+
|---------|------|--------------|
94+
| **v9.0.0** | November 2025 | New `run` API added<br>Old `execute` API deprecated with warnings |
95+
| **v9.x** | Nov 2025 - May 2026 | Migration period<br>Both APIs work |
96+
| **v10.0.0** | May-June 2026 | Old `execute` API removed |
97+
98+
**Deprecation period:** 6 months
99+
100+
---
101+
102+
## 🔧 Migration Guide
103+
104+
### Automated (Recommended)
105+
106+
Use global search and replace:
107+
108+
```
109+
.execute( → .run(
110+
.executeWithFuture( → .runWithFuture(
111+
.isExecuting → .isRunning
112+
.canExecute → .canRun
113+
```
114+
115+
### What Changes
116+
117+
| Old API | New API |
118+
|---------|---------|
119+
| `execute()` | `run()` |
120+
| `executeWithFuture()` | `runWithFuture()` |
121+
| `isExecuting` | `isRunning` |
122+
| `canExecute` | `canRun` |
123+
| `ifRestrictedExecuteInstead` | `ifRestrictedRunInstead` |
124+
125+
---
126+
127+
## 🤔 Help Us Decide: Awaitable Method Name
128+
129+
Which name do you prefer for the awaitable version?
130+
131+
### Option 1: `runWithFuture()` ⭐ (Current Recommendation)
132+
```dart
133+
await command.runWithFuture(param);
134+
```
135+
✅ Direct parallel to current `executeWithFuture()`
136+
✅ Clearly indicates it returns a Future
137+
✅ Easiest migration (suffix stays the same)
138+
139+
### Option 2: `runAwaited()`
140+
```dart
141+
await command.runAwaited(param);
142+
```
143+
✅ Shorter and more concise
144+
✅ Emphasizes await-ability
145+
⚠️ Less clear that it returns a Future
146+
147+
### Option 3: `runAsync()`
148+
```dart
149+
await command.runAsync(param);
150+
```
151+
✅ Short and commonly used
152+
⚠️ Ambiguous (async commands are already async)
153+
154+
### Option 4: `runFuture()`
155+
```dart
156+
await command.runFuture(param);
157+
```
158+
✅ Very short
159+
⚠️ Grammatically awkward
160+
161+
**Vote for your favorite!** 👆
162+
163+
---
164+
165+
## 💬 Feedback Welcome!
166+
167+
**What do you think?**
168+
169+
- Is "run" the right choice?
170+
- Prefer `runAwaited()` over `runWithFuture()`?
171+
- Need more time for migration?
172+
173+
**Join the discussion:**
174+
- 💬 GitHub Discussion: [link]
175+
- 💭 Discord: https://discord.gg/ZHYHYCM38h
176+
177+
---
178+
179+
## 📖 Complete Details
180+
181+
See [BREAKING_CHANGE_EXECUTE_TO_RUN.md](BREAKING_CHANGE_EXECUTE_TO_RUN.md) for:
182+
- Complete motivation and reasoning
183+
- Full API mapping (300+ affected locations)
184+
- Detailed migration examples
185+
- Implementation timeline
186+
- Risk assessment
187+
188+
---
189+
190+
<div align="center">
191+
192+
### **command_it**
193+
*Command pattern for Flutter with reactive state management*
194+
195+
[Documentation](https://flutter-it.dev/documentation/command_it/getting_started)[GitHub](https://github.com/flutter-it/command_it)[pub.dev](https://pub.dev/packages/command_it)
196+
197+
</div>

CHANGELOG.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
[9.1.1] - 2025-11-21
2+
3+
### Improvements
4+
5+
- **Renamed GlobalIfNoLocalErrorFilter**: Renamed `FirstLocalThenGlobalErrorFilter` to `GlobalIfNoLocalErrorFilter` for better clarity. The name now clearly indicates "global if no local handler".
6+
7+
### New Features
8+
9+
- **Added GlobalErrorFilter**: New filter that routes errors ONLY to the global handler, regardless of local listeners. Returns `ErrorReaction.globalHandler`.
10+
11+
### Fixes
12+
13+
- **Removed incorrectly named GlobalErrorFilter**: The previous `GlobalErrorFilter` that was deprecated in v9.1.0 has been removed and replaced with the correct implementation.
14+
115
[9.1.0] - 2025-11-21
216

317
### New Features
@@ -45,9 +59,9 @@ class MyApp extends WatchingWidget {
4559
- **Improved ErrorFilter class naming consistency**: Renamed `ErrorHandler*` classes to simpler `*ErrorFilter` pattern to better align with existing filters. Old names remain functional with deprecation warnings until v10.0.0.
4660

4761
**Class name changes:**
48-
- `ErrorHandlerGlobalIfNoLocal``GlobalErrorFilter` (deprecated)
62+
- `ErrorHandlerGlobalIfNoLocal``GlobalIfNoLocalErrorFilter` (deprecated)
4963
- `ErrorHandlerLocal``LocalErrorFilter` (deprecated)
50-
- `ErrorHandlerLocalAndGlobal``LocalAndGlobalErrorFilter` (deprecated)
64+
- `ErrorHandlerLocalAndGlobal``LocalAndGlobalIfNoLocalErrorFilter` (deprecated)
5165

5266
**Why this change:**
5367
- Better naming consistency: matches `TableErrorFilter` and `PredicatesErrorFilter` pattern
@@ -62,7 +76,7 @@ Command.errorFilterDefault = const ErrorHandlerGlobalIfNoLocal();
6276
errorFilter: const ErrorHandlerLocal()
6377
6478
// New
65-
Command.errorFilterDefault = const GlobalErrorFilter();
79+
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
6680
errorFilter: const LocalErrorFilter()
6781
```
6882

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,16 @@ Every Command exposes multiple `ValueListenable` interfaces for different aspect
133133
- `throwIfNoLocalHandler`: Throw if no local listeners
134134

135135
**Built-in ErrorFilter implementations**:
136-
- `ErrorHandlerGlobalIfNoLocal`: Default behavior
137-
- `ErrorHandlerLocal`: Local only
138-
- `ErrorHandlerLocalAndGlobal`: Both handlers
136+
- `GlobalIfNoLocalErrorFilter`: Default behavior
137+
- `LocalErrorFilter`: Local only
138+
- `LocalAndGlobalIfNoLocalErrorFilter`: Both handlers
139139
- `TableErrorFilter`: Map error types to reactions
140140
- `PredicatesErrorFilter`: Chain of predicate functions
141141
- `ErrorFilterExcemption<T>`: Special handling for specific type
142142

143143
**Global configuration**:
144144
```dart
145-
Command.errorFilterDefault = const ErrorHandlerGlobalIfNoLocal();
145+
Command.errorFilterDefault = const GlobalIfNoLocalErrorFilter();
146146
Command.globalExceptionHandler = (error, stackTrace) { /* log */ };
147147
Command.assertionsAlwaysThrow = true; // AssertionErrors bypass filters
148148
Command.reportAllExceptions = false; // Override filters, report everything

0 commit comments

Comments
 (0)