Skip to main content

rust_config_tree/
config.rs

1//! High-level `confique` integration and config-template rendering.
2//!
3//! This module loads `.env` values, builds a Figment runtime source graph,
4//! extracts it into a `confique` schema for defaults and validation, renders
5//! example templates that mirror the same include tree, and writes JSON Schema
6//! files that editors can use for completion and validation. YAML templates can
7//! also be split across nested schema sections.
8
9use std::path::PathBuf;
10
11use confique::Config;
12
13pub use crate::config_env::ConfiqueEnvProvider;
14pub use crate::config_format::ConfigFormat;
15pub use crate::config_load::{
16    build_config_figment, load_config, load_config_from_figment, load_config_with_figment,
17};
18pub(crate) use crate::config_output::resolve_config_template_output;
19pub use crate::config_schema::{
20    ConfigSchemaTarget, config_schema_targets_for_path, write_config_schema, write_config_schemas,
21};
22pub use crate::config_templates::{
23    ConfigTemplateTarget, template_for_path, template_targets_for_paths,
24    template_targets_for_paths_with_schema, write_config_templates,
25    write_config_templates_with_schema,
26};
27pub use crate::config_trace::trace_config_sources;
28
29/// Result type used by the high-level configuration API.
30///
31/// The error type is [`ConfigError`](crate::ConfigError).
32pub type ConfigResult<T> = std::result::Result<T, crate::ConfigError>;
33
34/// A `confique` schema that can expose recursive include paths and template
35/// section layout.
36///
37/// Implement this trait for the same type that derives `confique::Config`.
38/// `include_paths` receives a partially loaded layer so the crate can discover
39/// child config files before the final schema is merged.
40pub trait ConfigSchema: Config + Sized {
41    /// Returns include paths declared by a loaded config layer.
42    ///
43    /// Relative paths are resolved from the file that declared them. Empty paths
44    /// are rejected before traversal continues.
45    ///
46    /// # Arguments
47    ///
48    /// - `layer`: Partially loaded `confique` layer for one config file.
49    ///
50    /// # Returns
51    ///
52    /// Returns include paths declared by `layer`.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use confique::Config;
58    /// use rust_config_tree::ConfigSchema;
59    ///
60    /// #[derive(Config)]
61    /// struct AppConfig {
62    ///     #[config(default = [])]
63    ///     include: Vec<std::path::PathBuf>,
64    /// }
65    ///
66    /// impl ConfigSchema for AppConfig {
67    ///     fn include_paths(layer: &<Self as Config>::Layer) -> Vec<std::path::PathBuf> {
68    ///         layer.include.clone().unwrap_or_default()
69    ///     }
70    /// }
71    /// ```
72    fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf>;
73
74    /// Overrides the generated template file path for a split nested section.
75    ///
76    /// A nested section is split only when its field schema has
77    /// `x-tree-split = true`, for example
78    /// `#[schemars(extend("x-tree-split" = true))]`. By default, top-level
79    /// split sections are generated as `config/<field>.yaml` and nested split
80    /// sections as children of their parent section file stem, e.g.
81    /// `config/trading/risk.yaml`.
82    ///
83    /// # Arguments
84    ///
85    /// - `section_path`: Path of nested schema field names from the root schema
86    ///   to the section being rendered.
87    ///
88    /// # Returns
89    ///
90    /// Returns `Some(path)` to override the generated file path, or `None` to
91    /// use the default section path.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use confique::Config;
97    /// use rust_config_tree::ConfigSchema;
98    ///
99    /// #[derive(Config)]
100    /// struct AppConfig {
101    ///     #[config(default = [])]
102    ///     include: Vec<std::path::PathBuf>,
103    /// }
104    ///
105    /// impl ConfigSchema for AppConfig {
106    ///     fn include_paths(layer: &<Self as Config>::Layer) -> Vec<std::path::PathBuf> {
107    ///         layer.include.clone().unwrap_or_default()
108    ///     }
109    ///
110    ///     fn template_path_for_section(section_path: &[&str]) -> Option<std::path::PathBuf> {
111    ///         match section_path {
112    ///             ["server"] => Some(std::path::PathBuf::from("config/server.yaml")),
113    ///             _ => None,
114    ///         }
115    ///     }
116    /// }
117    /// ```
118    fn template_path_for_section(section_path: &[&str]) -> Option<PathBuf> {
119        let _ = section_path;
120        None
121    }
122}
123
124#[cfg(test)]
125#[path = "unit_tests/config.rs"]
126mod unit_tests;