aeson-pretty-0.8.10/0000755000000000000000000000000007346545000012423 5ustar0000000000000000aeson-pretty-0.8.10/CHANGELOG.markdown0000644000000000000000000000021307346545000015452 0ustar0000000000000000# aeson-pretty changelog ## 0.8.10 * Added support for Aeson 2.2 * Added support for Aeson 2.1 ## 0.8.9 * Added support for Aeson 2.0 aeson-pretty-0.8.10/Data/Aeson/Encode/0000755000000000000000000000000007346545000015536 5ustar0000000000000000aeson-pretty-0.8.10/Data/Aeson/Encode/Pretty.hs0000644000000000000000000001737707346545000017400 0ustar0000000000000000{-# LANGUAGE OverloadedStrings, RecordWildCards, CPP #-} -- |Aeson-compatible pretty-printing of JSON 'Value's. 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 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: -- -- An object might pretty-print as follows -- -- > { -- > "baz": ..., -- > "bar": ..., -- > "foo": ..., -- > "quux": ..., -- > } -- -- which is clearly a confusing order of keys. By using a comparison -- function such as -- -- > comp :: Text -> Text -> Ordering -- > comp = keyOrder ["foo","bar"] `mappend` comparing length -- -- we can achieve the desired neat result: -- -- > { -- > "foo": ..., -- > "bar": ..., -- > "baz": ..., -- > "quux": ..., -- > } -- mempty, -- |Serves as an order-preserving (non-)sort function. Re-exported from -- "Data.Monoid". compare, -- |Sort keys in their natural order, i.e. by comparing character codes. -- Re-exported from the Prelude and "Data.Ord" keyOrder ) where #if MIN_VERSION_aeson(2,0,0) import qualified Data.Aeson.Key as AK import qualified Data.Aeson.KeyMap as AKM #endif import Data.Aeson (Value(..), ToJSON(..)) import qualified Data.Aeson.Text as Aeson import Data.ByteString.Lazy (ByteString) import Data.Function (on) #if !MIN_VERSION_aeson(2,0,0) import qualified Data.HashMap.Strict as H (toList) #endif import Data.List (intersperse, sortBy, elemIndex) import Data.Maybe (fromMaybe) #if !MIN_VERSION_base(4,13,0) import Data.Semigroup ((<>)) #endif 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) import Prelude () import Prelude.Compat 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 -- | The standard behaviour of the 'Aeson.encode' function. Uses -- integer literals for integers (1, 2, 3...), simple decimals -- for fractional 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 :: Indent -- ^ Indentation per level of nesting , confCompare :: Text -> Text -> Ordering -- ^ Function used to sort keys in objects , confNumFormat :: NumberFormat , confTrailingNewline :: Bool -- ^ Whether to add a trailing newline to the output } -- |Sort keys by their order of appearance in the argument list. -- -- Keys that are not present in the argument list are considered to be greater -- than any key in the list and equal to all keys not in the list. I.e. keys -- not in the argument list are moved to the end, while their order is -- preserved. keyOrder :: [Text] -> Text -> Text -> Ordering keyOrder ks = comparing $ \k -> fromMaybe maxBound (elemIndex k ks) -- |The default configuration: indent by four spaces per level of nesting, do -- not sort objects by key, do not add trailing newline. -- -- > defConfig = Config { confIndent = Spaces 4, confCompare = mempty, confNumFormat = Generic, confTrailingNewline = False } defConfig :: Config defConfig = Config {confIndent = Spaces 4, confCompare = mempty, confNumFormat = Generic, confTrailingNewline = False} -- |A drop-in replacement for aeson's 'Aeson.encode' function, producing -- JSON-ByteStrings for human readers. -- -- Follows the default configuration in 'defConfig'. encodePretty :: ToJSON a => a -> ByteString encodePretty = encodePretty' defConfig -- |A variant of 'encodePretty' that takes an additional configuration -- parameter. encodePretty' :: ToJSON a => Config -> a -> ByteString encodePretty' conf = encodeUtf8 . toLazyText . encodePrettyToTextBuilder' conf -- |A drop-in replacement for aeson's 'Aeson.encodeToTextBuilder' function, -- producing JSON-ByteStrings for human readers. -- -- Follows the default configuration in 'defConfig'. encodePrettyToTextBuilder :: ToJSON a => a -> Builder encodePrettyToTextBuilder = encodePrettyToTextBuilder' defConfig -- |A variant of 'Aeson.encodeToTextBuilder' that takes an additional configuration -- parameter. encodePrettyToTextBuilder' :: ToJSON a => Config -> a -> Builder encodePrettyToTextBuilder' Config{..} x = fromValue st (toJSON x) <> trail where 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) trail = if confTrailingNewline then "\n" else "" fromValue :: PState -> Value -> Builder fromValue st@PState{..} val = go val where go (Array v) = fromCompound st ("[","]") fromValue (V.toList v) go (Object m) = fromCompound st ("{","}") fromPair (pSort (toList' m)) go (Number x) = fromNumber st x go v = Aeson.encodeToTextBuilder v #if MIN_VERSION_aeson(2,0,0) toList' = fmap (\(k, v) -> (AK.toText k, v)) . AKM.toList #else toList' = H.toList #endif fromCompound :: PState -> (Builder, Builder) -> (PState -> a -> Builder) -> [a] -> Builder fromCompound st@PState{..} (delimL,delimR) fromItem items = mconcat [ delimL , if null items then mempty else pNewline <> items' <> pNewline <> fromIndent st , delimR ] where items' = mconcat . intersperse (pItemSep <> pNewline) $ map (\item -> fromIndent st' <> fromItem st' item) items st' = st { pLevel = pLevel + 1} fromPair :: PState -> (Text, Value) -> Builder fromPair st (k,v) = Aeson.encodeToTextBuilder (toJSON k) <> pKeyValSep st <> fromValue st v fromIndent :: PState -> Builder fromIndent PState{..} = mconcat (replicate pLevel pIndent) fromNumber :: PState -> S.Scientific -> Builder fromNumber st x = case pNumFormat st of Generic | (x > 1.0e19 || x < -1.0e19) -> formatScientificBuilder S.Exponent Nothing x | otherwise -> Aeson.encodeToTextBuilder $ Number x Scientific -> formatScientificBuilder S.Exponent Nothing x Decimal -> formatScientificBuilder S.Fixed Nothing x Custom f -> f x aeson-pretty-0.8.10/LICENSE0000644000000000000000000000276107346545000013436 0ustar0000000000000000Copyright (c)2011, Falko Peters All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Falko Peters nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. aeson-pretty-0.8.10/README.markdown0000644000000000000000000000223607346545000015127 0ustar0000000000000000# Welcome to aeson-pretty This is a JSON pretty-printing Haskell library compatible with [aeson](http://hackage.haskell.org/package/aeson) as well as a command-line tool to improve readabilty of streams of JSON data. The **library** provides a single function `encodePretty`. It is a drop-in replacement for aeson's `encode` function, producing JSON-ByteStrings for human readers. The **command-line tool** reads JSON from stdin and writes prettified JSON to stdout. It also offers a complementary "compact"-mode, essentially the opposite of pretty-printing. # Join in! We are happy to receive bug reports, fixes, documentation enhancements, and other improvements. Please report bugs via the [github issue tracker](http://github.com/informatikr/aeson-pretty/issues). Master [git repository](http://github.com/informatikr/aeson-pretty): * `git clone git://github.com/informatikr/aeson-pretty.git` # Aeson / GHC support We support all GHCs supported by the latest Aeson release. This in turn determines which Aeson releases we support. # Authors This library is written by Falko Peters and maintained by Martijn Bastiaan . aeson-pretty-0.8.10/Setup.hs0000644000000000000000000000005607346545000014060 0ustar0000000000000000import Distribution.Simple main = defaultMain aeson-pretty-0.8.10/aeson-pretty.cabal0000644000000000000000000000473407346545000016051 0ustar0000000000000000cabal-version: 2.0 name: aeson-pretty version: 0.8.10 license: BSD3 license-file: LICENSE category: Text, Web, JSON, Pretty Printer copyright: Copyright 2011 Falko Peters author: Falko Peters maintainer: Martijn Bastiaan stability: experimental homepage: http://github.com/informatikr/aeson-pretty bug-reports: http://github.com/informatikr/aeson-pretty/issues build-type: Simple synopsis: JSON pretty-printing library and command-line tool. description: A JSON pretty-printing library compatible with aeson as well as a command-line tool to improve readabilty of streams of JSON data. . The /library/ provides the function "encodePretty". It is a drop-in replacement for aeson's "encode" function, producing JSON-ByteStrings for human readers. . The /command-line tool/ reads JSON from stdin and writes prettified JSON to stdout. It also offers a complementary "compact"-mode, essentially the opposite of pretty-printing. If you specify @-flib-only@ like this . > cabal install -flib-only aeson-pretty . the command-line tool will NOT be installed. extra-source-files: README.markdown CHANGELOG.markdown flag lib-only description: Only build/install the library, NOT the command-line tool. default: False library exposed-modules: Data.Aeson.Encode.Pretty build-depends: aeson ^>=1.1 || ^>=1.2 || ^>=1.3 || ^>=1.4 || ^>=1.5 || ^>=2.0 || ^>=2.1 || ^>=2.2, base >= 4.5, base-compat >= 0.9, bytestring >= 0.9, scientific >= 0.3, vector >= 0.9, text >= 0.11, unordered-containers >= 0.2.14.0 if !impl(ghc >= 8.0) build-depends: semigroups >= 0.18.2 ghc-options: -Wall default-language: Haskell2010 executable aeson-pretty hs-source-dirs: cli-tool main-is: Main.hs other-modules: Paths_aeson_pretty autogen-modules: Paths_aeson_pretty if flag(lib-only) buildable: False else build-depends: aeson >= 0.6, aeson-pretty, attoparsec >= 0.10, attoparsec-aeson, base == 4.*, bytestring >= 0.9, cmdargs >= 0.7 ghc-options: -Wall ghc-prof-options: -auto-all default-language: Haskell2010 source-repository head type: git location: http://github.com/informatikr/aeson-pretty aeson-pretty-0.8.10/cli-tool/0000755000000000000000000000000007346545000014145 5ustar0000000000000000aeson-pretty-0.8.10/cli-tool/Main.hs0000644000000000000000000000401707346545000015367 0ustar0000000000000000{-# LANGUAGE DeriveDataTypeable, RecordWildCards, OverloadedStrings #-} module Main (main) where import Prelude hiding (interact, concat, unlines, null) import Data.Aeson (Value(..), encode) import Data.Aeson.Encode.Pretty import Data.Aeson.Parser.Internal (value') import Data.Attoparsec.Lazy (Result(..), parse) import Data.ByteString.Lazy.Char8 (ByteString, interact, unlines, null) import Data.Version (showVersion) import Paths_aeson_pretty (version) import System.Console.CmdArgs data Options = Opts { compact :: Bool , indent :: Int , sort :: Bool } deriving (Data, Typeable) opts :: Options opts = Opts { compact = False &= help "Compact output." , indent = 4 &= help "Number of spaces per nesting-level (default 4)." , sort = False &= help "Sort objects by key (default: undefined order)." } &= program prog &= summary smry &= details info where prog = "aeson-pretty" smry = prog++" "++showVersion version++": Pretty JSON, the easy way." info :: [String] info = [ "Read JSON from stdin and pretty-print to stdout. The complementary " , "compact-mode removes whitespace from the input." , "" , "(c) Falko Peters 2011" , "" , "License: BSD3, for details see the source-repository at" , "http://www.github.com/informatikr/aeson-pretty." , "" ] main :: IO () main = do Opts{..} <- cmdArgs opts let conf = Config { confIndent = Spaces indent , confCompare = if sort then compare else mempty , confNumFormat = Generic , confTrailingNewline = False } enc = if compact then encode else encodePretty' conf interact $ unlines . map enc . values values :: ByteString -> [Value] values s = case parse value' s of Done rest v -> v : values rest Fail rest _ _ | null rest -> [] | otherwise -> error "invalid json"