pub(crate) const AUTOGEN_MARKER: &str = "<!-- Auto-generated - do not edit. -->";
pub(super) struct IndexEntry {
pub name: String,
pub summary: String,
}
fn doc_link(name: &str) -> String {
format!("{name}.md")
}
pub(super) fn render_page(name: &str, body: &str) -> String {
let mut out = String::new();
out.push_str(AUTOGEN_MARKER);
out.push_str("\n\n# ");
out.push_str(name);
out.push_str("\n\n");
out.push_str(body.trim());
while out.ends_with('\n') {
out.pop();
}
out.push('\n');
out
}
pub(super) fn render_index(assets: &[IndexEntry], ref_types: &[IndexEntry]) -> String {
let mut out = String::new();
out.push_str(AUTOGEN_MARKER);
out.push_str("\n\n# Assets\n\n");
for a in assets {
out.push_str(&index_line(a));
}
if !ref_types.is_empty() {
out.push_str("\n## Reference types\n\n");
for t in ref_types {
out.push_str(&index_line(t));
}
}
while out.ends_with('\n') {
out.pop();
}
out.push('\n');
out
}
fn index_line(e: &IndexEntry) -> String {
let summary = e.summary.trim();
if summary.is_empty() {
format!("- [{}]({})\n", e.name, doc_link(&e.name))
} else {
format!("- [{}]({}) - {}\n", e.name, doc_link(&e.name), summary)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_page_has_marker_then_h1_then_body() {
let page = render_page("Prop", "A prop.\n\n## Parameters\n\n- `x`: A float.");
let mut lines = page.lines();
assert_eq!(lines.next(), Some(AUTOGEN_MARKER));
assert_eq!(lines.next(), Some(""));
assert_eq!(lines.next(), Some("# Prop"));
assert!(page.contains("A prop."));
assert!(page.contains("## Parameters"));
assert!(page.ends_with('\n'));
assert!(!page.ends_with("\n\n"));
}
fn idx(name: &str, summary: &str) -> IndexEntry {
IndexEntry {
name: name.to_string(),
summary: summary.to_string(),
}
}
#[test]
fn render_index_lists_assets_then_reference_types() {
let assets = vec![idx("Camera3D", "A camera."), idx("Prop", "A prop.")];
let refs = vec![idx("PropCollider", "A collision volume.")];
let md = render_index(&assets, &refs);
assert!(md.starts_with(AUTOGEN_MARKER));
assert!(md.contains("# Assets"));
assert!(md.contains("- [Camera3D](Camera3D.md) - A camera."));
assert!(md.contains("- [Prop](Prop.md) - A prop."));
assert!(md.contains("## Reference types"));
assert!(md.contains("- [PropCollider](PropCollider.md) - A collision volume."));
let assets_pos = md.find("# Assets").unwrap();
let refs_pos = md.find("## Reference types").unwrap();
assert!(assets_pos < refs_pos);
}
#[test]
fn render_index_omits_reference_section_when_empty() {
let md = render_index(&[idx("Prop", "A prop.")], &[]);
assert!(!md.contains("Reference types"));
assert!(md.ends_with('\n'));
}
}