codama_stores/
file_module_store.rs1use codama_errors::{CodamaResult, IteratorCombineErrors};
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, PartialEq)]
5pub struct FileModuleStore {
6 pub file: syn::File,
7 pub file_modules: Vec<FileModuleStore>,
8 pub path: PathBuf,
9}
10
11impl FileModuleStore {
12 pub fn load_all(path: &Path, items: &[syn::Item]) -> CodamaResult<Vec<Self>> {
13 find_nested_file_modules(items)
14 .iter()
15 .map(|&item| FileModuleStore::load(path, item))
16 .collect_and_combine_errors()
17 }
18
19 pub fn load(path: &Path, item: &syn::ItemMod) -> CodamaResult<Self> {
20 let parent_directory = path.parent().unwrap();
21 let filename = path.file_stem().unwrap().to_str().unwrap();
22 let current_directory = parent_directory.join(filename);
23
24 let candidates = vec![
25 parent_directory.join(format!("{}.rs", item.ident)),
27 parent_directory.join(format!("{}/mod.rs", item.ident)),
28 current_directory.join(format!("{}.rs", item.ident)),
30 current_directory.join(format!("{}/mod.rs", item.ident)),
31 ];
32
33 let path = candidates
34 .into_iter()
35 .find(|p| p.exists())
36 .ok_or_else(|| syn::Error::new_spanned(item, "could not read file"))?;
37 let content = std::fs::read_to_string(&path)?;
38 let file = syn::parse_file(&content)?;
39 let modules = Self::load_all(&path, &file.items)?;
40
41 Ok(Self {
42 file,
43 file_modules: modules,
44 path,
45 })
46 }
47}
48
49fn find_nested_file_modules(items: &[syn::Item]) -> Vec<&syn::ItemMod> {
50 items
51 .iter()
52 .filter_map(|item| match item {
53 syn::Item::Mod(syn::ItemMod {
54 content: Some((_, items)),
55 ..
56 }) => Some(find_nested_file_modules(items)),
57 syn::Item::Mod(item_mod) => Some(vec![item_mod]),
58 _ => None,
59 })
60 .flatten()
61 .collect()
62}