spinne_core/
package_json.rs1use serde_json::Value;
2use spinne_logger::Logger;
3use std::fs;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Default)]
8pub struct PackageJson {
9 pub path: PathBuf,
11 pub name: Option<String>,
13 pub workspaces: Option<Vec<String>>,
15}
16
17impl PackageJson {
18 pub fn read(path: PathBuf) -> Option<Self> {
20 if !path.exists() {
21 Logger::error(&format!("No package.json found at {}", path.display()));
22 return None;
23 }
24
25 let mut package_json = Self::default();
26
27 match fs::read_to_string(&path) {
28 Ok(content) => match serde_json::from_str::<Value>(&content) {
29 Ok(mut parsed) => {
30 if let Some(json_object) = parsed.as_object_mut() {
31 json_object.remove("description");
33 json_object.remove("keywords");
34 json_object.remove("scripts");
35 json_object.remove("dependencies");
36 json_object.remove("devDependencies");
37 json_object.remove("peerDependencies");
38 json_object.remove("optionalDependencies");
39
40 package_json.name = json_object
42 .get("name")
43 .and_then(|field| field.as_str())
44 .map(ToString::to_string);
45
46 package_json.workspaces = Self::get_workspaces(&parsed);
48 }
49
50 Some(package_json)
51 }
52 Err(e) => {
53 Logger::error(&format!("Failed to parse package.json: {}", e));
54 None
55 }
56 },
57 Err(e) => {
58 Logger::error(&format!("Failed to read package.json: {}", e));
59 None
60 }
61 }
62 }
63
64 fn get_workspaces(json: &Value) -> Option<Vec<String>> {
66 let workspaces = json.get("workspaces").and_then(|field| field.as_array());
67
68 match workspaces {
69 Some(workspaces) => Some(
70 workspaces
71 .iter()
72 .map(|item| item.as_str().unwrap().to_string())
73 .collect(),
74 ),
75 None => None,
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use tempfile::TempDir;
84
85 fn setup_test_dir() -> TempDir {
86 let temp_dir = TempDir::new().unwrap();
87
88 fs::write(
89 temp_dir.path().join("package.json"),
90 r#"{
91 "name": "test-project",
92 "version": "1.0.0",
93 "workspaces": ["packages/*"],
94 "config": {
95 "components": {
96 "path": "src/components"
97 }
98 }
99 }"#,
100 )
101 .unwrap();
102
103 temp_dir
104 }
105
106 #[test]
107 fn test_read_package_json() {
108 let temp_dir = setup_test_dir();
109
110 let package_json = PackageJson::read(PathBuf::from(temp_dir.path().join("package.json")))
111 .expect("Failed to read package.json");
112 assert_eq!(package_json.name, Some("test-project".to_string()));
113 }
114
115 #[test]
116 fn test_missing_package_json() {
117 assert!(PackageJson::read(PathBuf::from("package.json")).is_none());
118 }
119
120 #[test]
121 fn test_resolves_workspaces() {
122 let temp_dir = setup_test_dir();
123
124 let package_json =
125 PackageJson::read(PathBuf::from(temp_dir.path().join("package.json"))).unwrap();
126
127 assert_eq!(
128 package_json.workspaces,
129 Some(vec!["packages/*".to_string()])
130 );
131 }
132}