--- name: circular-dependency-resolver description: This skill should be used when build fails with circular import warnings, user mentions "circular dependencies" or "dependency cycles", or fixing A→B→C→A import cycles. Detects and resolves circular dependencies using graph algorithms with DI, interface extraction, and shared code fix strategies. --- # Circular Dependency Resolver ## Overview Detect and resolve circular dependencies using graph analysis, multiple fix strategies, and automated validation. Prevents runtime and build issues caused by dependency cycles. ## When to Use This Skill Invoke when user: - Mentions "circular dependencies" - Has import cycle errors - Requests dependency analysis - Build fails with circular import warnings ## Resolution Workflow ### Step 1: Detect Circular Dependencies **Using Nx:** ```bash npx nx run-many --target=lint --all 2>&1 | grep -i "circular" ``` **Using madge (if installed):** ```bash npm install -g madge madge --circular --extensions ts libs/ madge --circular --image circular-deps.svg libs/ ``` **Using TypeScript:** ```bash npx tsc --noEmit --strict 2>&1 | grep -i "circular\|cycle" ``` ### Step 2: Analyze Each Cycle For each cycle found: ``` 📍 Circular Dependency Detected Cycle Path: 1. libs/oms/data-access/src/lib/services/order.service.ts → imports OrderValidator 2. libs/oms/data-access/src/lib/validators/order.validator.ts → imports OrderService 3. Back to order.service.ts Type: Service-Validator circular reference Severity: 🔴 Critical Files Involved: 2 ``` ### Step 3: Categorize by Severity **🔴 Critical (Must Fix):** - Service-to-service cycles - Data-access layer cycles - Store dependencies creating cycles **⚠️ Warning (Should Fix):** - Component-to-component cycles - Model cross-references - Utility function cycles **ℹ️ Info (Review):** - Type-only circular references (may be acceptable) - Test file circular imports ### Step 4: Choose Fix Strategy **Strategy 1: Extract to Shared Utility** ```typescript // BEFORE (Circular) // order.service.ts imports validator.ts // validator.ts imports order.service.ts // AFTER (Fixed) // Create @isa/oms/util/types.ts export interface OrderData { id: string; } // order.service.ts imports types // validator.ts imports types // No more cycle ``` **Strategy 2: Dependency Injection (Lazy)** ```typescript // BEFORE import { ServiceB } from './service-b'; export class ServiceA { constructor(private serviceB: ServiceB) {} } // AFTER import { Injector } from '@angular/core'; export class ServiceA { private serviceB!: ServiceB; constructor(private injector: Injector) { setTimeout(() => { this.serviceB = this.injector.get(ServiceB); }); } } ``` **Strategy 3: Interface Extraction** ```typescript // BEFORE (Models with circular reference) // order.ts ↔ customer.ts // AFTER // order.interface.ts - no imports export interface IOrder { customerId: string; } // customer.interface.ts - no imports export interface ICustomer { orderIds: string[]; } // order.ts imports only ICustomer // customer.ts imports only IOrder ``` **Strategy 4: Move Shared Code** ```typescript // BEFORE // feature-a imports feature-b // feature-b imports feature-a // AFTER // Extract to @isa/shared/[name] // Both features import from shared ``` **Strategy 5: Forward References (Angular)** ```typescript // Use forwardRef for components import { forwardRef } from '@angular/core'; @Component({ imports: [forwardRef(() => ChildComponent)] }) ``` ### Step 5: Implement Fix Apply chosen strategy: 1. Create new files if needed (util library, interfaces) 2. Update imports in both files 3. Remove circular import ### Step 6: Validate Fix ```bash # Check cycle resolved madge --circular --extensions ts libs/ # TypeScript compilation npx tsc --noEmit # Run tests npx nx affected:test --skip-nx-cache # Lint npx nx affected:lint ``` ### Step 7: Generate Report ``` Circular Dependency Resolution =============================== Analysis Date: [timestamp] 📊 Summary ---------- Circular dependencies found: XX 🔴 Critical: XX ⚠️ Warning: XX Fixed: XX 🔍 Detected Cycles ------------------ 🔴 Critical Cycle #1 (FIXED) Path: order.service → validator → order.service Strategy Used: Extract to Util Library Created: @isa/oms/util/order-types.ts Files Modified: 2 Status: ✅ Resolved ⚠️ Warning Cycle #2 (FIXED) Path: component-a → component-b → component-a Strategy Used: Move Shared to @isa/ui Created: @isa/ui/shared-component Files Modified: 3 Status: ✅ Resolved 💡 Fix Strategies Applied -------------------------- 1. Extract to Util: XX cycles 2. Interface Extraction: XX cycles 3. Move Shared Code: XX cycles 4. Dependency Injection: XX cycles ✅ Validation ------------- - madge check: ✅ No cycles - TypeScript: ✅ Compiles - Tests: ✅ XX/XX passing - Lint: ✅ Passed 🎯 Prevention Tips ------------------ 1. Add ESLint rule: import/no-cycle 2. Pre-commit hook for cycle detection 3. Regular architecture reviews ``` ## Prevention **ESLint Configuration:** ```json { "import/no-cycle": ["error", { "maxDepth": 1 }] } ``` **Pre-commit Hook:** ```bash #!/bin/bash madge --circular --extensions ts libs/ if [ $? -ne 0 ]; then echo "❌ Circular dependencies detected" exit 1 fi ``` ## References - Madge: https://github.com/pahen/madge - Nx dependency graph: https://nx.dev/features/explore-graph - ESLint import plugin: https://github.com/import-js/eslint-plugin-import