rust-relations-explorer 0.1.0

Explore relationships in Rust codebases: build a knowledge graph and run queries (connected files, function usage, cycles, paths, hubs, module centrality, trait impls).
Documentation

πŸ› οΈ CI and Coverage

  • CI workflow: .github/workflows/ci.yml
    • Runs format check, clippy (deny warnings), build, tests, docs.
  • Coverage workflow: .github/workflows/coverage.yml
    • Installs cargo-tarpaulin and uploads lcov.info.

Run coverage locally:

cargo install cargo-tarpaulin --locked
cargo tarpaulin --engine llvm --out Lcov --timeout 600 --workspace --exclude-files benches/*,examples/*,target/*

πŸ“š rust-relations-explorer β€” Rust Knowledge Graph System

Rust Edition Language Status Coverage CLI

A fast, lightweight tool to parse Rust projects into a knowledge graph and run insightful queries over code structure. Generate DOT/SVG visualizations, persist graphs to JSON, and explore code relationships via a clean CLI. ✨

✨ Features

  • βœ… Graph builder from source (KnowledgeGraph::build_from_directory)
  • βœ… Incremental builds with cache (reuse unchanged files; --no-cache, --rebuild)
  • βœ… Relationship analysis (imports, heuristics for calls)
  • βœ… JSON persistence (save/load)
  • βœ… DOT generation with styling (rankdir, splines, rounded, theme, clusters, legend)
  • βœ… SVG enhancement (interactive highlights, clickable nodes)
  • βœ… CLI powered by clap
  • βœ… Queries
    • connected-files β€” files related to a target file
    • item-info β€” show item metadata, code, and relations by ItemId
    • function-usage β€” callers/callees of a function
    • cycles β€” detect file-level cycles
    • path β€” shortest path between two files
    • hubs β€” top-N files by degree centrality (in/out/total)
    • module-centrality β€” top-N modules (directories) by degree centrality
    • trait-impls β€” list types and files implementing a given trait
  • 🚧 Pretty table output for terminal
  • 🚧 Advanced analyses and config system

🧰 Installation

Build from source:

# from repo root
cargo build --release

Run checks and tests:

cargo check
cargo test

πŸš€ Usage

Build a graph from a Rust project and export artifacts:

# Build and save artifacts (uses cache by default)
rust-relations-explorer build --path . \
  --json graph.json \
  --dot graph.dot \
  --svg graph.svg \
  --dot-rankdir LR --dot-splines curved --dot-rounded on \
  --dot-theme light --dot-clusters on --dot-legend on

# Force parsing all files without using cache
rust-relations-explorer build --path . --no-cache

# Rebuild cache from scratch (clears previous cache file)
rust-relations-explorer build --path . --rebuild

# Apply options from a configuration file
rust-relations-explorer build --path . --config rust-relations-explorer.toml --svg graph.svg

# Bypass ignore rules (include files even if ignored)
rust-relations-explorer build --path . --no-ignore

Run queries (builds the graph on-the-fly unless --graph is provided):

# Connected files for a given file
rust-relations-explorer query connected-files --path . --file src/lib.rs --format text

# Show detailed info for an item by ItemId (text or JSON)
rust-relations-explorer query item-info --path . --item-id fn:createIcons:6 --format text
rust-relations-explorer query item-info --path . --item-id fn:createIcons:6 --format json

# Function usage: who calls `foo` (callers) or who does `foo` call (callees)
rust-relations-explorer query function-usage --path . --function foo --direction callers --format json

# Detect cycles
rust-relations-explorer query cycles --path . --format text

# Shortest path between files
rust-relations-explorer query path --path . --from src/a.rs --to src/b.rs --format text

# Hubs: top-N by degree centrality
rust-relations-explorer query hubs --path . --metric total --top 10 --format text

# Module centrality: top-N modules by degree
rust-relations-explorer query module-centrality --path . --metric total --top 10 --format text

# Trait implementations for Display
rust-relations-explorer query trait-impls --path . --trait Display --format json

# Any query can also bypass ignore rules when building on-the-fly
rust-relations-explorer query cycles --path . --no-ignore --format text

Use a prebuilt graph for faster queries:

rust-relations-explorer query hubs --graph graph.json --metric in --top 5 --format json

πŸ“Ž Examples

Run the included examples to see the library API in action:

# Build all examples
cargo build --examples

# Basic graph build and stats
cargo run --example basic_build

# Print connected files to a target (defaults to src/lib.rs if present)
cargo run --example query_connected

Example sources:

  • examples/basic_build.rs
  • examples/query_connected.rs

🧭 Typical Workflows

  • Build and save graph to JSON

    rust-relations-explorer build --path . --json graph.json
    rust-relations-explorer query hubs --graph graph.json --metric total --top 10 --format json
    
  • Programmatic DOT/SVG generation

    cargo run --example generate_svg
    # Produces graph.dot and graph.svg
    
    • Requires Graphviz dot executable on PATH. Install via your OS package manager.
    • Options like clusters, theme, rankdir, splines are in visualization::DotOptions and visualization::SvgOptions.
  • Bypass ignore rules for one-off analyses

    rust-relations-explorer build --path . --no-ignore --svg graph.svg
    
  • Save and load graph JSON

    # Save
    rust-relations-explorer build --path . --json graph.json
    
    # Query using saved graph (faster)
    rust-relations-explorer query hubs --graph graph.json --metric in --top 5 --format json
    
  • Programmatic save/load JSON

    use rust_relations_explorer::graph::KnowledgeGraph;
    use rust_relations_explorer::utils::cache::CacheMode;
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let root = std::path::Path::new(".");
        let graph = KnowledgeGraph::build_from_directory_with_cache_opts(root, CacheMode::Use, false)?;
        // Save
        let json = serde_json::to_string_pretty(&graph)?;
        std::fs::write("graph.json", json)?;
        // Load later
        let loaded: KnowledgeGraph = serde_json::from_str(&std::fs::read_to_string("graph.json")?)?;
        println!("Loaded files: {}", loaded.files.len());
        Ok(())
    }
    

    Note: KnowledgeGraph implements serde::Serialize/Deserialize.

🧩 Mapping: CLI queries ↔ API

  • query connected-files β†’ query::ConnectedFilesQuery
  • query item-info --item-id ID β†’ query::ItemInfoQuery
  • query function-usage --direction callers|callees β†’ query::FunctionUsageQuery::{callers,callees}
  • query cycles β†’ query::CycleDetectionQuery
  • query path --from A --to B β†’ query::ShortestPathQuery::new(A,B)
  • query hubs --metric in|out|total β†’ query::HubsQuery with CentralityMetric
  • query module-centrality β†’ query::ModuleCentralityQuery
  • query trait-impls --trait NAME β†’ query::TraitImplsQuery::new(NAME)

πŸ› οΈ Troubleshooting

  • Graphviz dot not found
    • Ensure Graphviz is installed and dot is on PATH. The generate_svg example will print a hint on failure.
  • Empty graph
    • Check ignore rules. Try --no-ignore to include ignored files. See Ignore Patterns section.
  • Slow runs on large repos
    • Use saved JSON and query with --graph graph.json. Ensure cache (default) is enabled.

🧱 Design Overview

  • Graph model
    • Nodes: items parsed from Rust files (functions, structs, enums, traits, impls, etc.). See src/graph/mod.rs.
    • Edges: relationships between items (uses, implements, contains, extends, calls). Projectable to file-level.
  • File discovery & ignores
    • File walking in src/utils/mod.rs honors .gitignore, global ignores, nested ignores. Explicit override via --no-ignore.
  • Visualization
    • DOT via visualization::DotGenerator; SVG via visualization::SvgGenerator using Graphviz dot.

❓ FAQ

  • How do item-level relationships map to files?
    • Each relationship stores from_item/to_item (item IDs). For file-level analyses (e.g., connected files), items are mapped to their defining file and deduplicated.
  • Does the CLI modify environment variables for ignores?
    • No. Ignoring is controlled explicitly via flags. Legacy env is still read by the library for backwards compatibility but not set by the CLI.

πŸ—ΊοΈ Roadmap

See plan-tasks.md for full project plan, phases, and task status.

  • Core queries: βœ…
  • Centrality/hubs: βœ…
  • Table output: 🚧
  • Config file and ignores: 🚧
  • Performance (parallelism, caching, incremental): 🚧

🏁 Benchmarks

  • Run all benches

    cargo bench
    
  • Reports

    • Criterion stores results under target/criterion/.
    • With html_reports enabled, open target/criterion/report/index.html for an overview.
  • What’s measured

    • Build performance by cache mode: benches/build_graph.rs.
    • Query performance (connected files, hubs, shortest path): benches/queries.rs.
  • Notes

    • Benches use criterion 0.5. Setup occurs outside iter and results are black_boxed.

πŸ“Š Sample Results (local, 2025-08-18)

  • Build graph (lower is better)

    • rebuild: [6.86 ms, 6.98 ms, 7.11 ms]
    • use_cache: [4.42 ms, 4.46 ms, 4.52 ms]
    • ignore_cache: [7.06 ms, 7.20 ms, 7.35 ms]
  • Queries (lower is better)

    • connected_files: [55.65 Β΅s, 57.48 Β΅s, 59.75 Β΅s]
    • hubs (top10 total): [43.09 Β΅s, 44.77 Β΅s, 47.06 Β΅s]
    • shortest_path (aβ†’b): [42.73 Β΅s, 43.17 Β΅s, 43.64 Β΅s]

πŸ“¦ 10k synthetic project (release)

  • Dataset: generated via examples/generate_synthetic.rs (10,000 files)
  • Default (use cache), warm run: 0.29s elapsed, ~103 MB max RSS
  • No-cache: 0.85s elapsed, ~100 MB max RSS
  • Notes:
    • First invocation via cargo run includes compilation overhead; use the built binary for timing.
    • Results are for a simple synthetic workload (flat modules, tiny files). Real projects will vary.

Notes:

  • These are Criterion min/mean/max for 100 samples on the current machine and can vary across runs and environments.
  • Please record your machine specs (CPU model, cores, RAM, OS) alongside results for context.

πŸ–₯️ Machine specs (example, replace with yours)

  • CPU: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz (6 cores / 12 threads)
  • RAM: 32 GB
  • OS: Ubuntu 22.04 x86_64
  • Rust: nightly toolchain (see rust-toolchain.toml or rustup show)

πŸ”¬ Validate 10k-file Performance (Phase 4)

Use the synthetic generator example to create a large project and measure performance.

  1. Generate N files (e.g., 10,000):
cargo run --example generate_synthetic -- /tmp/kr_synth 10000
  1. Measure build time (Use cache by default):
# Build release binary once
cargo build --release

# Use the built binary to avoid compile overhead
/usr/bin/time -v target/release/rust-relations-explorer build --path /tmp/kr_synth --json /tmp/kr_graph.json
  1. Compare cache modes:
/usr/bin/time -v target/release/rust-relations-explorer build --path /tmp/kr_synth --json /tmp/kr_graph.json --rebuild
/usr/bin/time -v target/release/rust-relations-explorer build --path /tmp/kr_synth --json /tmp/kr_graph.json --no-cache
  1. Optional memory profiling:
/usr/bin/time -v target/release/rust-relations-explorer build --path /tmp/kr_synth --json /tmp/kr_graph.json
# or use heaptrack if available

Record the elapsed wall time and peak memory, and confirm the 10k-in-30s target.

πŸ§ͺ CLI Quick Examples

Build graph with DOT and SVG outputs:

cargo run -- build --path . --json graph.json --dot graph.dot --svg graph.svg

Connected files for a target file (JSON):

cargo run -- query connected-files --path . --file src/lib.rs --format json

Function usage: callers of function foo (JSON):

cargo run -- query function-usage --path . --function foo --direction callers --format json

Shortest path between two files (JSON):

cargo run -- query path --path . --from src/a.rs --to src/b.rs --format json

Top hubs by total degree (top 10):

cargo run -- query hubs --path . --metric total --top 10 --format text

Top modules (directories) by in-degree (top 5):

cargo run -- query module-centrality --path . --metric in --top 5 --format text

Types implementing a trait (e.g., Display):

cargo run -- query trait-impls --path . --trait Display --format json

🧠 Caching Modes

  • Default (Use) β€” reuse unchanged files from .knowledge_cache.json and only reparse changed/added files.
  • --no-cache (Ignore) β€” do not reuse cache; parse all files, then write a fresh cache at end.
  • --rebuild (Rebuild) β€” remove existing cache file first, then parse all files and write a new cache.

Cache file location: .knowledge_cache.json at the project root passed to --path.

πŸ—‚οΈ Ignore Patterns

  • File discovery respects .gitignore and .ignore files. Parent directories are traversed, so nested ignore files apply.
  • Global git excludes are intentionally disabled for determinism.
  • This affects which .rs files are scanned and parsed by build and on-the-fly builds for query.

Determinism: The CLI now passes ignore behavior explicitly to the file walker. This removes reliance on ambient environment state during normal operation.

Examples:

# src/.ignore (or .gitignore)
ignored.rs
# Nested ignore (src/a/.ignore)
skip.rs
# Negation pattern (src/.gitignore)
*.rs
!keep.rs

Bypass ignores (use with care):

# Preferred: CLI flag (explicit)
rust-relations-explorer build --path . --no-ignore

# Optional: environment variable (legacy/compat)
# Still supported, but not required since the CLI now passes the flag directly.
KNOWLEDGE_RS_NO_IGNORE=1 rust-relations-explorer build --path .

βš™οΈ Configuration

You can provide a TOML config with --config <path> for both build and all query subcommands.

  • Precedence:
    • CLI flags override binary defaults.
    • Config values are applied on top of CLI defaults to provide convenient project-wide settings (as implemented, config values for DOT/SVG and query format will be applied even if CLI uses defaulted values).

Example rust-relations-explorer.toml:

[dot]
clusters = true
legend = false
theme = "dark"      # "light" | "dark"
rankdir = "TB"      # "LR" | "TB"
splines = "ortho"   # "curved" | "ortho" | "polyline"
rounded = true

[svg]
interactive = true

[query]
default_format = "json" # "text" | "json"

πŸ“Ž References

🀝 Contributing

Issues and PRs are welcome! Please run cargo fmt, cargo clippy, and cargo test before submitting.

πŸ“„ License

TBD