Something went wrong. Try again.
"Leading Comma JSON Formatter"
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson (Value (..))import qualified Data.Aeson as Aesonimport qualified Data.Text as Timport LCJF (prettyLeadingComma)import Test.Hspec
main :: IO ()main = hspec spec
spec :: Specspec = do describe "prettyLeadingComma" $ do describe "primitive values" $ do it "formats null" $ do prettyLeadingComma Null `shouldBe` "null"
it "formats true" $ do prettyLeadingComma (Bool True) `shouldBe` "true"
it "formats false" $ do prettyLeadingComma (Bool False) `shouldBe` "false"
it "formats integers" $ do prettyLeadingComma (Number 42) `shouldBe` "42"
it "formats negative integers" $ do prettyLeadingComma (Number (-7)) `shouldBe` "-7"
it "formats decimals" $ do prettyLeadingComma (Number 3.14) `shouldBe` "3.14"
it "formats strings" $ do prettyLeadingComma (String "hello") `shouldBe` "\"hello\""
describe "string escaping" $ do it "escapes double quotes" $ do prettyLeadingComma (String "say \"hi\"") `shouldBe` "\"say \\\"hi\\\"\""
it "escapes backslashes" $ do prettyLeadingComma (String "a\\b") `shouldBe` "\"a\\\\b\""
it "escapes newlines" $ do prettyLeadingComma (String "line1\nline2") `shouldBe` "\"line1\\nline2\""
it "escapes tabs" $ do prettyLeadingComma (String "col1\tcol2") `shouldBe` "\"col1\\tcol2\""
it "escapes carriage returns" $ do prettyLeadingComma (String "a\rb") `shouldBe` "\"a\\rb\""
describe "empty containers" $ do it "formats empty array with spaces" $ do prettyLeadingComma (toJSON ([] :: [Int])) `shouldBe` "[ ]"
it "formats empty object with spaces" $ do prettyLeadingComma (Aeson.object []) `shouldBe` "{ }"
describe "arrays" $ do it "formats single-element array" $ do let result = prettyLeadingComma (toJSON [1 :: Int]) T.lines result `shouldBe` ["[ 1", "]"]
it "formats multi-element array with leading commas" $ do let result = prettyLeadingComma (toJSON [1 :: Int, 2, 3]) T.lines result `shouldBe` ["[ 1", ", 2", ", 3", "]"]
it "formats array of strings" $ do let result = prettyLeadingComma (toJSON ["a" :: T.Text, "b"]) T.lines result `shouldBe` ["[ \"a\"", ", \"b\"", "]"]
describe "objects" $ do it "formats single-field object" $ do let result = prettyLeadingComma (Aeson.object [("name", String "test")]) T.lines result `shouldBe` ["{ \"name\": \"test\"", "}"]
it "formats multi-field object with leading commas" $ do let result = prettyLeadingComma ( Aeson.object [ ("a", Number 1) , ("b", Number 2) ] ) T.lines result `shouldBe` ["{ \"a\": 1", ", \"b\": 2", "}"]
it "sorts object keys alphabetically" $ do let result = prettyLeadingComma ( Aeson.object [ ("zebra", Number 1) , ("apple", Number 2) ] ) T.lines result `shouldBe` ["{ \"apple\": 2", ", \"zebra\": 1", "}"]
describe "nested structures" $ do it "formats nested array on new line" $ do let result = prettyLeadingComma ( Aeson.object [("items", toJSON [1 :: Int, 2])] ) T.lines result `shouldBe` [ "{ \"items\":" , " [ 1" , " , 2" , " ]" , "}" ]
it "formats nested object on new line" $ do let result = prettyLeadingComma ( Aeson.object [("nested", Aeson.object [("x", Number 1)])] ) T.lines result `shouldBe` [ "{ \"nested\":" , " { \"x\": 1" , " }" , "}" ]
it "formats empty nested containers inline" $ do let result = prettyLeadingComma ( Aeson.object [ ("arr", toJSON ([] :: [Int])) , ("obj", Aeson.object []) ] ) T.lines result `shouldBe` [ "{ \"arr\": [ ]" , ", \"obj\": { }" , "}" ]
it "formats deeply nested structures" $ do let result = prettyLeadingComma ( Aeson.object [ ( "outer" , Aeson.object [("inner", toJSON [1 :: Int, 2])] ) ] ) T.lines result `shouldBe` [ "{ \"outer\":" , " { \"inner\":" , " [ 1" , " , 2" , " ]" , " }" , "}" ]
describe "complex example" $ do it "formats the example from requirements" $ do let input = Aeson.object [ ("field_one", String "string") , ("field_two", Null) , ("field_three", toJSON [5 :: Int, 248, 15187519]) , ("field_four", Aeson.object []) ] T.lines (prettyLeadingComma input) `shouldBe` [ "{ \"field_four\": { }" , ", \"field_one\": \"string\"" , ", \"field_three\":" , " [ 5" , " , 248" , " , 15187519" , " ]" , ", \"field_two\": null" , "}" ]
it "handles mixed value types in array" $ do let result = prettyLeadingComma ( toJSON [ toJSON (1 :: Int) , toJSON ("text" :: T.Text) , toJSON True , Null ] ) T.lines result `shouldBe` [ "[ 1" , ", \"text\"" , ", true" , ", null" , "]" ]
toJSON :: (Aeson.ToJSON a) => a -> ValuetoJSON = Aeson.toJSON