Agent skill
angular-component-rule
Enforce Angular 20 component companion-file and structure rules across `src/app/**` with deterministic, non-destructive auto-fix behavior. Use when users ask to create/fix missing component companions, enforce one-component-per-file conventions, externalize inline template/styles, remove static `host.class` styling, standardize `.component.variants.ts` extraction, or run CI/component-hygiene audits.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/angular-component-rule
SKILL.md
Angular 20 Component File Completeness and Structure Rule
Enforce deterministic component companion files in Angular workspaces. Auto-fix by creating missing files without overwriting existing files.
Scope and Matching
Scan only these roots when present:
src/app/**
Define a component as any file matching **/*.component.ts.
Define a variant companion as **/*.component.variants.ts.
Exclude:
**/node_modules/****/dist/****/.angular/****/.storybook/****/coverage/**
Enforcement Rules
For each X.component.ts, require:
X.component.tsX.component.htmlX.component.spec.ts- Exactly one accepted style companion:
X.component.scssorX.component.css(compatibility rule applies) X.component.stories.tsonly when Storybook is installed- Exactly one Angular component class (
@Component) perX.component.ts - Component variants must live in
X.component.variants.ts, not inX.component.ts
Structural constraints:
X.component.tsmust declare exactly one@Component-decorated classX.component.tsmust not declare additional@Component,@Directive, or@Pipeclasses- Variant unions, variant maps, variant option arrays, and variant class lookup objects must be declared in
X.component.variants.ts X.component.tsmay import and use variant exports, but should not define variant constants/types inline except for trivial one-off local values- Do not use inline template or inline styles in
@Componentmetadata (template,styles) - Do not place static host utility classes in
@Component({ host: { class: '...' } }); move them to template and/or stylesheet
Step 1: Determine Environment
Read root package.json.
Read root angular.json when present.
If either file is missing or unreadable, continue with best-effort fallbacks and record the limitation in the completion report.
Compute and report:
storybookInstalled- preferred style extension
styleExt(scssorcss)
Storybook detection
Set storybookInstalled = true if any condition is true:
package.jsonhas@storybook/angularin dependencies or devDependencies.storybook/exists in workspace rootpackage.jsonscripts includestorybookorbuild-storybook
Else set storybookInstalled = false.
Style extension detection (styleExt)
Resolve in strict priority order.
- Primary rule:
angular.json- Check
projects[*].schematics['@schematics/angular:component'].style - Else check top-level
schematics['@schematics/angular:component'].style - Else check
projects[*].architect.build.options.inlineStyleLanguage - If resolved value is
scss, choosescss - If resolved value is
css, choosecss
- Check
- Secondary rule: package dependencies
- If
sassexists in dependencies or devDependencies, choosescss - Otherwise choose
css
- If
- Tertiary rule: repository convention fallback
- Compare counts of
*.component.scssand*.component.cssin repo scope - If
scsscount is greater, choosescss - Otherwise choose
css
- Compare counts of
Failure and fallback handling:
- If
angular.jsonis unreadable or malformed, skip primary rule and continue with secondary rule - If
package.jsonis unreadable or missing, skip package-based Storybook and dependency checks - If both primary and secondary style rules are unavailable, run tertiary rule
- If tertiary counts cannot be computed, default
styleExt = css
Compatibility rule
Never force existing components to switch style extension.
- If
X.component.scssexists, accept it even when preferred style iscss - If
X.component.cssexists, accept it even when preferred style isscss - Create a style file only when both are missing, using resolved
styleExt
Multi-project rule
If multiple Angular projects use different component style settings, infer component ownership by path using angular.json project root/sourceRoot and prefer per-project style. Fall back to global rules only when ownership or project-level style is not inferable.
Step 2: Scan and Compute Expected Files
For each X.component.ts, compute required companions in the same folder:
X.component.htmlX.component.spec.ts- Style file:
- Accept existing
.component.scssor.component.css - If neither exists, require
X.component.<styleExt>
- Accept existing
X.component.stories.tswhenstorybookInstalledis true
Then validate structure:
- Count
@Componentdecorators inX.component.tsand require count = 1 - Detect variant declarations in
X.component.ts(for example:variant,size,tone,intent,stateunions or maps) and mark for extraction - If variant declarations are present in
X.component.ts, requireX.component.variants.ts - Detect
@Component.templateand@Component.styles; mark as inline violations - Detect
@Component.host.classstring literals; mark as host-class-inline violations
If no files match **/*.component.ts, produce a completion report with zero counts and no file changes.
Step 3: Validate and Auto-Fix
Default behavior is auto-fix. Create missing files without overwriting any existing file.
Create missing template file
Create X.component.html with:
<div class="component">
<!-- TODO: implement template -->
</div>
Create missing style file
If resolved extension is scss, create:
:host {
display: block;
}
If resolved extension is css, create:
:host {
display: block;
}
Create missing spec file
Create a minimal TestBed test that compiles and asserts should create.
Prefer a standalone-friendly template first:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ExampleComponent } from './example.component';
describe('ExampleComponent', () => {
let component: ExampleComponent;
let fixture: ComponentFixture<ExampleComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ExampleComponent],
}).compileComponents();
fixture = TestBed.createComponent(ExampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
If constructor dependencies or non-standalone setup break compilation, do not invent mocks. Add a TODO comment indicating missing providers/imports to be filled intentionally.
Create missing story file (only when Storybook is installed)
Create X.component.stories.ts with minimal story metadata:
import type { Meta, StoryObj } from '@storybook/angular';
import { ExampleComponent } from './example.component';
const meta: Meta<ExampleComponent> = {
title: 'Components/Example',
component: ExampleComponent,
};
export default meta;
type Story = StoryObj<ExampleComponent>;
export const Default: Story = {
args: {},
};
Detect obvious @Input values only as an optional enhancement. Default to empty args.
Enforce one component per .component.ts
If more than one @Component class is found in a single file:
- Do not auto-split classes blindly
- Report file as unfixable automatically
- Provide targeted follow-up action:
- Keep one component class in
X.component.ts - Move each additional component into its own
Y.component.tswith companions
- Keep one component class in
Enforce variants in separate TypeScript file
If component variants are defined inline in X.component.ts:
- Create
X.component.variants.tswhen missing - Move variant-related types/constants/helpers into
X.component.variants.ts - Update
X.component.tsimports to consume moved exports - Preserve runtime behavior and public API names
- If safe automated extraction is ambiguous, do not rewrite; report as manual follow-up
When creating X.component.variants.ts, use this skeleton:
export type ExampleVariant = 'default';
export const EXAMPLE_VARIANTS = {
default: '',
} as const;
Enforce no inline template/styles and no inline host class strings
For X.component.ts, enforce:
templateUrlmust be used instead oftemplatestyleUrl/styleUrlsmust be used instead ofstyles- Static class strings in
host.classmust not be used for styling distribution
Auto-fix policy:
- If
templateis inline andX.component.htmlis missing, createX.component.htmlwith inline content and switch metadata totemplateUrl - If
stylesis inline and style companion is missing, createX.component.<styleExt>with inline content and switch metadata tostyleUrl - If
host.classcontains static classes, move classes to:- Root element in
X.component.htmlwhen a stable root exists :hostinX.component.<styleExt>when classes map to host-level behavior
- Root element in
- Remove migrated inline metadata after successful move
- If safe migration target is ambiguous, do not rewrite; report manual follow-up with exact location
If host-class migration is ambiguous, keep behavior unchanged and include the exact metadata path and a one-step manual recommendation.
Step 4: Non-Destructive Guarantees
- Never overwrite files
- Never delete files
- Never rename files
- Inline metadata migration is allowed only for safe, deterministic conversions (
template->templateUrl,styles->styleUrl/styleUrls,host.classextraction). Otherwise report as manual follow-up.
Required Completion Report
Always output:
- Storybook detection result (
installedornot installed) plus reason - Style enforcement decision (
cssorscss) plus reason - Total components scanned
- Missing-file summary by type
- Created files with full paths
- Skipped or unfixable items with reasons
- Structural violations found:
- Files with multiple
@Componentclasses - Files with inline variant declarations
- Variant files created or updated
- Files with multiple
- Inline-metadata violations found:
- Files using inline
template - Files using inline
styles - Files using static
host.classstrings
- Files using inline
- Environment limitations and fallback paths used:
- Missing or unreadable config files
- Any fallback rule selected because of parse/read failures
Verification Gates
Before finalizing, verify these gates:
- Every
*.component.tsin scope has required companions or is listed as skipped/unfixable - No existing file was overwritten, deleted, or renamed
- Style companion decisions obey compatibility and per-project ownership rules
- Story files were created only when Storybook detection is
true - Any structural rewrite performed (
template/stylesextraction, variant extraction) is deterministic and behavior-preserving, otherwise reported as manual follow-up - Required completion report is fully populated with concrete counts and paths (not placeholders)
Assistant Portability Rules
- Use deterministic, file-system-based checks and avoid assumptions about specific editors or IDE integrations.
- Keep auto-fix behavior non-destructive and idempotent across repeated runs.
- If a safe rewrite cannot be proven, skip mutation and report an exact manual action with file path.
Edge Cases
- Component has neither
.cssnor.scssCreate exactly one style file usingstyleExt - Component already has
.cssbut preferred style isscssAccept existing.css; do not create.scss - Component already has
.scssbut preferred style iscssAccept existing.scss; do not create.css - Multiple
@Componentclasses in one file Do not perform unsafe split automatically; report required manual split plan - Variants declared inline in
X.component.tsExtract toX.component.variants.tswhen safe; otherwise report exact declarations requiring manual extraction - Component metadata uses
host.classwith Tailwind utility string Treat as violation; migrate classes toX.component.htmlroot or:hostinX.component.<styleExt> - Existing inline template/styles in legacy components Convert to external companion files when safe; otherwise report with explicit manual conversion steps
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?