Skip to main content

ralph/template/variables/
context.rs

1//! Purpose: Define shared data types for template-variable validation and
2//! substitution.
3//!
4//! Responsibilities:
5//! - Represent substitution context derived from targets and git state.
6//! - Represent validation warnings and aggregate validation results.
7//!
8//! Scope:
9//! - Data modeling only; no template scanning, substitution, or git probing.
10//!
11//! Usage:
12//! - Used by the `validate`, `detect`, and `substitute` companions and their
13//!   callers through re-exports from `template::variables`.
14//!
15//! Invariants/Assumptions:
16//! - Warning display text is part of the user-facing contract.
17//! - Validation helpers preserve existing warning semantics and ordering.
18
19/// Context for template variable substitution.
20#[derive(Debug, Clone, Default)]
21pub struct TemplateContext {
22    /// The target file/path provided by user.
23    pub target: Option<String>,
24    /// Module name derived from target (e.g., "src/cli/task.rs" -> "cli::task").
25    pub module: Option<String>,
26    /// Filename only (e.g., "src/cli/task.rs" -> "task.rs").
27    pub file: Option<String>,
28    /// Current git branch name.
29    pub branch: Option<String>,
30}
31
32/// Warning types for template validation.
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum TemplateWarning {
35    /// Unknown template variable found (variable name, optional field context).
36    UnknownVariable { name: String, field: Option<String> },
37    /// Git branch detection failed (error message).
38    GitBranchDetectionFailed { error: String },
39}
40
41impl std::fmt::Display for TemplateWarning {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            TemplateWarning::UnknownVariable { name, field: None } => {
45                write!(f, "Unknown template variable: {{{{{}}}}}", name)
46            }
47            TemplateWarning::UnknownVariable {
48                name,
49                field: Some(field),
50            } => {
51                write!(
52                    f,
53                    "Unknown template variable in {}: {{{{{}}}}}",
54                    field, name
55                )
56            }
57            TemplateWarning::GitBranchDetectionFailed { error } => {
58                write!(f, "Git branch detection failed: {}", error)
59            }
60        }
61    }
62}
63
64/// Result of template validation.
65#[derive(Debug, Clone, Default)]
66pub struct TemplateValidation {
67    /// Warnings collected during validation.
68    pub warnings: Vec<TemplateWarning>,
69    /// Whether the template uses {{branch}} variable.
70    pub uses_branch: bool,
71}
72
73impl TemplateValidation {
74    /// Check if there are any unknown variable warnings.
75    pub fn has_unknown_variables(&self) -> bool {
76        self.warnings
77            .iter()
78            .any(|w| matches!(w, TemplateWarning::UnknownVariable { .. }))
79    }
80
81    /// Get list of unknown variable names (deduplicated).
82    pub fn unknown_variable_names(&self) -> Vec<String> {
83        let mut names: Vec<String> = self
84            .warnings
85            .iter()
86            .filter_map(|w| match w {
87                TemplateWarning::UnknownVariable { name, .. } => Some(name.clone()),
88                _ => None,
89            })
90            .collect();
91        names.sort();
92        names.dedup();
93        names
94    }
95}