/** * @angular-modernizer/plugin-angular - Facade Pattern Transformation Rule * * Transform rule that extracts complex component logic into facade services. * This is part of the modernization to improve component maintainability and separation of concerns. * * Philosophy: "Thin Rule, Thick Orchestrator" * - The rule is a minimal wrapper * - All business logic lives in the orchestrator * - The rule handles the plugin protocol (TransformRule interface) */ import type { TransformRule, TransformContext, TransformResult, } from '@angular-modernizer/plugin-system'; import type { PublicApi } from '@angular-modernizer/api'; import { FacadePatternOrchestrator } from '../orchestrators/facade-pattern-orchestrator.js'; /** * Transform rule for extracting complex component logic into facade services. * * @remarks * This rule implements the {@link TransformRule} interface and serves as the * bridge between the Angular Modernizer's plugin system and the facade pattern * orchestrator. It follows the "Thin Rule, Thick Orchestrator" pattern * where the rule handles protocol compliance while delegating all business logic * to the {@link FacadePatternOrchestrator}. * * ## What It Does * * The rule orchestrates the extraction of complex business logic from components: * - **Complex Component Detection**: Identifies components with too many methods or complex logic * - **Facade Service Creation**: Creates dedicated facade services for business logic * - **Logic Extraction**: Moves complex methods from components to facade services * - **Dependency Injection**: Updates components to inject and use facade services * - **Import Management**: Updates imports and module declarations as needed * * ## Example Usage * * This rule is typically not used directly, but rather accessed through the * {@link AngularPlugin}: * * ```typescript * const plugin = new AngularPlugin(); * const rules = plugin.getTransformRules(); * const rule = rules.find(r => r.id === 'angular:facade-pattern'); * const result = await rule.transform(context); * ``` * * ## Transformation Behavior * * **Complex Component Detection**: * ```typescript * // Before (complex component) * @Component({...}) * export class UserManagementComponent { * users: User[] = []; * * constructor(private http: HttpClient) {} * * ngOnInit() { * this.loadUsers(); * } * * loadUsers() { * this.http.get('/api/users').subscribe(users => { * this.users = users.filter(u => u.active); * this.sortUsers(); * this.updateUserStats(); * }); * } * * sortUsers() { /* complex sorting logic *\/ } * updateUserStats() { /* complex stats calculation *\/ } * validateUser() { /* complex validation logic *\/ } * exportUsers() { /* complex export logic *\/ } * } * * // After (with facade service) * @Component({...}) * export class UserManagementComponent { * users: User[] = []; * * constructor(private userFacade: UserFacadeService) {} * * ngOnInit() { * this.userFacade.loadUsers(); * } * } * * @Injectable({ providedIn: 'root' }) * export class UserFacadeService { * users$ = new BehaviorSubject([]); * * constructor(private http: HttpClient) {} * * loadUsers() { * this.http.get('/api/users').subscribe(users => { * const filteredUsers = users.filter(u => u.active); * const sortedUsers = this.sortUsers(filteredUsers); * this.updateUserStats(sortedUsers); * this.users$.next(sortedUsers); * }); * } * * sortUsers(users: User[]) { /* complex sorting logic *\/ } * updateUserStats(users: User[]) { /* complex stats calculation *\/ } * validateUser(user: User) { /* complex validation logic *\/ } * exportUsers(users: User[]) { /* complex export logic *\/ } * } * ``` * * @see {@link FacadePatternOrchestrator} for transformation logic * @see {@link TransformRule} for the interface contract * @see {@link AngularPlugin} for plugin integration * * @public */ export class FacadePatternRule implements TransformRule { /** * Unique rule identifier. * Format: "plugin-name:rule-name" */ public readonly id = 'angular:facade-pattern'; /** * Human-readable rule name. */ public readonly name = 'Facade Pattern'; /** * Rule description. */ public readonly description = 'Extracts complex component logic into dedicated facade services for better separation of concerns'; /** * Rule category for grouping. */ public readonly category = 'modernization'; /** * Tags for filtering and search. */ public readonly tags = [ 'angular', 'component', 'facade', 'refactoring', 'separation-of-concerns', 'service', 'architecture', 'modernization', ]; /** * The orchestrator that performs the actual transformation. */ private readonly orchestrator = new FacadePatternOrchestrator(); /** * Transform a source file by extracting complex component logic into facade services. * * @remarks * This method implements the {@link TransformRule.transform} contract. * It delegates to the {@link FacadePatternOrchestrator} for the actual * transformation work, then packages the result into a {@link TransformResult}. * * The method: * 1. Captures the file's initial state * 2. Invokes the orchestrator to perform the facade extraction * 3. Detects whether the file was modified * 4. Returns a standardized {@link TransformResult} * * ## Return Value * * The transform result includes: * - `modified`: Whether the file was changed * - `message`: A human-readable summary * - `filePath`: The path to the transformed file * - `ruleId`: This rule's identifier * * @param context - Transform context with file, project, and API access * * @returns Promise resolving to the transformation result * * @example * ```typescript * const rule = new FacadePatternRule(); * const result = await rule.transform(context); * * if (result.modified) { * console.info(`Extracted facade services: ${result.filePath}`); * } * ``` * * @public */ async transform( context: TransformContext, ): Promise { const { sourceFile, filePath } = context; // Check if this transformation type is requested const pluginConfig = context.config[ '@angular-modernizer/plugin-angular' ] as Record | undefined; if (pluginConfig?.['transformationType'] !== 'facade-pattern') { return { ruleId: this.id, modified: false, message: 'Transformation type not applicable', filePath, }; } // Capture initial state to detect modifications const initialText = sourceFile.getFullText(); // Run the orchestrator this.orchestrator.run(context); // Detect if the file was modified const modified = sourceFile.getFullText() !== initialText; // Return the result return { ruleId: this.id, modified, message: modified ? `Successfully extracted complex component logic into facade services` : `No complex component logic found to extract`, filePath, }; } }