module Json
( jsonOptionsForPrefix
, deriveJSON
, deriveJSON_
, deriveJSONOptions
, deriveEnumJSON
) where
import Data.Aeson (FromJSON(..), ToJSON(..), Value(..))
import qualified Data.Aeson.TH as J (Options (..), defaultOptions, deriveJSON)
import Data.Char (toLower, isUpper)
import Data.Text as T (unpack)
import Language.Haskell.TH
import Language.Haskell.TH.Syntax (showName)
jsonOptionsForPrefix :: String -> J.Options
jsonOptionsForPrefix prefix =
J.defaultOptions
{ J.fieldLabelModifier = underscoreIt . (drop $ length prefix) }
underscoreIt :: String -> String
underscoreIt s = go [] s
where
go :: String -> String -> String
go [] (c:cs) = go [toLower c] cs
go r (c:cs) | isUpper c = go (r ++ "_" ++ [(toLower c)]) cs
go r (c:cs) = go (r ++ [c]) cs
go r [] = r
deriveJSONOptions :: J.Options -> Name -> Q [Dec]
deriveJSONOptions = J.deriveJSON
deriveJSON :: Name -> Q [Dec]
deriveJSON name = deriveJSONOptions (jsonOptionsForPrefix (nameBase name)) name
deriveJSON_ :: Name -> Q [Dec]
deriveJSON_ name = deriveJSONOptions (jsonOptionsForPrefix ('_' : nameBase name)) name
deriveEnumJSON :: Name -> Q [Dec]
deriveEnumJSON name = [d|
instance FromJSON $(conT name) where
parseJSON (String s) = return $ read . T.unpack $ s
parseJSON _ = fail $ "Invalid " ++ $(stringE (showName name))
instance ToJSON $(conT name) where
toJSON = toJSON . show
|]