openapi_nexus_core/
openapi_code_generator.rs

1//! Main code generation orchestrator
2
3use std::path::Path;
4
5use snafu::ResultExt as _;
6use tracing::error;
7
8use crate::error;
9use crate::generator_registry::{GeneratorRegistry, LanguageGenerator};
10use openapi_nexus_common::Language;
11use openapi_nexus_parser::parse_file;
12
13/// Main code generation orchestrator
14pub struct OpenApiCodeGenerator {
15    generator_registry: GeneratorRegistry,
16}
17
18impl OpenApiCodeGenerator {
19    /// Create a new code generator with default configuration
20    pub fn new() -> Self {
21        Self {
22            generator_registry: GeneratorRegistry::new(),
23        }
24    }
25
26    /// Register a language generator
27    pub fn register_language_generator<G>(
28        &mut self,
29        language: Language,
30        generator: G,
31    ) -> Result<(), error::Error>
32    where
33        G: LanguageGenerator + Send + Sync + 'static,
34    {
35        self.generator_registry
36            .register_generator(language, generator)
37            .map_err(|msg| {
38                error!(
39                    "Failed to register language generator for {}: {}",
40                    language, msg
41                );
42                error::Error::Generate {
43                    source: Box::new(std::io::Error::other(msg)),
44                }
45            })
46    }
47
48    /// Generate code from an OpenAPI specification file
49    pub fn generate_from_file<P: AsRef<Path>>(
50        &self,
51        input_path: P,
52        output_dir: P,
53        language: Language,
54    ) -> Result<(), error::Error> {
55        tracing::info!(
56            "Parsing OpenAPI specification from: {:?}",
57            input_path.as_ref()
58        );
59        let openapi = parse_file(input_path.as_ref())
60            .map_err(|e| {
61                error!(
62                    "Failed to parse OpenAPI file {:?}: {}",
63                    input_path.as_ref(),
64                    e
65                );
66                e
67            })
68            .context(error::ParseSnafu)?;
69
70        tracing::info!("Generating {} code", language);
71
72        // Check if generator is registered
73        if !self.generator_registry.has_generator(language) {
74            let err = error::Error::GeneratorNotFound {
75                language: language.to_string(),
76            };
77            error!("{}", err);
78            return Err(err);
79        }
80
81        // Get the generator and generate files
82        let generator = self
83            .generator_registry
84            .get_generator(language)
85            .ok_or_else(|| {
86                let err = error::Error::GeneratorNotFound {
87                    language: language.to_string(),
88                };
89                error!("{}", err);
90                err
91            })?;
92
93        let files = generator.generate(&openapi).map_err(|e| {
94            error!("Failed to generate code for {}: {}", language, e);
95            error::Error::Generate { source: e }
96        })?;
97
98        // Write files using the FileWriter trait
99        generator
100            .write_files(output_dir.as_ref(), &files)
101            .map_err(|e| {
102                error!("Failed to write files for {}: {}", language, e);
103                error::Error::Generate { source: e }
104            })?;
105
106        tracing::info!(
107            "Successfully generated {} files for {}",
108            files.len(),
109            language
110        );
111
112        Ok(())
113    }
114}
115
116impl Default for OpenApiCodeGenerator {
117    fn default() -> Self {
118        Self::new()
119    }
120}