UNPKG

@deepbrainspace/nx-surrealdb

Version:

NX plugin for SurrealDB migrations with modular architecture

161 lines 5.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DependencyResolver = void 0; const tslib_1 = require("tslib"); const config_loader_1 = require("../configuration/config-loader"); const fs = tslib_1.__importStar(require("fs/promises")); class DependencyResolver { constructor(basePath) { this.basePath = basePath; this.config = null; this.dependencyGraph = new Map(); } async initialize(configPath) { this.config = await config_loader_1.ConfigLoader.loadConfig(this.basePath, configPath); if (!this.config) { // Auto-discover modules if no config exists await this.autoDiscoverModules(); } this.buildDependencyGraph(); } async autoDiscoverModules() { try { const entries = await fs.readdir(this.basePath, { withFileTypes: true }); const modules = entries .filter(entry => entry.isDirectory()) .map(entry => entry.name) .filter(name => /^\d{1,4}_/.test(name)) .sort(); if (modules.length > 0) { this.config = config_loader_1.ConfigLoader.createDefaultConfig(modules); // console.log(`Auto-discovered ${modules.length} modules:`, modules.join(', ')); } else { this.config = { modules: {} }; } } catch { // console.warn(`Failed to auto-discover modules`); this.config = { modules: {} }; } } buildDependencyGraph() { if (!this.config) return; this.dependencyGraph.clear(); // First pass: create all nodes for (const [moduleId, moduleConfig] of Object.entries(this.config.modules)) { this.dependencyGraph.set(moduleId, { moduleId, config: moduleConfig, dependencies: [...moduleConfig.dependencies], dependents: [], }); } // Second pass: build dependents lists for (const [moduleId, moduleConfig] of Object.entries(this.config.modules)) { for (const dependency of moduleConfig.dependencies) { const depNode = this.dependencyGraph.get(dependency); if (depNode) { depNode.dependents.push(moduleId); } } } } getExecutionOrder(targetModules) { if (!this.config) return []; const requestedModules = targetModules || Object.keys(this.config.modules); const result = []; const visited = new Set(); const visiting = new Set(); const visit = (moduleId) => { if (visited.has(moduleId)) return; if (visiting.has(moduleId)) { throw new Error(`Circular dependency detected involving ${moduleId}`); } const node = this.dependencyGraph.get(moduleId); if (!node) return; visiting.add(moduleId); // Visit all dependencies first (dependencies are always included) for (const dependency of node.dependencies) { visit(dependency); } visiting.delete(moduleId); visited.add(moduleId); result.push(moduleId); }; // Visit all requested modules for (const moduleId of requestedModules) { visit(moduleId); } return result; } getRollbackOrder(targetModules) { // Rollback is the reverse of execution order return this.getExecutionOrder(targetModules).reverse(); } validateRollback(moduleId, targetModules) { const node = this.dependencyGraph.get(moduleId); if (!node) { return { canRollback: false, blockedBy: [], reason: `Module ${moduleId} not found in dependency graph`, }; } // Check if any dependents would be affected // Only consider dependents that are NOT also being rolled back const affectedDependents = node.dependents.filter(dependent => { // If targetModules is specified, exclude dependents that are also in the rollback list return !targetModules || !targetModules.includes(dependent); }); if (affectedDependents.length > 0) { return { canRollback: false, blockedBy: affectedDependents, reason: `Cannot rollback ${moduleId} because it has active dependents: ${affectedDependents.join(', ')}`, }; } return { canRollback: true, blockedBy: [], }; } validateModuleExists(moduleId) { return this.dependencyGraph.has(moduleId); } getModuleDependencies(moduleId) { const node = this.dependencyGraph.get(moduleId); return node ? [...node.dependencies] : []; } getModuleDependents(moduleId) { const node = this.dependencyGraph.get(moduleId); return node ? [...node.dependents] : []; } getAllModules() { return Array.from(this.dependencyGraph.keys()).sort(); } getResolutionResult(targetModules) { return { executionOrder: this.getExecutionOrder(targetModules), dependencyGraph: new Map(this.dependencyGraph), }; } getConfig() { return this.config; } hasConfig() { return this.config !== null && Object.keys(this.config.modules).length > 0; } // Static utility method for testing static async createResolver(basePath, configPath) { const resolver = new DependencyResolver(basePath); await resolver.initialize(configPath); return resolver; } } exports.DependencyResolver = DependencyResolver; //# sourceMappingURL=dependency-resolver.js.map