cargo_wiki/generators/
module_gen.rs1use crate::gen_path;
2use crate::generators::struct_gen::StructGenerator;
3use crate::generators::{ExternalCrates, Generator, Index, Paths};
4use anyhow::Result;
5use rustdoc_types::{Item, ItemEnum, Module};
6use std::fs;
7
8pub const MODULE_FILE_NAME: &str = "README";
9
10#[derive(Default)]
11pub struct ModuleItems<'a> {
12 pub modules: Vec<ModuleField<'a>>,
13 pub traits: Vec<ModuleField<'a>>,
14 pub functions: Vec<ModuleField<'a>>,
15 pub macros: Vec<ModuleField<'a>>,
16 pub re_exports: Vec<ModuleField<'a>>,
17 pub structs: Vec<ModuleField<'a>>,
18 pub enums: Vec<ModuleField<'a>>,
19 pub consts: Vec<ModuleField<'a>>,
20}
21
22pub struct ModuleField<'a> {
23 pub name: &'a str,
24 pub link: String,
25 pub description: &'a str,
26}
27
28impl<'a> ModuleField<'a> {
29 pub fn to_string(&self) -> String {
30 let mut field_string = String::new();
31
32 field_string.push_str("- [`");
33 field_string.push_str(self.name);
34 field_string.push_str("`](");
35 field_string.push_str(&self.link);
36 field_string.push_str(")\n");
37
38 if !self.description.is_empty() {
39 field_string.push_str("\n\t");
40 field_string.push_str(self.description);
41 field_string.push_str("\n");
42 }
43
44 field_string
45 }
46}
47
48pub struct ModuleGenerator<'a> {
49 pub prefix_path: String,
50 pub module_file_name: &'a str,
51 pub root_item: &'a Item,
52 pub index: &'a Index,
53 pub paths: &'a Paths,
54 pub external_crate: &'a ExternalCrates,
55}
56
57impl<'a> ModuleGenerator<'a> {
58 pub fn new(
59 prefix_path: String,
60 module_file_name: &'a str,
61 root_item: &'a Item,
62 index: &'a Index,
63 paths: &'a Paths,
64 external_crate: &'a ExternalCrates,
65 ) -> Self {
66 Self {
67 prefix_path,
68 module_file_name,
69 root_item,
70 index,
71 paths,
72 external_crate,
73 }
74 }
75
76 pub fn auto(self) -> Result<()> {
77 let Some(module_name) = &self.root_item.name else {
78 return Err(anyhow::Error::msg(format!(
79 "Every module should have a name. Id: {}",
80 self.root_item.id.0
81 )));
82 };
83 let ItemEnum::Module(Module {
84 items, is_stripped, ..
85 }) = &self.root_item.inner
86 else {
87 return Err(anyhow::Error::msg(
88 "The Root module can't have inner item type anything other than Module. If \
89 you think this is an error, please open the issue at \
90 https://github.com/as1100k/cargo-wiki/issues with appropriate logs.",
91 ));
92 };
93 let mut path = format!("{}/{}", self.prefix_path, module_name);
94 let mut module_file_content = format!("# {}\n\n", module_name);
95 let mut module_information = ModuleItems::default();
96
97 gen_path(&path)?;
98
99 for item in items {
100 let Some(item) = self.index.get(item) else {
101 eprintln!("Failed to find item with id: {} in index", item.0);
102 continue;
103 };
104 let Some(item_name) = &item.name else {
105 continue;
108 };
109
110 let item_description = match &item.docs {
111 Some(doc) => &doc[..doc.len().min(50)],
112 None => ""
113 };
114
115 let mut path = format!("{}", path);
116 let mut file_content = format!("# {}\n\n", item_name);
117
118 match &item.inner {
119 ItemEnum::Module(_) => {
120 module_information.modules.push(ModuleField {
121 name: item_name,
122 link: format!("./{}/{}.md", item_name, self.module_file_name),
123 description: &item_description,
124 });
125
126 let new_module_generator = Self::new(
127 path,
128 &self.module_file_name,
129 item,
130 self.index,
131 self.paths,
132 self.external_crate,
133 );
134 new_module_generator.auto()?;
135 continue;
137 }
138 ItemEnum::Struct(_) => {
139 module_information.structs.push(ModuleField {
140 name: item_name,
141 link: format!("./struct.{}.md", item_name),
142 description: &item_description,
143 });
144
145 path.push_str("/struct.");
146 path.push_str(item_name);
147
148 let syntax = StructGenerator::generate_syntax(
149 item,
150 self.index,
151 self.paths,
152 self.external_crate,
153 )?;
154 file_content.push_str(&syntax);
155 }
156 _ => continue,
157 }
158
159 path.push_str(".md");
160 fs::write(path, file_content)
161 .expect("TODO: panic message at `src/generators/module_gen.rs`");
162 }
163
164 path.push_str("/");
165 path.push_str(self.module_file_name);
166 path.push_str(".md");
167
168 module_file_content.push_str(&Self::generate_module_docs(&module_information));
169 fs::write(path, module_file_content).expect(
170 "TODO: panic message at `src/generators/module_gen.rs` while saving module file",
171 );
172
173 Ok(())
174 }
175
176 pub fn generate_module_docs(module_information: &ModuleItems) -> String {
177 let mut module_information_string = String::new();
178
179 if module_information.modules.len() > 0 {
181 module_information_string.push_str("\n## Modules\n\n");
182 for field in &module_information.modules {
183 module_information_string.push_str(&field.to_string());
184 }
185 }
186
187 if module_information.consts.len() > 0 {
189 module_information_string.push_str("## Constants\n\n");
190 for field in &module_information.consts {
191 module_information_string.push_str(&field.to_string());
192 }
193 }
194
195 if module_information.structs.len() > 0 {
197 module_information_string.push_str("## Structs\n\n");
198 for field in &module_information.structs {
199 module_information_string.push_str(&field.to_string());
200 }
201 }
202
203 if module_information.enums.len() > 0 {
205 module_information_string.push_str("## Enums\n\n");
206 for field in &module_information.enums {
207 module_information_string.push_str(&field.to_string());
208 }
209 }
210
211 if module_information.traits.len() > 0 {
213 module_information_string.push_str("## Traits\n\n");
214 for field in &module_information.traits {
215 module_information_string.push_str(&field.to_string());
216 }
217 }
218
219 if module_information.functions.len() > 0 {
221 module_information_string.push_str("## Functions\n\n");
222 for field in &module_information.functions {
223 module_information_string.push_str(&field.to_string());
224 }
225 }
226
227 if module_information.macros.len() > 0 {
229 module_information_string.push_str("## Macros\n\n");
230 for field in &module_information.macros {
231 module_information_string.push_str(&field.to_string());
232 }
233 }
234
235 if module_information.re_exports.len() > 0 {
237 module_information_string.push_str("## Re-exports\n\n");
238 for field in &module_information.re_exports {
239 module_information_string.push_str(&field.to_string());
240 }
241 }
242
243 module_information_string
244 }
245}