NPM.Dependency.Graph (NPM v0.7.4)

Copy Markdown View Source

Dependency graph operations on the lockfile.

Provides adjacency-list based graph algorithms for analyzing the dependency structure: detecting cycles, computing fan-in/out, and finding orphans.

Summary

Functions

Build an adjacency list from the lockfile.

Detect circular dependencies. Returns list of cycle paths.

Compute fan-in (number of dependents) for each package.

Compute fan-out (number of dependencies) for each package.

Compute impact score — how many packages transitively depend on a package.

Find leaf packages (no dependencies).

Compute the maximum dependency depth from a package.

Reverse the graph so all edges point from dependencies to dependents.

Find root packages (not depended on by any other package).

Find the shortest path between two packages.

Compute the transitive closure — all reachable packages from a root.

Functions

adjacency_list(lockfile)

@spec adjacency_list(%{required(String.t()) => NPM.Lockfile.entry()}) :: %{
  required(String.t()) => [String.t()]
}

Build an adjacency list from the lockfile.

Returns %{name => [dep_name, ...]}.

cycles(adj)

@spec cycles(%{required(String.t()) => [String.t()]}) :: [[String.t()]]

Detect circular dependencies. Returns list of cycle paths.

Uses Erlang's :digraph_utils for reliable cycle detection.

fan_in(adj)

@spec fan_in(%{required(String.t()) => [String.t()]}) :: %{
  required(String.t()) => non_neg_integer()
}

Compute fan-in (number of dependents) for each package.

fan_out(adj)

@spec fan_out(%{required(String.t()) => [String.t()]}) :: %{
  required(String.t()) => non_neg_integer()
}

Compute fan-out (number of dependencies) for each package.

impact(adj, package)

@spec impact(%{required(String.t()) => [String.t()]}, String.t()) :: non_neg_integer()

Compute impact score — how many packages transitively depend on a package.

leaves(adj)

@spec leaves(%{required(String.t()) => [String.t()]}) :: [String.t()]

Find leaf packages (no dependencies).

max_depth(adj, root)

@spec max_depth(%{required(String.t()) => [String.t()]}, String.t()) ::
  non_neg_integer()

Compute the maximum dependency depth from a package.

reverse(adj)

@spec reverse(%{required(String.t()) => [String.t()]}) :: %{
  required(String.t()) => [String.t()]
}

Reverse the graph so all edges point from dependencies to dependents.

roots(adj)

@spec roots(%{required(String.t()) => [String.t()]}) :: [String.t()]

Find root packages (not depended on by any other package).

shortest_path(adj, from, to)

@spec shortest_path(%{required(String.t()) => [String.t()]}, String.t(), String.t()) ::
  [String.t()] | nil

Find the shortest path between two packages.

transitive_deps(adj, root)

@spec transitive_deps(%{required(String.t()) => [String.t()]}, String.t()) ::
  MapSet.t(String.t())

Compute the transitive closure — all reachable packages from a root.