UNPKG

adam-java-analytics

Version:

Java code analyzer for detecting package dependencies and circular references

138 lines (117 loc) 4.2 kB
interface Package { name: string parent: string | null hasChildren: boolean } interface Dependency { source: string target: string } interface ProjectData { rootPackage: string packages: Package[] dependencies: Dependency[] circularDependencies: string[][] } /** * Analyzes a Java project to extract package and dependency information */ export async function analyzeProject(projectPath: string): Promise<ProjectData> { try { // This would be a server action in a real implementation // For demo purposes, we'll return mock data return getMockProjectData() } catch (error) { console.error("Error analyzing project:", error) throw new Error("Failed to analyze project") } } /** * Detects circular dependencies in the project */ export function detectCircularDependencies(packages: Package[], dependencies: Dependency[]): string[][] { const graph: Record<string, string[]> = {} // Build adjacency list packages.forEach((pkg) => { graph[pkg.name] = [] }) dependencies.forEach((dep) => { if (graph[dep.source]) { graph[dep.source].push(dep.target) } }) const cycles: string[][] = [] const visited = new Set<string>() const recursionStack = new Set<string>() function dfs(node: string, path: string[] = []): void { if (recursionStack.has(node)) { // Found a cycle const cycleStart = path.indexOf(node) if (cycleStart !== -1) { const cycle = path.slice(cycleStart).concat(node) // Check if this cycle or its rotation is already in cycles const isNewCycle = !cycles.some((existingCycle) => { if (existingCycle.length !== cycle.length) return false // Check all possible rotations for (let i = 0; i < existingCycle.length; i++) { const rotated = [...existingCycle.slice(i), ...existingCycle.slice(0, i)] if (JSON.stringify(rotated) === JSON.stringify(cycle)) return true } return false }) if (isNewCycle) { cycles.push(cycle) } } return } if (visited.has(node)) return visited.add(node) recursionStack.add(node) path.push(node) for (const neighbor of graph[node] || []) { dfs(neighbor, [...path]) } recursionStack.delete(node) } // Run DFS from each node for (const node of Object.keys(graph)) { if (!visited.has(node)) { dfs(node) } } return cycles } /** * Returns mock project data for demonstration */ function getMockProjectData(): ProjectData { const packages: Package[] = [ { name: "com.example", parent: null, hasChildren: true }, { name: "com.example.app", parent: "com.example", hasChildren: true }, { name: "com.example.app.controller", parent: "com.example.app", hasChildren: false }, { name: "com.example.app.service", parent: "com.example.app", hasChildren: false }, { name: "com.example.app.repository", parent: "com.example.app", hasChildren: false }, { name: "com.example.app.model", parent: "com.example.app", hasChildren: false }, { name: "com.example.util", parent: "com.example", hasChildren: true }, { name: "com.example.util.helper", parent: "com.example.util", hasChildren: false }, { name: "com.example.util.formatter", parent: "com.example.util", hasChildren: false }, ] const dependencies: Dependency[] = [ { source: "com.example.app.controller", target: "com.example.app.service" }, { source: "com.example.app.service", target: "com.example.app.repository" }, { source: "com.example.app.repository", target: "com.example.app.model" }, { source: "com.example.app.model", target: "com.example.util.formatter" }, { source: "com.example.util.formatter", target: "com.example.util.helper" }, // Circular dependency for demonstration { source: "com.example.app.service", target: "com.example.app.controller" }, { source: "com.example.util.helper", target: "com.example.app.model" }, ] const circularDependencies = detectCircularDependencies(packages, dependencies) return { rootPackage: "com.example", packages, dependencies, circularDependencies, } }