angular-signal-migration
v0.1.14
Published
Migrate Angular projects to signal-based components using official Angular schematics plus a conservative custom codemod.
Maintainers
Readme
Angular Signal Migration CLI
This CLI migrates Angular projects toward signal-based components. It first runs the official Angular signal migrations (@angular/core:signal-input-migration and @angular/core:signal-queries-migration) and then applies its own conservative codemod for additional safe signal opportunities.
Status
The tool focuses on safety before rewrite:
- runs official Angular signal-input and signal-queries migrations first
- component and directive discovery
- template symbol tracking, including
ng-templatelocals and Angular 20 control-flow aliases ng-templateand embedded view detection- unsafe mutation detection in class code and templates
- migration suggestions for fields that appear safe to convert to signals
- applies safe codemods by default; use
--dry-runto analyze only
Unsafe cases the analyzer guards against
Class-side mutations:
- direct/compound assignment (
this.count += 1) - increment/decrement (
this.count++) - element-access assignment (
this.items[0] = 1) - mutating method calls (
this.items.push(1)) - alias-based mutation (
const alias = this.value; alias.count += 1) - destructuring alias mutation (
const { count } = this.value; count += 1) - for-of/for-in alias mutation (
for (const item of this.items) { item.count += 1 }) - passing a symbol to a potentially mutating call (
mutate(this.items)) @Inputmutation
Template-side mutations:
- event handler assignments (
(click)="count = count + 1") - event handler mutating method calls (
(click)="items.push(1)") - two-way bindings (
[(ngModel)]="user")
Excluded symbols:
@Output()fields- fields already initialized with
signal(),input(),model(),computed(), ortoSignal()
Computed and input getter/setter support
The analyzer detects pure template getters that can become computed():
get fullName() {
return `${this.firstName} ${this.lastName}`;
}It also detects fields read in templates whose initializer depends on signal-like symbols (@Input(), input(), signal(), computed(), model(), signal queries, etc.) and converts them to computed() instead of signal():
readonly fullName = computed(() => `${this.firstName()} ${this.lastName()}`);For @Input() getter/setter pairs, both accessors are classified as input and are excluded from signal-field migration.
Usage
Interactive scope selection (default behavior applies migrations):
npx angular-signal-migration /path/to/angular-appAnalyze only without writing files:
npx angular-signal-migration /path/to/angular-app --dry-run
# or
npx angular-signal-migration /path/to/angular-app --analyzeMigrate a specific scope. The official Angular schematics receive the same scope, operating on directories for --kind=file and --kind=ng-module because they do not support single-file migration:
npx angular-signal-migration /path/to/angular-app src/app/feature --kind=folder --non-interactive
npx angular-signal-migration /path/to/angular-app src/app/feature.module.ts --kind=ng-module --non-interactive
npx angular-signal-migration /path/to/angular-app src/app/app.component.ts --kind=file --non-interactiveSkip the official Angular signal migrations and run only the custom analyzer:
npx angular-signal-migration /path/to/angular-app --skip-schematicsOptional JSON output:
npx angular-signal-migration /path/to/angular-app --jsonNon-interactive mode (useful in CI or when stdin is not a TTY):
npx angular-signal-migration /path/to/angular-app --non-interactivePublishing
Publishing automatically bumps the patch version before the tarball is created:
npm publishThe prepublishOnly script runs npm version patch --no-git-tag-version to bump package.json, then npm publish ships the new version. No git commit or tag is created automatically.
If you prefer the explicit two-step flow with a git commit and tag, use:
npm run releaseNotes
This is intentionally conservative. If the analyzer cannot confidently prove a case is safe, it will report the risk instead of proposing an automatic rewrite.
