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
JavaScript
;
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