DependencyGraphBuilder.kt
package com.depanalyzer.core.graph
import com.depanalyzer.parser.ParsedDependency
import com.depanalyzer.report.Vulnerability
class DependencyGraphBuilder {
fun buildGraph(
directDependencies: List<ParsedDependency>,
allDependencies: List<ParsedDependency>,
vulnerabilities: Map<String, List<Vulnerability>> = emptyMap()
): DependencyGraph {
val directCoordinates = directDependencies.map { "${it.groupId}:${it.artifactId}:${it.version}" }.toSet()
val nodeMap = mutableMapOf<String, DependencyNode>()
allDependencies.forEach { dep ->
val coordinate = "${dep.groupId}:${dep.artifactId}:${dep.version}"
val vulns = vulnerabilities[coordinate] ?: emptyList()
val node = DependencyNode(
id = coordinate,
groupId = dep.groupId,
artifactId = dep.artifactId,
version = dep.version ?: "unknown",
vulnerabilities = vulns,
ecosystem = dep.ecosystem
)
nodeMap[coordinate] = node
}
val rootNodes = mutableListOf<DependencyNode>()
directDependencies.forEach { dep ->
val coordinate = "${dep.groupId}:${dep.artifactId}:${dep.version}"
nodeMap[coordinate]?.let { rootNodes.add(it) }
}
val transitiveDeps = allDependencies.filterNot { dep ->
directCoordinates.contains("${dep.groupId}:${dep.artifactId}:${dep.version}")
}
transitiveDeps.forEach { transitiv ->
val transitiveCoord = "${transitiv.groupId}:${transitiv.artifactId}:${transitiv.version}"
val transitiveNode = nodeMap[transitiveCoord] ?: return@forEach
directDependencies.forEach { direct ->
val directCoord = "${direct.groupId}:${direct.artifactId}:${direct.version}"
nodeMap[directCoord]?.addChild(transitiveNode)
}
}
return DependencyGraph(rootNodes)
}
}