1use std::{fs, path::PathBuf};
2
3use serde_json::Value;
4use spinne_logger::Logger;
5
6#[derive(Debug, PartialEq, Clone)]
7pub struct ConfigValues {
8 pub exclude: Option<Vec<String>>,
9 pub include: Option<Vec<String>>,
10 pub entry_points: Option<Vec<String>>,
11}
12
13pub struct Config {
18 pub path: PathBuf,
19}
20
21impl Config {
22 pub fn read(path: PathBuf) -> Option<ConfigValues> {
24 let config = fs::read_to_string(path);
25
26 if config.is_err() {
27 Logger::error("Failed to read config file");
28 return None;
29 }
30
31 match serde_json::from_str::<Value>(&config.unwrap()) {
32 Ok(value) => {
33 let exclude_value = value.get("exclude");
34 let include_value = value.get("include");
35 let entry_points_value = value.get("entry_points");
36
37 let exclude = match exclude_value {
38 Some(value) => Some(Self::get_array_of_strings(value)),
39 None => None,
40 };
41
42 let include = match include_value {
43 Some(value) => Some(Self::get_array_of_strings(value)),
44 None => None,
45 };
46
47 let entry_points = match entry_points_value {
48 Some(value) => Some(Self::get_array_of_strings(value)),
49 None => None,
50 };
51
52 Some(ConfigValues {
53 exclude,
54 include,
55 entry_points,
56 })
57 }
58 Err(err) => {
59 Logger::error("Failed to parse config file");
60 Logger::error(&err.to_string());
61 return None;
62 }
63 }
64 }
65
66 fn get_array_of_strings(value: &Value) -> Vec<String> {
68 value
69 .as_array()
70 .unwrap_or(&vec![])
71 .iter()
72 .map(|v| v.as_str().unwrap_or("").to_string())
73 .collect::<Vec<String>>()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use crate::util::test_utils::create_mock_project;
80
81 use super::*;
82
83 #[test]
84 fn test_config_read() {
85 let temp_dir = create_mock_project(&vec![(
86 "spinne.json",
87 r#"{"exclude": ["test.tsx"], "include": ["test.tsx"], "entry_points": ["src/index.tsx"]}"#,
88 )]);
89 let config = Config::read(temp_dir.path().join("spinne.json"));
90
91 assert_eq!(
92 config,
93 Some(ConfigValues {
94 exclude: Some(vec!["test.tsx".to_string()]),
95 include: Some(vec!["test.tsx".to_string()]),
96 entry_points: Some(vec!["src/index.tsx".to_string()])
97 })
98 );
99 }
100
101 #[test]
102 fn test_config_read_no_config() {
103 let temp_dir = create_mock_project(&vec![]);
104 let config = Config::read(temp_dir.path().join("spinne.json"));
105
106 assert_eq!(config, None);
107 }
108
109 #[test]
110 fn test_config_read_invalid_config() {
111 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"]ht["te)}"#)]);
112 let config = Config::read(temp_dir.path().join("spinne.json"));
113
114 assert_eq!(config, None);
115 }
116
117 #[test]
118 fn test_config_without_include() {
119 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"exclude": ["test.tsx"]}"#)]);
120 let config = Config::read(temp_dir.path().join("spinne.json"));
121
122 assert_eq!(
123 config,
124 Some(ConfigValues {
125 exclude: Some(vec!["test.tsx".to_string()]),
126 include: None,
127 entry_points: None
128 })
129 );
130 }
131
132 #[test]
133 fn test_config_without_exclude() {
134 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"include": ["test.tsx"]}"#)]);
135 let config = Config::read(temp_dir.path().join("spinne.json"));
136
137 assert_eq!(
138 config,
139 Some(ConfigValues {
140 exclude: None,
141 include: Some(vec!["test.tsx".to_string()]),
142 entry_points: None
143 })
144 );
145 }
146
147 #[test]
148 fn test_config_without_entry_points() {
149 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"include": ["test.tsx"]}"#)]);
150 let config = Config::read(temp_dir.path().join("spinne.json"));
151
152 assert_eq!(
153 config,
154 Some(ConfigValues {
155 exclude: None,
156 include: Some(vec!["test.tsx".to_string()]),
157 entry_points: None
158 })
159 );
160 }
161
162 #[test]
163 fn test_config_with_only_entry_points() {
164 let temp_dir = create_mock_project(&vec![(
165 "spinne.json",
166 r#"{"entry_points": ["src/index.tsx", "src/components/index.ts"]}"#,
167 )]);
168 let config = Config::read(temp_dir.path().join("spinne.json"));
169
170 assert_eq!(
171 config,
172 Some(ConfigValues {
173 exclude: None,
174 include: None,
175 entry_points: Some(vec![
176 "src/index.tsx".to_string(),
177 "src/components/index.ts".to_string()
178 ])
179 })
180 );
181 }
182}