118 lines
3.4 KiB
TypeScript
118 lines
3.4 KiB
TypeScript
import * as plugins from './mod.plugins.js';
|
|
import { BaseFormatter } from './classes.baseformatter.js';
|
|
|
|
export interface IModuleDependency {
|
|
module: string;
|
|
dependencies: Set<string>;
|
|
dependents: Set<string>;
|
|
}
|
|
|
|
export class DependencyAnalyzer {
|
|
private moduleDependencies: Map<string, IModuleDependency> = 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<string>();
|
|
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)
|
|
);
|
|
}
|
|
}
|