pyo3_stub_gen/docgen/
config.rs

1//! Configuration for documentation generation
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6/// Configuration for documentation generation from pyproject.toml
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[non_exhaustive]
9pub struct DocGenConfig {
10    /// Output directory for generated documentation
11    #[serde(rename = "output-dir", default = "default_output_dir")]
12    pub output_dir: PathBuf,
13
14    /// Name of the JSON output file
15    #[serde(rename = "json-output", default = "default_json_output")]
16    pub json_output: String,
17
18    /// Generate separate .rst pages for each module (default: true)
19    #[serde(rename = "separate-pages", default = "default_separate_pages")]
20    pub separate_pages: bool,
21
22    /// Custom intro message for index.rst (default: standard message, empty string to omit)
23    #[serde(rename = "intro-message", default)]
24    pub intro_message: Option<String>,
25
26    /// Custom title for index.rst (default: "{package_name} API Reference", empty string to use "API Reference")
27    #[serde(rename = "index-title", default)]
28    pub index_title: Option<String>,
29
30    /// Generate module contents tables (default: false)
31    #[serde(rename = "contents-table", default)]
32    pub contents_table: bool,
33
34    /// Generate separate .rst pages for each class/function (default: false)
35    /// When true, module pages show a summary table with links to individual item pages.
36    #[serde(rename = "separate-items", default)]
37    pub separate_items: bool,
38
39    /// Generate index.rst file (default: true)
40    /// Set to false to skip generating index.rst, useful when a hand-maintained index.rst exists.
41    #[serde(rename = "generate-index", default = "default_generate_index")]
42    pub generate_index: bool,
43}
44
45impl Default for DocGenConfig {
46    fn default() -> Self {
47        Self {
48            output_dir: default_output_dir(),
49            json_output: default_json_output(),
50            separate_pages: default_separate_pages(),
51            intro_message: None,
52            index_title: None,
53            contents_table: false,
54            separate_items: false,
55            generate_index: default_generate_index(),
56        }
57    }
58}
59
60fn default_output_dir() -> PathBuf {
61    PathBuf::from("docs/api")
62}
63
64fn default_json_output() -> String {
65    "api_reference.json".to_string()
66}
67
68fn default_separate_pages() -> bool {
69    true
70}
71
72fn default_generate_index() -> bool {
73    true
74}
75
76impl DocGenConfig {
77    /// Validate configuration consistency
78    pub fn validate(&self) -> anyhow::Result<()> {
79        anyhow::ensure!(
80            !(self.separate_items && !self.contents_table),
81            "separate-items = true requires contents-table = true. \
82             Module pages need a summary table to link to individual item pages."
83        );
84        anyhow::ensure!(
85            !(self.separate_items && !self.separate_pages),
86            "separate-items = true requires separate-pages = true. \
87             Item pages need separate module pages to link from."
88        );
89        Ok(())
90    }
91
92    /// Convert output_dir to relative POSIX path for JSON serialization
93    pub fn to_relative_posix_path(&self, base_dir: &std::path::Path) -> String {
94        let relative_path = if self.output_dir.is_absolute() {
95            self.output_dir
96                .strip_prefix(base_dir)
97                .unwrap_or(&self.output_dir)
98        } else {
99            &self.output_dir
100        };
101
102        // Convert to POSIX format (forward slashes)
103        relative_path
104            .components()
105            .filter_map(|c| match c {
106                std::path::Component::Normal(s) => Some(s.to_string_lossy().into_owned()),
107                _ => None,
108            })
109            .collect::<Vec<_>>()
110            .join("/")
111    }
112}