import * as plugins from './mod.plugins.js'; import { BaseFormatter } from './classes.baseformatter.js'; export interface IModuleDependency { module: string; dependencies: Set; dependents: Set; } export class DependencyAnalyzer { private moduleDependencies: Map = new Map(); constructor() { this.initializeDependencies(); } private initializeDependencies(): void { // Define dependencies between format modules const dependencies = { 'cleanup': [], // No dependencies 'npmextra': [], // No dependencies 'license': ['npmextra'], // Depends on npmextra for config 'packagejson': ['npmextra'], // Depends on npmextra for config 'templates': ['npmextra', 'packagejson'], // Depends on both 'gitignore': ['templates'], // Depends on templates 'tsconfig': ['packagejson'], // Depends on package.json 'prettier': ['cleanup', 'npmextra', 'packagejson', 'templates', 'gitignore', 'tsconfig'], // Runs after most others 'readme': ['npmextra', 'packagejson'], // Depends on project metadata 'copy': ['npmextra'], // Depends on config }; // Initialize all modules for (const [module, deps] of Object.entries(dependencies)) { this.moduleDependencies.set(module, { module, dependencies: new Set(deps), dependents: new Set() }); } // Build reverse dependencies (dependents) for (const [module, deps] of Object.entries(dependencies)) { for (const dep of deps) { const depModule = this.moduleDependencies.get(dep); if (depModule) { depModule.dependents.add(module); } } } } getExecutionGroups(modules: BaseFormatter[]): BaseFormatter[][] { const modulesMap = new Map(modules.map(m => [m.name, m])); const executed = new Set(); const groups: BaseFormatter[][] = []; while (executed.size < modules.length) { const currentGroup: BaseFormatter[] = []; for (const module of modules) { if (executed.has(module.name)) continue; const dependency = this.moduleDependencies.get(module.name); if (!dependency) { // Unknown module, execute in isolation currentGroup.push(module); continue; } // Check if all dependencies have been executed const allDepsExecuted = Array.from(dependency.dependencies) .every(dep => executed.has(dep) || !modulesMap.has(dep)); if (allDepsExecuted) { currentGroup.push(module); } } if (currentGroup.length === 0) { // Circular dependency or error - execute remaining modules for (const module of modules) { if (!executed.has(module.name)) { currentGroup.push(module); } } } currentGroup.forEach(m => executed.add(m.name)); groups.push(currentGroup); } return groups; } canRunInParallel(module1: string, module2: string): boolean { const dep1 = this.moduleDependencies.get(module1); const dep2 = this.moduleDependencies.get(module2); if (!dep1 || !dep2) return false; // Check if module1 depends on module2 or vice versa return !dep1.dependencies.has(module2) && !dep2.dependencies.has(module1) && !dep1.dependents.has(module2) && !dep2.dependents.has(module1); } }