spec_driven_docs/services/
reader.rs1use include_dir::Dir;
9
10use crate::domain::docs_catalog::ShelfId;
11
12#[derive(Debug, Clone, Copy)]
14pub struct Shelf {
15 pub id: ShelfId,
17 pub dir: &'static Dir<'static>,
19 pub strip: Option<&'static str>,
21}
22
23pub const METHOD: Shelf = Shelf {
25 id: ShelfId::Method,
26 dir: &crate::embedded::METHOD,
27 strip: None,
28};
29pub const SPECS: Shelf = Shelf {
31 id: ShelfId::Spec,
32 dir: &crate::embedded::SPECS,
33 strip: Some("SPEC-"),
34};
35pub const TEMPLATES: Shelf = Shelf {
37 id: ShelfId::Template,
38 dir: &crate::embedded::TEMPLATES,
39 strip: Some("TEMPLATE-"),
40};
41
42fn short_name<'a>(shelf: &Shelf, file_name: &'a str) -> Option<&'a str> {
43 let stem = file_name.strip_suffix(".md")?;
44 shelf
45 .strip
46 .map_or(Some(stem), |prefix| stem.strip_prefix(prefix))
47}
48
49#[must_use]
51pub fn list(shelf: &Shelf) -> Vec<String> {
52 let mut names: Vec<String> = shelf
53 .dir
54 .files()
55 .filter_map(|file| {
56 let name = file.path().as_os_str().to_str()?;
57 short_name(shelf, name).map(String::from)
58 })
59 .collect();
60 names.sort();
61 names
62}
63
64#[must_use]
66pub fn get(shelf: &Shelf, name: &str) -> Option<&'static str> {
67 let wanted = name.strip_suffix(".md").unwrap_or(name);
68 shelf.dir.files().find_map(|file| {
69 let file_name = file.path().as_os_str().to_str()?;
70 let stem = file_name.strip_suffix(".md")?;
71 let matches = stem == wanted || short_name(shelf, file_name) == Some(wanted);
72 if matches { file.contents_utf8() } else { None }
73 })
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn shelves_list_their_short_names() {
82 assert!(list(&METHOD).contains(&"glossary".to_string()));
83 assert!(list(&SPECS).contains(&"distribution".to_string()));
84 assert!(list(&TEMPLATES).contains(&"adr".to_string()));
85 }
86
87 #[test]
88 fn documents_resolve_by_short_and_full_names() {
89 let by_short = get(&SPECS, "distribution").unwrap();
90 assert_eq!(get(&SPECS, "SPEC-distribution").unwrap(), by_short);
91 assert_eq!(get(&SPECS, "SPEC-distribution.md").unwrap(), by_short);
92 assert!(by_short.contains("distribution:instances-operate-offline"));
93 assert!(get(&SPECS, "nonexistent").is_none());
94 }
95}