rapid_cli/commands/
routes.rs1use super::RapidCommand;
2use crate::{cli::Config, tui::{logo, chevrons, clean_console}, rapid_config::config::{find_rapid_config, ServerConfig}};
3use clap::{ArgMatches, Command};
4use walkdir::WalkDir;
5use std::fs::File;
6use std::io::Read;
7use colorful::{Color, Colorful};
8use regex::Regex;
9
10pub const REMIX_ROUTE_PATH: &'static str = "app/api/routes";
11pub const NEXTJS_ROUTE_PATH: &'static str = "pages/api/routes";
12
13pub struct Routes {}
15
16impl RapidCommand for Routes {
17 fn cmd() -> clap::Command {
18 Command::new("routes").about("Show all the routes in your rapid project!")
19 }
20
21 fn execute(_: &Config, _args: &ArgMatches) -> Result<(), crate::cli::CliError<'static>> {
22 println!("{}", logo());
23 let config = find_rapid_config();
25 let routes_dir = match config.app_type.as_str() {
26 "server" => get_routes_dir(config.server.as_ref()),
27 "remix" => REMIX_ROUTE_PATH.to_owned(),
28 _ => NEXTJS_ROUTE_PATH.to_owned(),
29 };
30 generate_routes(&routes_dir);
31 Ok(())
32 }
33}
34
35pub fn generate_routes(routes_dir: &str) {
36 let mut routes = vec![];
37 for route_file in WalkDir::new(routes_dir.clone()) {
38 let entry = match route_file {
39 Ok(val) => val,
40 Err(e) => panic!("An error occurred what attempting to parse directory: {}", e),
41 };
42
43 if entry.path().is_dir() {
45 continue;
46 }
47
48 let mut file = File::open(&entry.path()).unwrap();
50 let mut route_file_contents = String::new();
51 file.read_to_string(&mut route_file_contents).unwrap();
52
53 let file_name = entry.file_name();
54
55 if file_name == "_middleware.rs" || file_name == "mod.rs" {
57 continue;
58 }
59
60 let parsed_route_dir = entry
61 .path()
62 .to_str()
63 .unwrap_or("/")
64 .to_string()
65 .replace(routes_dir, "");
66
67 routes.push(parsed_route_dir);
68 }
69
70 let total_routes_count = routes.len();
71
72 clean_console();
74 println!();
75
76 for route in routes {
77 let route_url = remove_last_occurrence(&route.replace(".rs", ""), "index");
78 let route_path = format!("{}{}", routes_dir, route);
79 let dynamic_route_regex = Regex::new(r"_(.*?)_").unwrap();
80 println!("{} {} {}\n", route_path, "➜".color(Color::LightCyan).bold(), dynamic_route_regex.replace_all(&route_url, "{$1}").bold());
81 }
82
83 println!("{} Found {} routes in your project\n", chevrons(), total_routes_count.to_string().color(Color::Blue).bold());
84}
85
86pub fn remove_last_occurrence(s: &str, sub: &str) -> String {
87 let mut split = s.rsplitn(2, sub);
88 let back = split.next().unwrap_or("");
89 let front = split.next().unwrap_or("").to_owned();
90 front + back
91}
92
93pub fn get_routes_dir(rapid_server_config: Option<&ServerConfig>) -> String {
94 match rapid_server_config {
95 Some(server) => match server.routes_directory.clone() {
96 Some(dir) => match dir == "/" {
97 true => panic!("The 'routes_directory' variable cannot be set to a base path. Please use something nested!"),
98 false => dir,
99 },
100 None => panic!("Error: the 'routes_directory' variable must be set in your rapid config file!"),
101 },
102 None => panic!("You must have a valid rapid config file in the base project directory!"),
103 }
104}