{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Data.Swagger.Build.Util where import Control.Monad.Trans.State.Strict import Data.Swagger.Model.Api as Api import Data.Swagger.Model.Authorisation (Scope) import Data.Text (Text) import Prelude type Elem a b = IsElem a b ~ 'True type family IsElem a b where IsElem a (a ': t) = 'True IsElem a (h ': t) = IsElem a t -- | Common contains recurring fields to allow reuse of names. -- The first type variable is used to constrain the valid fields, e.g. -- -- @ -- type Foo = Common '["description", "models"] Bar -- @ -- -- The various state monad updates check if their field is part of the -- type-level list, cf. for example 'description'. -- data Common f a = Common { descr :: Maybe Text , reqrd :: Maybe Bool , prod :: Maybe [Text] , cons :: Maybe [Text] , modls :: Maybe [Model] , auths :: Maybe [(Text, Maybe Scope)] , other :: a } common :: a -> Common f a common = Common Nothing (Just True) Nothing Nothing Nothing Nothing description :: Elem "description" f => Text -> State (Common f a) () description d = modify $ \c -> c { descr = Just d } optional :: Elem "required" f => State (Common f a) () optional = modify $ \c -> c { reqrd = Nothing } produces :: Elem "produces" f => Text -> State (Common f a) () produces t = modify $ \c -> c { prod = maybe (Just [t]) (Just . (t:)) (prod c) } consumes :: Elem "consumes" f => Text -> State (Common f a) () consumes t = modify $ \c -> c { cons = maybe (Just [t]) (Just . (t:)) (cons c) } model :: Elem "models" f => Model -> State (Common f a) () model m = modify $ \c -> c { modls = maybe (Just [m]) (Just . (m:)) (modls c) } data Auth = Basic | ApiKey | OAuth2 Scope | None authorisation :: Elem "authorisations" f => Auth -> State (Common f a) () authorisation a = modify $ \c -> c { auths = maybe (Just (f a)) (Just . (f a ++)) (auths c) } where f Basic = [("basic", Nothing)] f ApiKey = [("apiKey", Nothing)] f (OAuth2 s) = [("oauth2", Just s)] f None = [] -- | If cases where no build steps are provided but a builder is required -- 'end' can be used, e.g. @defineModel \"Foo\" end@ end :: Monad m => m () end = return ()