Skip to main content

openapi_nexus_core/traits/
file_writer.rs

1//! Trait for language-specific file writing operations
2
3use std::collections::HashMap;
4use std::fs;
5
6/// File category for organizing generated files
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub enum FileCategory {
9    /// Represents files without a category. Used internally.
10    /// These files are not written to the output directory.
11    None,
12    /// README or documentation files (e.g., README.md)
13    Readme,
14    /// API client classes
15    Apis,
16    /// Data models and schemas
17    Models,
18    /// Project configuration files (index.ts, package.json, etc.)
19    ProjectFiles,
20    /// Runtime utilities
21    Runtime,
22}
23
24/// Generic file information for writing
25#[derive(Debug, Clone)]
26pub struct FileInfo {
27    pub filename: String,
28    pub content: String,
29    pub category: FileCategory,
30}
31
32impl FileInfo {
33    /// Create a new FileInfo with the specified category
34    pub fn new(filename: String, content: String, category: FileCategory) -> Self {
35        Self {
36            filename,
37            content,
38            category,
39        }
40    }
41
42    /// Create a new FileInfo without a category
43    pub fn none(filename: String, content: String) -> Self {
44        Self::new(filename, content, FileCategory::None)
45    }
46
47    /// Create a new FileInfo for README files
48    pub fn readme(filename: String, content: String) -> Self {
49        Self::new(filename, content, FileCategory::Readme)
50    }
51
52    /// Create a new FileInfo for API files
53    pub fn api(filename: String, content: String) -> Self {
54        Self::new(filename, content, FileCategory::Apis)
55    }
56
57    /// Create a new FileInfo for model files
58    pub fn model(filename: String, content: String) -> Self {
59        Self::new(filename, content, FileCategory::Models)
60    }
61
62    /// Create a new FileInfo for project files
63    pub fn project(filename: String, content: String) -> Self {
64        Self::new(filename, content, FileCategory::ProjectFiles)
65    }
66
67    /// Create a new FileInfo for runtime files
68    pub fn runtime(filename: String, content: String) -> Self {
69        Self::new(filename, content, FileCategory::Runtime)
70    }
71}
72
73/// Trait for language-specific file writing operations
74pub trait FileWriter {
75    /// Write generated files to the output directory
76    fn write_files(
77        &self,
78        output_dir: &std::path::Path,
79        files: &[FileInfo],
80    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
81        // Group files by category
82        let mut files_by_category: HashMap<FileCategory, Vec<&FileInfo>> = HashMap::new();
83        for file in files {
84            files_by_category
85                .entry(file.category.clone())
86                .or_default()
87                .push(file);
88        }
89
90        // Write files for each category
91        for (category, category_files) in files_by_category {
92            let category_dir = match category {
93                FileCategory::None => continue,
94                FileCategory::Readme => output_dir.to_path_buf(),
95                FileCategory::Apis => output_dir.join("apis"),
96                FileCategory::Models => output_dir.join("models"),
97                FileCategory::ProjectFiles => output_dir.to_path_buf(),
98                FileCategory::Runtime => output_dir.join("runtime"),
99            };
100
101            // Create directory if it doesn't exist
102            if !category_dir.exists() {
103                fs::create_dir_all(&category_dir)?;
104            }
105
106            // Write files in this category
107            for file in category_files {
108                let file_path = category_dir.join(&file.filename);
109
110                // Create parent directories if they don't exist (for subdirectories)
111                if let Some(parent) = file_path.parent() {
112                    fs::create_dir_all(parent)?;
113                }
114
115                fs::write(&file_path, &file.content)?;
116            }
117        }
118
119        Ok(())
120    }
121}