NpmIntegration.kt
package com.depanalyzer.parser.npm
import com.depanalyzer.core.graph.DependencyNode
import com.depanalyzer.parser.Ecosystem
import com.depanalyzer.parser.ParsedDependency
import java.io.File
object NpmIntegration {
private val packageParser = NpmPackageParser()
private val lockParser = NpmLockParser()
fun analyzeNpmProject(projectDir: File): Pair<List<ParsedDependency>, List<DependencyNode>> {
val packageJsonFile = File(projectDir, "package.json")
val directDeclared = packageParser.parse(packageJsonFile)
val directPackageNames = directDeclared.map { it.packageName }.toSet()
val lockFile = File(projectDir, "package-lock.json")
val roots = lockParser.parse(lockFile, directPackageNames)
val dependencies = if (roots.isNotEmpty()) {
flatten(roots)
} else {
directDeclared.map {
ParsedDependency(
groupId = it.groupId,
artifactId = it.artifactId,
version = it.version,
scope = it.scope,
section = it.section,
ecosystem = Ecosystem.NPM
)
}
}
val rootNodes = if (roots.isNotEmpty()) {
roots
} else {
directDeclared.map { dep ->
DependencyNode(
id = "${dep.groupId}:${dep.artifactId}:${dep.version}",
groupId = dep.groupId,
artifactId = dep.artifactId,
version = dep.version ?: "unknown",
scope = dep.scope,
ecosystem = Ecosystem.NPM
)
}
}
return Pair(dependencies, rootNodes)
}
private fun flatten(nodes: List<DependencyNode>): List<ParsedDependency> {
val result = mutableListOf<ParsedDependency>()
fun visit(node: DependencyNode) {
result += ParsedDependency(
groupId = node.groupId,
artifactId = node.artifactId,
version = node.version,
scope = node.scope ?: "dependencies",
section = com.depanalyzer.parser.DependencySection.DEPENDENCIES,
ecosystem = Ecosystem.NPM
)
node.children.forEach(::visit)
}
nodes.forEach(::visit)
return result
}
}