aeson-pretty 0.7.2 → 0.8.0
raw patch · 3 files changed
+71/−25 lines, 3 filesdep +scientificdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: scientific
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.Aeson.Encode.Pretty: confCompare :: Config -> Text -> Text -> Ordering
- Data.Aeson.Encode.Pretty: confIndent :: Config -> Int
+ Data.Aeson.Encode.Pretty: Custom :: (Scientific -> Builder) -> NumberFormat
+ Data.Aeson.Encode.Pretty: Decimal :: NumberFormat
+ Data.Aeson.Encode.Pretty: Generic :: NumberFormat
+ Data.Aeson.Encode.Pretty: Scientific :: NumberFormat
+ Data.Aeson.Encode.Pretty: Spaces :: Int -> Indent
+ Data.Aeson.Encode.Pretty: Tab :: Indent
+ Data.Aeson.Encode.Pretty: [confCompare] :: Config -> Text -> Text -> Ordering
+ Data.Aeson.Encode.Pretty: [confIndent] :: Config -> Indent
+ Data.Aeson.Encode.Pretty: [confNumFormat] :: Config -> NumberFormat
+ Data.Aeson.Encode.Pretty: data Indent
+ Data.Aeson.Encode.Pretty: data NumberFormat
- Data.Aeson.Encode.Pretty: Config :: Int -> (Text -> Text -> Ordering) -> Config
+ Data.Aeson.Encode.Pretty: Config :: Indent -> (Text -> Text -> Ordering) -> NumberFormat -> Config
Files
- Data/Aeson/Encode/Pretty.hs +66/−22
- aeson-pretty.cabal +2/−1
- cli-tool/Main.hs +3/−2
Data/Aeson/Encode/Pretty.hs view
@@ -4,18 +4,19 @@ module Data.Aeson.Encode.Pretty ( -- * Simple Pretty-Printing encodePretty, encodePrettyToTextBuilder,- + -- * Pretty-Printing with Configuration Options encodePretty', encodePrettyToTextBuilder', Config (..), defConfig,+ Indent(..), NumberFormat(..), -- ** Sorting Keys in Objects- -- |With the Aeson library, the order of keys in objects is undefined due+ -- |With the Aeson library, the order of keys in objects is undefined due to -- objects being implemented as HashMaps. To allow user-specified key -- orders in the pretty-printed JSON, 'encodePretty'' can be configured -- with a comparison function. These comparison functions can be composed -- using the 'Monoid' interface. Some other useful helper functions to keep -- in mind are 'comparing' and 'on'.- -- + -- -- Consider the following deliberately convoluted example, demonstrating -- the use of comparison functions: --@@ -43,7 +44,7 @@ -- > "quux": ..., -- > } --- + mempty, -- |Serves as an order-preserving (non-)sort function. Re-exported from -- "Data.Monoid".@@ -60,23 +61,46 @@ import qualified Data.HashMap.Strict as H (toList) import Data.List (intersperse, sortBy, elemIndex) import Data.Maybe (fromMaybe)-import Data.Monoid ((<>), mconcat, mempty)-import Data.Ord+import Data.Monoid ((<>))+import qualified Data.Scientific as S (Scientific, FPFormat(..))+import Data.Ord (comparing) import Data.Text (Text) import Data.Text.Lazy.Builder (Builder, toLazyText)+import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder) import Data.Text.Lazy.Encoding (encodeUtf8) import qualified Data.Vector as V (toList) -data PState = PState { pstIndent :: Int- , pstLevel :: Int- , pstSort :: [(Text, Value)] -> [(Text, Value)]++data PState = PState { pLevel :: Int+ , pIndent :: Builder+ , pNewline :: Builder+ , pItemSep :: Builder+ , pKeyValSep :: Builder+ , pNumFormat :: NumberFormat+ , pSort :: [(Text, Value)] -> [(Text, Value)] } +-- | Indentation per level of nesting. @'Spaces' 0@ removes __all__ whitespace+-- from the output.+data Indent = Spaces Int | Tab++data NumberFormat+ -- | Use decimal notation for values between 0.1 and 9,999,999, and scientific+ -- notation otherwise.+ = Generic+ -- | Scientific notation (e.g. 2.3e123).+ | Scientific+ -- | Standard decimal notation+ | Decimal+ -- | Custom formatting function+ | Custom (S.Scientific -> Builder)+ data Config = Config- { confIndent :: Int- -- ^ Indentation spaces per level of nesting+ { confIndent :: Indent+ -- ^ Indentation per level of nesting , confCompare :: Text -> Text -> Ordering -- ^ Function used to sort keys in objects+ , confNumFormat :: NumberFormat } -- |Sort keys by their order of appearance in the argument list.@@ -92,11 +116,12 @@ -- |The default configuration: indent by four spaces per level of nesting, do -- not sort objects by key. ----- > defConfig = Config { confIndent = 4, confCompare = mempty }+-- > defConfig = Config { confIndent = 4, confCompare = mempty, confNumFormat = Generic } defConfig :: Config-defConfig = Config { confIndent = 4, confCompare = mempty }+defConfig =+ Config {confIndent = Spaces 4, confCompare = mempty, confNumFormat = Generic} --- |A drop-in replacement for aeson's 'Aeson.encode' function, producing +-- |A drop-in replacement for aeson's 'Aeson.encode' function, producing -- JSON-ByteStrings for human readers. -- -- Follows the default configuration in 'defConfig'.@@ -120,15 +145,26 @@ encodePrettyToTextBuilder' :: ToJSON a => Config -> a -> Builder encodePrettyToTextBuilder' Config{..} = fromValue st . toJSON where- st = PState confIndent 0 condSort- condSort = sortBy (confCompare `on` fst)+ st = PState 0 indent newline itemSep kvSep confNumFormat sortFn+ indent = case confIndent of+ Spaces n -> mconcat (replicate n " ")+ Tab -> "\t"+ newline = case confIndent of+ Spaces 0 -> ""+ _ -> "\n"+ itemSep = ","+ kvSep = case confIndent of+ Spaces 0 -> ":"+ _ -> ": "+ sortFn = sortBy (confCompare `on` fst) fromValue :: PState -> Value -> Builder fromValue st@PState{..} = go where go (Array v) = fromCompound st ("[","]") fromValue (V.toList v)- go (Object m) = fromCompound st ("{","}") fromPair (pstSort (H.toList m))+ go (Object m) = fromCompound st ("{","}") fromPair (pSort (H.toList m))+ go (Number x) = fromNumber st x go v = Aeson.encodeToTextBuilder v fromCompound :: PState@@ -139,17 +175,25 @@ fromCompound st@PState{..} (delimL,delimR) fromItem items = mconcat [ delimL , if null items then mempty- else "\n" <> items' <> "\n" <> fromIndent st+ else pNewline <> items' <> pNewline <> fromIndent st , delimR ] where- items' = mconcat . intersperse ",\n" $+ items' = mconcat . intersperse (pItemSep <> pNewline) $ map (\item -> fromIndent st' <> fromItem st' item) items- st' = st { pstLevel = pstLevel + 1 }+ st' = st { pLevel = pLevel + 1 } fromPair :: PState -> (Text, Value) -> Builder-fromPair st (k,v) = Aeson.encodeToTextBuilder (toJSON k) <> ": " <> fromValue st v+fromPair st (k,v) =+ Aeson.encodeToTextBuilder (toJSON k) <> pKeyValSep st <> fromValue st v fromIndent :: PState -> Builder-fromIndent PState{..} = mconcat $ replicate (pstIndent * pstLevel) " "+fromIndent PState{..} = mconcat (replicate pLevel pIndent)++fromNumber :: PState -> S.Scientific -> Builder+fromNumber st x = case pNumFormat st of+ Generic -> formatScientificBuilder S.Generic Nothing x+ Scientific -> formatScientificBuilder S.Exponent Nothing x+ Decimal -> formatScientificBuilder S.Fixed Nothing x+ Custom f -> f x
aeson-pretty.cabal view
@@ -1,5 +1,5 @@ name: aeson-pretty-version: 0.7.2+version: 0.8.0 license: BSD3 license-file: LICENSE category: Text, Web, JSON, Pretty Printer@@ -43,6 +43,7 @@ aeson >= 0.7, base >= 4.5, bytestring >= 0.9,+ scientific >= 0.3, vector >= 0.9, text >= 0.11, unordered-containers >= 0.1.3.0
cli-tool/Main.hs view
@@ -44,8 +44,9 @@ main :: IO () main = do Opts{..} <- cmdArgs opts- let conf = Config { confIndent = indent- , confCompare = if sort then compare else mempty+ let conf = Config { confIndent = Spaces indent+ , confCompare = if sort then compare else mempty+ , confNumFormat = Generic } enc = if compact then encode else encodePretty' conf interact $ unlines . map enc . values