THIS IS A WORK IN PROGRESS!!! SEVERELY VIBECODED. NOT PRODUCTION READY. DO NOT TAKE ANY OF THIS CODE SERIOUSLY!
inverse excalidraw - go from code to graph visualization.
Rust Sparse CLI is a small Rust tool that parses a crate’s module imports starting from a given entrypoint, walks through local dependencies in a breadth-first search (BFS) fashion, and produces a module dependency graph in JSON format.
It’s designed for architecture visualization — showing how modules in a codebase are related via uses and contains relationships.
-
Start from the entrypoint
The user specifies:- The crate root folder
- The main entrypoint file (e.g.,
compiler.rs) - The maximum depth to traverse
-
Parse imports in the entrypoint
- Identify all local modules and functions imported in the file
- Ignore:
- Utility functions within the same file
- External crates (std or 3rd-party)
- Each discovered module is:
- Added as a node in the graph
- Added to the BFS processing queue
- Connected with a
usesedge from the current file
-
Breadth-First Search (BFS)
- Process files from the queue one at a time
- For each file:
- Parse its imports
- Add any new local modules to the queue
- Create edges in the graph:
uses= current file imports another filecontains= module file contains submodules (e.g.,mod.rscontainssubmodule.rs)
-
Stop conditions
- Queue is empty
- Current BFS depth exceeds the user’s
max_depth
-
Output
- All modules and edges are written to a
.jsonfile in this format:{ "nodes": [ { "id": 0, "kind": "module", "name": "main.rs", "file": "main.rs" } ], "edges": [ { "from": 0, "to": 1, "label": "uses" } ] }
- All modules and edges are written to a
For a simple project:
src/
├── main.rs → imports app, config, io, domain
├── app.rs → imports config, io::fs, io::net, domain::auth, domain::user
├── config.rs
├── io/
│ ├── mod.rs → contains fs, net
│ ├── fs.rs
│ └── net.rs → imports config
└── domain/
├── mod.rs → contains auth, user
├── auth.rs → imports user
└── user.rs
The graph output might look like:
{
"nodes": [
{ "id": 0, "kind": "module", "name": "main.rs", "file": "main.rs" },
{ "id": 1, "kind": "module", "name": "app.rs", "file": "app.rs" },
{ "id": 2, "kind": "module", "name": "config.rs", "file": "config.rs" },
{ "id": 3, "kind": "module", "name": "io/mod.rs", "file": "io/mod.rs" },
{ "id": 4, "kind": "module", "name": "domain/mod.rs", "file": "domain/mod.rs" },
{ "id": 5, "kind": "module", "name": "io/fs.rs", "file": "io/fs.rs" },
{ "id": 6, "kind": "module", "name": "io/net.rs", "file": "io/net.rs" },
{ "id": 7, "kind": "module", "name": "domain/auth.rs", "file": "domain/auth.rs" },
{ "id": 8, "kind": "module", "name": "domain/user.rs", "file": "domain/user.rs" }
],
"edges": [
{ "from": 0, "to": 1, "label": "contains" },
{ "from": 0, "to": 1, "label": "uses" },
{ "from": 0, "to": 2, "label": "contains" },
{ "from": 0, "to": 3, "label": "contains" },
{ "from": 0, "to": 4, "label": "contains" },
{ "from": 1, "to": 2, "label": "uses" },
{ "from": 1, "to": 5, "label": "uses" },
{ "from": 1, "to": 6, "label": "uses" },
{ "from": 1, "to": 7, "label": "uses" },
{ "from": 1, "to": 8, "label": "uses" },
{ "from": 3, "to": 5, "label": "contains" },
{ "from": 3, "to": 6, "label": "contains" },
{ "from": 4, "to": 7, "label": "contains" },
{ "from": 4, "to": 8, "label": "contains" },
{ "from": 6, "to": 2, "label": "uses" },
{ "from": 7, "to": 8, "label": "uses" }
]
}