rhai_autodocs/
generate.rs1use serde_json::json;
2
3use crate::{item::Item, module::Documentation};
4
5#[derive(Debug)]
7pub struct Glossary {
8 pub content: String,
10}
11
12pub const GLOSSARY_COLOR_FN: &str = "#C6cacb";
13pub const GLOSSARY_COLOR_OP: &str = "#16c6f3";
14pub const GLOSSARY_COLOR_GETSET: &str = "#25c2a0";
15pub const GLOSSARY_COLOR_INDEX: &str = "#25c2a0";
16
17#[derive(Default)]
18pub struct DocusaurusOptions {
19 slug: Option<String>,
20 module_name: Option<String>,
21}
22
23impl DocusaurusOptions {
24 #[must_use]
31 pub fn with_slug(mut self, slug: &str) -> Self {
32 self.slug = Some(slug.to_string());
33
34 self
35 }
36
37 #[must_use]
48 pub fn rename_root_module(mut self, name: &str) -> Self {
49 self.module_name = Some(name.to_string());
50
51 self
52 }
53
54 #[allow(clippy::missing_panics_doc)]
64 pub fn generate(
65 self,
66 module: &Documentation,
67 ) -> Result<std::collections::HashMap<String, String>, handlebars::RenderError> {
68 let mut hbs_registry = handlebars::Handlebars::new();
69 let mut module = module.clone();
70
71 if let Some(module_name) = self.module_name {
72 module.name = module_name;
73 }
74
75 hbs_registry
76 .register_template_string(
77 "docusaurus-module",
78 include_str!("handlebars/docusaurus/module.hbs"),
79 )
80 .expect("template is valid");
81
82 hbs_registry
84 .register_partial("ContentPartial", "{{{content}}}")
85 .expect("partial is valid");
86
87 generate(
88 &module,
89 "docusaurus-module",
90 self.slug.as_deref(),
91 &hbs_registry,
92 )
93 }
94}
95
96#[must_use]
98pub fn docusaurus() -> DocusaurusOptions {
99 DocusaurusOptions::default()
100}
101
102#[derive(Default)]
103pub struct DocusaurusGlossaryOptions {
104 slug: Option<String>,
105}
106
107impl DocusaurusGlossaryOptions {
108 #[must_use]
112 pub fn with_slug(mut self, slug: &str) -> Self {
113 self.slug = Some(slug.to_string());
114
115 self
116 }
117
118 #[allow(clippy::missing_panics_doc)]
129 pub fn generate(self, module: &Documentation) -> Result<String, handlebars::RenderError> {
130 let mut hbs = handlebars::Handlebars::new();
131
132 hbs.register_template_string(
133 "docusaurus-glossary",
134 include_str!("handlebars/docusaurus/glossary.hbs"),
135 )
136 .expect("template is valid");
137
138 self.generate_inner(&hbs, true, module)
139 }
140
141 fn generate_inner(
142 &self,
143 hbs: &handlebars::Handlebars<'_>,
144 is_root: bool,
145 module: &Documentation,
146 ) -> Result<String, handlebars::RenderError> {
147 let mut flatten_items = Vec::default();
148
149 for item in &module.items {
150 match item {
151 Item::Function { metadata, .. } => {
152 for m in metadata {
153 let definition = m.generate_function_definition();
154 let serialized = definition.display();
155 let ty = definition.type_to_str();
156 let color = match ty {
157 "op" => GLOSSARY_COLOR_OP,
158 "get/set" => GLOSSARY_COLOR_GETSET,
159 "index get/set" => GLOSSARY_COLOR_INDEX,
160 _ => GLOSSARY_COLOR_FN,
161 };
162
163 flatten_items.push(json!({
164 "color": color,
165 "type": ty,
166 "definition": serialized.trim_start_matches(ty).trim(),
167 "heading_id": item.heading_id(),
168 }));
169 }
170 }
171 Item::CustomType { metadata, .. } => {
172 flatten_items.push(json!({
173 "color": GLOSSARY_COLOR_FN,
174 "type": "type",
175 "definition": metadata.display_name,
176 "heading_id": item.heading_id(),
177 }));
178 }
179 }
180 }
181
182 let data = json!({
183 "title": module.name,
184 "root": is_root,
185 "slug": self.slug.clone().unwrap_or_default(),
186 "items": flatten_items,
187 });
188
189 let mut glossary = hbs.render("docusaurus-glossary", &data)?;
190
191 for module in &module.sub_modules {
192 glossary += self.generate_inner(hbs, false, module)?.as_str();
193 }
194
195 Ok(glossary)
196 }
197}
198
199#[must_use]
201pub fn docusaurus_glossary() -> DocusaurusGlossaryOptions {
202 DocusaurusGlossaryOptions::default()
203}
204
205#[derive(Default)]
206pub struct MDBookOptions;
207
208impl MDBookOptions {
209 #[allow(clippy::missing_panics_doc)]
217 pub fn generate(
218 self,
219 module: &Documentation,
220 ) -> Result<std::collections::HashMap<String, String>, handlebars::RenderError> {
221 let mut hbs_registry = handlebars::Handlebars::new();
222
223 hbs_registry
224 .register_template_string(
225 "mdbook-module",
226 include_str!("handlebars/mdbook/module.hbs"),
227 )
228 .expect("template is valid");
229
230 hbs_registry
232 .register_partial("ContentPartial", "{{{content}}}")
233 .expect("partial is valid");
234
235 generate(module, "mdbook-module", None, &hbs_registry)
236 }
237}
238
239#[allow(clippy::missing_const_for_fn)]
241#[must_use]
242pub fn mdbook() -> MDBookOptions {
243 MDBookOptions
244}
245
246fn generate(
247 module: &Documentation,
248 template: &str,
249 slug: Option<&str>,
250 hbs_registry: &handlebars::Handlebars<'_>,
251) -> Result<std::collections::HashMap<String, String>, handlebars::RenderError> {
252 let mut documentation = std::collections::HashMap::default();
253
254 if !module.items.is_empty() {
255 let data = json!({
256 "title": module.name,
257 "slug": slug.map_or_else(|| format!("/{}", module.name), |slug| format!("{}/{}", slug, module.name)),
258 "description": module.documentation,
259 "namespace": module.namespace,
260 "items": module.items,
261 });
262
263 documentation.insert(
264 module.name.to_string(),
265 hbs_registry.render(template, &data)?,
266 );
267 }
268
269 for sub in &module.sub_modules {
270 documentation.extend(generate(sub, template, slug, hbs_registry)?);
271 }
272
273 Ok(documentation)
274}