npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gleam-type-graph

v0.2.0

Published

Static type-graph extractor for Gleam codebases. Maps types to the functions that transform them, rendered as mermaid / graphviz / json / interactive HTML.

Downloads

296

Readme

gleam-type-graph

Statically extract a directed graph of types and the functions that transform them from a Gleam codebase.

  • Nodes = types (Order, OrderSnapshot, Json, String, ...)
  • Edges = functions that turn one type into another (order.snapshot, json.to_string, ...)

Read the resulting graph as: to convert an X into a Y, here's the path of functions to compose.

Quick start

cd /your/gleam/project
npx gleam-type-graph --open

That's it. From inside any Gleam project (or any subdirectory of one), this walks up to find your gleam.toml, scans src/, renders an interactive mermaid diagram, and opens it in your browser.

No gleam toolchain required on your machine — the tool ships pre-compiled to JavaScript.

Other invocations

# Interactive cytoscape view: compound modules with click-to-expand,
# magnetic drag, focus-narrowing on type click, source-jump on function
# click, sticky right-click menu, undo (Ctrl-Z).
npx gleam-type-graph --format cytoscape --open

# Mermaid to stdout (good for piping into a markdown file)
npx gleam-type-graph

# Sorted plain-text edge list, easiest to grep / diff
npx gleam-type-graph --format text

# Drop edges between stdlib / primitive types — show just the domain core
npx gleam-type-graph --domain-only --open

# Graphviz dot (for `dot -Tpng -o graph.png`)
npx gleam-type-graph --format=dot > graph.dot
dot -Tpng graph.dot -o graph.png

# JSON for downstream tooling
npx gleam-type-graph --format=json > graph.json

# Light-theme HTML
npx gleam-type-graph --open --theme light

# Module-level overview: collapse every type/function into its owning
# module bubble so you see only how modules connect.
npx gleam-type-graph --collapse modules --open

# Point at a specific src/ tree
npx gleam-type-graph /some/other/project/src --open

Cytoscape view interactions

  • Click a type node → focus its 1-hop neighborhood. Click the same node again → also resurrect previously-hidden neighbors. Click a third time → reset.
  • Click a function node or labelled edge → opens its source (hex docs, or GitHub source for @internal items).
  • Click a collapsed module → expand it. Double-click an expanded module → collapse.
  • Click an expanded module's empty area → focus on the module's full neighborhood (the module + every node any of its children connects to).
  • Right-click anything → sticky menu: focus, expand/collapse, open source, hide.
  • Drag a node → connected neighbors follow (magnetic spring-ish feel). Toggle off with the freeze drag button.
  • Hover anything → triple-size highlight of involved nodes; everything else dims.
  • Ctrl-Z / Cmd-Z → undo focus/hide actions.

Example output

Given a project with Order, OrderSnapshot, Money, CustomerId, and a JSON encoder:

$ npx gleam-type-graph --format text
Int                  --[money.from_cents]--> money.Money
String               --[customer.new_id]--> customer.CustomerId
String               --[order.new_id]--> order.OrderId
money.Money          --[money.to_cents]--> Int
money.Money          --[money.to_json]--> json.Json
order.Order          --[order.order_to_json]--> json.Json
order.Order          --[order.snapshot]--> order.OrderSnapshot
order.OrderSnapshot  --[order.restore]--> order.Order

Two seconds of reading and you know:

  • String → OrderId and String → CustomerId are smart constructors
  • Order ↔ OrderSnapshot is a symmetric snapshot/restore pair
  • The path to put an Order on disk is Order → snapshot → OrderSnapshot → order_to_json → Json → ...

With --domain-only the same project collapses to just the user-defined core:

$ npx gleam-type-graph --format text --domain-only
order.Order          --[order.snapshot]--> order.OrderSnapshot
order.OrderSnapshot  --[order.restore]--> order.Order

When a function takes multiple typed parameters — say make_order(c: CustomerId, id: OrderId, total: Money) -> Order — the output groups the inputs to make the and-relation visible:

{customer.CustomerId, money.Money, order.OrderId} --[order.make_order]--> order.Order

In mermaid / dot this renders as a single fan-in node that all inputs flow into and the return type flows out of, so a reader can see at a glance that all three inputs are required.

