dot_shorthand
Migrate a Dart or Flutter codebase to dot shorthands, in bulk from the command line or one quick fix at a time in the editor.
// before
Column(mainAxisAlignment: MainAxisAlignment.center, children: children);
Text(label, textAlign: TextAlign.center);
Future<void>.delayed(Duration.zero);
final Status status = Status.idle;
// after
Column(mainAxisAlignment: .center, children: children);
Text(label, textAlign: .center);
Future<void>.delayed(.zero);
final Status status = .idle;
Dart 3.10 lets you write .red instead of Color.red wherever the context type already says Color.
The SDK has no migration for it, so existing code keeps the long form.
This package finds every place where the context type makes the shorthand legal and rewrites it.
Command line
dart pub global activate dot_shorthand
dot_shorthand lib test # list every place that can use the shorthand
dot_shorthand --fix lib test # rewrite them, rescan, drop imports and shown names that became unused
Scan first. The scan is the dry run: it changes nothing and exits with code 1 when there is anything to rewrite, so it can also gate CI.
| Flag | Effect |
|---|---|
--fix |
Rewrites every finding in place, rescans the changed files, and drops the imports, or the names in their show lists, the rewrite left unused or unnecessary |
--exclude <glob> |
Skips matching paths, relative to the package root; repeatable |
--format json |
Prints one object: findings (each with path, line, column, source, shorthand, contextType), changedFiles (paths), removedImports (each with path, uri, name; name is null when the whole import went); paths are relative to the working directory |
--version |
Prints the version |
Paths default to the current directory. Each path is analysed inside the nearest package above it (the closest pubspec.yaml), so context types resolve the same way they do in the editor.
Exit codes: 0 when nothing is left to rewrite, 1 when findings remain, 2 when a path does not exist, 64 on a bad flag.
Editor plugin
Add the plugin to the analysis_options.yaml at the root of a package and restart the analysis server:
plugins:
dot_shorthand: ^1.1.0
The rule prefer_dot_shorthand reports each place as a diagnostic, with a quick fix that drops the type name.
dart analyze reports the same diagnostics.
As of Dart 3.13, dart fix --apply does not run plugin fixes; use the command line --fix for bulk rewrites.
A local checkout works too:
plugins:
dot_shorthand:
path: ../dot_shorthand
Cost in a large workspace
Any analyzer plugin, this one included, runs in its own isolate of the analysis server.
That isolate resolves every Dart file of the context root a second time, even for dart analyze <one file>, and keeps the result in memory only (dart-lang/sdk#64381, #64202).
A plugin that registers no rules costs the same; the rule's own work is a small fraction of it.
The server also compiles one plugin snapshot per context root path under ~/.dartServer/.plugin_manager/ and never deletes it (#63244), so every new worktree adds one.
For a large workspace, or one checked out in many worktrees at once, leave the plugin out of analysis_options.yaml and run the command line scan in CI instead.
Suppressing findings
| Comment | Scope |
|---|---|
// ignore: prefer_dot_shorthand on the line or the line above |
One finding |
// ignore: dot_shorthand/prefer_dot_shorthand |
Same, in the plugin-prefixed form the analyzer also accepts |
// ignore_for_file: prefer_dot_shorthand |
The whole file |
// dot_shorthand: ignore on the line |
Every finding on that line, with or without the plugin loaded |
The command line and the plugin honour all four.
What it rewrites
Context kinds the tool understands
| Kind | Example |
|---|---|
| Default parameter values | this.status = Status.initial |
| Named and positional arguments | take(Color.red) |
| Typed variable and field declarations | final Color c = Color.red |
| Plain assignments | c = Color.red |
| Constructor field initializers | : _color = Color.red |
| Returns with a declared return type | Color pick() => Color.red |
Equality (== and !=) against a typed left side |
if (c == Color.red) |
| Switch cases and if-case patterns | case Color.red: |
| Conditional branches in a typed position | flag ? Color.red : Color.green |
| Collection elements with a known element type | final List<Color> all = [Color.red] |
| Type arguments fixed by the receiver | target.add(Color.red) where target: List<Color> |
| Fields of a generic class | slot.value = Color.red where slot: Slot<Color> |
| Members the context type forwards to the written type | padding: EdgeInsets.all(8) and padding: EdgeInsets.zero where the parameter is EdgeInsetsGeometry, because EdgeInsetsGeometry.all redirects to EdgeInsets.all and EdgeInsetsGeometry.zero holds the same object |
What it leaves alone, and why
| Kind | Reason |
|---|---|
| Unnamed constructors | .new(...) reads worse than the type name |
| A written type carrying type arguments | Foo<int>.bar() cannot drop the type name and keep the arguments |
| A static member reached through a supertype | Only rewritten when the supertype has a redirecting constructor of that name, or a static const holding the same object |
| An argument whose type comes from the invocation's own type parameters | Inferred from the argument itself, no context to resolve against |
Enum.values |
The shorthand form does not apply |
??, await, yield, cascade positions |
The language does not read a context type there |
| Generated files | .g.dart, .gen.dart, .freezed.dart, .mocks.dart, and any file with a GENERATED CODE - DO NOT MODIFY BY HAND or FILE GENERATED BY FLUTTERFIRE CLI header in its first ten lines |
| Files below language version 3.10 | Dot shorthands do not exist there |
Requirements
| What | Version |
|---|---|
| Dart SDK to run the tool or the plugin | 3.13.2 or later |
| Language version of the scanned files | 3.10 or later |
The plugin builds on analysis_server_plugin, which is pre-1.0 and tracks the SDK closely. CI runs the tests on the oldest supported SDK and on current stable.
CI
- run: dart pub global activate dot_shorthand
- run: dot_shorthand lib test
The step fails while anything is left to rewrite.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
no such path |
A path argument does not exist | The paths passed on the command line |
| The scan finds nothing in a package that needs it | The package's language version is below 3.10 | The sdk: lower bound in pubspec.yaml |
| The plugin does not load in the editor | Plugin not configured or analysis server needs a restart | analysis_options.yaml sits at the package root; restart the analysis server; read the plugin log under ~/.dartServer/.plugin_manager/ |
| The scan is slow on a large repo | Every file is resolved | Narrow the paths, or --exclude generated and vendored trees |
The compiler reports dot_shorthand_missing_context after a fix |
The tool read a context type the compiler does not | Add // dot_shorthand: ignore to that line, restore the type name, and please open an issue with the snippet |
Contributing
Issues and pull requests: https://github.com/valentingrigorean/dot_shorthand. Run dart test before sending one.
MIT license.
Libraries
- dot_shorthand
- Finds and rewrites member references that a context type already
supplies, so
Color.redbecomes.red. - main
- Entry point loaded by the analysis server.