Packages

Clarity is an interactive introspection and visualization tool for Elixir projects, providing navigable graphs and diagrams for frameworks like Ash, Phoenix, and Ecto.

Current section

Files

Jump to
clarity lib clarity.ex
Raw

lib/clarity.ex

readme_path = Path.join(__DIR__, "../README.md")
readme_content =
readme_path
|> File.read!()
|> String.replace(~r/<!-- ex_doc_ignore_start -->.*?<!-- ex_doc_ignore_end -->/s, "")
defmodule Clarity do
@moduledoc """
#{readme_content}
"""
use Agent
@external_resource readme_path
@type tree() :: %{
node: :digraph.vertex(),
children: %{
optional(:digraph.label()) => [tree()]
}
}
@type t() :: %__MODULE__{
graph: :digraph.graph(),
root: Clarity.Vertex.t(),
tree: tree(),
vertices: %{String.t() => Clarity.Vertex.t()}
}
@enforce_keys [:graph, :root, :tree, :vertices]
defstruct [:graph, :root, :tree, :vertices]
@doc false
@spec start_link(opts :: GenServer.options()) :: Agent.on_start()
def start_link(opts \\ []) do
opts = Keyword.put_new(opts, :name, __MODULE__)
Agent.start_link(fn -> nil end, opts)
end
@doc """
Gets the current state of the clarity.
"""
@spec get(name :: Agent.agent()) :: t()
def get(name \\ __MODULE__) do
Agent.get_and_update(
name,
fn
nil ->
state = introspect()
{state, state}
value ->
{value, value}
end,
to_timeout(minute: 1)
)
end
@spec update(name :: Agent.agent()) :: t()
def update(name \\ __MODULE__) do
Agent.get_and_update(name, fn _state ->
clarity = introspect()
{clarity, clarity}
end)
end
@doc """
Builds a new clarity by introspecting the current state of the system.
"""
@spec introspect() :: t()
def introspect do
graph = Clarity.Introspector.introspect(:digraph.new())
vertices =
for vertex <- :digraph.vertices(graph),
into: %{},
do: {Clarity.Vertex.unique_id(vertex), vertex}
root_vertex = Map.fetch!(vertices, "root")
tree = Clarity.GraphUtil.graph_to_tree(graph, root_vertex)
%__MODULE__{graph: graph, root: root_vertex, tree: tree, vertices: vertices}
end
end