1use jsonpath_rust::JsonPath;
2use serde_json::Value;
3use thiserror::Error;
4
5use crate::core::manifest::{ResponseConfig, ResponseFormat};
6
7#[derive(Error, Debug)]
8pub enum ResponseError {
9 #[error("JSONPath extraction failed: {0}")]
10 ExtractionFailed(String),
11}
12
13pub fn process_response(
15 response: &Value,
16 config: Option<&ResponseConfig>,
17) -> Result<Value, ResponseError> {
18 let config = match config {
19 Some(c) => c,
20 None => return Ok(response.clone()), };
22
23 let extracted = match &config.extract {
25 Some(path_str) => extract_jsonpath(response, path_str)?,
26 None => response.clone(),
27 };
28
29 Ok(extracted)
30}
31
32fn extract_jsonpath(value: &Value, path: &str) -> Result<Value, ResponseError> {
34 let path = JsonPath::try_from(path)
35 .map_err(|e| ResponseError::ExtractionFailed(format!("Invalid JSONPath '{path}': {e}")))?;
36
37 let results = path.find_slice(value);
38
39 if results.is_empty() {
40 return Ok(Value::Null);
41 }
42
43 let values: Vec<Value> = results.into_iter().map(|v| v.to_data()).collect();
45
46 if values.len() == 1 {
47 Ok(values.into_iter().next().unwrap())
48 } else {
49 Ok(Value::Array(values))
50 }
51}
52
53pub fn get_format(config: Option<&ResponseConfig>, value: &Value) -> ResponseFormat {
55 if let Some(config) = config {
56 return config.format.clone();
57 }
58
59 if let Value::Array(arr) = value {
61 if arr.iter().all(|v| v.is_object()) {
62 return ResponseFormat::MarkdownTable;
63 }
64 }
65
66 ResponseFormat::Text
67}