Files
ISA-Frontend/.claude/skills/standalone-component-migrator/SKILL.md
Lorenz Hilpert bcb412e48d chore: add Claude Code infrastructure and documentation system
Add comprehensive Claude Code tooling:
- Agents: docs-researcher, docs-researcher-advanced for documentation research
- Commands: dev:add-e2e-attrs, docs:library, docs:refresh-reference, quality:bundle-analyze, quality:coverage
- Skills: 8 specialized skills including api-change-analyzer, architecture-enforcer, library-scaffolder, and more

Update documentation:
- Comprehensive CLAUDE.md overhaul with library reference system
- Update testing guidelines in docs/guidelines/testing.md
- Update READMEs for checkout, icons, scanner, and scroll-position libraries

Remove outdated checkout-completion-flow-documentation.md

Update .gitignore for Claude Code files
2025-10-22 15:02:53 +02:00

5.6 KiB

name, description
name description
standalone-component-migrator This skill should be used when converting Angular NgModule-based components to standalone architecture. It handles dependency analysis, template scanning, route refactoring, and test updates. Use this skill when the user requests component migration to standalone, mentions "convert to standalone", or wants to modernize Angular components to the latest patterns.

Standalone Component Migrator

Overview

Automate the conversion of Angular components from NgModule-based architecture to standalone components with explicit imports. This skill analyzes component dependencies, updates routing configurations, migrates tests, and optionally converts to modern Angular control flow syntax (@if, @for, @switch).

When to Use This Skill

Invoke this skill when:

  • User requests component conversion to standalone
  • User mentions "migrate to standalone" or "modernize component"
  • User wants to remove NgModule declarations
  • User references Angular's standalone component architecture

Migration Workflow

Step 1: Analyze Component Dependencies

  1. Read Component File

    • Identify component decorator configuration
    • Note selector, template path, style paths
    • Check if already standalone
  2. Analyze Template

    • Read template file (HTML)
    • Scan for directives: *ngIf, *ngFor, *ngSwitch → requires CommonModule
    • Scan for forms: ngModel, formControl → requires FormsModule or ReactiveFormsModule
    • Scan for built-in pipes: async, date, json → CommonModule
    • Scan for custom components: identify all component selectors
    • Scan for router directives: routerLink, router-outlet → RouterModule
  3. Find Parent NgModule

    • Search for NgModule that declares this component
    • Read NgModule file to understand current imports

Step 2: Convert Component to Standalone

Add standalone: true and explicit imports array:

// BEFORE
import { Component } from '@angular/core';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html'
})
export class MyComponent { }

// AFTER
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { ChildComponent } from './child.component';
import { CustomPipe } from '@isa/utils/pipes';

@Component({
  selector: 'app-my-component',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    RouterModule,
    ChildComponent,
    CustomPipe
  ],
  templateUrl: './my-component.component.html'
})
export class MyComponent { }

Step 3: Update Parent NgModule

Remove component from declarations, add to imports if exported:

// BEFORE
@NgModule({
  declarations: [MyComponent, OtherComponent],
  imports: [CommonModule],
  exports: [MyComponent]
})

// AFTER
@NgModule({
  declarations: [OtherComponent],
  imports: [CommonModule, MyComponent], // Import standalone component
  exports: [MyComponent]
})

If NgModule becomes empty (no declarations), consider removing it entirely.

Step 4: Update Routes (if applicable)

Convert to lazy-loaded standalone component:

// BEFORE
const routes: Routes = [
  { path: 'feature', component: MyComponent }
];

// AFTER (lazy loading)
const routes: Routes = [
  {
    path: 'feature',
    loadComponent: () => import('./my-component.component').then(m => m.MyComponent)
  }
];

Step 5: Update Tests

Convert test configuration:

// BEFORE
TestBed.configureTestingModule({
  declarations: [MyComponent],
  imports: [CommonModule, FormsModule]
});

// AFTER
TestBed.configureTestingModule({
  imports: [MyComponent] // Component imports its own dependencies
});

Step 6: Optional - Migrate to Modern Control Flow

If requested, convert to new Angular control flow syntax:

// OLD
<div *ngIf="condition">Content</div>
<div *ngFor="let item of items; trackBy: trackById">{{ item.name }}</div>
<div [ngSwitch]="value">
  <div *ngSwitchCase="'a'">A</div>
  <div *ngSwitchDefault>Default</div>
</div>

// NEW
@if (condition) {
  <div>Content</div>
}
@for (item of items; track item.id) {
  <div>{{ item.name }}</div>
}
@switch (value) {
  @case ('a') { <div>A</div> }
  @default { <div>Default</div> }
}

Step 7: Validate and Test

  1. Compile Check

    npx tsc --noEmit
    
  2. Run Tests

    npx nx test [library-name] --skip-nx-cache
    
  3. Lint Check

    npx nx lint [library-name]
    
  4. Verify Application Runs

    npm start
    

Common Import Patterns

Template Usage Required Import
*ngIf, *ngFor, *ngSwitch CommonModule
ngModel FormsModule
formControl, formGroup ReactiveFormsModule
routerLink, router-outlet RouterModule
async, date, json pipes CommonModule
Custom components Direct component import
Custom pipes Direct pipe import

Error Handling

Issue: Circular dependencies

  • Extract shared interfaces to util library
  • Use dependency injection for services
  • Avoid component A importing component B when B imports A

Issue: Missing imports causing template errors

  • Check browser console for specific errors
  • Verify all template dependencies are in imports array
  • Use Angular Language Service in IDE for hints

References