1use comfy_table::{Table, presets::UTF8_FULL_CONDENSED};
2use serde_json::{Map, Value, json};
3
4pub enum OutputFormat {
5 Table,
6 Json,
7}
8
9impl OutputFormat {
10 pub fn from_flag(flag: Option<&str>, is_tty: bool) -> Self {
11 match flag {
12 Some("json") => Self::Json,
13 Some("table") => Self::Table,
14 Some(_) => Self::Table,
15 None if is_tty => Self::Table,
16 None => Self::Json,
17 }
18 }
19}
20
21pub fn format_json(headers: &[String], rows: &[Vec<String>]) -> String {
22 let items: Vec<Value> = rows
23 .iter()
24 .map(|row| {
25 let mut map = Map::new();
26 for (i, header) in headers.iter().enumerate() {
27 let val = row.get(i).cloned().unwrap_or_default();
28 map.insert(header.clone(), Value::String(val));
29 }
30 Value::Object(map)
31 })
32 .collect();
33 serde_json::to_string_pretty(&items).unwrap_or_else(|_| "[]".into())
34}
35
36pub fn format_table(headers: &[String], rows: &[Vec<String>]) -> String {
37 let mut table = Table::new();
38 table.load_preset(UTF8_FULL_CONDENSED);
39 table.set_header(headers);
40 for row in rows {
41 table.add_row(row);
42 }
43 table.to_string()
44}
45
46pub fn format_error_json(message: &str, code: &str) -> String {
47 serde_json::to_string_pretty(&json!({
48 "error": message,
49 "code": code,
50 }))
51 .unwrap_or_else(|_| format!(r#"{{"error":"{message}","code":"{code}"}}"#))
52}
53
54pub fn is_tty() -> bool {
55 std::io::IsTerminal::is_terminal(&std::io::stdout())
56}