1use super::*;
2
3fn get_directory_name(template_type: &TemplateType) -> String {
13 match template_type {
14 TemplateType::Controller => TEMPLATE_TYPE_CONTROLLER.to_string(),
15 TemplateType::Domain => TEMPLATE_TYPE_DOMAIN.to_string(),
16 TemplateType::Exception => TEMPLATE_TYPE_EXCEPTION.to_string(),
17 TemplateType::Mapper => TEMPLATE_TYPE_MAPPER.to_string(),
18 TemplateType::Model => TEMPLATE_TYPE_MODEL.to_string(),
19 TemplateType::Repository => TEMPLATE_TYPE_REPOSITORY.to_string(),
20 TemplateType::Service => TEMPLATE_TYPE_SERVICE.to_string(),
21 TemplateType::Utils => TEMPLATE_TYPE_UTILS.to_string(),
22 TemplateType::View => TEMPLATE_TYPE_VIEW.to_string(),
23 }
24}
25
26fn get_model_sub_type_name(sub_type: &ModelSubType) -> String {
36 match sub_type {
37 ModelSubType::Application => MODEL_SUB_TYPE_APPLICATION.to_string(),
38 ModelSubType::Request => MODEL_SUB_TYPE_REQUEST.to_string(),
39 ModelSubType::Response => MODEL_SUB_TYPE_RESPONSE.to_string(),
40 }
41}
42
43async fn ensure_directory(path: &Path) -> Result<(), TemplateError> {
53 if !path.exists() {
54 create_dir_all(path).await?;
55 }
56 Ok(())
57}
58
59async fn write_mod_rs(path: &Path, modules: &[&str]) -> Result<(), TemplateError> {
70 let mut content: String = String::new();
71 for module in modules {
72 let mod_name: String = if module.starts_with("r#") {
73 module.to_string()
74 } else {
75 format!("r#{module}")
76 };
77 content.push_str(&format!("mod {mod_name};\n"));
78 }
79 content.push('\n');
80 let mut pub_use_parts: Vec<String> = Vec::new();
81 for module in modules {
82 let raw_name: &str = if let Some(stripped) = module.strip_prefix("r#") {
83 stripped
84 } else {
85 module
86 };
87 let mod_name: String = if module.starts_with("r#") {
88 module.to_string()
89 } else {
90 format!("r#{module}")
91 };
92 if raw_name == MODULE_NAME_CONST || raw_name == MODULE_NAME_STATIC {
93 pub_use_parts.push(mod_name);
94 } else if raw_name == MODULE_NAME_ENUM || raw_name == MODULE_NAME_FN {
95 pub_use_parts.push(format!("{mod_name}::*"));
96 } else if raw_name == MODULE_NAME_STRUCT {
97 pub_use_parts.push(mod_name);
98 }
99 }
100 if !pub_use_parts.is_empty() {
101 content.push_str(PUB_USE_PREFIX);
102 content.push_str(&pub_use_parts.join(", "));
103 content.push_str("};\n");
104 }
105 content.push('\n');
106 content.push_str(KEYWORD_FILE_HEADER);
107 write(path, content).await?;
108 Ok(())
109}
110
111async fn write_empty_mod_rs(path: &Path) -> Result<(), TemplateError> {
121 write(path, "\n").await?;
122 Ok(())
123}
124
125async fn create_controller_template(
136 target_dir: &Path,
137 _component_name: &str,
138) -> Result<(), TemplateError> {
139 ensure_directory(target_dir).await?;
140 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
141 write_mod_rs(
142 &mod_rs,
143 &[MODULE_NAME_FN, MODULE_NAME_IMPL, MODULE_NAME_STRUCT],
144 )
145 .await?;
146 let fn_rs: PathBuf = target_dir.join(FILE_NAME_FN_RS);
147 write(&fn_rs, KEYWORD_FILE_HEADER).await?;
148 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
149 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
150 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
151 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
152 Ok(())
153}
154
155async fn create_view_template(
166 target_dir: &Path,
167 _component_name: &str,
168) -> Result<(), TemplateError> {
169 ensure_directory(target_dir).await?;
170 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
171 write_mod_rs(
172 &mod_rs,
173 &[MODULE_NAME_FN, MODULE_NAME_IMPL, MODULE_NAME_STRUCT],
174 )
175 .await?;
176 let fn_rs: PathBuf = target_dir.join(FILE_NAME_FN_RS);
177 write(&fn_rs, KEYWORD_FILE_HEADER).await?;
178 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
179 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
180 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
181 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
182 Ok(())
183}
184
185async fn create_service_template(
196 target_dir: &Path,
197 _component_name: &str,
198) -> Result<(), TemplateError> {
199 ensure_directory(target_dir).await?;
200 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
201 write_mod_rs(&mod_rs, &[MODULE_NAME_IMPL, MODULE_NAME_STRUCT]).await?;
202 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
203 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
204 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
205 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
206 Ok(())
207}
208
209async fn create_domain_template(
220 target_dir: &Path,
221 _component_name: &str,
222) -> Result<(), TemplateError> {
223 ensure_directory(target_dir).await?;
224 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
225 write_mod_rs(&mod_rs, &[MODULE_NAME_IMPL, MODULE_NAME_STRUCT]).await?;
226 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
227 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
228 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
229 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
230 Ok(())
231}
232
233async fn create_mapper_template(
244 target_dir: &Path,
245 _component_name: &str,
246) -> Result<(), TemplateError> {
247 ensure_directory(target_dir).await?;
248 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
249 write_mod_rs(
250 &mod_rs,
251 &[
252 MODULE_NAME_CONST,
253 MODULE_NAME_ENUM,
254 MODULE_NAME_FN,
255 MODULE_NAME_IMPL,
256 MODULE_NAME_STATIC,
257 MODULE_NAME_STRUCT,
258 ],
259 )
260 .await?;
261 let const_rs: PathBuf = target_dir.join(FILE_NAME_CONST_RS);
262 write(&const_rs, KEYWORD_FILE_HEADER).await?;
263 let enum_rs: PathBuf = target_dir.join(FILE_NAME_ENUM_RS);
264 write(&enum_rs, KEYWORD_FILE_HEADER).await?;
265 let fn_rs: PathBuf = target_dir.join(FILE_NAME_FN_RS);
266 write(&fn_rs, KEYWORD_FILE_HEADER).await?;
267 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
268 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
269 let static_rs: PathBuf = target_dir.join(FILE_NAME_STATIC_RS);
270 write(&static_rs, KEYWORD_FILE_HEADER).await?;
271 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
272 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
273 Ok(())
274}
275
276async fn create_utils_template(
287 target_dir: &Path,
288 _component_name: &str,
289) -> Result<(), TemplateError> {
290 ensure_directory(target_dir).await?;
291 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
292 write_mod_rs(&mod_rs, &[MODULE_NAME_FN]).await?;
293 let fn_rs: PathBuf = target_dir.join(FILE_NAME_FN_RS);
294 write(&fn_rs, KEYWORD_FILE_HEADER).await?;
295 Ok(())
296}
297
298async fn create_exception_template(
309 target_dir: &Path,
310 _component_name: &str,
311) -> Result<(), TemplateError> {
312 ensure_directory(target_dir).await?;
313 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
314 write_empty_mod_rs(&mod_rs).await?;
315 Ok(())
316}
317
318async fn create_repository_template(
329 target_dir: &Path,
330 _component_name: &str,
331) -> Result<(), TemplateError> {
332 ensure_directory(target_dir).await?;
333 let mod_rs: PathBuf = target_dir.join(FILE_NAME_MOD_RS);
334 write_mod_rs(&mod_rs, &[MODULE_NAME_IMPL, MODULE_NAME_STRUCT]).await?;
335 let impl_rs: PathBuf = target_dir.join(FILE_NAME_IMPL_RS);
336 write(&impl_rs, KEYWORD_FILE_HEADER).await?;
337 let struct_rs: PathBuf = target_dir.join(FILE_NAME_STRUCT_RS);
338 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
339 Ok(())
340}
341
342async fn create_model_template(
354 target_dir: &Path,
355 _component_name: &str,
356 sub_type: &ModelSubType,
357) -> Result<(), TemplateError> {
358 let sub_type_name: String = get_model_sub_type_name(sub_type);
359 let model_dir: PathBuf = target_dir.join(&sub_type_name);
360 ensure_directory(&model_dir).await?;
361 let mod_rs: PathBuf = model_dir.join(FILE_NAME_MOD_RS);
362 write_mod_rs(&mod_rs, &[MODULE_NAME_STRUCT]).await?;
363 let struct_rs: PathBuf = model_dir.join(FILE_NAME_STRUCT_RS);
364 write(&struct_rs, KEYWORD_FILE_HEADER).await?;
365 Ok(())
366}
367
368pub async fn execute_template(
380 template_type: TemplateType,
381 component_name: &str,
382 model_sub_type: Option<ModelSubType>,
383) -> Result<(), TemplateError> {
384 let config: TemplateConfig =
385 TemplateConfig::new(template_type, component_name.to_string(), model_sub_type);
386 let base_path: PathBuf = PathBuf::from(&config.base_directory);
387 let dir_name: String = get_directory_name(&config.template_type);
388 let type_dir: PathBuf = base_path.join(&dir_name);
389 let target_dir: PathBuf = type_dir.join(&config.component_name);
390 if target_dir.exists() {
391 return Err(TemplateError::DirectoryExists(
392 target_dir.to_string_lossy().to_string(),
393 ));
394 }
395 ensure_directory(&type_dir).await?;
396 match config.template_type {
397 TemplateType::Controller => {
398 create_controller_template(&target_dir, &config.component_name).await?
399 }
400 TemplateType::View => create_view_template(&target_dir, &config.component_name).await?,
401 TemplateType::Service => {
402 create_service_template(&target_dir, &config.component_name).await?
403 }
404 TemplateType::Domain => create_domain_template(&target_dir, &config.component_name).await?,
405 TemplateType::Mapper => create_mapper_template(&target_dir, &config.component_name).await?,
406 TemplateType::Utils => create_utils_template(&target_dir, &config.component_name).await?,
407 TemplateType::Exception => {
408 create_exception_template(&target_dir, &config.component_name).await?
409 }
410 TemplateType::Repository => {
411 create_repository_template(&target_dir, &config.component_name).await?
412 }
413 TemplateType::Model => {
414 let sub_type: ModelSubType = config.model_sub_type.ok_or_else(|| {
415 TemplateError::InvalidModelSubType(ERROR_MISSING_MODEL_SUB_TYPE.to_string())
416 })?;
417 create_model_template(&target_dir, &config.component_name, &sub_type).await?;
418 }
419 }
420 let _: Result<(), io::Error> = format_generated_path(&target_dir).await;
421 log::info!(
422 "Created {dir_name} '{}' at {}",
423 config.component_name,
424 target_dir.display()
425 );
426 Ok(())
427}
428
429async fn format_generated_path(path: &Path) -> Result<(), io::Error> {
440 let mut cmd: Command = Command::new(CARGO_FMT_PROGRAM);
441 cmd.arg("fmt");
442 cmd.arg("--");
443 cmd.arg(path);
444 cmd.stdout(Stdio::null()).stderr(Stdio::null());
445 cmd.status().await?;
446 Ok(())
447}