| name | migration-assistant |
| description | Legacy Pattern Migrator - Migrates Angular/TypeScript code from legacy patterns to modern ones.
Handles NgModules to standalone, *ngIf to @if, decorators to functions, BehaviorSubject to signals, PrimeNG directives to components.
TRIGGERS: migrate, migration, modernize, upgrade pattern, legacy to modern, convert ngIf, convert to signals, migrate standalone, modernizar
|
@migration-assistant - Legacy Pattern Migrator
Migrates code from legacy Angular/TypeScript patterns to modern equivalents defined in the architecture knowledge base.
Required Reading
.agent/System/architecture-knowledge/12-FRONTEND-PATTERNS.md
.agent/System/architecture-knowledge/08-REACTIVE-PROGRAMMING.md
.agent/System/architecture-knowledge/07-STATE-MANAGEMENT.md
.agent/System/angular_best_practices.md
.agent/System/primeng_best_practices.md
Invocation Pattern
@migration-assistant
migration: [migration-type]
scope: [files | project | scope | affected]
mode: report | fix
Available Migrations
1. standalone - NgModules to Standalone Components
Detect:
@NgModule({ declarations: [MyComponent], imports: [...], exports: [...] })
export class MyModule {}
Migrate to:
@Component({
standalone: true,
imports: [CommonModule, ...requiredModules],
})
export class MyComponent {}
Steps:
- Find all
@NgModule declarations
- Identify components declared in each module
- Add
standalone: true to each component
- Move module imports to component imports
- Remove the module file
- Update all references (routes, other imports)
2. control-flow - *ngIf/*ngFor to @if/@for
Detect:
<div *ngIf="condition">...</div>
<div *ngIf="condition; else elseBlock">...</div>
<div *ngFor="let item of items; trackBy: trackByFn">...</div>
<div [ngSwitch]="value">
<span *ngSwitchCase="'a'">A</span>
</div>
Migrate to:
@if (condition) { <div>...</div> }
@if (condition) { <div>...</div> } @else { ... }
@for (item of items; track item.id) { <div>...</div> }
@switch (value) {
@case ('a') { <span>A</span> }
}
Steps:
- Parse template for *ngIf, *ngFor, [ngSwitch] usage
- Convert each to @if/@for/@switch syntax
- Remove ng-template#elseBlock references
- Convert trackBy functions to track expressions
- Remove CommonModule import if no other directives used
3. signals - BehaviorSubject to Signals
Detect:
private subject$ = new BehaviorSubject<string>('');
value$ = this.subject$.asObservable();
Migrate to:
value = signal<string>('');
Steps:
- Find BehaviorSubject declarations in components/facades
- Convert to signal() with same initial value
- Replace .next() with .set() or .update()
- Replace .pipe(map(...)) with computed()
- Replace async pipe in templates with signal calls
- Remove RxJS imports if no longer needed
4. inputs-outputs - Decorators to Functions
Detect:
@Input() name: string = '';
@Input() set data(value: Data) { this._data = value; }
@Output() clicked = new EventEmitter<void>();
Migrate to:
name = input<string>('');
data = input<Data>();
clicked = output<void>();
Steps:
- Find @Input() and @Output() decorators
- Convert to input() and output() functions
- Handle required inputs:
input.required<Type>()
- Handle setter inputs: use
effect() for side effects
- Replace EventEmitter with output()
- Update template references if needed
5. inject - Constructor Injection to inject()
Detect:
constructor(
private readonly userService: UserService,
private readonly router: Router,
@Inject(TOKEN) private readonly config: Config
) {}
Migrate to:
private readonly userService = inject(UserService);
private readonly router = inject(Router);
private readonly config = inject(TOKEN);
Steps:
- Find constructor parameters with injection
- Convert each to class field with inject()
- Handle @Inject() tokens
- Handle @Optional() with second arg
- Remove constructor if empty after migration
6. primeng - Directives to Components
Detect:
<button pButton label="Save"></button>
<input pInputText />
<p-dropdown [options]="opts"></p-dropdown>
<p-calendar [(ngModel)]="date"></p-calendar>
<ng-template pTemplate="body">...</ng-template>
Migrate to:
<p-button label="Save"></p-button>
<p-inputtext />
<p-select [options]="opts"></p-select>
<p-date-picker [(ngModel)]="date"></p-date-picker>
<ng-template #body>...</ng-template>
Steps:
- Find PrimeNG directive usage in templates
- Convert to component equivalents
- Update imports (ButtonModule stays, but usage changes)
- Handle pTemplate to #template conversion
- Verify PrimeNG version compatibility
7. barrel-to-direct - Barrel Imports to Direct
Detect:
import { UserDto, CreateUserDto } from '@project/user/domain';
Migrate to:
import { UserDto } from '@project/user/domain/dtos/user.dto';
import { CreateUserDto } from '@project/user/domain/dtos/create-user.dto';
Steps:
- Find barrel imports (imports from index.ts paths)
- Trace each symbol to its source file
- Replace with direct import path
- Verify tsconfig.base.json has wildcard paths configured
Output Format
Report Mode
## Migration Report: [migration-type]
**Scope**: [scope]
**Files Affected**: [count]
**Estimated Changes**: [count]
### Files Requiring Migration
| File | Pattern Found | Occurrences |
|------|--------------|-------------|
| path/file.ts | *ngIf | 3 |
| path/file.ts | *ngFor | 2 |
### Migration Plan
1. [file] - [changes needed]
2. ...
### Risks
- [potential breaking changes]
Fix Mode
## Migration Complete: [migration-type]
**Files Modified**: [count]
**Changes Made**: [count]
### Changes
| File | Before | After |
|------|--------|-------|
| path/file.ts | *ngIf="x" | @if (x) |
### Verification
- [ ] `nx affected:lint` passes
- [ ] `nx affected:test` passes
- [ ] `nx affected:build` passes