1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::cli::{binary_dir, current_directory};
use colorful::{Color, Colorful};
use serde::Deserialize;
use std::fs::read_to_string;
use strum_macros::EnumString;
use toml;

#[derive(Debug, PartialEq, EnumString)]
#[strum(ascii_case_insensitive)]
#[derive(Deserialize, Clone)]
pub enum AppType {
	Server,
	Remix,
	Nextjs
}

#[derive(Deserialize, Clone)]
pub struct ServerConfig {
	pub port: Option<u16>,
	pub is_logging: Option<bool>,
	pub show_error_pages: Option<bool>,
	pub serve_static_files: Option<bool>,
	pub bindings_export_path: Option<String>,
	pub routes_directory: Option<String>,
	pub typescript_generation: Option<bool>,
	pub typescript_generation_directory: Option<String>,
}

#[derive(Deserialize, Clone)]
pub struct ReactFrameworkConfig {
	pub server_port: Option<u16>,
	pub is_logging: Option<bool>,
	pub show_error_pages: Option<bool>,
	pub serve_static_files: Option<bool>,
	pub bindings_export_path: Option<String>,
	pub typescript_generation: Option<bool>,
	pub typescript_generation_directory: Option<String>,
}

#[derive(Deserialize, Clone)]
/// Eventually rapid will have something called plugins -- for now "features" are simply optional internal functionality
/// that can be toggled by adding the desired feature to this "features" object inside of the rapid.toml config file
pub struct Features {
	// TODO: Add features here as needed
}

#[derive(Deserialize, Clone)]
/// The RapidConfig file schemea
/// # Example:
pub struct RapidConfig {
	pub app_type: String,
	pub features: Option<Features>,
	pub server: Option<ServerConfig>,
	pub remix: Option<ReactFrameworkConfig>,
	pub nextjs: Option<ReactFrameworkConfig>,
}

pub fn find_rapid_config() -> RapidConfig {
	let dir = current_directory();
	find_config(&dir)
}

pub fn find_rapid_config_from_binary() -> RapidConfig {
	let dir = binary_dir();
	find_config(&dir)
}

// A helper function to check if the current running process is inside of a rapid application
// aka does it have a rapid.toml
pub fn is_rapid() -> bool {
	let dir = current_directory();

	let config_file_contents = read_to_string(dir.join("rapid.toml"));

	// Check to make sure that the config file did not throw an error
	if let Err(_) = config_file_contents {
		return false;
	}

	return true;
}

pub fn find_config(dir: &std::path::PathBuf) -> RapidConfig {
	// Look for the Rapid config file inside of the current working directory
	let config_file_contents = read_to_string(dir.join("rapid.toml"));

	// Check to make sure that the config file did not throw an error
	if let Err(_) = config_file_contents {
		// TODO: We should improve error log styling later (just uses standard exit 200 best practices for now)
		eprintln!("Could not find a valid config file in the current working directory. Please make sure you are in a project scaffolded with the Rapid CLI.");
		std::process::exit(200);
	}

	// Parse/deserialize the rapid config file from the .toml file format
	let rapid_config: RapidConfig = toml::from_str(&config_file_contents.unwrap()).unwrap();

	// Before we output the config, we need to make sure that the app_type is valid (`it can only be either `server`, `remix`, or `nextjs`)
	let app_type = rapid_config.app_type.clone();

	if app_type != "server" && app_type != "remix" && app_type != "nextjs" {
		eprintln!(
			"{}",
			"Invalid `app_type` found in rapid.toml. The app_type can only be either `server`, `remix`, or `nextjs`."
				.color(Color::Red)
				.bold()
		);
		std::process::exit(200);
	}

	rapid_config
}