소스 정보
- 저장소
- SAP/fundamental-ngx
- 최근 소스 활동
- 2026년 7월 16일 15:51
- 감지된 SKILL.md 언어
- 영어
- 스타
- 295
- 포크
- 148
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SKILL.md 표시 중
SKILL.md
소스 지침 · 읽기 전용 미리보기- name
- migrate
- description
- Migrate a component or directive to Angular 22+ signal-based patterns
- argument-hint
- ["component-path-or-folder"]
# Angular 22+ Migration: $ARGUMENTS
If `$ARGUMENTS` is empty, ask the user for a component path or folder before proceeding.
## Phase 1: Analyze
Read all files in the target path. For each component, directive, or service, scan for migration items below. If a folder is given, process all `.ts` and `.html` files within it.
### What to migrate
**Inputs / Outputs / Models:**
- `@Input()` → `input()` or `input.required()`
- `@Input()` with setter → `input()` + `linkedSignal()` (preferred) or `effect()` (only for DOM side effects)
- `@Input()` + `@Output()` pair (e.g. `value` / `valueChange`) → `model()`
- `@Output()` → `output()`
- Boolean inputs: add `{ transform: booleanAttribute }`
- Number inputs: add `{ transform: numberAttribute }`
**Host bindings:**
- `@HostBinding('class.x')` → `host: { '[class.x]': 'expr()' }`
- `@HostBinding('attr.x')` → `host: { '[attr.x]': 'expr()' }`
- `@HostBinding('style.x')` → `host: { '[style.x]': 'expr()' }`
- `@HostListener('event')` → `host: { '(event)': 'handler($event)' }`
**Queries:**
- `@ViewChild()` → `viewChild()` or `viewChild.required()`
- `@ViewChildren()` → `viewChildren()`
- `@ContentChild()` → `contentChild()`
- `@ContentChildren()` → `contentChildren()`
**Template syntax:**
- `*ngIf` → `@if`
- `*ngFor` → `@for` (requires `track` expression)
- `*ngSwitch` / `*ngSwitchCase` → `@switch` / `@case`
**State management:**
- `BehaviorSubject` used for local component state → `signal()`
- `BehaviorSubject` + `combineLatest` → `computed()`
- `Subject<void>` used only to trigger side effects → `effect()`
- `effect()` that only calls `signal.set()` for derived state → `computed()` or `linkedSignal`
- Redundant `markForCheck()` after signal updates → remove
- Object/array mutation in place + `signal.set()` with same ref → immutable update with `signal.update()`
**CSS class building:**
- `CssClassBuilder` + `@applyCssClass` → `computed()` returning class string + `host: { '[class]': '_cssClass()' }`
**Cleanup patterns:**
- Custom `DestroyedService` → `DestroyRef` + `takeUntilDestroyed()`
- `ngOnDestroy` only for `destroy$.next()` → remove entirely after migration
**Decorator cleanup:**
- Remove `standalone: true` (default since Angular 19)
- Remove `allowSignalWrites` option in `effect()` (the option no longer exists)
**Imports:**
- Deprecated `*Module` classes → individual component/directive imports
**Member ordering** (ESLint enforced):
1. Decorated properties (any remaining `@Input`, `@Output`, `@ViewChild`)
2. Signal inputs/outputs (`input()`, `output()`, `model()`)
3. Public → Protected → Private fields
4. Constructor
5. Public → Protected → Private methods
### What NOT to migrate
Do NOT convert these — they should stay as-is:
- **RxJS for async operations**: HTTP calls, WebSocket streams, timers, interval-based logic → keep as Observable
- **BehaviorSubject with complex operators**: `switchMap`, `debounceTime`, `distinctUntilChanged`, `combineLatest` with async sources → keep as RxJS
- **Plain properties with no reactive consumer**: If nothing in template, host binding, computed, or effect reads it → keep as plain property, do not wrap in `signal()`
- **Signals for internal bookkeeping**: One-time flags, cached DOM measurements, counters with no reactive consumer → use plain property
### Migration is optional for existing code
The migration targets are recommendations, not mandatory fixes. Present all findings but let the user decide scope. Existing `@Input()` / `@Output()` decorators are valid — only migrate them if the user wants to or if the code is being substantially reworked.
## Phase 2: Present Plan
Output a structured migration plan:
```
## Migration Plan: [component name]
### Files affected
- path/to/component.ts
- path/to/component.html
- path/to/component.spec.ts
### Inputs / Outputs
| Current | Migration | Notes |
|---------|-----------|-------|
| `@Input() label: string` | `readonly label = input<string>('')` | |
| `@Input() disabled: boolean` | `readonly disabled = input(false, { transform: booleanAttribute })` | |
| `@Input() value` + `@Output() valueChange` | `readonly value = model<T>()` | Two-way binding |
### Host Bindings
| Current | Migration |
|---------|-----------|
| `@HostBinding('class.is-open')` | `host: { '[class.is-open]': 'isOpen()' }` |
### Template Changes
| Current | Migration |
|---------|-----------|
| `*ngIf="condition"` | `@if (condition) { ... }` |
| `*ngFor="let item of items"` | `@for (item of items; track item.id) { ... }` |
### State Management
| Current | Migration | Reason |
|---------|-----------|--------|
| `BehaviorSubject<boolean>` | `signal(false)` | Local state, no async consumers |
### Skipped (intentionally not migrated)
| Item | Reason |
|------|--------|
| `httpData$` Observable | Async HTTP stream |
### Test Updates
- [ ] Replace `component.input = value` with `fixture.componentRef.setInput('input', value)`
- [ ] Update module imports to individual components
- [ ] Verify existing tests still pass after migration
### Docs Updates
- [ ] Update examples if public API changed (input names, usage patterns)
- [ ] Ensure examples use individual imports, not deprecated modules
### Breaking Changes
- [ ] List any renamed/removed inputs or outputs
- [ ] Draft BREAKING CHANGE footer if needed
```
**Stop here and wait for approval before proceeding.**
## Phase 3: Execute
After approval:
1. Apply all migrations from the approved plan
2. Format code: `yarn format`
3. Run build: `nx run <library>:build`
4. Run lint: `nx run <library>:lint`
5. Run tests: `nx run <library>:test --testfile=<spec-file> --skip-nx-cache`
6. Report results and any issues
GitHub에서 보기