Skip to main content

drft/builders/
markdown.rs

1//! The `markdown` builder: emits link edges from `[text](path)` body links. It
2//! contributes no node metadata — cross-graph linkage to `fs` nodes happens at
3//! compose by path coincidence.
4
5use globset::GlobSet;
6
7use crate::builders::link_edge;
8use crate::model::Graph;
9use crate::parsers::Parser;
10use crate::parsers::markdown::MarkdownParser;
11
12/// Build the `markdown` graph fragment from text files, labeled `label`.
13/// `filter` scopes which paths the builder reads (`None` reads all). The
14/// fragment carries only edges.
15pub fn build(label: &str, texts: &[(String, String)], filter: Option<GlobSet>) -> Graph {
16    let parser = MarkdownParser {
17        file_filter: filter,
18    };
19    let mut graph = Graph::labeled(label);
20
21    for (path, content) in texts {
22        if !parser.matches(path) {
23            continue;
24        }
25        for raw in parser.parse(path, content).links {
26            if let Some(edge) = link_edge(path, &raw) {
27                graph.add_edge(edge);
28            }
29        }
30    }
31
32    graph.sort_edges();
33    graph
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    fn texts(pairs: &[(&str, &str)]) -> Vec<(String, String)> {
41        pairs
42            .iter()
43            .map(|(p, c)| (p.to_string(), c.to_string()))
44            .collect()
45    }
46
47    #[test]
48    fn emits_resolved_edges() {
49        let t = texts(&[("docs/index.md", "[setup](setup.md) and [faq](../faq.md)")]);
50        let graph = build("markdown", &t, None);
51        assert_eq!(graph.label.as_deref(), Some("markdown"));
52        assert!(graph.nodes.is_empty(), "markdown contributes no nodes");
53        let targets: Vec<&str> = graph.edges.iter().map(|e| e.target.as_str()).collect();
54        assert_eq!(targets, vec!["docs/setup.md", "faq.md"]);
55    }
56
57    #[test]
58    fn filter_scopes_files() {
59        let mut builder = globset::GlobSetBuilder::new();
60        builder.add(globset::Glob::new("**/*.md").unwrap());
61        let filter = builder.build().unwrap();
62
63        let t = texts(&[("a.md", "[x](x.md)"), ("notes.txt", "[y](y.md)")]);
64        let graph = build("markdown", &t, Some(filter));
65        assert_eq!(graph.edges.len(), 1);
66        assert_eq!(graph.edges[0].source, "a.md");
67    }
68}