json.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package render
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "github.com/kotoyuuko/zenmux-usage-cli/internal/api"
  7. )
  8. // jsonAccountEntry is the shape of each element in multi-account JSON mode.
  9. type jsonAccountEntry struct {
  10. Account string `json:"account"`
  11. Success bool `json:"success"`
  12. Data *api.Data `json:"data"`
  13. Error *string `json:"error"`
  14. }
  15. // RenderJSONSingle writes the raw API body to w with a trailing newline.
  16. // Used when exactly one account was resolved — preserves the exact shape
  17. // returned by the API so `jq .data.plan.tier` keeps working.
  18. func RenderJSONSingle(w io.Writer, raw []byte) error {
  19. if _, err := w.Write(raw); err != nil {
  20. return err
  21. }
  22. if len(raw) == 0 || raw[len(raw)-1] != '\n' {
  23. if _, err := w.Write([]byte{'\n'}); err != nil {
  24. return err
  25. }
  26. }
  27. return nil
  28. }
  29. // RenderJSONMulti emits an ordered JSON array with one object per result.
  30. // Successful entries have data populated and error: null; failed entries
  31. // have data: null and a non-empty error message.
  32. func RenderJSONMulti(w io.Writer, results []AccountResult) error {
  33. out := make([]jsonAccountEntry, len(results))
  34. for i, r := range results {
  35. entry := jsonAccountEntry{Account: r.Name}
  36. switch {
  37. case r.Err != nil:
  38. entry.Success = false
  39. msg := r.Err.Error()
  40. entry.Error = &msg
  41. case r.Response == nil:
  42. entry.Success = false
  43. msg := "no response"
  44. entry.Error = &msg
  45. default:
  46. entry.Success = r.Response.Success
  47. entry.Data = &r.Response.Data
  48. if !r.Response.Success {
  49. msg := r.Response.Error
  50. if msg == "" {
  51. msg = "api returned success=false"
  52. }
  53. entry.Error = &msg
  54. entry.Data = nil
  55. }
  56. }
  57. out[i] = entry
  58. }
  59. enc := json.NewEncoder(w)
  60. enc.SetIndent("", " ")
  61. if err := enc.Encode(out); err != nil {
  62. return fmt.Errorf("encode multi-account json: %w", err)
  63. }
  64. return nil
  65. }