drft/rules/
orphan_node.rs1use crate::diagnostic::Diagnostic;
2use crate::rules::{Rule, RuleContext};
3
4pub struct OrphanNodeRule;
5
6impl Rule for OrphanNodeRule {
7 fn name(&self) -> &str {
8 "orphan-node"
9 }
10
11 fn evaluate(&self, ctx: &RuleContext) -> Vec<Diagnostic> {
12 let result = &ctx.graph.degree;
13
14 result
15 .nodes
16 .iter()
17 .filter(|nd| nd.in_degree == 0)
18 .map(|nd| Diagnostic {
19 rule: "orphan-node".into(),
20 message: "no inbound links".into(),
21 node: Some(nd.node.clone()),
22 fix: Some(format!(
23 "{} has no inbound links — either link to it from another file or remove it",
24 nd.node
25 )),
26 ..Default::default()
27 })
28 .collect()
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use crate::graph::Graph;
36 use crate::graph::test_helpers::{make_edge, make_enriched, make_node};
37 use crate::rules::RuleContext;
38
39 #[test]
40 fn detects_orphan() {
41 let mut graph = Graph::new();
42 graph.add_node(make_node("index.md"));
43 graph.add_node(make_node("orphan.md"));
44 graph.add_edge(make_edge("index.md", "setup.md"));
45
46 let enriched = make_enriched(graph);
47 let ctx = RuleContext {
48 graph: &enriched,
49 options: None,
50 };
51 let diagnostics = OrphanNodeRule.evaluate(&ctx);
52
53 let orphan_nodes: Vec<&str> = diagnostics
54 .iter()
55 .map(|d| d.node.as_deref().unwrap())
56 .collect();
57 assert!(orphan_nodes.contains(&"orphan.md"));
58 assert!(orphan_nodes.contains(&"index.md"));
59 }
60
61 #[test]
62 fn linked_file_is_not_orphan() {
63 let mut graph = Graph::new();
64 graph.add_node(make_node("index.md"));
65 graph.add_node(make_node("setup.md"));
66 graph.add_edge(make_edge("index.md", "setup.md"));
67
68 let enriched = make_enriched(graph);
69 let ctx = RuleContext {
70 graph: &enriched,
71 options: None,
72 };
73 let diagnostics = OrphanNodeRule.evaluate(&ctx);
74
75 let orphan_nodes: Vec<&str> = diagnostics
76 .iter()
77 .map(|d| d.node.as_deref().unwrap())
78 .collect();
79 assert!(!orphan_nodes.contains(&"setup.md"));
80 assert!(orphan_nodes.contains(&"index.md"));
81 }
82}