1use serde::{Deserialize, Deserializer, Serialize};
2use std::collections::HashMap;
3use std::fs;
4use std::path::Path;
5
6use super::errors::{DnxError, Result};
7
8pub type Dependencies = HashMap<String, String>;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct PackageJson {
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub name: Option<String>,
14
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub version: Option<String>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub description: Option<String>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub main: Option<String>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub license: Option<String>,
26
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub dependencies: Option<Dependencies>,
29
30 #[serde(rename = "devDependencies", skip_serializing_if = "Option::is_none")]
31 pub dev_dependencies: Option<Dependencies>,
32
33 #[serde(rename = "peerDependencies", skip_serializing_if = "Option::is_none")]
34 pub peer_dependencies: Option<Dependencies>,
35
36 #[serde(
37 rename = "optionalDependencies",
38 skip_serializing_if = "Option::is_none"
39 )]
40 pub optional_dependencies: Option<Dependencies>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub scripts: Option<HashMap<String, String>>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub bin: Option<BinField>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub engines: Option<HashMap<String, String>>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub private: Option<bool>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub overrides: Option<HashMap<String, String>>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub resolutions: Option<HashMap<String, String>>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub workspaces: Option<Vec<String>>,
65}
66
67#[derive(Debug, Clone, Serialize)]
68#[serde(untagged)]
69pub enum BinField {
70 Single(String),
71 Map(HashMap<String, String>),
72}
73
74impl<'de> Deserialize<'de> for BinField {
75 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
76 where
77 D: Deserializer<'de>,
78 {
79 #[derive(Deserialize)]
80 #[serde(untagged)]
81 enum BinFieldHelper {
82 Single(String),
83 Map(HashMap<String, String>),
84 }
85
86 match BinFieldHelper::deserialize(deserializer)? {
87 BinFieldHelper::Single(s) => Ok(BinField::Single(s)),
88 BinFieldHelper::Map(m) => Ok(BinField::Map(m)),
89 }
90 }
91}
92
93impl PackageJson {
94 pub fn read(path: &Path) -> Result<Self> {
95 let content = fs::read_to_string(path).map_err(|e| {
96 DnxError::Io(format!(
97 "Failed to read package.json at {}: {}",
98 path.display(),
99 e
100 ))
101 })?;
102
103 let package_json: PackageJson = serde_json::from_str(&content).map_err(|e| {
104 DnxError::ParseError(format!(
105 "Failed to parse package.json at {}: {}",
106 path.display(),
107 e
108 ))
109 })?;
110
111 Ok(package_json)
112 }
113
114 pub fn write(&self, path: &Path) -> Result<()> {
115 let content = serde_json::to_string_pretty(self).map_err(|e| {
116 DnxError::ParseError(format!("Failed to serialize package.json: {}", e))
117 })?;
118
119 fs::write(path, content).map_err(|e| {
120 DnxError::Io(format!(
121 "Failed to write package.json to {}: {}",
122 path.display(),
123 e
124 ))
125 })?;
126
127 Ok(())
128 }
129
130 pub fn all_dependencies(&self) -> HashMap<String, String> {
131 let mut all_deps = HashMap::new();
132
133 if let Some(deps) = &self.dependencies {
134 all_deps.extend(deps.clone());
135 }
136
137 if let Some(dev_deps) = &self.dev_dependencies {
138 all_deps.extend(dev_deps.clone());
139 }
140
141 all_deps
142 }
143}