lean_ctx/server/
helpers.rs1use serde_json::Value;
2
3pub fn get_str_array(
4 args: &Option<serde_json::Map<String, Value>>,
5 key: &str,
6) -> Option<Vec<String>> {
7 let arr = args.as_ref()?.get(key)?.as_array()?;
8 let mut out = Vec::with_capacity(arr.len());
9 for v in arr {
10 let s = v.as_str()?.to_string();
11 out.push(s);
12 }
13 Some(out)
14}
15
16pub fn get_str(args: &Option<serde_json::Map<String, Value>>, key: &str) -> Option<String> {
17 args.as_ref()?.get(key)?.as_str().map(|s| s.to_string())
18}
19
20pub fn get_int(args: &Option<serde_json::Map<String, Value>>, key: &str) -> Option<i64> {
21 args.as_ref()?.get(key)?.as_i64()
22}
23
24pub fn get_bool(args: &Option<serde_json::Map<String, Value>>, key: &str) -> Option<bool> {
25 args.as_ref()?.get(key)?.as_bool()
26}
27
28pub fn md5_hex(s: &str) -> String {
29 use md5::{Digest, Md5};
30 let mut hasher = Md5::new();
31 hasher.update(s.as_bytes());
32 format!("{:x}", hasher.finalize())
33}
34
35pub fn canonicalize_json(v: &Value) -> Value {
36 match v {
37 Value::Object(map) => {
38 let mut keys: Vec<&String> = map.keys().collect();
39 keys.sort();
40 let mut out = serde_json::Map::new();
41 for k in keys {
42 if let Some(val) = map.get(k) {
43 out.insert(k.clone(), canonicalize_json(val));
44 }
45 }
46 Value::Object(out)
47 }
48 Value::Array(arr) => Value::Array(arr.iter().map(canonicalize_json).collect()),
49 other => other.clone(),
50 }
51}
52
53pub fn canonical_args_string(args: &Option<serde_json::Map<String, Value>>) -> String {
54 let v = args
55 .as_ref()
56 .map(|m| Value::Object(m.clone()))
57 .unwrap_or(Value::Null);
58 let canon = canonicalize_json(&v);
59 serde_json::to_string(&canon).unwrap_or_default()
60}
61
62pub fn extract_search_pattern_from_command(command: &str) -> Option<String> {
63 let parts: Vec<&str> = command.split_whitespace().collect();
64 if parts.len() < 2 {
65 return None;
66 }
67 let cmd = parts[0];
68 if cmd == "grep" || cmd == "rg" || cmd == "ag" || cmd == "ack" {
69 for (i, part) in parts.iter().enumerate().skip(1) {
70 if !part.starts_with('-') {
71 return Some(part.to_string());
72 }
73 if (*part == "-e" || *part == "--regexp" || *part == "-m") && i + 1 < parts.len() {
74 return Some(parts[i + 1].to_string());
75 }
76 }
77 }
78 if cmd == "find" || cmd == "fd" {
79 for (i, part) in parts.iter().enumerate() {
80 if (*part == "-name" || *part == "-iname") && i + 1 < parts.len() {
81 return Some(
82 parts[i + 1]
83 .trim_matches('\'')
84 .trim_matches('"')
85 .to_string(),
86 );
87 }
88 }
89 if cmd == "fd" && parts.len() >= 2 && !parts[1].starts_with('-') {
90 return Some(parts[1].to_string());
91 }
92 }
93 None
94}