UNPKG

ruch

Version:

Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance. Create maintainable, scalable applications with domain-driven design and integrated AI tooling.

143 lines • 6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.visualizeDomains = void 0; const file_operations_1 = require("../utils/file-operations"); const logger_1 = require("../utils/logger"); const dependency_analyzer_1 = require("../utils/dependency-analyzer"); const path_1 = __importDefault(require("path")); /** * Analyze and visualize domain dependencies */ const visualizeDomains = async (options = {}) => { const fileSystem = (0, file_operations_1.createFileSystem)(); const projectRoot = options.projectRoot || process.cwd(); const outputFormat = options.format || 'console'; const outputFile = options.output || path_1.default.join(projectRoot, 'domain-graph.json'); try { logger_1.logger.info('šŸ” Analyzing domain dependencies...'); // Generate graph data const graphData = await (0, dependency_analyzer_1.generateGraphData)(fileSystem, projectRoot); if (graphData.nodes.length === 0) { logger_1.logger.warning('āš ļø No domains found in the project.'); logger_1.logger.info('Make sure your project has domains in the src/domains/ directory.'); return; } logger_1.logger.info(`āœ… Found ${graphData.nodes.length} domains with ${graphData.edges.length} dependencies`); // Detect circular dependencies const cycles = detectCircularDependencies(graphData.edges); if (cycles.length > 0) { logger_1.logger.warning(`āš ļø Detected ${cycles.length} circular dependencies:`); cycles.forEach((cycle, index) => { logger_1.logger.warning(` ${index + 1}. ${cycle.join(' → ')}`); }); } if (outputFormat === 'json') { // Save to JSON file const jsonOutput = JSON.stringify(graphData, null, 2); await (0, file_operations_1.writeFileContent)(fileSystem, outputFile, jsonOutput); logger_1.logger.success(`šŸ“„ Graph data saved to: ${outputFile}`); } // Display in console displayGraphInConsole(graphData, cycles); logger_1.logger.info('✨ Domain analysis complete!'); } catch (error) { logger_1.logger.error('āŒ Failed to analyze domains:'); logger_1.logger.error(error instanceof Error ? error.message : String(error)); process.exit(1); } }; exports.visualizeDomains = visualizeDomains; /** * Detect circular dependencies in the graph */ const detectCircularDependencies = (edges) => { const graph = new Map(); const cycles = []; // Build adjacency list edges.forEach(edge => { if (!graph.has(edge.source)) { graph.set(edge.source, []); } graph.get(edge.source).push(edge.target); }); // DFS to detect cycles const visited = new Set(); const recursionStack = new Set(); const dfs = (node, path) => { visited.add(node); recursionStack.add(node); path.push(node); const neighbors = graph.get(node) || []; for (const neighbor of neighbors) { if (!visited.has(neighbor)) { dfs(neighbor, [...path]); } else if (recursionStack.has(neighbor)) { // Found a cycle const cycleStart = path.indexOf(neighbor); if (cycleStart !== -1) { cycles.push([...path.slice(cycleStart), neighbor]); } } } recursionStack.delete(node); }; // Check all nodes graph.forEach((_, node) => { if (!visited.has(node)) { dfs(node, []); } }); return cycles; }; /** * Display graph information in console */ const displayGraphInConsole = (graphData, cycles) => { logger_1.logger.info('\nšŸ“Š DOMAIN ARCHITECTURE OVERVIEW'); logger_1.logger.info('================================'); // Display domains logger_1.logger.info(`\nšŸ—ļø DOMAINS (${graphData.nodes.length}):`); graphData.nodes.forEach((node) => { const isInCycle = cycles.some(cycle => cycle.includes(node.id)); const status = isInCycle ? 'šŸ”“' : '🟢'; logger_1.logger.info(` ${status} ${node.label} (${node.type || 'feature'})`); }); // Display dependencies if (graphData.edges.length > 0) { logger_1.logger.info(`\nšŸ”— DEPENDENCIES (${graphData.edges.length}):`); graphData.edges.forEach((edge) => { logger_1.logger.info(` ${edge.source} → ${edge.target}`); if (edge.metadata.path) { logger_1.logger.info(` šŸ“ ${edge.metadata.path}${edge.metadata.line ? `:${edge.metadata.line}` : ''}`); } }); } // Display circular dependencies if (cycles.length > 0) { logger_1.logger.info('\n🚨 CIRCULAR DEPENDENCIES:'); cycles.forEach((cycle, index) => { logger_1.logger.warning(` ${index + 1}. ${cycle.join(' → ')}`); }); } // Display summary logger_1.logger.info('\nšŸ“ˆ SUMMARY:'); logger_1.logger.info(` • Total domains: ${graphData.nodes.length}`); logger_1.logger.info(` • Total dependencies: ${graphData.edges.length}`); logger_1.logger.info(` • Circular dependencies: ${cycles.length}`); const avgDependencies = graphData.nodes.length > 0 ? (graphData.edges.length / graphData.nodes.length).toFixed(1) : '0'; logger_1.logger.info(` • Average dependencies per domain: ${avgDependencies}`); if (cycles.length === 0) { logger_1.logger.success('\nāœ… No circular dependencies detected - Good architecture!'); } else { logger_1.logger.warning('\nāš ļø Consider refactoring circular dependencies for better maintainability.'); } }; //# sourceMappingURL=visualize.js.map