What is @snyk/dep-graph?
@snyk/dep-graph is an npm package that provides tools for creating, manipulating, and analyzing dependency graphs. It is particularly useful for understanding the structure of dependencies in a project, identifying vulnerabilities, and optimizing dependency management.
What are @snyk/dep-graph's main functionalities?
Creating a Dependency Graph
This feature allows you to create a dependency graph by adding nodes and dependencies between them. The code sample demonstrates how to create a simple dependency graph with a root package and two dependencies.
const { DepGraph } = require('@snyk/dep-graph');
const depGraph = new DepGraph();
depGraph.addNode('root', { name: 'root-package', version: '1.0.0' });
depGraph.addNode('dep1', { name: 'dependency1', version: '1.0.0' });
depGraph.addNode('dep2', { name: 'dependency2', version: '2.0.0' });
depGraph.addDependency('root', 'dep1');
depGraph.addDependency('root', 'dep2');
console.log(depGraph.toJSON());
Analyzing a Dependency Graph
This feature allows you to analyze the dependency graph by retrieving all the packages in the graph. The code sample demonstrates how to get all the dependencies of the root package.
const { DepGraph } = require('@snyk/dep-graph');
const depGraph = new DepGraph();
depGraph.addNode('root', { name: 'root-package', version: '1.0.0' });
depGraph.addNode('dep1', { name: 'dependency1', version: '1.0.0' });
depGraph.addNode('dep2', { name: 'dependency2', version: '2.0.0' });
depGraph.addDependency('root', 'dep1');
depGraph.addDependency('root', 'dep2');
const allDeps = depGraph.getDepPkgs();
console.log(allDeps);
Visualizing a Dependency Graph
This feature allows you to visualize the dependency graph using Graphviz. The code sample demonstrates how to render the dependency graph to a Graphviz format.
const { DepGraph } = require('@snyk/dep-graph');
const { renderGraph } = require('@snyk/dep-graph/dist/graphviz');
const depGraph = new DepGraph();
depGraph.addNode('root', { name: 'root-package', version: '1.0.0' });
depGraph.addNode('dep1', { name: 'dependency1', version: '1.0.0' });
depGraph.addNode('dep2', { name: 'dependency2', version: '2.0.0' });
depGraph.addDependency('root', 'dep1');
depGraph.addDependency('root', 'dep2');
const graphviz = renderGraph(depGraph);
console.log(graphviz);
Other packages similar to @snyk/dep-graph
dependency-tree
The 'dependency-tree' package helps in generating a dependency tree from a module. It is useful for analyzing the structure of dependencies in a project. Compared to @snyk/dep-graph, it focuses more on generating a tree structure rather than a graph, and it is less feature-rich in terms of manipulation and visualization.
madge
Madge is a tool that can create visualizations of module dependencies, find circular dependencies, and more. It is similar to @snyk/dep-graph in terms of visualization capabilities but also includes additional features like circular dependency detection. However, it is more focused on JavaScript and TypeScript projects.
npmgraph
Npmgraph is a tool for visualizing npm dependencies. It provides a web-based interface to explore the dependency graph of npm packages. While it offers visualization similar to @snyk/dep-graph, it is more of a standalone tool rather than a library for programmatic manipulation and analysis.
Snyk helps you find, fix and monitor for known vulnerabilities in your dependencies, both on an ad hoc basis and as part of your CI (Build) system.
Snyk dep-graph
This library provides a time and space efficient representation of a resolved package dependency graph, which can be used to construct, query and de/serialize dep-graphs.
The Graph
A directed graph, where a node represents a package instance and an edge from node foo
to node bar
means bar
is a dependency of foo
.
A package (name@version
) can have several different nodes (i.e. instances) in the graph. This flexibility is useful for some ecosystems, for example:
- in
npm
due to conflict-resolutions by duplication. e.g. try to npm i tap@5.7
and then run npm ls
and look for strip-ansi@3.0.1
. You'll see that in some instances it depends on ansi-regex@2.0.0
while in others on ansi-regex@2.1.1
. - in
maven
due to "exclusion" rules. A dependency foo
can be declared in the pom.xml
such that some of it's sub-dependencies are excluded via the <exclusions>
tag. If the same dependency is required elsewhere without (or with different) exclusions then foo
can appear in the tree with different sub-trees.
This can also be used to break cycles in the graph, e.g.:
instead of:
A -> B -> C -> A
can have:
A -> B -> C -> A'
API Reference
DepGraph
Interface
A dep-graph instance can be queried using the following interface:
export interface DepGraph {
readonly pkgManager: {
name: string;
version?: string;
repositories?: Array<{
alias: string;
}>;
};
readonly rootPkg: {
name: string;
version?: string;
};
getPkgs(): Array<{
name: string;
version?: string;
}>;
getDepPkgs(): Array<{
name: string;
version?: string;
}>;
pkgPathsToRoot(pkg: Pkg): Array<Array<{
name: string;
version?: string;
}>>;
directDepsLeadingTo(pkg: Pkg): Array<{
name: string;
version?: string;
}>;
countPathsToRoot(pkg: Pkg): number;
toJSON(): DepGraphData;
equals(other: DepGraph, options?: { compareRoot?: boolean }): boolean;
}
DepGraphData
A dep-graph can be serialised into the following format:
export interface DepGraphData {
schemaVersion: string;
pkgManager: {
name: string;
version?: string;
repositories?: Array<{
alias: string;
}>;
};
pkgs: Array<{
id: string;
info: {
name: string;
version?: string;
};
}>;
graph: {
rootNodeId: string;
nodes: Array<{
nodeId: string;
pkgId: string;
info?: {
versionProvenance?: {
type: string;
location: string;
property?: {
name: string;
};
},
labels?: {
[key: string]: string | undefined;
};
};
deps: Array<{
nodeId: string;
}>;
}>;
};
}
createFromJSON
DepGraphData
can be used to construct a DepGraph
instance using createFromJSON
DepGraphBuilder
DepGraphBuilder
is used to create new DepGraph
instances by adding packages and their connections.
public constructor(pkgManager: types.PkgManager, rootPkg?: types.PkgInfo)
public addPkgNode(pkgInfo: types.PkgInfo, nodeId: string, nodeInfo?: types.NodeInfo)
public connectDep(parentNodeId: string, depNodeId: string)
public build(): types.DepGraph
The legacy
module
A DepTree
is a legacy structure used by the Snyk CLI to represent dependency trees. Conversion functions in the legacy
module ease the gradual migration of code that relies on the legacy format.
Legacy DepTree
A DepTree
is a recursive structure that is quite similar to the output of npm list --json
, and (omitting some details) looks like:
interface DepTree {
name: string;
version: string;
dependencies?: {
[depName: string]: DepTree
};
}
The legacy
conversion functions aim to maintain extra data that might be attached to the dep-tree and is dependant upon in code that wasn't yet updated to use solely dep-graphs:
targetOS
which exists on tree roots for Docker scansversionProvenance
which might exist on the nodes of maven trees, storing information about the source manifest that caused the specfic version to be resolved