Primary Constructors
/act-dart-migrate-primary-constructors migrates eligible Dart declarations to the new primary constructor syntax.
The skill is an LLM wrapper around ACT’s deterministic Dart migration CLI. The model checks prerequisites, runs the shared migration launcher, formats only the changed Dart files, and verifies the result. The CLI owns discovery, planning, source edits, parser validation, file writes, and the machine-readable report.
This makes the migration much faster and safer than asking an agent to inspect a large package and hand-edit constructor boilerplate. The LLM does the workflow orchestration; the deterministic tool does the code transformation.
Example
Section titled “Example”If your code has constructor boilerplate like this:
class Point { final int x; final int y;
Point(this.x, this.y);}The skill can migrate it to this:
class Point(final int x, final int y);The constructor call shape stays the same:
final point = Point(1, 2);On larger packages, the same tool can migrate dozens or hundreds of declarations in one pass while reporting exactly what changed and what was skipped.
/act-dart-migrate-primary-constructorsRun it from the package root that contains the pubspec.yaml you want to migrate. The skill applies all supported migrations in one pass.
Before You Run It
Section titled “Before You Run It”The skill does not edit the pubspec.yaml and analysis_options.yaml files for you. This is intentional to ensure you have full control over the migration process.
Before migration, make sure:
- your worktree is on a branch or worktree where the diff can be reviewed or reverted
- your Flutter version is
3.44.0or higher, or your Dart version is3.12.0or higher for pure Dart packages
Your pubspec.yaml file should have the following:
environment: sdk: ^3.12.0Your analysis_options.yaml file should have:
analyzer: enable-experiment: - primary-constructorsAfter making these changes, run flutter analyze or dart analyze and fix any analyzer warnings before running the skill.
What It Migrates
Section titled “What It Migrates”The migration focuses on rewrites that remove boilerplate while preserving the public constructor API shape.
It can migrate:
- eligible classes with one safe non-redirecting generative constructor target, including unnamed, named, and
.newconstructors - eligible
constconstructors while preservingconstsemantics - enhanced enums with a single safe constructor target
- constructor field-formal parameters into
finalorvardeclaring parameters - typed field formals, function-typed field formals, simple pass-through parameters, simple
superparameters, named parameters, optional positional parameters, defaults, andrequired - safe initializer-list assertions and field assignments when moving them preserves evaluation order
- supported primary-constructor bodies and retained
super(...)orsuper.named(...)initializers - constructors that remain in declaration bodies to constructor declaration shorthand such as
new(),new named(),factory(), andfactory named() - empty bodies to semicolon form for supported declarations, unless the body contains comments
- valid extension type primary constructors as fixed-point input, with safe body transforms where supported
For fields moved into the primary constructor header, the skill preserves existing mutability: final fields become final declaring parameters, and mutable fields become var declaring parameters.
The CLI also skips generated files, nested packages, nested repositories, hidden directories, and build-output directories before planning migrations. Those skips are reported separately from declaration-level skips.
Why It Is Safer
Section titled “Why It Is Safer”The migration is conservative by design. If the CLI cannot prove that a rewrite preserves behavior, it leaves the declaration unchanged and reports a stable reason code.
Before writing files, the CLI:
- discovers target Dart files deterministically
- ignores generated files and separate package/repository boundaries
- parses input source with the
primary-constructorsexperiment enabled - plans source edits from supported AST shapes only
- validates source edit ranges and rejects overlapping edits
- parses every transformed file in memory before writing anything
If transformed-source validation fails, no changed files are written. Formatting, analysis, tests, package setup, and git operations stay outside the CLI so failures in those steps are visible instead of being hidden inside the migration.
What It Skips
Section titled “What It Skips”The skill skips cases where a safe rewrite is unclear, unsupported, or would risk changing behavior.
Common skip categories include:
- generated files such as
*.g.dart,*.freezed.dart,*.mocks.dart, and files markedGENERATED CODE - DO NOT MODIFY - nested packages, nested repositories, hidden directories, and build-output directories
- declarations with more than one non-redirecting generative constructor
- declarations without a safe primary-constructor target
- non-trivial mixin class primary constructors
externalconstructors, redirecting constructors, and unsupported constructor bodies- constructor, parameter, or field metadata that would need to move
- comments whose attachment would become ambiguous after moving fields into parameters
- fields that are static, late, external, initialized, multi-variable, or otherwise unsupported as declaring parameters
- initializer-list entries that depend on unsupported values or would change evaluation order
- migrations that would change field mutability, nullability, default values, parameter order, or call-site API shape
- empty-body collapse when the class body contains comments
Skipped declarations are expected conservative outcomes. They are reported with reasons instead of being guessed at, so you can decide whether a manual follow-up is worth doing.
Verification and Report
Section titled “Verification and Report”The skill runs pre-migration analysis before invoking the launcher. If the package already has analyzer issues, it stops before editing files.
After the CLI edits files, the skill formats only changed Dart files:
dart format --enable-experiment=primary-constructors <changed-dart-files>Then it verifies the package:
- Flutter projects:
flutter analyze, thenflutter test --enable-experiment=primary-constructors --no-pubwhen tests exist - Pure Dart packages:
dart analyze, thendart test --enable-experiment=primary-constructorswhen tests exist
The CLI returns a deterministic JSON report, and the skill summarizes it in a concise final report:
- changed file count
- migrated declaration count and transform breakdown
- skipped declarations, skipped files, and skipped directories with reasons
- skip reason counts
- formatting, analysis, and test results
- notes about residual risks or follow-up work
If the launcher itself fails, diagnostics are prefixed with [act-dart-migrate] so environment or installation problems are easy to distinguish from migration failures.
If post-migration analysis or tests fail, ACT reports the failure and does not automatically undo the edits.
- Keep SDK and analyzer experiment setup in a separate commit from the migration diff.
- Invoke the skill from the package root you want to migrate.
- Review skipped declarations before manually changing edge cases.
- If the launcher is missing, reinstall ACT so the shared runtime helper and bundled migration snapshot are installed.
- Large packages no longer need the model to inspect every migration candidate manually; the deterministic CLI does that work and the model only orchestrates the workflow.
References
Section titled “References”- Dart primary constructors: official language feature guide
- Dart constructors: constructor kinds, initialization, and concise constructor syntax
- Dart experiment flags: enabling experiments for command-line tools and analysis
- Dart analysis options: configuring
analysis_options.yaml - Dart language versioning: package language-version behavior