opencode_sdk_rs/resources/
file.rs1use serde::{Deserialize, Serialize};
4
5use crate::{client::Opencode, error::OpencodeError};
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "lowercase")]
14pub enum FileStatus {
15 Added,
17 Deleted,
19 Modified,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27pub struct FileInfo {
28 pub added: i64,
30 pub path: String,
32 pub removed: i64,
34 pub status: FileStatus,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
40#[serde(rename_all = "lowercase")]
41pub enum FileReadType {
42 Raw,
44 Patch,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
50pub struct FileReadResponse {
51 pub content: String,
53 #[serde(rename = "type")]
55 pub file_type: FileReadType,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
60pub struct FileReadParams {
61 pub path: String,
63}
64
65pub type FileStatusResponse = Vec<FileInfo>;
67
68pub struct FileResource<'a> {
74 client: &'a Opencode,
75}
76
77impl<'a> FileResource<'a> {
78 pub(crate) const fn new(client: &'a Opencode) -> Self {
79 Self { client }
80 }
81
82 pub async fn read(&self, params: &FileReadParams) -> Result<FileReadResponse, OpencodeError> {
86 self.client.get_with_query("/file", Some(params), None).await
87 }
88
89 pub async fn status(&self) -> Result<FileStatusResponse, OpencodeError> {
93 self.client.get("/file/status", None).await
94 }
95}
96
97#[cfg(test)]
102mod tests {
103 use serde_json;
104
105 use super::*;
106
107 #[test]
108 fn file_status_round_trip() {
109 for (variant, expected) in [
110 (FileStatus::Added, "\"added\""),
111 (FileStatus::Deleted, "\"deleted\""),
112 (FileStatus::Modified, "\"modified\""),
113 ] {
114 let json = serde_json::to_string(&variant).unwrap();
115 assert_eq!(json, expected);
116 let parsed: FileStatus = serde_json::from_str(&json).unwrap();
117 assert_eq!(parsed, variant);
118 }
119 }
120
121 #[test]
122 fn file_info_round_trip() {
123 let info = FileInfo {
124 added: 10,
125 path: "src/main.rs".to_string(),
126 removed: 3,
127 status: FileStatus::Modified,
128 };
129 let json = serde_json::to_string(&info).unwrap();
130 let parsed: FileInfo = serde_json::from_str(&json).unwrap();
131 assert_eq!(parsed, info);
132 }
133
134 #[test]
135 fn file_info_deserialize_from_js() {
136 let json = r#"{
137 "added": 5,
138 "path": "README.md",
139 "removed": 0,
140 "status": "added"
141 }"#;
142 let info: FileInfo = serde_json::from_str(json).unwrap();
143 assert_eq!(info.added, 5);
144 assert_eq!(info.path, "README.md");
145 assert_eq!(info.removed, 0);
146 assert_eq!(info.status, FileStatus::Added);
147 }
148
149 #[test]
150 fn file_read_type_round_trip() {
151 for (variant, expected) in
152 [(FileReadType::Raw, "\"raw\""), (FileReadType::Patch, "\"patch\"")]
153 {
154 let json = serde_json::to_string(&variant).unwrap();
155 assert_eq!(json, expected);
156 let parsed: FileReadType = serde_json::from_str(&json).unwrap();
157 assert_eq!(parsed, variant);
158 }
159 }
160
161 #[test]
162 fn file_read_response_round_trip() {
163 let resp =
164 FileReadResponse { content: "fn main() {}".to_string(), file_type: FileReadType::Raw };
165 let json = serde_json::to_string(&resp).unwrap();
166 assert!(json.contains(r#""type":"raw""#));
167 let parsed: FileReadResponse = serde_json::from_str(&json).unwrap();
168 assert_eq!(parsed, resp);
169 }
170
171 #[test]
172 fn file_read_response_deserialize_from_js() {
173 let json = r#"{"content": "diff --git a/file", "type": "patch"}"#;
174 let resp: FileReadResponse = serde_json::from_str(json).unwrap();
175 assert_eq!(resp.content, "diff --git a/file");
176 assert_eq!(resp.file_type, FileReadType::Patch);
177 }
178
179 #[test]
180 fn file_read_params_round_trip() {
181 let params = FileReadParams { path: "src/lib.rs".to_string() };
182 let json = serde_json::to_string(¶ms).unwrap();
183 let parsed: FileReadParams = serde_json::from_str(&json).unwrap();
184 assert_eq!(parsed, params);
185 }
186
187 #[test]
188 fn file_status_response_round_trip() {
189 let response: FileStatusResponse = vec![
190 FileInfo { added: 1, path: "a.rs".to_string(), removed: 0, status: FileStatus::Added },
191 FileInfo {
192 added: 0,
193 path: "b.rs".to_string(),
194 removed: 10,
195 status: FileStatus::Deleted,
196 },
197 ];
198 let json = serde_json::to_string(&response).unwrap();
199 let parsed: FileStatusResponse = serde_json::from_str(&json).unwrap();
200 assert_eq!(parsed, response);
201 }
202}