@@ -1,19 +1,3 @@
2−{-# LANGUAGE ConstraintKinds #-}
3−{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−#if !MIN_VERSION_base(4,8,0)
7−{-# LANGUAGE NullaryTypeClasses #-}
9−{-# LANGUAGE MultiParamTypeClasses #-}
10−{-# LANGUAGE ScopedTypeVariables #-}
11−{-# LANGUAGE TemplateHaskell #-}
12−{-# LANGUAGE TypeFamilies #-}
13−{-# LANGUAGE TypeOperators #-}
14−{-# LANGUAGE UndecidableInstances #-}
15−{-# LANGUAGE OverloadedStrings #-}
17-- | Generalizes all the data needed to make code generation work with
1-- | Generalizes all the data needed to make code generation work with
18-- arbitrary programming languages.
2-- arbitrary programming languages.
19module Servant.Foreign
3module Servant.Foreign
@@ -46,244 +30,5 @@ module Servant.Foreign
46 , module Servant.API
30 , module Servant.API
49−import Control.Lens (makeLenses, (%~), (&), (.~), (<>~))
50−import qualified Data.Char as C
53−import GHC.Exts (Constraint)
55−import Prelude hiding (concat)
56−import Servant.API
33+import Servant.API
57−
34+import Servant.Foreign.Internal
58−-- | Function name builder that simply concat each part together
59−concatCase :: FunctionName -> Text
62−-- | Function name builder using the snake_case convention.
63−-- each part is separated by a single underscore character.
64−snakeCase :: FunctionName -> Text
65−snakeCase = intercalate "_"
67−-- | Function name builder using the CamelCase convention.
68−-- each part begins with an upper case character.
69−camelCase :: FunctionName -> Text
70−camelCase = camelCase' . Prelude.map (replace "-" "")
71− where camelCase' [] = ""
72− camelCase' (p:ps) = concat $ p : Prelude.map capitalize ps
74− capitalize name = C.toUpper (Data.Text.head name) `cons` Data.Text.tail name
78−newtype Segment = Segment { _segment :: SegmentType }
81−data SegmentType = Static Text -- ^ a static path segment. like "/foo"
82− | Cap Arg -- ^ a capture. like "/:userid"
93−data QueryArg = QueryArg
95− , _argType :: ArgType
96− } deriving (Eq, Show)
98−data HeaderArg = HeaderArg
99− { headerArgName :: Text
102− { headerArgName :: Text
103− , headerPattern :: Text
104− } deriving (Eq, Show)
109− , _queryStr :: [QueryArg]
110− } deriving (Eq, Show)
115−type FunctionName = [Text]
120− , _reqMethod :: Method
121− , _reqHeaders :: [HeaderArg]
123− , _funcName :: FunctionName
124− } deriving (Eq, Show)
126−makeLenses ''QueryArg
131−isCapture :: Segment -> Bool
132−isCapture (Segment (Cap _)) = True
135−captureArg :: Segment -> Arg
136−captureArg (Segment (Cap s)) = s
137−captureArg _ = error "captureArg called on non capture"
140−defReq = Req defUrl "GET" [] False []
142−-- | To be used exclusively as a "negative" return type/constraint
143−-- by @'Elem`@ type family.
146−type family Elem (a :: *) (ls::[*]) :: Constraint where
147− Elem a '[] = NotFound
148− Elem a (a ': list) = ()
149− Elem a (b ': list) = Elem a list
151−class HasForeign (layout :: *) where
152− type Foreign layout :: *
153− foreignFor :: Proxy layout -> Req -> Foreign layout
155−instance (HasForeign a, HasForeign b)
156− => HasForeign (a :<|> b) where
157− type Foreign (a :<|> b) = Foreign a :<|> Foreign b
159− foreignFor Proxy req =
160− foreignFor (Proxy :: Proxy a) req
161− :<|> foreignFor (Proxy :: Proxy b) req
163−instance (KnownSymbol sym, HasForeign sublayout)
164− => HasForeign (Capture sym a :> sublayout) where
165− type Foreign (Capture sym a :> sublayout) = Foreign sublayout
167− foreignFor Proxy req =
168− foreignFor (Proxy :: Proxy sublayout) $
169− req & reqUrl.path <>~ [Segment (Cap str)]
170− & funcName %~ (++ ["by", str])
172− where str = pack . symbolVal $ (Proxy :: Proxy sym)
174−instance Elem JSON list => HasForeign (Delete list a) where
175− type Foreign (Delete list a) = Req
177− foreignFor Proxy req =
178− req & funcName %~ ("delete" :)
179− & reqMethod .~ "DELETE"
181−instance Elem JSON list => HasForeign (Get list a) where
182− type Foreign (Get list a) = Req
184− foreignFor Proxy req =
185− req & funcName %~ ("get" :)
186− & reqMethod .~ "GET"
188−instance (KnownSymbol sym, HasForeign sublayout)
189− => HasForeign (Header sym a :> sublayout) where
190− type Foreign (Header sym a :> sublayout) = Foreign sublayout
192− foreignFor Proxy req =
193− foreignFor subP (req & reqHeaders <>~ [HeaderArg hname])
195− where hname = pack . symbolVal $ (Proxy :: Proxy sym)
196− subP = Proxy :: Proxy sublayout
198−instance Elem JSON list => HasForeign (Post list a) where
199− type Foreign (Post list a) = Req
201− foreignFor Proxy req =
202− req & funcName %~ ("post" :)
203− & reqMethod .~ "POST"
205−instance Elem JSON list => HasForeign (Put list a) where
206− type Foreign (Put list a) = Req
208− foreignFor Proxy req =
209− req & funcName %~ ("put" :)
210− & reqMethod .~ "PUT"
212−instance (KnownSymbol sym, HasForeign sublayout)
213− => HasForeign (QueryParam sym a :> sublayout) where
214− type Foreign (QueryParam sym a :> sublayout) = Foreign sublayout
216− foreignFor Proxy req =
217− foreignFor (Proxy :: Proxy sublayout) $
218− req & reqUrl.queryStr <>~ [QueryArg str Normal]
220− where str = pack . symbolVal $ (Proxy :: Proxy sym)
222−instance (KnownSymbol sym, HasForeign sublayout)
223− => HasForeign (QueryParams sym a :> sublayout) where
224− type Foreign (QueryParams sym a :> sublayout) = Foreign sublayout
226− foreignFor Proxy req =
227− foreignFor (Proxy :: Proxy sublayout) $
228− req & reqUrl.queryStr <>~ [QueryArg str List]
230− where str = pack . symbolVal $ (Proxy :: Proxy sym)
232−instance (KnownSymbol sym, HasForeign sublayout)
233− => HasForeign (QueryFlag sym :> sublayout) where
234− type Foreign (QueryFlag sym :> sublayout) = Foreign sublayout
236− foreignFor Proxy req =
237− foreignFor (Proxy :: Proxy sublayout) $
238− req & reqUrl.queryStr <>~ [QueryArg str Flag]
240− where str = pack . symbolVal $ (Proxy :: Proxy sym)
242−instance HasForeign Raw where
243− type Foreign Raw = Method -> Req
245− foreignFor Proxy req method =
246− req & funcName %~ ((toLower method) :)
247− & reqMethod .~ method
249−instance (Elem JSON list, HasForeign sublayout) => HasForeign (ReqBody list a :> sublayout) where
250− type Foreign (ReqBody list a :> sublayout) = Foreign sublayout
252− foreignFor Proxy req =
253− foreignFor (Proxy :: Proxy sublayout) $
254− req & reqBody .~ True
256−instance (KnownSymbol path, HasForeign sublayout)
257− => HasForeign (path :> sublayout) where
258− type Foreign (path :> sublayout) = Foreign sublayout
260− foreignFor Proxy req =
261− foreignFor (Proxy :: Proxy sublayout) $
262− req & reqUrl.path <>~ [Segment (Static str)]
263− & funcName %~ (++ [str])
265− where str = Data.Text.map (\c -> if c == '.' then '_' else c) . pack . symbolVal $ (Proxy :: Proxy path)
267−instance HasForeign sublayout => HasForeign (RemoteHost :> sublayout) where
268− type Foreign (RemoteHost :> sublayout) = Foreign sublayout
270− foreignFor Proxy req =
271− foreignFor (Proxy :: Proxy sublayout) req
273−instance HasForeign sublayout => HasForeign (IsSecure :> sublayout) where
274− type Foreign (IsSecure :> sublayout) = Foreign sublayout
276− foreignFor Proxy req =
277− foreignFor (Proxy :: Proxy sublayout) req
279−instance HasForeign sublayout => HasForeign (Vault :> sublayout) where
280− type Foreign (Vault :> sublayout) = Foreign sublayout
282− foreignFor Proxy req =
283− foreignFor (Proxy :: Proxy sublayout) req
285−instance HasForeign sublayout => HasForeign (HttpVersion :> sublayout) where
286− type Foreign (HttpVersion :> sublayout) = Foreign sublayout
288− foreignFor Proxy req =
289− foreignFor (Proxy :: Proxy sublayout) req