CLI

Usage: gleam-type-graph [PATH] [OPTIONS]

Arguments:
  PATH                Directory to scan. If omitted, walks up from cwd
                      looking for gleam.toml and uses its src/.

Options:
  --format <FMT>      Output format: mermaid|dot|json|text|html|cytoscape
                      (default: html when --open, mermaid otherwise)
  --open              Render to a temp file and open in your browser
  --collapse <MODE>   Collapse the graph. Modes: modules
  --theme <NAME>      Color palette for HTML: dark (default) or light
  --include <PAT>     Module substring to include (repeatable)
  --exclude <PAT>     Module substring to exclude (repeatable)
  --domain-only       Drop edges touching stdlib / primitives
  -h, --help          Show this help

--include and --exclude match the substring against either endpoint module or the function label, so --include order keeps every edge involving the order module on either side.

How edges are derived

For a single-arg public function module.fn(p: T) -> R:

  • One edge T → R, labelled module.fn

For a multi-arg public function module.fn(p1: T1, p2: T2, ...) -> R:

  • A synthetic fan-in node module.fn() is introduced (rendered as a stadium in mermaid, an ellipse in dot, {...} braces in text).
  • Each typed parameter type flows into the fan-in node; the return type flows out. Reads as: "you need T1 and T2 and ... to produce R."
  • Duplicate input types are deduped, so merge(Order, Order, String) -> Order shows {Order, String} flowing into the fan-in, with Order also flowing out as a self-cycle.

Across both cases:

  • Result(T, E) returns are unwrapped to T (the success path is the transformation; the error type is metadata)
  • Option(T) returns are unwrapped to T
  • List(T) → List(S) is unwrapped to T → S (container-preserving)

Type references are resolved through the module's import table:

  • import app/order.{type OrderSnapshot}OrderSnapshot resolves to app/order.OrderSnapshot
  • import app/order as oo.OrderSnapshot resolves to app/order.OrderSnapshot
  • import app/orderorder.OrderSnapshot resolves the same way

Unresolvable qualified references show up as Unknown(module.Type) rather than crashing the run.

Parameterized types

A Qualified or Primitive TypeRef can carry parameters. The identity rule:

  • If every parameter is a type variable (Generic), the node collapses to its bare form: List(a) and List(b) and bare List are all the same node.
  • If any parameter is concrete, the parameterised form is the node identity: List(Order) and List(Customer) are distinct nodes, distinct from bare List.

So list.map(List(a), fn(a) -> b) -> List(b) connects ListFnList, but string.concat(List(String)) -> String shows up as a distinct List(String) → String edge, and any function returning List(Order) lives in its own corner of the graph.

Limitations (MVP scope)

  • Only src/ is parsed. test/ and build/packages/<dep>/src/ aren't crawled yet.
  • Only public functions are included.
  • Type aliases are treated as opaque — pub type UserId = String shows up as UserId, not String (short alias bodies are inlined under the alias name in the HTML / cytoscape views).

Tracked next steps live in docs/todos.md and docs/orbital-layout.md.

Development

gleam build                                # Compile (requires Gleam ≥ 1.x)
gleam test                                 # Run the test suite
./bin/gleam-type-graph.mjs ./src           # Run the local binary
npm pack && npx ./gleam-type-graph-*.tgz   # Smoke-test the npm package

The pipeline is small enough to read top-to-bottom:

src/type_graph.gleam              # CLI + pipeline
src/type_graph/parse.gleam        # walk src/, parse with `glance`
src/type_graph/extract.gleam      # AST → edges, with import resolution
src/type_graph/graph.gleam        # core TypeRef + Edge model
src/type_graph/filter.gleam       # primitive / stdlib / pattern filters
src/type_graph/collapse.gleam     # graph-level collapse (modules)
src/type_graph/theme.gleam        # color palettes (dark / light)
src/type_graph/render.gleam       # mermaid | dot | json | text | html | cytoscape
src/type_graph/sys.gleam          # tmp file + open-in-browser
src/type_graph_ffi.mjs            # JS FFI for sys
bin/gleam-type-graph.mjs          # npm bin shim

License

MIT.