use std::path::PathBuf;
use std::{env, fs};
use crate::collector::MetadataCollector;
use crate::generators::generator_base::PydanticCodeGenerator;
use crate::models::ItemMetadata;
use convert_case::{Case, Casing};
use super::generator_base::{GeneratorConfig, PydanticCodeGeneratorFactory};
pub struct PydanticGenerator {
header_comment: String,
package_name: String,
base_path: String,
models_package_name: String,
collector: MetadataCollector,
generators: Vec<Box<dyn PydanticCodeGenerator>>,
}
impl PydanticGenerator {
pub(crate) fn new(
package_name: String,
base_path: String,
models_package_name: String,
collector: MetadataCollector,
) -> Self {
let version = env::var("CARGO_PKG_VERSION").unwrap();
let header_comment = format!("# Generated by rustantic version: {}", version).to_string();
Self {
header_comment,
package_name,
base_path,
models_package_name,
collector,
generators: Vec::new(),
}
}
pub(crate) fn register<T>(mut self) -> Self
where
T: PydanticCodeGeneratorFactory,
{
self.generators.push(T::create());
self
}
pub(crate) fn generate(&mut self) {
println!(
"cargo::warning=Rustantic generator stated, packageName='{}', basePath'{}', modelPackage='{}'",
&self.package_name, &self.base_path, &self.models_package_name
);
self.collector.collect();
println!(
"cargo:warning=Rustantic collected '{}' items",
self.collector.entities().len()
);
self.generate_init_file();
self.collector
.entities()
.iter()
.for_each(|(_, meta)| self.generate_entity_file(meta));
}
fn generate_entity_file(&self, meta: &ItemMetadata) {
for generator in self.generators.iter() {
if generator.is_item_supported(meta) {
let config = GeneratorConfig {
header_comment: &self.header_comment,
package_name: &self.package_name,
models_package_name: &self.models_package_name,
};
let generated_code = generator
.generate(config, &self.collector, meta)
.expect("Generation failed for entity");
self.create_pydantic_file(meta.ident(), &generated_code);
}
}
}
fn generate_init_file(&self) {
let mut path = PathBuf::from(&self.base_path);
path.push("__init__.py");
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, "").unwrap();
}
fn create_pydantic_file(&self, ident: &str, generated_code: &str) {
println!("cargo:warning=Start Rustantic generator for '{}'", ident);
let mut path = PathBuf::from(&self.base_path);
path.push(self.create_path(ident));
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, generated_code).unwrap();
}
fn create_path(&self, identifier: &str) -> String {
format!("{}.py", identifier.to_string().to_case(Case::Snake))
}
}