dev_kit/command/json/
mod.rs

1use crate::command::http_parser::HttpRequest;
2use anyhow::anyhow;
3use derive_more::Display;
4use std::fs;
5use std::path::PathBuf;
6use std::sync::Arc;
7use strum::EnumIter;
8
9#[derive(clap::Subcommand)]
10pub enum JsonCommand {
11    #[clap(about = "json beautify, alias 'format'", alias = "format")]
12    Beauty {
13        #[arg(help = "json input, support string, file-path, url, cmd", default_value = "")]
14        json: Json,
15        #[arg(short, long, help = "json path to extract")]
16        query: Option<String>,
17        #[arg(short, long, help = "file to write output")]
18        file: Option<PathBuf>,
19    },
20    #[clap(about = "json query, alias 'search'", alias = "search")]
21    Query {
22        #[arg(help = "json input, support string, file-path, url, cmd", default_value = "")]
23        json: Json,
24        #[arg(short, long, help = "json path to extract")]
25        query: String,
26        #[arg(long, help = "beauty output", alias = "format", default_value = "false")]
27        beauty: bool,
28        #[arg(short, long, help = "file to write output")]
29        file: Option<PathBuf>,
30    },
31    #[clap(about = "json diff with left and right")]
32    Diff {
33        #[arg(help = "json input, support string, file-path, url, cmd", default_value = "")]
34        left: Json,
35        #[arg(help = "json input, support string, file-path, url, cmd", default_value = "")]
36        right: Json,
37        #[arg(short, long, help = "json path to extract")]
38        query: Option<String>,
39        #[arg(long, help = "diff tool to use, alias dt, support idea/zed/vscode, and will auto detect if not set", alias = "dt")]
40        diff_tool: Option<DiffTool>,
41    },
42}
43
44impl super::Command for JsonCommand {
45    fn run(&self) -> crate::Result<()> {
46        match self {
47            JsonCommand::Beauty { json, query, file } => {
48                let result = json.beautify(query.as_deref())?;
49                if let Some(file) = file {
50                    fs::write(&file, result).map_err(|err|
51                        anyhow!("write to {} failed, {}", file.display(), err)
52                    )?;
53                    println!("write to {}", file.display())
54                } else {
55                    println!("{result}");
56                }
57                Ok(())
58            }
59            JsonCommand::Query { json, query, beauty, file } => {
60                let result = json.query(query, *beauty)?;
61                if let Some(file) = file {
62                    let content = result.join("\n");
63                    fs::write(&file, content)?;
64                    println!("write to {}", file.display())
65                } else {
66                    for row in result {
67                        println!("{}", row);
68                    }
69                }
70                Ok(())
71            }
72            JsonCommand::Diff { left, right, query, diff_tool } => {
73                let _ = left.diff(right, query.as_deref(), diff_tool.map(|it| it))?;
74                Ok(())
75            }
76        }
77    }
78}
79
80#[derive(Debug, Clone, Display)]
81pub enum Json {
82    #[display("{_0}")]
83    Cmd(String),
84    #[display("{_0}")]
85    HttpRequest(HttpRequest),
86    #[display("{}", _0.display())]
87    Path(PathBuf),
88    #[display("{_0}")]
89    String(String),
90    #[display("{}", _0.to_string())]
91    JsonValue(Arc<serde_json::Value>),
92}
93
94mod json;
95
96#[derive(Debug, Copy, Clone, Display, EnumIter)]
97pub enum DiffTool {
98    #[display("{_0}")]
99    JetbrainsIDE(JetbrainsIDE),
100    #[display("zed")]
101    Zed,
102    #[display("vscode")]
103    VSCode,
104}
105
106mod difftool;
107
108#[derive(Debug, Copy, Clone, Display, EnumIter, Default)]
109#[display(rename_all = "lowercase")]
110pub enum JetbrainsIDE {
111    #[default]
112    Idea,
113    CLion,
114    RustRover,
115    GoLand,
116    PyCharm,
117    WebStorm,
118    Rider,
119    DataGrip,
120    AppCode,
121}
122
123#[cfg(test)]
124mod tests {
125    #[test]
126    fn test() -> crate::Result<()> {
127        let json1 = r#"{"a":1,"b":2,"c":3}"#;
128        let json1: serde_json::Value = serde_json::from_str(json1)?;
129        let json1 = serde_json::to_string(&json1)?;
130        println!("{}", json1);
131        let json2 = r#"{"c":3,"b":2,"a":1, "d":{"g":"gg","f":"ff","e":"ee"}}"#;
132        let json2: serde_json::Value = serde_json::from_str(json2)?;
133        let json2 = serde_json::to_string(&json2)?;
134        println!("{}", json2);
135        Ok(())
136    }
137}