ferro_cli/commands/
make_inertia.rs1use console::style;
2use std::fs;
3use std::path::Path;
4
5use crate::templates;
6
7pub fn run(name: String) {
8 let page_name = to_page_name(&name);
10
11 if !is_valid_component_name(&page_name) {
13 eprintln!(
14 "{} '{}' is not a valid page name",
15 style("Error:").red().bold(),
16 name
17 );
18 std::process::exit(1);
19 }
20
21 let pages_dir = Path::new("frontend/src/pages");
22 let page_file = pages_dir.join(format!("{page_name}.tsx"));
23
24 if !pages_dir.exists() {
26 eprintln!(
27 "{} Pages directory not found at frontend/src/pages",
28 style("Error:").red().bold()
29 );
30 eprintln!(
31 "{}",
32 style("Make sure you're in a Ferro project root directory.").dim()
33 );
34 std::process::exit(1);
35 }
36
37 if page_file.exists() {
39 eprintln!(
40 "{} Page '{}' already exists at {}",
41 style("Info:").yellow().bold(),
42 page_name,
43 page_file.display()
44 );
45 std::process::exit(0);
46 }
47
48 let page_content = templates::inertia_page_template(&page_name);
50
51 if let Err(e) = fs::write(&page_file, page_content) {
53 eprintln!(
54 "{} Failed to write page file: {}",
55 style("Error:").red().bold(),
56 e
57 );
58 std::process::exit(1);
59 }
60 println!("{} Created {}", style("✓").green(), page_file.display());
61
62 println!();
63 println!(
64 "Page {} created successfully!",
65 style(&page_name).cyan().bold()
66 );
67 println!();
68 println!("Usage:");
69 println!(" {} Use the page in a controller:", style("1.").dim());
70 println!(" inertia_response!(\"{page_name}\", props)");
71 println!();
72}
73
74fn is_valid_component_name(name: &str) -> bool {
75 if name.is_empty() {
76 return false;
77 }
78
79 let mut chars = name.chars();
80
81 match chars.next() {
83 Some(c) if c.is_ascii_uppercase() => {}
84 _ => return false,
85 }
86
87 chars.all(|c| c.is_alphanumeric())
89}
90
91fn to_pascal_case(s: &str) -> String {
92 let mut result = String::new();
93 let mut capitalize_next = true;
94
95 for c in s.chars() {
96 if c == '_' || c == '-' || c == ' ' {
97 capitalize_next = true;
98 } else if capitalize_next {
99 result.push(c.to_uppercase().next().unwrap());
100 capitalize_next = false;
101 } else {
102 result.push(c);
103 }
104 }
105 result
106}
107
108fn to_page_name(input: &str) -> String {
109 let pascal = to_pascal_case(input);
111
112 if pascal.ends_with("Page") {
114 pascal
115 } else {
116 format!("{pascal}Page")
117 }
118}