UNPKG

adam-java-analytics

Version:

Java code analyzer for detecting package dependencies and circular references

127 lines (103 loc) 3.25 kB
"use server" import fs from "fs" import path from "path" import { promisify } from "util" const readFile = promisify(fs.readFile) export interface JavaFile { class: string package: string path: string fullName: string imports: string[] } export interface JavaProjectData { files: JavaFile[] circularDependencies: string[][] } export async function analyzeProject(projectPath: string): Promise<JavaProjectData> { try { const javaFiles: string[] = [] const sourceRoots = [ path.join(projectPath, "src", "main", "java"), path.join(projectPath, "src"), projectPath, ] function collectJavaFiles(dir: string) { if (!fs.existsSync(dir)) return const entries = fs.readdirSync(dir, { withFileTypes: true }) for (const entry of entries) { const fullPath = path.join(dir, entry.name) if (entry.isDirectory()) { collectJavaFiles(fullPath) } else if (entry.isFile() && entry.name.endsWith(".java")) { javaFiles.push(fullPath) } } } sourceRoots.forEach(collectJavaFiles) console.log("✅ Java files found:", javaFiles.length) const files: JavaFile[] = [] const dependencyEdges = new Set<string>() const dependencyGraph: Record<string, string[]> = {} for (const filePath of javaFiles) { const content = await readFile(filePath, "utf8") const packageMatch = content.match(/package\s+([\w\.]+);/) const classMatch = filePath.match(/([^\/\\]+)\.java$/) const importMatches = [...content.matchAll(/import\s+([\w\.]+);/g)] if (!packageMatch || !classMatch) continue const packageName = packageMatch[1] const className = classMatch[1] const fullName = `${packageName}.${className}` const imports = importMatches.map((m) => m[1]) files.push({ class: className, package: packageName, path: filePath, fullName, imports, }) dependencyGraph[fullName] = imports } const circularDependencies = detectCircularDependencies(dependencyGraph) console.log(files); return { files, circularDependencies, } } catch (error) { console.error("❌ Error analyzing project:", error) throw new Error("Failed to analyze project") } } function detectCircularDependencies(graph: Record<string, string[]>): string[][] { const cycles: string[][] = [] const visited = new Set<string>() const recursionStack = new Set<string>() function dfs(node: string, path: string[] = []) { if (recursionStack.has(node)) { const cycleStart = path.indexOf(node) if (cycleStart !== -1) { const cycle = path.slice(cycleStart).concat(node) const cycleKey = cycle.join("->") if (!cycles.some((c) => c.join("->") === cycleKey)) { 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) } for (const node of Object.keys(graph)) { if (!visited.has(node)) { dfs(node) } } return cycles }