use crate::*;
fn get_directory_name(template_type: &TemplateType) -> String {
match template_type {
TemplateType::Controller => "controller".to_string(),
TemplateType::Domain => "domain".to_string(),
TemplateType::Exception => "exception".to_string(),
TemplateType::Mapper => "mapper".to_string(),
TemplateType::Model => "model".to_string(),
TemplateType::Repository => "repository".to_string(),
TemplateType::Service => "service".to_string(),
TemplateType::Utils => "utils".to_string(),
TemplateType::View => "view".to_string(),
}
}
fn get_model_sub_type_name(sub_type: &ModelSubType) -> String {
match sub_type {
ModelSubType::Application => "application".to_string(),
ModelSubType::Request => "request".to_string(),
ModelSubType::Response => "response".to_string(),
}
}
fn ensure_directory(path: &Path) -> Result<(), TemplateError> {
if !path.exists() {
create_dir_all(path)?;
}
Ok(())
}
fn write_mod_rs(path: &Path, modules: &[&str]) -> Result<(), TemplateError> {
let mut content: String = String::new();
for module in modules {
let mod_name: String = if module.starts_with("r#") {
module.to_string()
} else {
format!("r#{module}")
};
content.push_str(&format!("mod {mod_name};\n"));
}
content.push('\n');
let mut pub_use_parts: Vec<String> = Vec::new();
for module in modules {
let raw_name: &str = if let Some(stripped) = module.strip_prefix("r#") {
stripped
} else {
module
};
let mod_name: String = if module.starts_with("r#") {
module.to_string()
} else {
format!("r#{module}")
};
if raw_name == "const" || raw_name == "static" {
pub_use_parts.push(mod_name);
} else if raw_name == "enum" || raw_name == "fn" {
pub_use_parts.push(format!("{mod_name}::*"));
} else if raw_name == "struct" {
pub_use_parts.push(mod_name);
}
}
if !pub_use_parts.is_empty() {
content.push_str("pub use {");
content.push_str(&pub_use_parts.join(", "));
content.push_str("};\n");
}
content.push('\n');
content.push_str("use super::*;\n");
write(path, content)?;
Ok(())
}
fn write_empty_mod_rs(path: &Path) -> Result<(), TemplateError> {
write(path, "\n")?;
Ok(())
}
fn create_controller_template(
target_dir: &Path,
_component_name: &str,
) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["fn", "impl", "struct"])?;
let fn_rs: PathBuf = target_dir.join("fn.rs");
write(&fn_rs, "use super::*;\n")?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_view_template(target_dir: &Path, _component_name: &str) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["fn", "impl", "struct"])?;
let fn_rs: PathBuf = target_dir.join("fn.rs");
write(&fn_rs, "use super::*;\n")?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_service_template(target_dir: &Path, _component_name: &str) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["impl", "struct"])?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_domain_template(target_dir: &Path, _component_name: &str) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["impl", "struct"])?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_mapper_template(target_dir: &Path, _component_name: &str) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(
&mod_rs,
&["const", "enum", "fn", "impl", "static", "struct"],
)?;
let const_rs: PathBuf = target_dir.join("const.rs");
write(&const_rs, "use super::*;\n")?;
let enum_rs: PathBuf = target_dir.join("enum.rs");
write(&enum_rs, "use super::*;\n")?;
let fn_rs: PathBuf = target_dir.join("fn.rs");
write(&fn_rs, "use super::*;\n")?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let static_rs: PathBuf = target_dir.join("static.rs");
write(&static_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_utils_template(target_dir: &Path, _component_name: &str) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["fn"])?;
let fn_rs: PathBuf = target_dir.join("fn.rs");
write(&fn_rs, "use super::*;\n")?;
Ok(())
}
fn create_exception_template(
target_dir: &Path,
_component_name: &str,
) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_empty_mod_rs(&mod_rs)?;
Ok(())
}
fn create_repository_template(
target_dir: &Path,
_component_name: &str,
) -> Result<(), TemplateError> {
ensure_directory(target_dir)?;
let mod_rs: PathBuf = target_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["impl", "struct"])?;
let impl_rs: PathBuf = target_dir.join("impl.rs");
write(&impl_rs, "use super::*;\n")?;
let struct_rs: PathBuf = target_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
fn create_model_template(
target_dir: &Path,
_component_name: &str,
sub_type: &ModelSubType,
) -> Result<(), TemplateError> {
let sub_type_name: String = get_model_sub_type_name(sub_type);
let model_dir: PathBuf = target_dir.join(&sub_type_name);
ensure_directory(&model_dir)?;
let mod_rs: PathBuf = model_dir.join("mod.rs");
write_mod_rs(&mod_rs, &["struct"])?;
let struct_rs: PathBuf = model_dir.join("struct.rs");
write(&struct_rs, "use super::*;\n")?;
Ok(())
}
pub(crate) async fn execute_template(
template_type: TemplateType,
component_name: &str,
model_sub_type: Option<ModelSubType>,
) -> Result<(), TemplateError> {
let config: TemplateConfig =
TemplateConfig::new(template_type, component_name.to_string(), model_sub_type);
let base_path: PathBuf = PathBuf::from(&config.base_directory);
let dir_name: String = get_directory_name(&config.template_type);
let type_dir: PathBuf = base_path.join(&dir_name);
let target_dir: PathBuf = type_dir.join(&config.component_name);
if target_dir.exists() {
return Err(TemplateError::DirectoryExists(
target_dir.to_string_lossy().to_string(),
));
}
ensure_directory(&type_dir)?;
match config.template_type {
TemplateType::Controller => {
create_controller_template(&target_dir, &config.component_name)?
}
TemplateType::View => create_view_template(&target_dir, &config.component_name)?,
TemplateType::Service => create_service_template(&target_dir, &config.component_name)?,
TemplateType::Domain => create_domain_template(&target_dir, &config.component_name)?,
TemplateType::Mapper => create_mapper_template(&target_dir, &config.component_name)?,
TemplateType::Utils => create_utils_template(&target_dir, &config.component_name)?,
TemplateType::Exception => create_exception_template(&target_dir, &config.component_name)?,
TemplateType::Repository => {
create_repository_template(&target_dir, &config.component_name)?
}
TemplateType::Model => {
let sub_type: ModelSubType = config.model_sub_type.ok_or_else(|| {
TemplateError::InvalidModelSubType("Missing model subtype".to_string())
})?;
create_model_template(&target_dir, &config.component_name, &sub_type)?;
}
}
let _: Result<(), std::io::Error> = crate::fmt::format_path(&target_dir).await;
println!(
"Created {} '{}' at {}",
dir_name,
config.component_name,
target_dir.display()
);
Ok(())
}