package main import ( "bytes" "encoding/json" "fmt" "io" "os" "strings" "testing" ) // PrettyJSON validates src as JSON and returns it formatted with two-space indentation. func PrettyJSON(src []byte) ([]byte, error) { var buf bytes.Buffer dec := json.NewDecoder(bytes.NewReader(src)) dec.UseNumber() var value any if err := dec.Decode(&value); err != nil { return nil, err } // Reject trailing non-whitespace data after the first JSON value. if err := dec.Decode(&struct{}{}); err != io.EOF { return nil, fmt.Errorf("invalid trailing JSON") } enc := json.NewEncoder(&buf) enc.SetIndent("", " ") enc.SetEscapeHTML(false) if err := enc.Encode(value); err != nil { return nil, err } return buf.Bytes(), nil } func main() { input, err := io.ReadAll(os.Stdin) if err != nil { fmt.Fprintln(os.Stderr, "read stdin:", err) os.Exit(1) } output, err := PrettyJSON(input) if err != nil { fmt.Fprintln(os.Stderr, "pretty json:", err) os.Exit(1) } if _, err := os.Stdout.Write(output); err != nil { fmt.Fprintln(os.Stderr, "write stdout:", err) os.Exit(1) } } func TestPrettyJSONFormatsObjects(t *testing.T) { got, err := PrettyJSON([]byte(`{"name":"Ada","langs":["go","json"],"active":true}`)) if err != nil { t.Fatal(err) } want := strings.Join([]string{ "{", ` "active": true,`, ` "langs": [`, ` "go",`, ` "json"`, " ],", ` "name": "Ada"`, "}", "", }, "\n") if string(got) != want { t.Fatalf("unexpected output:\n%s", got) } } func TestPrettyJSONRejectsTrailingData(t *testing.T) { if _, err := PrettyJSON([]byte(`{"ok":true} false`)); err == nil { t.Fatal("expected trailing JSON error") } }