{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ < 710
{-# LANGUAGE OverlappingInstances #-}
#endif
module Hackage.Security.Util.JSON (
ToJSON(..)
, FromJSON(..)
, ToObjectKey(..)
, FromObjectKey(..)
, ReportSchemaErrors(..)
, Expected
, Got
, expected'
, fromJSObject
, fromJSField
, fromJSOptField
, mkObject
, JSValue(..)
, Int54
) where
import MyPrelude
import Control.Monad (liftM)
import Data.Maybe (catMaybes)
import Data.Map (Map)
import Data.Time
import Text.JSON.Canonical
import Network.URI
import qualified Data.Map as Map
#if !MIN_VERSION_time(1,5,0)
import System.Locale (defaultTimeLocale)
#endif
import Hackage.Security.Util.Path
class ToJSON m a where
toJSON :: a -> m JSValue
class FromJSON m a where
fromJSON :: JSValue -> m a
class ToObjectKey m a where
toObjectKey :: a -> m String
class FromObjectKey m a where
fromObjectKey :: String -> m (Maybe a)
class (Applicative m, Monad m) => ReportSchemaErrors m where
expected :: Expected -> Maybe Got -> m a
type Expected = String
type Got = String
expected' :: ReportSchemaErrors m => Expected -> JSValue -> m a
expected' :: forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expected' Expected
descr JSValue
val = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected Expected
descr (forall a. a -> Maybe a
Just (JSValue -> Expected
describeValue JSValue
val))
where
describeValue :: JSValue -> String
describeValue :: JSValue -> Expected
describeValue (JSValue
JSNull ) = Expected
"null"
describeValue (JSBool Bool
_) = Expected
"bool"
describeValue (JSNum Int54
_) = Expected
"num"
describeValue (JSString Expected
_) = Expected
"string"
describeValue (JSArray [JSValue]
_) = Expected
"array"
describeValue (JSObject [(Expected, JSValue)]
_) = Expected
"object"
unknownField :: ReportSchemaErrors m => String -> m a
unknownField :: forall (m :: * -> *) a. ReportSchemaErrors m => Expected -> m a
unknownField Expected
field = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected (Expected
"field " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> Expected
show Expected
field) forall a. Maybe a
Nothing
instance Monad m => ToObjectKey m String where
toObjectKey :: Expected -> m Expected
toObjectKey = forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => FromObjectKey m String where
fromObjectKey :: Expected -> m (Maybe Expected)
fromObjectKey = forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just
instance Monad m => ToObjectKey m (Path root) where
toObjectKey :: Path root -> m Expected
toObjectKey (Path Expected
fp) = forall (m :: * -> *) a. Monad m => a -> m a
return Expected
fp
instance Monad m => FromObjectKey m (Path root) where
fromObjectKey :: Expected -> m (Maybe (Path root))
fromObjectKey = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Expected -> Path a
Path) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
FromObjectKey m a =>
Expected -> m (Maybe a)
fromObjectKey
instance Monad m => ToJSON m JSValue where
toJSON :: JSValue -> m JSValue
toJSON = forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => FromJSON m JSValue where
fromJSON :: JSValue -> m JSValue
fromJSON = forall (m :: * -> *) a. Monad m => a -> m a
return
instance Monad m => ToJSON m String where
toJSON :: Expected -> m JSValue
toJSON = forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expected -> JSValue
JSString
instance ReportSchemaErrors m => FromJSON m String where
fromJSON :: JSValue -> m Expected
fromJSON (JSString Expected
str) = forall (m :: * -> *) a. Monad m => a -> m a
return Expected
str
fromJSON JSValue
val = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expected' Expected
"string" JSValue
val
instance Monad m => ToJSON m Int54 where
toJSON :: Int54 -> m JSValue
toJSON = forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int54 -> JSValue
JSNum
instance ReportSchemaErrors m => FromJSON m Int54 where
fromJSON :: JSValue -> m Int54
fromJSON (JSNum Int54
i) = forall (m :: * -> *) a. Monad m => a -> m a
return Int54
i
fromJSON JSValue
val = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expected' Expected
"int" JSValue
val
instance
#if __GLASGOW_HASKELL__ >= 710
{-# OVERLAPPABLE #-}
#endif
(Monad m, ToJSON m a) => ToJSON m [a] where
toJSON :: [a] -> m JSValue
toJSON = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [JSValue] -> JSValue
JSArray forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON
instance
#if __GLASGOW_HASKELL__ >= 710
{-# OVERLAPPABLE #-}
#endif
(ReportSchemaErrors m, FromJSON m a) => FromJSON m [a] where
fromJSON :: JSValue -> m [a]
fromJSON (JSArray [JSValue]
as) = forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON [JSValue]
as
fromJSON JSValue
val = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expected' Expected
"array" JSValue
val
instance Monad m => ToJSON m UTCTime where
toJSON :: UTCTime -> m JSValue
toJSON = forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expected -> JSValue
JSString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. FormatTime t => TimeLocale -> Expected -> t -> Expected
formatTime TimeLocale
defaultTimeLocale Expected
"%FT%TZ"
instance ReportSchemaErrors m => FromJSON m UTCTime where
fromJSON :: JSValue -> m UTCTime
fromJSON JSValue
enc = do
Expected
str <- forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
enc
case forall (m :: * -> *) t.
(MonadFail m, ParseTime t) =>
Bool -> TimeLocale -> Expected -> Expected -> m t
parseTimeM Bool
False TimeLocale
defaultTimeLocale Expected
"%FT%TZ" Expected
str of
Just UTCTime
time -> forall (m :: * -> *) a. Monad m => a -> m a
return UTCTime
time
Maybe UTCTime
Nothing -> forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected Expected
"valid date-time string" (forall a. a -> Maybe a
Just Expected
str)
#if !MIN_VERSION_time(1,5,0)
where
parseTimeM _trim = parseTime
#endif
instance ( Monad m
, ToObjectKey m k
, ToJSON m a
) => ToJSON m (Map k a) where
toJSON :: Map k a -> m JSValue
toJSON = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [(Expected, JSValue)] -> JSValue
JSObject forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (k, a) -> m (Expected, JSValue)
aux forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Map k a -> [(k, a)]
Map.toList
where
aux :: (k, a) -> m (String, JSValue)
aux :: (k, a) -> m (Expected, JSValue)
aux (k
k, a
a) = do Expected
k' <- forall (m :: * -> *) a. ToObjectKey m a => a -> m Expected
toObjectKey k
k; JSValue
a' <- forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON a
a; forall (m :: * -> *) a. Monad m => a -> m a
return (Expected
k', JSValue
a')
instance ( ReportSchemaErrors m
, Ord k
, FromObjectKey m k
, FromJSON m a
) => FromJSON m (Map k a) where
fromJSON :: JSValue -> m (Map k a)
fromJSON JSValue
enc = do
[(Expected, JSValue)]
obj <- forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(Expected, JSValue)]
fromJSObject JSValue
enc
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [Maybe a] -> [a]
catMaybes forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Expected, JSValue) -> m (Maybe (k, a))
aux [(Expected, JSValue)]
obj
where
aux :: (String, JSValue) -> m (Maybe (k, a))
aux :: (Expected, JSValue) -> m (Maybe (k, a))
aux (Expected
k, JSValue
a) = Maybe k -> a -> Maybe (k, a)
knownKeys forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a.
FromObjectKey m a =>
Expected -> m (Maybe a)
fromObjectKey Expected
k forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
a
knownKeys :: Maybe k -> a -> Maybe (k, a)
knownKeys :: Maybe k -> a -> Maybe (k, a)
knownKeys Maybe k
Nothing a
_ = forall a. Maybe a
Nothing
knownKeys (Just k
k) a
a = forall a. a -> Maybe a
Just (k
k, a
a)
instance Monad m => ToJSON m URI where
toJSON :: URI -> m JSValue
toJSON = forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> Expected
show
instance ReportSchemaErrors m => FromJSON m URI where
fromJSON :: JSValue -> m URI
fromJSON JSValue
enc = do
Expected
str <- forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
enc
case Expected -> Maybe URI
parseURI Expected
str of
Maybe URI
Nothing -> forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> Maybe Expected -> m a
expected Expected
"valid URI" (forall a. a -> Maybe a
Just Expected
str)
Just URI
uri -> forall (m :: * -> *) a. Monad m => a -> m a
return URI
uri
fromJSObject :: ReportSchemaErrors m => JSValue -> m [(String, JSValue)]
fromJSObject :: forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(Expected, JSValue)]
fromJSObject (JSObject [(Expected, JSValue)]
obj) = forall (m :: * -> *) a. Monad m => a -> m a
return [(Expected, JSValue)]
obj
fromJSObject JSValue
val = forall (m :: * -> *) a.
ReportSchemaErrors m =>
Expected -> JSValue -> m a
expected' Expected
"object" JSValue
val
fromJSField :: (ReportSchemaErrors m, FromJSON m a)
=> JSValue -> String -> m a
fromJSField :: forall (m :: * -> *) a.
(ReportSchemaErrors m, FromJSON m a) =>
JSValue -> Expected -> m a
fromJSField JSValue
val Expected
nm = do
[(Expected, JSValue)]
obj <- forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(Expected, JSValue)]
fromJSObject JSValue
val
case forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Expected
nm [(Expected, JSValue)]
obj of
Just JSValue
fld -> forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
fld
Maybe JSValue
Nothing -> forall (m :: * -> *) a. ReportSchemaErrors m => Expected -> m a
unknownField Expected
nm
fromJSOptField :: (ReportSchemaErrors m, FromJSON m a)
=> JSValue -> String -> m (Maybe a)
fromJSOptField :: forall (m :: * -> *) a.
(ReportSchemaErrors m, FromJSON m a) =>
JSValue -> Expected -> m (Maybe a)
fromJSOptField JSValue
val Expected
nm = do
[(Expected, JSValue)]
obj <- forall (m :: * -> *).
ReportSchemaErrors m =>
JSValue -> m [(Expected, JSValue)]
fromJSObject JSValue
val
case forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Expected
nm [(Expected, JSValue)]
obj of
Just JSValue
fld -> forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
fld
Maybe JSValue
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
mkObject :: forall m. Monad m => [(String, m JSValue)] -> m JSValue
mkObject :: forall (m :: * -> *).
Monad m =>
[(Expected, m JSValue)] -> m JSValue
mkObject = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [(Expected, JSValue)] -> JSValue
JSObject forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Expected, m JSValue)] -> m [(Expected, JSValue)]
sequenceFields
where
sequenceFields :: [(String, m JSValue)] -> m [(String, JSValue)]
sequenceFields :: [(Expected, m JSValue)] -> m [(Expected, JSValue)]
sequenceFields [] = forall (m :: * -> *) a. Monad m => a -> m a
return []
sequenceFields ((Expected
fld,m JSValue
val):[(Expected, m JSValue)]
flds) = do JSValue
val' <- m JSValue
val
[(Expected, JSValue)]
flds' <- [(Expected, m JSValue)] -> m [(Expected, JSValue)]
sequenceFields [(Expected, m JSValue)]
flds
forall (m :: * -> *) a. Monad m => a -> m a
return ((Expected
fld,JSValue
val')forall a. a -> [a] -> [a]
:[(Expected, JSValue)]
flds')