packages feed

language-conf-0.2.1.0: src/Data/Conf/Aeson.hs

{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE OverloadedStrings    #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Data.Conf.Aeson
  where

import           Control.Monad
import           Data.Aeson
import           Data.Aeson
import           Data.Aeson.Types
import qualified Data.HashMap.Strict   as HashMap
import qualified Data.Scientific       as Scientific
import           Data.String
import qualified Data.Text             as Text
import qualified Data.Vector           as Vector

import           Data.Conf.PrettyPrint
import           Data.Conf.Types

fromToJSON :: ToJSON a => a -> Result Conf
fromToJSON = fromJSON . toJSON

instance FromJSON Conf where
    parseJSON (Object obj) = do
        let oList = HashMap.toList obj
        forM oList $ \(k, v) ->
            case v of
                o@(Object _) -> do
                    cs <- parseJSON o
                    return $ ConfStatementBlock (Block (Text.words k) cs)
                (Array vs) -> return $
                    ConfStatementExpression (Expression k (map toExpressionValue (Vector.toList vs)))
                value -> return $
                    ConfStatementExpression (Expression k [toExpressionValue value])
          where
            toExpressionValue (Number oc) =
                case Scientific.floatingOrInteger oc of
                    Left f -> fromString (show (f :: Double))
                    Right i -> fromString (show (i :: Integer))
            toExpressionValue (String oc) = oc
            toExpressionValue (Bool b) = if b then "true" else "false"
            toExpressionValue _ = error "Invalid type"

    parseJSON invalid = typeMismatch "Conf" invalid

instance ToJSON Conf where
    toJSON cs = object ps
      where
        ps = concatMap toPair cs
        toPair (ConfStatementExpression (Expression e [v])) = [ e .= String v ]
        toPair (ConfStatementExpression (Expression e vs)) = [ e .= toJSON vs ]
        toPair (ConfStatementBlock (Block [k] css)) = [ k .= toJSON css ]
        toPair (ConfStatementBlock (Block ks css)) = [ Text.unwords ks .= toJSON css ]
        toPair ConfStatementEmptyLine = []
        toPair (ConfStatementComment _) = []