ferro_cli/commands/
make_resource.rs1use console::style;
2use std::fs;
3use std::path::Path;
4
5use crate::templates;
6
7pub fn run(name: String, model: Option<String>) {
8 let name = if name.ends_with("Resource") {
10 name
11 } else {
12 format!("{name}Resource")
13 };
14
15 let file_name = to_snake_case(&name);
17
18 if !is_valid_identifier(&file_name) {
20 eprintln!(
21 "{} '{}' is not a valid resource name",
22 style("Error:").red().bold(),
23 name
24 );
25 std::process::exit(1);
26 }
27
28 let resources_dir = Path::new("src/resources");
29 let resource_file = resources_dir.join(format!("{file_name}.rs"));
30
31 if !resources_dir.exists() {
33 if let Err(e) = fs::create_dir_all(resources_dir) {
34 eprintln!(
35 "{} Failed to create resources directory: {}",
36 style("Error:").red().bold(),
37 e
38 );
39 std::process::exit(1);
40 }
41 println!("{} Created src/resources/", style("✓").green());
42 }
43
44 if resource_file.exists() {
46 eprintln!(
47 "{} Resource '{}' already exists at {}",
48 style("Info:").yellow().bold(),
49 file_name,
50 resource_file.display()
51 );
52 std::process::exit(0);
53 }
54
55 let content = templates::resource_template(&name, model.as_deref());
57
58 if let Err(e) = fs::write(&resource_file, content) {
60 eprintln!(
61 "{} Failed to write resource file: {}",
62 style("Error:").red().bold(),
63 e
64 );
65 std::process::exit(1);
66 }
67 println!("{} Created {}", style("✓").green(), resource_file.display());
68
69 println!();
70 println!(
71 "Resource {} created successfully!",
72 style(&name).cyan().bold()
73 );
74 println!();
75 println!(
76 " {} Add `pub mod {};` to src/resources/mod.rs",
77 style("→").dim(),
78 file_name
79 );
80 println!();
81}
82
83fn is_valid_identifier(name: &str) -> bool {
84 if name.is_empty() {
85 return false;
86 }
87
88 let mut chars = name.chars();
89
90 match chars.next() {
92 Some(c) if c.is_alphabetic() || c == '_' => {}
93 _ => return false,
94 }
95
96 chars.all(|c| c.is_alphanumeric() || c == '_')
98}
99
100fn to_snake_case(s: &str) -> String {
101 let mut result = String::new();
102 for (i, c) in s.chars().enumerate() {
103 if c.is_uppercase() {
104 if i > 0 {
105 result.push('_');
106 }
107 result.push(c.to_lowercase().next().unwrap());
108 } else {
109 result.push(c);
110 }
111 }
112 result
113}