rustantic 0.2.0

Rust to Pydantic generator
Documentation
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))
    }
}