/** * @angular-modernizer/plugin-angular - Core and Shared Modules Organization Rule * * Analyzes and organizes Angular applications into proper Core and Shared module architecture. * This is a prerequisite step before migrating to standalone components. * * Philosophy: "Thin Rule, Thick Orchestrator" * - This rule is a minimal protocol wrapper * - CoreSharedModulesOrchestrator contains all business logic */ import type { TransformRule, TransformContext, TransformResult, } from '@angular-modernizer/plugin-system'; import type { PublicApi } from '@angular-modernizer/api'; import { CoreSharedModulesOrchestrator } from '../orchestrators/core-shared-modules-orchestrator.js'; /** * Rule for organizing Angular applications into Core and Shared module architecture. * * @remarks * This rule helps organize legacy Angular applications by: * - Identifying singleton services that should be in CoreModule * - Finding reusable components/directives/pipes for SharedModule * - Creating proper CoreModule with import guard * - Creating proper SharedModule with exports * - Generating reports and file move recommendations * * This is particularly useful for large legacy codebases that need proper organization * before they can migrate to standalone components. * * ## Core Module Purpose * * CoreModule should contain: * - Singleton services (AuthService, LoggerService, etc.) * - HTTP interceptors * - Global state management * - Guards and resolvers * - Should only be imported once in AppModule * * ## Shared Module Purpose * * SharedModule should contain: * - Reusable UI components * - Custom directives * - Custom pipes * - Common Angular modules (CommonModule, FormsModule, etc.) * - Can be imported by any feature module * * ## Example Transformation * * **Before:** * ``` * app/ * ├── auth.service.ts (scattered) * ├── logger.service.ts (scattered) * ├── loading-spinner.component.ts (duplicated in features) * ├── feature1/ * └── feature2/ * ``` * * **After:** * ``` * app/ * ├── core/ * │ ├── core.module.ts * │ ├── services/ * │ │ ├── auth.service.ts * │ │ └── logger.service.ts * ├── shared/ * │ ├── shared.module.ts * │ ├── components/ * │ │ └── loading-spinner.component.ts * ├── feature1/ * └── feature2/ * ``` * * @public */ export class CoreSharedModulesRule implements TransformRule { /** * Unique rule identifier. */ public readonly id = 'angular:core-shared-modules'; /** * Human-readable rule name. */ public readonly name = 'Core and Shared Modules Organization'; /** * Detailed rule description. */ public readonly description = 'Organizes Angular applications into proper Core and Shared module architecture, identifying singleton services and reusable components for better structure before standalone migration'; /** * Rule category. */ public readonly category = 'modernization'; /** * Rule tags for filtering and organization. */ public readonly tags = [ 'angular', 'modules', 'architecture', 'organization', 'core', 'shared', 'best-practices', 'legacy', ]; /** * Orchestrator instance (stateless). */ private readonly orchestrator = new CoreSharedModulesOrchestrator(); /** * Analyze and organize an Angular application into Core and Shared modules. * * @param context - Transform context with source file and configuration * * @returns Transform result with analysis report and modifications * * @public */ async transform( context: TransformContext, ): Promise { const { sourceFile, filePath } = context; // Check configuration to determine if this transformation should run const pluginConfig = context.config[ '@angular-modernizer/plugin-angular' ] as Record | undefined; if (pluginConfig?.['transformationType'] !== 'core-shared-modules') { 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 const report = this.orchestrator.run(context); // Detect if any modifications were made const modified = sourceFile.getFullText() !== initialText; // Build message with report summary let message = modified ? 'Updated module structure for Core/Shared architecture' : 'Analyzed module structure'; if (report) { message += `\n\nAnalysis Report:\n${report}`; } return { ruleId: this.id, modified, message, filePath, }; } }