flutter_style_expiring_todos 0.2.0
flutter_style_expiring_todos: ^0.2.0 copied to clipboard
An analyzer plugin that enforces Flutter-style TODO comments with optional expiry conditions (// TODO(username)[condition]: message) and reports TODOs whose conditions are met.
flutter_style_expiring_todos #
An analyzer plugin that enforces Flutter-style TODO comments with optional
expiry conditions — // TODO(username)[condition]: message — and reports TODOs
when their conditions are met.
Overview #
TODO comments can outlive their relevance. Add a date or version condition to a TODO, and this plugin reports it in your IDE and CI as soon as that condition is met.
The plugin extends the official
flutter_style_todos
lint. Existing conditionless Flutter-style TODOs continue to work, while the
extended form adds expiry conditions for dates, the project version,
dependencies, and the Dart and Flutter SDKs.
Diagnostics #
All diagnostics are enabled by default and can be configured individually.
| Rule | Reports |
|---|---|
flutter_style_expiring_todos |
TODO comments that do not follow the expected format |
expired_todo |
Well-formed TODOs whose date or version condition has been met |
unresolved_todo_condition |
TODOs whose condition cannot be resolved |
flutter_style_expiring_todos and unresolved_todo_condition report defects
in the comment itself. expired_todo reacts to time and package state, so it
can be disabled when those changes should not fail CI.
Install #
The plugin requires Dart 3.11+ / Flutter 3.38+.
Add it under the top-level plugins: section of analysis_options.yaml, then
disable the official flutter_style_todos lint. The official lint rejects the
conditional syntax, whereas this plugin accepts both forms.
Minimal configuration #
plugins:
flutter_style_expiring_todos: 0.1.0
linter:
rules:
flutter_style_todos: false
Optional: configure individual diagnostics #
Use this complete alternative configuration when you need to control
diagnostics individually. Do not add it alongside the minimal
flutter_style_expiring_todos: 0.1.0 declaration above.
plugins:
flutter_style_expiring_todos:
version: 0.1.0
diagnostics:
flutter_style_expiring_todos: true
expired_todo: true
unresolved_todo_condition: true
linter:
rules:
flutter_style_todos: false
Set a diagnostic to false to disable it. Restart the analysis server after
adding or changing plugin configuration (for example, Dart: Restart Analysis
Server in VS Code).
TODO syntax #
Two forms are accepted:
// TODO(username): message <- Flutter style; never expires
// TODO(username)[condition, ...]: message <- one or more expiry conditions
- A username must match
[a-zA-Z0-9][-a-zA-Z0-9.]*. - In the conditional form,
)and[must be adjacent. Conditions are separated by,, optionally followed by one space; no whitespace is allowed inside a condition. - Either form may end with an issue URL:
, https://....
// Valid:
// TODO(alice): migrate to the new API
// TODO(alice)[2026/12/31]: remove this fallback
// TODO(alice)[>=2.0.0]: drop this shim once we ship 2.0
// TODO(alice)[provider@>=7.0.0]: use the new provider API
// TODO(alice)[2026/12/31, provider@>=7.0.0]: whichever comes first
// TODO(alice)[2026/12/31]: track issue, https://github.com/org/repo/issues/42
// Invalid (flutter_style_expiring_todos):
// TODO: no username
// Todo(alice): lowercase keyword
// TODO(alice) missing colon
// TODO(alice) [2026/12/31]: space before bracket
// TODO(alice)[< 1.0.0]: unsupported operator
// TODO(alice)[2026/2/3]: date not zero-padded
// TODO(alice)[2026/02/30]: date does not exist
// TODO(alice)[2026/12/31, 2027/01/01]: two dates are not allowed
Conditions #
Conditions are written inside [...]. Only > and >= comparison operators
are accepted. Versions use semver: 1 and 5.3 mean 1.0.0 and 5.3.0, and
pre-releases sort below their corresponding release.
| Condition | Syntax | Resolves against | Reports when |
|---|---|---|---|
| Date | [YYYY/MM/DD] |
Local time, at day granularity | The day after the date |
| Project version | [>=1.0.0], [>2] |
Top-level version: in pubspec.yaml |
The project reaches the version |
| Dependency version | [name@>=version] |
Resolved version in pubspec.lock |
The dependency reaches the version |
| Dart SDK | [sdk@>=version] |
Lower bound of environment.sdk |
The lower bound reaches the version |
| Flutter SDK | [flutter@>=version] |
Lower bound of environment.flutter |
The lower bound reaches the version |
Multiple conditions can be separated by ,. Each is evaluated independently
and can produce its own diagnostic. A date and a project-version condition may
each appear at most once; conditions for different dependencies may be
repeated.
Evaluation details #
- A date is valid on its due date and expires on the following local day.
- Version conditions use strict (
>) or inclusive (>=) semver precedence. - SDK and Flutter environment constraints are ranges. Their lower bounds are
used:
^3.11.0resolves to3.11.0and>=3.10.0 <4.0.0resolves to3.10.0. - An unbounded-below environment constraint such as
anyhas no lower bound.
Unresolved conditions #
unresolved_todo_condition reports the following cases:
- A dependency is absent from
pubspec.lock. - A project-version condition has no top-level
version:. - An SDK or Flutter condition has no matching environment entry or no lower bound.
Files outside a pub package (with no ancestor pubspec.yaml) silently skip
version conditions.
Compatibility and scope #
flutter_style_expiring_todos is compatible with the official
flutter_style_todos rule, except that it additionally accepts
// TODO(username)[condition, ...]: message. Disable the official lint to
avoid it reporting that extended form.
The design is based on
eslint-plugin-unicorn/expiring-todo-comments,
using pub equivalents: resolved dependency versions from pubspec.lock and
SDK lower bounds from pubspec.yaml. Its [+package] and [-package]
conditions are not currently implemented.
CI #
Plugin diagnostics use INFO severity, matching flutter_style_todos. Make
them fail CI with:
dart analyze --fatal-infos
If date or version expiry should not fail CI, replace the plugin declaration
with a configuration that disables expired_todo:
plugins:
flutter_style_expiring_todos:
version: 0.1.0
diagnostics:
expired_todo: false
flutter_style_expiring_todos and unresolved_todo_condition remain enabled.
This setting affects both CI and the IDE. In a pub workspace, configure each
package from its own analysis_options.yaml as needed.
Command-line usage #
The package also includes a CLI that recursively scans Dart files and prints
expired TODOs in a compact, CI-friendly format inspired by
reminder-lint:
dart run :flutter_style_expiring_todos_cli check-expired-todos
./lib/main.dart:12 // TODO(alice)[2026/07/20]: remove fallback
The command exits with status 1 when at least one expired TODO is found and
0 otherwise. Pass one or more files or directories to limit the scan:
dart run :flutter_style_expiring_todos_cli check-expired-todos \
lib test/example.dart
Only .dart files are scanned. .dart_tool, .git, .idea, .vscode, and
build directories are skipped. --date YYYY/MM/DD overrides the evaluation
date, which is useful for deterministic checks.
dart run :flutter_style_expiring_todos_cli check-expired-todos \
--date 2026/07/23 lib
Run the CLI without a command to list available commands, or show detailed help for the scanner command:
dart run :flutter_style_expiring_todos_cli
dart run :flutter_style_expiring_todos_cli help check-expired-todos
When invoking the executable from another package, use the fully qualified
target
flutter_style_expiring_todos:flutter_style_expiring_todos_cli instead of the
leading-colon shorthand.
Suppress a diagnostic #
Diagnostic codes are namespaced by the plugin name:
// ignore: flutter_style_expiring_todos/expired_todo
// TODO(alice)[2020/01/01]: grandfathered in, tracked elsewhere
// ignore_for_file: flutter_style_expiring_todos/expired_todo works too.
Limitations #
- Only a TODO at the start of a comment is recognized.
- Block comments are exempt from format validation, matching
flutter_style_todos. A valid dated TODO at the start of a block comment is still expiry-checked. - TODOs on inner lines of multi-line block comments are not detected.
- Only the first TODO in a comment is detected.
Contributing #
See CONTRIBUTING.md for development, verification, and compatibility-suite maintenance.
License #
MIT — see LICENSE.
test/compatibility/flutter_style_todos_official_test.dart is ported from the
Dart SDK and retains its BSD-3-Clause copyright header.