boots_core/config/
parser.rs1use super::types::*;
2use crate::error::{BootsError, Result};
3use std::process::Command;
4
5fn get_git_config(key: &str) -> String {
7 Command::new("git")
8 .args(["config", "--get", key])
9 .output()
10 .ok()
11 .and_then(|output| {
12 if output.status.success() {
13 String::from_utf8(output.stdout).ok()
14 } else {
15 None
16 }
17 })
18 .map(|s| s.trim().to_string())
19 .unwrap_or_default()
20}
21
22pub fn parse_options(
23 project_type: ProjectType,
24 name: &str,
25 options: Option<&str>,
26) -> Result<ProjectConfig> {
27 let author_name = get_git_config("user.name");
28 let author_email = get_git_config("user.email");
29
30 let mut config = ProjectConfig {
31 name: name.to_string(),
32 project_type,
33 persistence: None,
34 frontend: None,
35 has_grpc: false,
36 has_http: true,
37 has_client: false,
38 author_name,
39 author_email,
40 };
41
42 if let Some(opts) = options {
43 let opts_list: Vec<&str> = opts.split(',').map(|s| s.trim()).collect();
44
45 if opts_list.contains(&"sample") {
47 let other_options: Vec<&str> = opts_list
48 .iter()
49 .filter(|o| **o != "sample")
50 .copied()
51 .collect();
52 if !other_options.is_empty() {
53 eprintln!(
54 "Warning: 'sample' option ignores other options: {:?}",
55 other_options
56 );
57 }
58 config.persistence = Some(PersistenceType::Postgres);
60 config.frontend = Some(FrontendType::Spa);
61 return Ok(config);
62 }
63
64 for option in opts_list {
65 match option {
66 "postgres" => config.persistence = Some(PersistenceType::Postgres),
67 "sqlite" => config.persistence = Some(PersistenceType::Sqlite),
68 "file" => config.persistence = Some(PersistenceType::File),
69 "grpc" => config.has_grpc = true,
70 "http" => config.has_http = true,
71 "client" => config.has_client = true,
72 "persistence" => {
73 if config.persistence.is_none() {
74 config.persistence = Some(PersistenceType::File);
75 }
76 }
77 "fe:spa" | "fe-spa" | "spa" => config.frontend = Some(FrontendType::Spa),
79 "fe:ssr" | "fe-ssr" | "ssr" => config.frontend = Some(FrontendType::Ssr),
80 "" => continue,
81 _ => return Err(BootsError::InvalidOption(option.to_string())),
82 }
83 }
84 }
85
86 Ok(config)
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_parse_service_default() {
95 let config = parse_options(ProjectType::Service, "test-svc", None).unwrap();
96 assert_eq!(config.project_type, ProjectType::Service);
97 assert!(config.persistence.is_none());
98 assert!(!config.has_grpc);
99 assert!(config.has_http);
100 }
101
102 #[test]
103 fn test_parse_service_with_postgres() {
104 let config = parse_options(ProjectType::Service, "test-svc", Some("postgres")).unwrap();
105 assert_eq!(config.persistence, Some(PersistenceType::Postgres));
106 }
107
108 #[test]
109 fn test_parse_service_with_multiple_options() {
110 let config =
111 parse_options(ProjectType::Service, "test-svc", Some("postgres,grpc")).unwrap();
112 assert_eq!(config.persistence, Some(PersistenceType::Postgres));
113 assert!(config.has_grpc);
114 }
115
116 #[test]
117 fn test_parse_cli_with_client() {
118 let config = parse_options(ProjectType::Cli, "test-cli", Some("client")).unwrap();
119 assert!(config.has_client);
120 }
121
122 #[test]
123 fn test_invalid_option() {
124 let result = parse_options(ProjectType::Service, "test", Some("invalid_option"));
125 assert!(result.is_err());
126 }
127
128 #[test]
129 fn test_parse_service_with_spa() {
130 let config = parse_options(ProjectType::Service, "test-svc", Some("fe:spa")).unwrap();
131 assert_eq!(config.frontend, Some(FrontendType::Spa));
132 }
133
134 #[test]
135 fn test_parse_service_with_ssr() {
136 let config = parse_options(ProjectType::Service, "test-svc", Some("fe:ssr")).unwrap();
137 assert_eq!(config.frontend, Some(FrontendType::Ssr));
138 }
139
140 #[test]
141 fn test_parse_service_with_postgres_and_spa() {
142 let config =
143 parse_options(ProjectType::Service, "test-svc", Some("postgres,fe:spa")).unwrap();
144 assert_eq!(config.persistence, Some(PersistenceType::Postgres));
145 assert_eq!(config.frontend, Some(FrontendType::Spa));
146 }
147
148 #[test]
149 fn test_parse_sample_default() {
150 let config = parse_options(ProjectType::Sample, "test-board", Some("sample")).unwrap();
151 assert_eq!(config.project_type, ProjectType::Sample);
152 assert_eq!(config.persistence, Some(PersistenceType::Postgres));
153 assert_eq!(config.frontend, Some(FrontendType::Spa));
154 }
155
156 #[test]
157 fn test_parse_sample_ignores_other_options() {
158 let config = parse_options(
160 ProjectType::Sample,
161 "test-board",
162 Some("sample,grpc,sqlite"),
163 )
164 .unwrap();
165 assert_eq!(config.persistence, Some(PersistenceType::Postgres)); assert!(!config.has_grpc); assert_eq!(config.frontend, Some(FrontendType::Spa));
168 }
169}