Skip to main content

wowlab_docgen_cli/context/
mod.rs

1mod children;
2pub mod collectors;
3mod deps;
4mod features;
5mod nav;
6mod used_by;
7
8use std::collections::BTreeMap;
9
10use minijinja::Value;
11use serde::Serialize;
12
13use crate::{RenderCtx, infra::metadata::PackageKind};
14
15fn ctx<'a>(map: &mut BTreeMap<&'a str, Value>, key: &'a str, val: impl Serialize) {
16    map.insert(key, Value::from_serialize(val));
17}
18
19/// Build the full template context from workspace and package metadata.
20#[must_use]
21pub fn build(render_ctx: &RenderCtx<'_>) -> Value {
22    let name = render_ctx.metadata.name.as_deref().unwrap_or("");
23    let display_name = crate::display_name(name);
24    let meta = render_ctx.metadata;
25    let description = meta.description.as_deref().unwrap_or("");
26
27    let mut map = BTreeMap::<&str, Value>::new();
28
29    ctx(&mut map, "display_name", &display_name);
30    ctx(&mut map, "crate_name", name);
31    ctx(&mut map, "subtitle", description);
32    ctx(&mut map, "version", &meta.version);
33    ctx(&mut map, "msrv", &meta.msrv);
34    ctx(&mut map, "features", features::gather(render_ctx));
35    ctx(&mut map, "deps", deps::gather(render_ctx));
36    ctx(&mut map, "children", children::gather(render_ctx));
37    ctx(&mut map, "nav", nav::build(render_ctx));
38    ctx(&mut map, "used_by", used_by::gather(render_ctx));
39    ctx(&mut map, "external_deps", &meta.external_deps);
40
41    for (key, value) in collectors::collect_all(render_ctx) {
42        map.insert(key, value);
43    }
44
45    Value::from_serialize(&map)
46}
47
48/// Resolve a base template for auto-wrapping `.md.in` files without `{% extends %}`.
49#[must_use]
50pub fn default_base(ctx: &RenderCtx<'_>) -> &'static str {
51    let is_readme = ctx.output_stem.eq_ignore_ascii_case("README");
52
53    if is_readme {
54        if ctx.is_root() {
55            return "root.md.j2";
56        }
57
58        match ctx.metadata.kind {
59            PackageKind::RustCrate => "crate.md.j2",
60            PackageKind::NodePackage => "package.md.j2",
61            _ => "directory.md.j2",
62        }
63    } else {
64        if ctx.is_root() {
65            return "claude-root.md.j2";
66        }
67
68        match ctx.metadata.kind {
69            PackageKind::RustCrate => "claude-crate.md.j2",
70            PackageKind::NodePackage => "claude-package.md.j2",
71            _ => "claude-directory.md.j2",
72        }
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use googletest::prelude::*;
79
80    use super::*;
81    use crate::test_helpers::{meta, test_ctx};
82
83    #[gtest]
84    fn root_readme_uses_root_base() -> Result<()> {
85        let m = meta(PackageKind::RustCrate);
86
87        verify_eq!(
88            default_base(&test_ctx(m.kind, ".", "README", &m)),
89            "root.md.j2"
90        )
91    }
92
93    #[gtest]
94    fn crate_readme_uses_crate_base() -> Result<()> {
95        let m = meta(PackageKind::RustCrate);
96
97        verify_eq!(
98            default_base(&test_ctx(m.kind, "crates/common", "README", &m)),
99            "crate.md.j2"
100        )
101    }
102
103    #[gtest]
104    fn package_readme_uses_package_base() -> Result<()> {
105        let m = meta(PackageKind::NodePackage);
106
107        verify_eq!(
108            default_base(&test_ctx(m.kind, "apps/portal", "README", &m)),
109            "package.md.j2"
110        )
111    }
112
113    #[gtest]
114    fn directory_readme_uses_directory_base() -> Result<()> {
115        let m = meta(PackageKind::Directory);
116
117        verify_eq!(
118            default_base(&test_ctx(m.kind, "deploy", "README", &m)),
119            "directory.md.j2"
120        )
121    }
122
123    #[gtest]
124    fn claude_crate_uses_claude_crate_base() -> Result<()> {
125        let m = meta(PackageKind::RustCrate);
126
127        verify_eq!(
128            default_base(&test_ctx(m.kind, "crates/common", "CLAUDE", &m)),
129            "claude-crate.md.j2"
130        )
131    }
132
133    #[gtest]
134    fn claude_package_uses_claude_package_base() -> Result<()> {
135        let m = meta(PackageKind::NodePackage);
136
137        verify_eq!(
138            default_base(&test_ctx(m.kind, "apps/portal", "CLAUDE", &m)),
139            "claude-package.md.j2"
140        )
141    }
142
143    #[gtest]
144    fn agents_uses_claude_base() -> Result<()> {
145        let m = meta(PackageKind::RustCrate);
146
147        verify_eq!(
148            default_base(&test_ctx(m.kind, ".", "AGENTS", &m)),
149            "claude-root.md.j2"
150        )
151    }
152}