package utils import ( "bytes" "encoding/json" "fmt" "os" "text/tabwriter" ) const ( colorReset = "\033[0m" colorKey = "\033[36m" colorString = "\033[32m" colorNumber = "\033[33m" colorBool = "\033[35m" colorNull = "\033[90m" colorBrace = "\033[37m" ) func colorizeJSON(data []byte) string { if !isTerminal() { return string(data) } var result bytes.Buffer var inString bool var isKey bool var depth int for i := 0; i < len(data); i++ { c := data[i] switch c { case '"': if i > 0 && data[i-1] != '\\' { inString = !inString if inString { if i > 0 && (data[i-1] == '{' || data[i-1] == ',' || data[i-1] == '[' || data[i-1] == '\n' || data[i-1] == ' ') { isKey = true result.WriteString(colorKey) } else { result.WriteString(colorString) } } else { result.WriteByte(c) result.WriteString(colorReset) if isKey && i+1 < len(data) && data[i+1] == ':' { isKey = false } continue } } result.WriteByte(c) case '{', '}', '[', ']': if !inString { result.WriteString(colorBrace) result.WriteByte(c) result.WriteString(colorReset) if c == '{' || c == '[' { depth++ } else { depth-- } } else { result.WriteByte(c) } case 't', 'f': if !inString && i+3 < len(data) { word := string(data[i:min(i+5, len(data))]) if word[:4] == "true" || word[:5] == "false" { result.WriteString(colorBool) if word[:4] == "true" { result.WriteString("true") i += 3 } else { result.WriteString("false") i += 4 } result.WriteString(colorReset) } else { result.WriteByte(c) } } else { result.WriteByte(c) } case 'n': if !inString && i+3 < len(data) && string(data[i:i+4]) == "null" { result.WriteString(colorNull) result.WriteString("null") result.WriteString(colorReset) i += 3 } else { result.WriteByte(c) } case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': if !inString { result.WriteString(colorNumber) for i < len(data) && (data[i] >= '0' && data[i] <= '9' || data[i] == '.' || data[i] == '-' || data[i] == 'e' || data[i] == 'E' || data[i] == '+') { result.WriteByte(data[i]) i++ } i-- result.WriteString(colorReset) } else { result.WriteByte(c) } default: result.WriteByte(c) } } return result.String() } func PrintJSON(data any) error { output, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Errorf("failed to format JSON: %w", err) } fmt.Println(colorizeJSON(output)) return nil } func PrintTable(headers []string, rows [][]string) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) defer w.Flush() for _, h := range headers { fmt.Fprintf(w, "%s\t", h) } fmt.Fprintln(w) for _, row := range rows { for _, col := range row { fmt.Fprintf(w, "%s\t", col) } fmt.Fprintln(w) } } func PrintError(err error) { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) }