dev_kit/command/json/
mod.rs

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