You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3.0 KiB
3.0 KiB
+++
title = "Add graph computation module (src/graph.rs)"
priority = 5
status = "done"
ticket_type = "feature"
dependencies = []
+++
Implement src/graph.rs — a module that builds a directed dependency graph from a flat list of tickets and provides the data structures needed by the ASCII renderer and JSON output.
Motivation
The nbd graph command (see CLI ticket) needs to traverse Ticket.dependencies edges to produce an ordered, tree-structured representation of the dependency DAG. This module isolates that logic from I/O and rendering.
Data structures
/// A node in the dependency graph.
pub struct GraphNode<'a> {
pub ticket: &'a Ticket,
/// Direct dependents (tickets that list this ticket as a dependency).
pub dependents: Vec<&'a str>,
/// Direct dependencies (tickets this ticket depends on).
pub dependencies: Vec<&'a str>,
}
/// A directed dependency graph built from a flat list of tickets.
pub struct TicketGraph<'a> {
nodes: IndexMap<&'a str, GraphNode<'a>>,
}
Functions to implement
TicketGraph::build(tickets: &[Ticket]) -> TicketGraph
- Constructs
nodesmap keyed by ticket ID. - Iterates
ticket.dependenciesto populate bothdependencies(forward) anddependents(reverse) edges. - IDs in
dependenciesthat do not correspond to a known ticket are silently ignored (dangling references are tolerated).
TicketGraph::roots(&self) -> Vec<&Ticket>
- Returns tickets with no dependencies (or whose dependencies are all outside the graph).
- Sorted by priority descending (same ordering as
list_tickets). - These become the starting points for the recursive ASCII tree renderer.
TicketGraph::subtree(&self, root_id: &str) -> Vec<&str>
- Returns all ticket IDs reachable from
root_idby followingdependenciesedges in depth-first order, includingroot_iditself. - Cycles: track visited set; stop recursion when an ID has been visited. This makes the function safe even if the data contains cycles.
TicketGraph::to_json_value(&self) -> serde_json::Value
- Returns an object like:
{ "nodes": [ {"id": "a3f9c2", "title": "...", "status": "todo", "dependencies": ["b7d41e"]}, ... ], "edges": [ {"from": "a3f9c2", "to": "b7d41e"}, ... ] }
Crate dependencies
No new crates needed. If IndexMap insertion-order is useful, indexmap can be added — but a HashMap with a separate sorted Vec<&str> of keys also works. Prefer whatever avoids adding a new crate dependency.
Files touched
src/graph.rs— new file, public modulesrc/main.rs—mod graph;declaration
Tests (unit, in src/tests.rs)
buildwith an empty slice returns an empty graph.rootsreturns only tickets with no in-graph dependencies.subtreereturns the correct set of IDs for a linear chain.subtreedoes not infinite-loop when the data contains a cycle.to_json_valuecontains all expected IDs innodesand all edges inedges.