# `NPM.Dependency.Graph`
[🔗](https://github.com/elixir-volt/npm_ex/blob/v0.7.4/lib/npm/dependency/graph.ex#L1)

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.

# `adjacency_list`

```elixir
@spec adjacency_list(%{required(String.t()) =&gt; NPM.Lockfile.entry()}) :: %{
  required(String.t()) =&gt; [String.t()]
}
```

Build an adjacency list from the lockfile.

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

# `cycles`

```elixir
@spec cycles(%{required(String.t()) =&gt; [String.t()]}) :: [[String.t()]]
```

Detect circular dependencies. Returns list of cycle paths.

Uses Erlang's `:digraph_utils` for reliable cycle detection.

# `fan_in`

```elixir
@spec fan_in(%{required(String.t()) =&gt; [String.t()]}) :: %{
  required(String.t()) =&gt; non_neg_integer()
}
```

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

# `fan_out`

```elixir
@spec fan_out(%{required(String.t()) =&gt; [String.t()]}) :: %{
  required(String.t()) =&gt; non_neg_integer()
}
```

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

# `impact`

```elixir
@spec impact(%{required(String.t()) =&gt; [String.t()]}, String.t()) :: non_neg_integer()
```

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

# `leaves`

```elixir
@spec leaves(%{required(String.t()) =&gt; [String.t()]}) :: [String.t()]
```

Find leaf packages (no dependencies).

# `max_depth`

```elixir
@spec max_depth(%{required(String.t()) =&gt; [String.t()]}, String.t()) ::
  non_neg_integer()
```

Compute the maximum dependency depth from a package.

# `reverse`

```elixir
@spec reverse(%{required(String.t()) =&gt; [String.t()]}) :: %{
  required(String.t()) =&gt; [String.t()]
}
```

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

# `roots`

```elixir
@spec roots(%{required(String.t()) =&gt; [String.t()]}) :: [String.t()]
```

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

# `shortest_path`

```elixir
@spec shortest_path(%{required(String.t()) =&gt; [String.t()]}, String.t(), String.t()) ::
  [String.t()] | nil
```

Find the shortest path between two packages.

# `transitive_deps`

```elixir
@spec transitive_deps(%{required(String.t()) =&gt; [String.t()]}, String.t()) ::
  MapSet.t(String.t())
```

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
