# `ArchTest.Collector`
[🔗](https://github.com/yoavgeva/arch_test/blob/v0.3.1/lib/arch_test/collector.ex#L1)

Builds a module dependency graph using OTP's `:xref` tool.

The graph is a map of `%{caller_module => [callee_module]}` derived from
BEAM files. Results are cached in `:persistent_term` for the duration of
the test run.

No external dependencies are required — `:xref` and `:beam_lib` are
standard OTP applications.

# `graph`

```elixir
@type graph() :: %{required(module()) =&gt; [module()]}
```

# `all_modules`

```elixir
@spec all_modules(graph()) :: [module()]
```

Returns all modules known in the graph.

# `build_graph`

```elixir
@spec build_graph(
  atom() | :all,
  keyword()
) :: graph()
```

Returns the dependency graph for the given OTP application (or all loaded
modules if `app` is `:all`).

The graph is cached in `:persistent_term` after the first call.
Pass `force: true` to bypass the cache and rebuild.

## Options
- `:app` — OTP app atom or `:all` (default `:all`)
- `:apps` — list of OTP apps to inspect together
- `:paths` — BEAM ebin path or paths to inspect instead of an app
- `:include` — list of module glob patterns to keep
- `:exclude` — list of module glob patterns to remove
- `:force` — boolean, bypass cache (default `false`)

# `build_graph_from_path`

```elixir
@spec build_graph_from_path(
  String.t(),
  keyword()
) :: graph()
```

Builds a dependency graph from a specific BEAM directory path.

Useful for testing against a pre-compiled application without registering
it as an OTP application.

## Options
- `:force` — boolean, bypass cache (default `false`)

## Example

    ebin = "test/support/fixture_app/_build/dev/lib/fixture_app/ebin"
    graph = ArchTest.Collector.build_graph_from_path(ebin)

# `build_graph_from_paths`

```elixir
@spec build_graph_from_paths(
  String.t() | [String.t()],
  keyword()
) :: graph()
```

Builds a dependency graph from one or more BEAM directory paths.

Options:
- `:force` — bypass cache
- `:include` — list of module glob patterns to keep
- `:exclude` — list of module glob patterns to remove

# `calls`

```elixir
@spec calls(
  atom() | :all,
  keyword()
) :: [ArchTest.Call.t()]
```

Returns function-level call metadata for the given OTP application.

Requires BEAM files compiled with debug info. Missing debug info yields an
empty call list for that module rather than an exception.

Accepts the same scope and filter options as `build_graph/2`: `:apps`,
`:paths`, `:include`, `:exclude`, and `:force`. Compiler-generated metadata
calls are omitted. Remote captures and static `apply/3` calls are reported
when debug information exposes them.

# `calls_from_path`

```elixir
@spec calls_from_path(
  String.t(),
  keyword()
) :: [ArchTest.Call.t()]
```

Returns function-level call metadata from a BEAM directory path.

# `calls_from_paths`

```elixir
@spec calls_from_paths(
  String.t() | [String.t()],
  keyword()
) :: [ArchTest.Call.t()]
```

Returns function-level call metadata from one or more BEAM directory paths.

Options:
- `:force` — bypass cache
- `:include` — list of caller/callee module glob patterns to keep
- `:exclude` — list of caller/callee module glob patterns to remove

# `cycles`

```elixir
@spec cycles(graph()) :: [[module()]]
```

Returns all dependency cycles found in the given modules.

Each cycle is a list of modules forming a circular dependency chain.

# `dependencies_of`

```elixir
@spec dependencies_of(graph(), module()) :: [module()]
```

Returns the direct dependencies of `module` (modules it calls).

# `dependents_of`

```elixir
@spec dependents_of(graph(), module()) :: [module()]
```

Returns all modules that directly depend on `module` (callers of it).

# `transitive_dependencies_of`

```elixir
@spec transitive_dependencies_of(graph(), module(), pos_integer() | :infinity) :: [
  module()
]
```

Computes transitive dependencies of `module` up to `max_depth` hops
(default: unlimited).

---

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