ferrous_forge/
templates.rs

1//! Template system for Ferrous Forge
2//!
3//! This module manages project templates and configuration files that get
4//! injected into new Rust projects to enforce standards.
5
6use crate::{Error, Result};
7use handlebars::Handlebars;
8use serde_json::json;
9use std::path::Path;
10
11/// Template manager for Ferrous Forge
12pub struct TemplateManager {
13    handlebars: Handlebars<'static>,
14}
15
16impl TemplateManager {
17    /// Create a new template manager
18    pub fn new() -> Result<Self> {
19        let mut handlebars = Handlebars::new();
20
21        // Register built-in templates
22        handlebars
23            .register_template_string("cargo_toml", include_str!("../templates/Cargo.toml.hbs"))
24            .map_err(|e| {
25                Error::template(format!("Failed to register Cargo.toml template: {}", e))
26            })?;
27
28        handlebars
29            .register_template_string("main_rs", include_str!("../templates/main.rs.hbs"))
30            .map_err(|e| Error::template(format!("Failed to register main.rs template: {}", e)))?;
31
32        handlebars
33            .register_template_string("lib_rs", include_str!("../templates/lib.rs.hbs"))
34            .map_err(|e| Error::template(format!("Failed to register lib.rs template: {}", e)))?;
35
36        handlebars
37            .register_template_string("github_workflow", include_str!("../templates/ci.yml.hbs"))
38            .map_err(|e| {
39                Error::template(format!(
40                    "Failed to register GitHub workflow template: {}",
41                    e
42                ))
43            })?;
44
45        Ok(Self { handlebars })
46    }
47
48    /// Generate a Cargo.toml file with Ferrous Forge standards
49    pub fn generate_cargo_toml(&self, project_name: &str, is_lib: bool) -> Result<String> {
50        let data = json!({
51            "project_name": project_name,
52            "is_lib": is_lib,
53            "version": "0.1.0",
54            "edition": "2024",
55            "rust_version": "1.85",
56        });
57
58        self.handlebars
59            .render("cargo_toml", &data)
60            .map_err(|e| Error::template(format!("Failed to render Cargo.toml: {}", e)))
61    }
62
63    /// Generate a main.rs file with Ferrous Forge standards
64    pub fn generate_main_rs(&self, project_name: &str) -> Result<String> {
65        let data = json!({
66            "project_name": project_name,
67        });
68
69        self.handlebars
70            .render("main_rs", &data)
71            .map_err(|e| Error::template(format!("Failed to render main.rs: {}", e)))
72    }
73
74    /// Generate a lib.rs file with Ferrous Forge standards
75    pub fn generate_lib_rs(&self, project_name: &str) -> Result<String> {
76        let data = json!({
77            "project_name": project_name,
78        });
79
80        self.handlebars
81            .render("lib_rs", &data)
82            .map_err(|e| Error::template(format!("Failed to render lib.rs: {}", e)))
83    }
84
85    /// Generate GitHub Actions CI workflow
86    pub fn generate_github_workflow(&self, project_name: &str) -> Result<String> {
87        let data = json!({
88            "project_name": project_name,
89        });
90
91        self.handlebars
92            .render("github_workflow", &data)
93            .map_err(|e| Error::template(format!("Failed to render GitHub workflow: {}", e)))
94    }
95
96    /// Apply templates to an existing project
97    pub async fn apply_to_project(&self, project_path: &Path) -> Result<()> {
98        // This would be used to retrofit existing projects with Ferrous Forge standards
99        // For now, just create a placeholder
100        tracing::info!(
101            "Applying Ferrous Forge templates to project: {}",
102            project_path.display()
103        );
104
105        // TODO: Implement project retrofitting
106        // - Backup existing files
107        // - Update Cargo.toml with Edition 2024
108        // - Add strict clippy configuration
109        // - Add GitHub Actions if .git exists
110        // - Update main.rs/lib.rs with documentation requirements
111
112        Ok(())
113    }
114}
115
116impl Default for TemplateManager {
117    fn default() -> Self {
118        Self::new().unwrap_or_else(|_| {
119            // Fallback to a basic template manager if initialization fails
120            TemplateManager {
121                handlebars: Handlebars::new(),
122            }
123        })
124    }
125}
126
127/// Information about a project template
128#[derive(Debug, Clone)]
129pub struct ProjectTemplate {
130    /// Name of the template
131    pub name: String,
132    /// Description of what this template provides
133    pub description: String,
134    /// Files that this template will create/modify
135    pub files: Vec<String>,
136}
137
138/// Get available project templates
139pub fn available_templates() -> Vec<ProjectTemplate> {
140    vec![
141        ProjectTemplate {
142            name: "basic".to_string(),
143            description: "Basic Rust project with Ferrous Forge standards".to_string(),
144            files: vec![
145                "Cargo.toml".to_string(),
146                "src/main.rs".to_string(),
147                ".github/workflows/ci.yml".to_string(),
148            ],
149        },
150        ProjectTemplate {
151            name: "library".to_string(),
152            description: "Rust library project with Ferrous Forge standards".to_string(),
153            files: vec![
154                "Cargo.toml".to_string(),
155                "src/lib.rs".to_string(),
156                ".github/workflows/ci.yml".to_string(),
157            ],
158        },
159    ]
160}