{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

module Language.JavaScript.Inline.Aeson where

import qualified Data.Aeson as A
import Language.JavaScript.Inline.Core

-- | If a Haskell type @a@ has 'A.ToJSON' and 'A.FromJSON' instances, then we
-- can derive 'ToJS' and 'FromJS' instances for it using:
--
-- 1. @deriving (ToJS, FromJS) via (Aeson a)@, using the @DerivingVia@ extension
-- 2. @deriving (ToJS, FromJS)@, using the @GeneralizedNewtypeDeriving@
--    extension
newtype Aeson a = Aeson
  { Aeson a -> a
unAeson :: a
  }
  deriving (Int -> Aeson a -> ShowS
[Aeson a] -> ShowS
Aeson a -> String
(Int -> Aeson a -> ShowS)
-> (Aeson a -> String) -> ([Aeson a] -> ShowS) -> Show (Aeson a)
forall a. Show a => Int -> Aeson a -> ShowS
forall a. Show a => [Aeson a] -> ShowS
forall a. Show a => Aeson a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Aeson a] -> ShowS
$cshowList :: forall a. Show a => [Aeson a] -> ShowS
show :: Aeson a -> String
$cshow :: forall a. Show a => Aeson a -> String
showsPrec :: Int -> Aeson a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Aeson a -> ShowS
Show)

instance A.ToJSON a => ToJS (Aeson a) where
  toJS :: Aeson a -> JSExpr
toJS = EncodedJSON -> JSExpr
forall a. ToJS a => a -> JSExpr
toJS (EncodedJSON -> JSExpr)
-> (Aeson a -> EncodedJSON) -> Aeson a -> JSExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> EncodedJSON
EncodedJSON (ByteString -> EncodedJSON)
-> (Aeson a -> ByteString) -> Aeson a -> EncodedJSON
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. ToJSON a => a -> ByteString
A.encode (a -> ByteString) -> (Aeson a -> a) -> Aeson a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Aeson a -> a
forall a. Aeson a -> a
unAeson

instance A.FromJSON a => FromJS (Aeson a) where
  rawJSType :: Proxy (Aeson a) -> RawJSType
rawJSType Proxy (Aeson a)
_ = RawJSType
RawJSON
  toRawJSType :: Proxy (Aeson a) -> JSExpr
toRawJSType Proxy (Aeson a)
_ = JSExpr
"a => a"
  fromJS :: Session -> ByteString -> IO (Aeson a)
fromJS Session
_ ByteString
s = case ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
A.eitherDecode' ByteString
s of
    Left String
err -> String -> IO (Aeson a)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
    Right a
a -> Aeson a -> IO (Aeson a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Aeson a -> IO (Aeson a)) -> Aeson a -> IO (Aeson a)
forall a b. (a -> b) -> a -> b
$ a -> Aeson a
forall a. a -> Aeson a
Aeson a
a