Claude-skill-registry-data migration-lint
Comprehensive Angular migration compliance checker with auto-fix capabilities. Use when reviewing migrated code for DDD architecture, Angular 20 syntax, and UI pattern compliance.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry-data
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/migration-lint" ~/.claude/skills/majiayu000-claude-skill-registry-data-migration-lint && rm -rf "$T"
manifest:
data/migration-lint/SKILL.mdsource content
Migration Lint Command
Review and fix migrated Angular code for compliance. This command reads ALL migration guidelines and performs a comprehensive checklist review.
Arguments
- Target path to review (e.g.,$ARGUMENTS
)libs/mxsecurity/connection-management-page
Workflow
Step 1: Load ALL Migration Guidelines
IMPORTANT: Read the core SKILL.md first, then reference documents as needed from ``.
Core:
one-ui-migration skill
| # | Topic | File | Category |
|---|---|---|---|
| 1 | Migration Context | rules/reference/migration-context.md | Foundation |
| 2 | Angular 20 Syntax | rules/reference/angular-20-syntax.md | Foundation |
| 3 | DDD Architecture | rules/reference/ddd-architecture.md | Architecture |
| 4 | State Management | rules/reference/state-management.md | Architecture |
| 5 | Authentication | rules/tools/auth.md | Architecture |
| 6 | Migration Checklist | rules/reference/migration-checklist.md | Foundation |
| 7 | Pitfalls Index | rules/reference/pitfalls/index.md | Pitfalls |
| 7a | Pitfalls: Translation & Layout | rules/reference/pitfalls/translation-layout.md | Pitfalls |
| 7b | Pitfalls: DDD Violations | rules/reference/pitfalls/ddd-violations.md | Pitfalls |
| 7c | Pitfalls: Angular Syntax | rules/reference/pitfalls/angular-syntax.md | Pitfalls |
| 7d | Pitfalls: Forms & Services | rules/reference/pitfalls/forms-services.md | Pitfalls |
| 8 | Validators | rules/tools/forms/validators.md | Forms |
| 9 | Error Handling | rules/tools/forms/error-handling.md | Forms |
| 10 | Form Patterns | rules/tools/forms/patterns.md | Forms |
| 11 | Page Layout | rules/tools/ui/page-layout.md | UI Patterns |
| 12a | Forms | rules/tools/ui/forms.md | UI Patterns |
| 12b | Buttons | rules/tools/ui/buttons.md | UI Patterns |
| 12c | Components | rules/tools/ui/components.md | UI Patterns |
| 13 | Dialogs | rules/tools/ui/dialogs.md | UI Patterns |
| 14 | Table Basics | rules/tools/tables/basics.md | Tables |
| 15 | Table Columns | rules/tools/tables/columns.md | Tables |
| 16 | Table Advanced | rules/tools/tables/advanced.md | Tables |
| 17 | API Type Definitions | rules/reference/api-types.md | API |
| 18 | Shared Stores | rules/reference/shared-stores.md | State |
Step 2: Read Target Files
Read all
.ts, .html, and .scss files in the target path:
{target}/domain/src/lib/**/*.ts{target}/features/src/lib/**/*.ts{target}/features/src/lib/**/*.html{target}/features/src/lib/**/*.scss{target}/ui/src/lib/**/*.ts{target}/ui/src/lib/**/*.html{target}/ui/src/lib/**/*.scss{target}/shell/src/lib/**/*.ts
Step 3: Comprehensive Checklist Review
Check EVERY item from EVERY migration file:
Checklist by Category
Category 1: Foundation & Pitfalls
migration-context.md
- Project follows one-ui monorepo structure
- Uses correct scope tags (
)scope:mxsecurity - Library types match DDD pattern (
,domain
,features
,ui
)shell
angular-syntax.md
- Uses
instead of@if*ngIf - Uses
instead of@for (item of items; track item.id)*ngFor - Uses
instead of@switchngSwitch - Uses
instead of constructor injectioninject() - Uses
instead ofinput()@Input() - Uses
instead ofoutput()@Output() - Uses
/viewChild()
instead ofviewChildren()
/@ViewChild()@ViewChildren() - Uses
/contentChild()
instead ofcontentChildren()
/@ContentChild()@ContentChildren() - Uses
for two-way binding where appropriatemodel() - Components are standalone (default in Angular 20)
- Uses
ChangeDetectionStrategy.OnPush
migration-checklist.md
- Domain layer contains only business logic, models, services, state
- Features layer contains smart components with store injection
- UI layer contains presentational components with input/output ONLY (NO store injection)
- Shell layer contains routing configuration
- Barrel exports (
) are properly configuredindex.ts
pitfalls/translation-layout.md
- Translation keys match source exactly (no new keys created)
- Form layout matches source (row groupings preserved)
- No padding in page component styles
- Page uses
class (not ng-container)gl-page-content - Table toolbar button order: Refresh → Create/Delete (only if old code has refresh)
pitfalls/ddd-violations.md
- No form templates in features layer (extract to UI)
- No store injection in UI components
- Dialogs are in features layer (not UI)
- No business logic in features (move to domain)
- No HTTP calls in UI components
pitfalls/angular-syntax.md
- No mixing old/new control flow (
with*ngIf
)@for - All
loops have@fortrack - No NgModule patterns (use standalone)
-
called at field level (not in computed)langChanged() - Uses
instead of constructor injectioninject()
pitfalls/forms-services.md
-
/mutationMethod
imported fromqueryMethod
(NOT@one-ui/mxsecurity/shared/domain
)shared/util - No unnecessary
files for constants.def.ts - Uses
(notMxSnackbarService
)MatSnackBar - Uses
(notcontrols.xxx
).get('xxx') - Form valueChanges uses
in effectstoSignal() - Uses
constant (notEMPTY_DASH
)utils.emptyDash - Uses
(notoneUiNumberOnly
)appNumberOnly - Uses
for password fieldsmx-password-input - Uses
for readonly displaysmx-key-value - No
provider (use global translation keys)TRANSLOCO_SCOPE - No endpoint constants (
) - inline URLs directly in API methods#ENDPOINTS = {}
Category 2: Architecture
ddd-architecture.md
- Domain layer has correct structure
- Features layer has correct structure
- UI layer has correct structure
- Shell layer has correct structure
- Dependencies flow correctly (UI → Domain, Features → UI/Domain)
- No UI components importing from features
- Shared domain utilities used where appropriate
state-management.md
- Uses NgRx SignalStore for state management
- Store follows correct naming convention (
)XxxStore - Uses
for entity managementwithEntities() - Uses
for loading stateswithRequestStatus() - Uses
for API integrationwithDataService() - Effects handle success/error properly
- Uses
correctlypatchState() - Store is provided in correct scope
authentication.md
- Uses
for authentication stateAuthStore - Permission checks use correct patterns
- Protected routes have guards
- API calls include proper authentication headers
Category 3: Forms (forms/)
validators.md
- Uses
(notOneValidators.required
)Validators.required - Uses
(notOneValidators.email
)Validators.email - Uses
(notOneValidators.minLength(n)
)Validators.minLength - Uses
(notOneValidators.maxLength(n)
)Validators.maxLength - Uses
(notOneValidators.min(n)
)Validators.min - Uses
(notOneValidators.max(n)
)Validators.max - Uses
(notOneValidators.pattern(x)
)Validators.pattern - Custom validators follow correct patterns
- Cross-field validators implemented correctly
- Import from
@one-ui/mxsecurity/shared/domain
error-handling.md
- Form errors displayed using
<mat-error> - Error messages use translation keys
- Async validators handle errors
- API errors displayed to user
- Uses
for notificationsMxSnackbarService
patterns.md
- Uses
(notNonNullableFormBuilder
)FormBuilder - Form controls accessed via
(notcontrols.xxx
).get('xxx') -
used for form submissiongetRawValue() - Dynamic forms use
correctlyFormArray - Form reset/patch follows patterns
- Forms in UI layer use
/input()
for data flowoutput()
Category 4: UI Patterns (ui/)
ui/page-layout.md
- Root wrapper has
class="gl-page-content" - Uses
at top<one-ui-breadcrumb /> - Uses
for page title<mx-page-title [title]="t('...')"> - Content wrapped in
(NOTclass="content-wrapper"
)mat-card - Uses
pattern*transloco="let t" - Section titles use
class="gl-title-md"
buttons.md
- Submit button uses
mat-flat-button color="primary" - Cancel button uses
mat-button - Toolbar buttons use
mat-stroked-button - NO
(usemat-raised-button
)mat-flat-button - Loading state uses
directive[mxButtonIsLoading] - Disabled state properly handles
noPermission()
forms.md
- Single form field NOT wrapped in
<div class="form-row"> - Multiple fields on same row use
<div class="form-row">
dialogs.md
- Uses shared dialog config (
,smallDialogConfig
,mediumDialogConfig
)largeDialogConfig - Has
when dialog uses storeviewContainerRef: this.#viewContainerRef -
result checked as boolean (NOTConfirmDialogComponent
)result?.confirm - Dialog data typed properly
- Dialog returns correct type
-
subscription cleaned up properlyafterClosed()
Category 5: Tables (tables/)
basics.md
- Uses
component<mx-table> - Column definitions use
MxColumnDef[] - Has
attributesdata-testid - Loading state shows skeleton
- Empty state handled properly
columns.md
- Column types match data
- Custom templates import
andMatTableModuleMatSortModule - Link columns use proper navigation
- Status columns use proper styling
- Action columns positioned correctly
advanced.md
- Selection implemented correctly (if applicable)
- Sorting configured properly
- Pagination implemented (if applicable)
- Filtering works correctly (if applicable)
- Toolbar buttons use
mat-stroked-button
Category 6: API & Services
api-types.md
- API types defined in domain layer
- Request/Response types properly typed
- Uses proper HTTP methods
- Error responses typed
- Enums defined for constants
- NO endpoint constants (
) - inline URL strings directly in methods#ENDPOINTS = {...}
shared-stores.md
- Uses shared stores where appropriate (e.g.,
)TimeZoneStore - Shared store initialization handled
- Cross-feature state accessed via shared stores
- No duplicate state management
Category 7: Additional Checks
Translation (Transloco)
- Uses
or*transloco="let t"@let t = translocoT - NO
pipetranslate - Translation keys follow naming convention
- Parameters passed correctly to
t()
Directives
-
(notoneUiNumberOnly
)appNumberOnly - Custom directives use
prefixone-ui
Services
-
(notMxSnackbarService
)MatSnackBar - Snackbar:
(notsnackBar.open(msg)
)snackBar.open(msg, '', { duration: 3000 })
Constants
-
fromEMPTY_DASH
(not@one-ui/mxsecurity/shared/domain
)utils.emptyDash
Imports
- No circular imports
- Imports from correct library paths
- No relative imports crossing library boundaries
Password Fields
- Uses
for password fields<mx-password-input>
Readonly Display
- Uses
for readonly key-value displays<mx-key-value>
Step 4: Fix Issues
Auto-fix the following issues:
| Issue | Fix |
|---|---|
| → |
| → |
| → |
| → |
| → |
| → |
| → |
| → |
| → |
| → |
| → |
| → Remove constant, inline URLs directly in each method |
(for mutationMethod/queryMethod) | → |
Step 5: Generate Report
Output a compliance report:
## Migration Lint Report **Path:** {target_path} **Date:** {current_date} ### Checklist Summary | Category | Files Checked | Pass | Fail | N/A | |----------|---------------|------|------|-----| | Foundation (01, 02, 06) | 3 | Pass | Fail | - | | Architecture (03, 04, 05) | 3 | Pass | Fail | - | | Pitfalls (08, 08a, 08b, 08c, 08d) | 5 | Pass | Fail | - | | Forms (09a, 09b, 09c) | 3 | Pass | Fail | - | | UI Patterns (10a, 10b, 10c) | 3 | Pass | Fail | - | | Tables (11a, 11b, 11c) | 3 | Pass | Fail | - | | API & Services (12, 13) | 2 | Pass | Fail | - | | **Total** | **22** | **X** | **Y** | **Z** | ### Issues Fixed | File | Line | Issue | Fix Applied | |------|------|-------|-------------| | component.html | 15 | mat-raised-button | Changed to mat-flat-button | ### Issues Found (Manual Review Needed) | File | Line | Issue | Recommendation | Guide Ref | |------|------|-------|----------------|-----------| | component.ts | 42 | Missing viewContainerRef | Add viewContainerRef to dialog config | dialogs.md | | store.ts | 20 | Store in UI layer | Move to features layer | ddd-architecture.md | ### Detailed Checklist Results #### migration-context.md (Pass) - [x] Project follows one-ui monorepo structure - [x] Uses correct scope tags #### angular-syntax.md (Warning) - [x] Uses @if instead of *ngIf - [ ] Uses inject() instead of constructor injection (line 45) ... (continue for all files) ### Summary - **Migration Files Checked:** 22/22 - **Auto-fixed:** X issues - **Manual review needed:** Y issues - **Passed checks:** Z items - **Failed checks:** W items
Quick Reference
Button Types
<!-- Form submit button --> <button mat-flat-button color="primary" type="submit">Apply</button> <!-- Table toolbar button --> <button mat-stroked-button>Create</button> <!-- Cancel/secondary button --> <button mat-button type="button">Cancel</button>
Page Layout
<div *transloco="let t" class="gl-page-content"> <one-ui-breadcrumb /> <mx-page-title [title]="t('page.title')" /> <div class="content-wrapper"> <!-- content here, NO mat-card --> </div> </div>
Form Row
<!-- Single field - NO form-row wrapper --> <mat-form-field> <mat-label>{{ t('label') }}</mat-label> <input matInput formControlName="field" /> </mat-form-field> <!-- Multiple fields on same row - USE form-row wrapper --> <div class="form-row"> <mat-form-field>...</mat-form-field> <mat-form-field>...</mat-form-field> </div>
Dialog Config
import { mediumDialogConfig } from '@one-ui/mxsecurity/shared/domain'; this.#dialog.open(MyDialog, { ...mediumDialogConfig, data: dialogData, viewContainerRef: this.#viewContainerRef // Required if dialog uses store });
Validators
import { OneValidators } from '@one-ui/mxsecurity/shared/domain'; this.#fb.group({ name: ['', [OneValidators.required, OneValidators.maxLength(32)]], email: ['', [OneValidators.required, OneValidators.email]], port: ['', [OneValidators.required, OneValidators.min(1), OneValidators.max(65535)]] });
ConfirmDialogComponent
// ConfirmDialogComponent returns boolean, NOT { confirm: boolean } const dialogRef = this.#dialog.open<ConfirmDialogComponent, ConfirmDialogData, boolean>( ConfirmDialogComponent, { ...mediumDialogConfig, viewContainerRef: this.#viewContainerRef, data: { title: '...', desc: '...' } } ); dialogRef.afterClosed().subscribe((result) => { if (result) { // result is boolean this.doSomething(); } });
Snackbar Service
// Use MxSnackbarService instead of MatSnackBar import { MxSnackbarService } from '@moxa/formoxa/mx-snackbar'; readonly #snackBar = inject(MxSnackbarService); // Simple usage this.#snackBar.open('Success message'); // Persistent message (no auto-dismiss) this.#snackBar.open('Saving...', { duration: 0 });
Section Title
<!-- Use gl-title-md class (global style) --> <h3 class="gl-title-md">{{ t('section.title') }}</h3> <!-- NOT section-title (requires custom SCSS) --> <h3 class="section-title">{{ t('section.title') }}</h3>
Form Controls Access
// .get() - no type safety const value = this.form.get('username')?.value; // controls.xxx - type safe const value = this.form.controls.username.value; // In ValidatorFn - use type assertion #myValidator(): ValidatorFn { return (formGroup: AbstractControl): null => { const controls = (formGroup as typeof this.form).controls; const fieldValue = controls.fieldName.value; return null; }; }
Password Input
<!-- Use mx-password-input for password fields --> <mx-password-input formControlName="password" [maxlength]="32" ></mx-password-input>
Key-Value Display
<!-- Use mx-key-value for readonly displays --> <mx-key-value [key]="t('label')" [value]="displayValue"></mx-key-value>
UI Component Pattern
// UI components use input()/output() ONLY - NO store injection export class MyUiComponent { readonly data = input<MyData>(); readonly isLoading = input<boolean>(false); readonly save = output<MyData>(); readonly cancel = output<void>(); }
Features Component Pattern
// Features components can inject stores export class MyFeatureComponent { readonly #store = inject(MyStore); readonly data = this.#store.data; readonly isLoading = this.#store.isLoading; }