{-# LANGUAGE FlexibleInstances #-}

-- | A cheap and cheerful pretty-printing library
module Data.API.PP
    ( PP(..)
    , PPLines(..)
    , inFrontOf
    , indent
    ) where

import           Data.API.Scan (keywords)
import           Data.API.Types

import qualified Data.Aeson                     as JS
import qualified Data.Aeson.Encode.Pretty       as JS
import qualified Data.ByteString.Lazy.Char8     as BL
import           Data.List
import           Data.Set (Set)
import qualified Data.Set                       as Set
import qualified Data.Text                      as T
import           Data.Version


class PP t where
  pp :: t -> String

class PPLines t where
  ppLines :: t -> [String]


inFrontOf :: String -> [String] -> [String]
inFrontOf :: String -> [String] -> [String]
inFrontOf String
x []     = [String
x]
inFrontOf String
x (String
s:[String]
ss) = (String
x forall a. [a] -> [a] -> [a]
++ String
s) forall a. a -> [a] -> [a]
: [String]
ss

indent :: [String] -> [String]
indent :: [String] -> [String]
indent = forall a b. (a -> b) -> [a] -> [b]
map (String
"  " forall a. [a] -> [a] -> [a]
++)


instance PP [Char] where
  pp :: String -> String
pp = forall a. a -> a
id

instance PP Version where
  pp :: Version -> String
pp = Version -> String
showVersion

instance PP t => PP (Set t) where
  pp :: Set t -> String
pp Set t
s = forall a. [a] -> [[a]] -> [a]
intercalate String
", " (forall a b. (a -> b) -> [a] -> [b]
map forall t. PP t => t -> String
pp forall a b. (a -> b) -> a -> b
$ forall a. Set a -> [a]
Set.toList Set t
s)

instance PP T.Text where
  pp :: Text -> String
pp = Text -> String
T.unpack

instance PPLines JS.Value where
  ppLines :: Value -> [String]
ppLines Value
v = String -> [String]
lines forall a b. (a -> b) -> a -> b
$ ByteString -> String
BL.unpack forall a b. (a -> b) -> a -> b
$ forall a. ToJSON a => a -> ByteString
JS.encodePretty Value
v

instance PP TypeName where
  pp :: TypeName -> String
pp = Text -> String
T.unpack forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypeName -> Text
_TypeName

instance PP FieldName where
  pp :: FieldName -> String
pp (FieldName Text
fn_t) | String
fn forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
keywords = String
"'" forall a. [a] -> [a] -> [a]
++ String
fn forall a. [a] -> [a] -> [a]
++ String
"'"
                      | Bool
otherwise          = String
fn
    where
      fn :: String
fn = Text -> String
T.unpack Text
fn_t

instance PP APIType where
  pp :: APIType -> String
pp (TyList  APIType
ty) = String
"[" forall a. [a] -> [a] -> [a]
++ forall t. PP t => t -> String
pp APIType
ty forall a. [a] -> [a] -> [a]
++ String
"]"
  pp (TyMaybe APIType
ty) = String
"? " forall a. [a] -> [a] -> [a]
++ forall t. PP t => t -> String
pp APIType
ty
  pp (TyName  TypeName
t)  = forall t. PP t => t -> String
pp TypeName
t
  pp (TyBasic BasicType
b)  = forall t. PP t => t -> String
pp BasicType
b
  pp  APIType
TyJSON      = String
"json"

instance PP BasicType where
  pp :: BasicType -> String
pp BasicType
BTstring = String
"string"
  pp BasicType
BTbinary = String
"binary"
  pp BasicType
BTbool   = String
"boolean"
  pp BasicType
BTint    = String
"integer"
  pp BasicType
BTutc    = String
"utc"

instance PP DefaultValue where
  pp :: DefaultValue -> String
pp DefaultValue
DefValList           = String
"[]"
  pp DefaultValue
DefValMaybe          = String
"nothing"
  pp (DefValString Text
t)     = forall a. Show a => a -> String
show Text
t
  pp (DefValBool   Bool
True)  = String
"true"
  pp (DefValBool   Bool
False) = String
"false"
  pp (DefValInt    Int
i)     = forall a. Show a => a -> String
show Int
i
  pp (DefValUtc    UTCTime
u)     = forall a. Show a => a -> String
show UTCTime
u


instance PPLines t => PPLines [t] where
  ppLines :: [t] -> [String]
ppLines = forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall t. PPLines t => t -> [String]
ppLines

instance (PPLines s, PPLines t) => PPLines (s, t) where
  ppLines :: (s, t) -> [String]
ppLines (s
s, t
t) = forall t. PPLines t => t -> [String]
ppLines s
s forall a. [a] -> [a] -> [a]
++ forall t. PPLines t => t -> [String]
ppLines t
t