analyze_dependency_graph
Analyze code dependency graphs to detect circular dependencies, identify module clusters, and examine import/export relationships between files.
Instructions
코드 의존성 그래프를 분석합니다.
키워드: 의존성, 관계 분석, 순환 참조, dependency graph, circular dependency
분석 내용:
파일 간 import/export 관계
순환 의존성 감지
모듈 클러스터 식별
코드 결합도 분석
사용 예시:
"src 폴더의 의존성 그래프 분석해줘"
"index.ts의 의존 관계 보여줘"
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectPath | Yes | 프로젝트 경로 | |
| targetFile | No | 특정 파일 분석 (선택사항) | |
| maxDepth | No | 최대 탐색 깊이 (기본값: 3) | |
| includeExternal | No | 외부 패키지 포함 여부 (기본값: false) | |
| detectCircular | No | 순환 의존성 감지 (기본값: true) |
Implementation Reference
- Main handler function that performs dependency graph analysis on TypeScript projects using ts-morph. Builds graph from imports/exports, detects circular dependencies, identifies clusters, generates Mermaid diagrams and statistics.export async function analyzeDependencyGraph(args: AnalyzeDependencyGraphArgs): Promise<ToolResult> { try { const { projectPath, targetFile, maxDepth = 3, includeExternal = false, detectCircular = true } = args; const project = ProjectCache.getInstance().getOrCreate(projectPath); const sourceFiles = project.getSourceFiles(); if (sourceFiles.length === 0) { return { content: [{ type: 'text', text: `✗ 프로젝트에서 소스 파일을 찾을 수 없습니다: ${projectPath}` }] }; } const graph: DependencyGraph = { nodes: [], edges: [], circularDependencies: [], clusters: [] }; const fileMap = new Map<string, DependencyNode>(); const adjacencyList = new Map<string, Set<string>>(); // Build dependency graph for (const sourceFile of sourceFiles) { const filePath = sourceFile.getFilePath(); const relativePath = getRelativePath(filePath, projectPath); // Skip if targeting specific file and this isn't it or related if (targetFile && !relativePath.includes(targetFile) && !shouldIncludeInGraph(relativePath, targetFile, maxDepth)) { continue; } const imports: string[] = []; const exports: string[] = []; // Get imports const importDeclarations = sourceFile.getImportDeclarations(); for (const imp of importDeclarations) { const moduleSpecifier = imp.getModuleSpecifierValue(); // Skip external packages unless requested if (!includeExternal && (moduleSpecifier.startsWith('@') || !moduleSpecifier.startsWith('.'))) { continue; } const resolvedPath = resolveImportPath(moduleSpecifier, filePath, projectPath); if (resolvedPath) { imports.push(resolvedPath); // Add edge graph.edges.push({ from: relativePath, to: resolvedPath, type: 'import' }); // Update adjacency list if (!adjacencyList.has(relativePath)) { adjacencyList.set(relativePath, new Set()); } adjacencyList.get(relativePath)!.add(resolvedPath); } } // Get exports const exportDeclarations = sourceFile.getExportDeclarations(); for (const exp of exportDeclarations) { const namedExports = exp.getNamedExports(); for (const named of namedExports) { exports.push(named.getName()); } } // Also get exported declarations const exportedDeclarations = sourceFile.getExportedDeclarations(); exportedDeclarations.forEach((declarations: any[], name: string) => { if (!exports.includes(name)) { exports.push(name); } }); const node: DependencyNode = { file: relativePath, imports, exports, depth: 0 }; fileMap.set(relativePath, node); graph.nodes.push(node); } // Detect circular dependencies if (detectCircular) { graph.circularDependencies = findCircularDependencies(adjacencyList); } // Detect clusters (strongly connected components) graph.clusters = findClusters(adjacencyList); // Generate output let output = `## 의존성 그래프 분석\n\n`; output += `**프로젝트**: ${projectPath}\n`; output += `**분석된 파일**: ${graph.nodes.length}개\n`; output += `**의존 관계**: ${graph.edges.length}개\n\n`; // Show target file dependencies if specified if (targetFile) { const targetNode = graph.nodes.find(n => n.file.includes(targetFile)); if (targetNode) { output += `### ${targetFile} 의존성\n\n`; output += `**Imports** (${targetNode.imports.length}개):\n`; for (const imp of targetNode.imports) { output += `- ← ${imp}\n`; } output += `\n**Exports** (${targetNode.exports.length}개):\n`; for (const exp of targetNode.exports) { output += `- → ${exp}\n`; } output += '\n'; } } // Circular dependencies warning if (graph.circularDependencies.length > 0) { output += `### ⚠️ 순환 의존성 감지됨\n\n`; for (const cycle of graph.circularDependencies) { output += `- ${cycle.join(' → ')} → ${cycle[0]}\n`; } output += '\n'; } // Clusters if (graph.clusters.length > 0) { output += `### 모듈 클러스터\n\n`; for (let i = 0; i < graph.clusters.length; i++) { if (graph.clusters[i].length > 1) { output += `**클러스터 ${i + 1}** (${graph.clusters[i].length}개):\n`; for (const file of graph.clusters[i].slice(0, 5)) { output += ` - ${file}\n`; } if (graph.clusters[i].length > 5) { output += ` - ... 외 ${graph.clusters[i].length - 5}개\n`; } output += '\n'; } } } // Mermaid diagram for small graphs if (graph.nodes.length <= 20) { output += `### 의존성 다이어그램\n\n`; output += generateMermaidDiagram(graph); } // Statistics output += `### 통계\n\n`; output += generateStatistics(graph); return { content: [{ type: 'text', text: output }] }; } catch (error) { return { content: [{ type: 'text', text: `✗ 의존성 분석 오류: ${error instanceof Error ? error.message : '알 수 없는 오류'}` }] }; } }
- ToolDefinition object defining the tool's name, description, input schema (projectPath required, optional targetFile, maxDepth, etc.), and annotations.export const analyzeDependencyGraphDefinition: ToolDefinition = { name: 'analyze_dependency_graph', description: `코드 의존성 그래프를 분석합니다. 키워드: 의존성, 관계 분석, 순환 참조, dependency graph, circular dependency **분석 내용:** - 파일 간 import/export 관계 - 순환 의존성 감지 - 모듈 클러스터 식별 - 코드 결합도 분석 사용 예시: - "src 폴더의 의존성 그래프 분석해줘" - "index.ts의 의존 관계 보여줘"`, inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: '프로젝트 경로' }, targetFile: { type: 'string', description: '특정 파일 분석 (선택사항)' }, maxDepth: { type: 'number', description: '최대 탐색 깊이 (기본값: 3)' }, includeExternal: { type: 'boolean', description: '외부 패키지 포함 여부 (기본값: false)' }, detectCircular: { type: 'boolean', description: '순환 의존성 감지 (기본값: true)' } }, required: ['projectPath'] }, annotations: { title: 'Analyze Dependency Graph', audience: ['user', 'assistant'], readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } };
- TypeScript interface defining the input arguments for the handler function, matching the inputSchema.interface AnalyzeDependencyGraphArgs { projectPath: string; targetFile?: string; maxDepth?: number; includeExternal?: boolean; detectCircular?: boolean; }
- src/index.ts:115-115 (registration)Registration of the tool definition in the tools array used by ListToolsRequestHandler.analyzeDependencyGraphDefinition,
- src/index.ts:180-180 (registration)Registration of the tool handler in the toolHandlers object for dynamic dispatch in CallToolRequestHandler.'analyze_dependency_graph': analyzeDependencyGraph,