{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}

module Lackey
  ( rubyForAPI,
  )
where

import qualified Data.Char as Char
import Data.Function ((&))
import qualified Data.Maybe as Maybe
import qualified Data.Proxy as Proxy
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Servant.Foreign as Servant

type Language = Servant.NoTypes

languageProxy :: Proxy.Proxy Language
languageProxy :: Proxy Language
languageProxy = forall {k} (t :: k). Proxy t
Proxy.Proxy

type Request = Servant.NoContent

requestProxy :: Proxy.Proxy Request
requestProxy :: Proxy Request
requestProxy = forall {k} (t :: k). Proxy t
Proxy.Proxy

renderRequests :: [Servant.Req Request] -> Text.Text
renderRequests :: [Req Request] -> Text
renderRequests [Req Request]
requests = [Req Request]
requests forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Req Request -> Text
renderRequest forall a b. a -> (a -> b) -> b
& Text -> [Text] -> Text
Text.intercalate Text
";"

functionName :: Servant.Req Request -> Text.Text
functionName :: Req Request -> Text
functionName Req Request
request = Req Request
request forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> FunctionName
Servant._reqFuncName forall a b. a -> (a -> b) -> b
& FunctionName -> Text
Servant.snakeCase

hasBody :: Servant.Req Request -> Bool
hasBody :: Req Request -> Bool
hasBody Req Request
request = case forall ftype. Req ftype -> Maybe ftype
Servant._reqBody Req Request
request of
  Maybe Request
Nothing -> Bool
False
  Just Request
_ -> Bool
True

bodyArgument :: Text.Text
bodyArgument :: Text
bodyArgument = Text
"body"

underscore :: Text.Text -> Text.Text
underscore :: Text -> Text
underscore Text
text =
  Text
text forall a b. a -> (a -> b) -> b
& Text -> Text
Text.toLower forall a b. a -> (a -> b) -> b
& (Char -> Char) -> Text -> Text
Text.map (\Char
c -> if Char -> Bool
Char.isAlphaNum Char
c then Char
c else Char
'_')

getHeaders :: Servant.Req Request -> [Text.Text]
getHeaders :: Req Request -> [Text]
getHeaders Req Request
request =
  Req Request
request
    forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> [HeaderArg ftype]
Servant._reqHeaders
    forall a b. a -> (a -> b) -> b
& forall a b. (a -> Maybe b) -> [a] -> [b]
Maybe.mapMaybe
      ( \HeaderArg Request
h -> case HeaderArg Request
h of
          Servant.HeaderArg Arg Request
x -> forall a. a -> Maybe a
Just Arg Request
x
          Servant.ReplaceHeaderArg Arg Request
_ Text
_ -> forall a. Maybe a
Nothing
      )
    forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PathSegment -> Text
Servant.unPathSegment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Arg ftype -> PathSegment
Servant._argName)

getURLPieces :: Servant.Req Request -> [Either Text.Text Text.Text]
getURLPieces :: Req Request -> [Either Text Text]
getURLPieces Req Request
request =
  let url :: Url Request
url = Req Request
request forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> Url ftype
Servant._reqUrl
      path :: [Text]
path =
        Url Request
url
          forall a b. a -> (a -> b) -> b
& forall ftype. Url ftype -> Path ftype
Servant._path
          forall a b. a -> (a -> b) -> b
& forall a b. (a -> Maybe b) -> [a] -> [b]
Maybe.mapMaybe
            ( ( \SegmentType Request
segment -> case SegmentType Request
segment of
                  Servant.Static PathSegment
_ -> forall a. Maybe a
Nothing
                  Servant.Cap Arg Request
arg -> forall a. a -> Maybe a
Just Arg Request
arg
              )
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Segment ftype -> SegmentType ftype
Servant.unSegment
            )
          forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PathSegment -> Text
Servant.unPathSegment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Arg ftype -> PathSegment
Servant._argName)
      query :: [Text]
query =
        Url Request
url
          forall a b. a -> (a -> b) -> b
& forall ftype. Url ftype -> [QueryArg ftype]
Servant._queryStr
          forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            (PathSegment -> Text
Servant.unPathSegment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Arg ftype -> PathSegment
Servant._argName forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. QueryArg ftype -> Arg ftype
Servant._queryArgName)
   in forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. a -> Either a b
Left [Text]
path forall a. Semigroup a => a -> a -> a
<> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. b -> Either a b
Right [Text]
query

functionArguments :: Servant.Req Request -> Text.Text
functionArguments :: Req Request -> Text
functionArguments Req Request
request =
  [Text] -> Text
Text.concat
    [ Text
"(",
      [ [forall a. a -> Maybe a
Just Text
"excon"],
        Req Request
request
          forall a b. a -> (a -> b) -> b
& Req Request -> [Either Text Text]
getURLPieces
          forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( \Either Text Text
piece -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ case Either Text Text
piece of
                Left Text
capture -> Text -> Text
underscore Text
capture
                Right Text
param -> Text -> Text
underscore Text
param forall a. Semigroup a => a -> a -> a
<> Text
": nil"
            ),
        Req Request
request forall a b. a -> (a -> b) -> b
& Req Request -> [Text]
getHeaders forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Semigroup a => a -> a -> a
<> Text
": nil") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
underscore),
        [if Req Request -> Bool
hasBody Req Request
request then forall a. a -> Maybe a
Just Text
bodyArgument else forall a. Maybe a
Nothing]
      ]
        forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        forall a b. a -> (a -> b) -> b
& forall a. [Maybe a] -> [a]
Maybe.catMaybes
        forall a b. a -> (a -> b) -> b
& Text -> [Text] -> Text
Text.intercalate Text
",",
      Text
")"
    ]

requestMethod :: Servant.Req Request -> Text.Text
requestMethod :: Req Request -> Text
requestMethod Req Request
request =
  Req Request
request forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> Method
Servant._reqMethod forall a b. a -> (a -> b) -> b
& Method -> Text
Text.decodeUtf8 forall a b. a -> (a -> b) -> b
& Text -> Text
Text.toLower forall a b. a -> (a -> b) -> b
& Char -> Text -> Text
Text.cons Char
':'

requestPath :: Servant.Req Request -> Text.Text
requestPath :: Req Request -> Text
requestPath Req Request
request =
  let path :: Text
path =
        Req Request
request
          forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> Url ftype
Servant._reqUrl
          forall a b. a -> (a -> b) -> b
& forall ftype. Url ftype -> Path ftype
Servant._path
          forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( ( \SegmentType Request
x -> case SegmentType Request
x of
                  Servant.Static PathSegment
y -> PathSegment -> Text
Servant.unPathSegment PathSegment
y
                  Servant.Cap Arg Request
y ->
                    let z :: Text
z =
                          Arg Request
y forall a b. a -> (a -> b) -> b
& forall ftype. Arg ftype -> PathSegment
Servant._argName forall a b. a -> (a -> b) -> b
& PathSegment -> Text
Servant.unPathSegment forall a b. a -> (a -> b) -> b
& Text -> Text
underscore
                     in Text
"#{" forall a. Semigroup a => a -> a -> a
<> Text
z forall a. Semigroup a => a -> a -> a
<> Text
"}"
              )
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Segment ftype -> SegmentType ftype
Servant.unSegment
            )
          forall a b. a -> (a -> b) -> b
& Text -> [Text] -> Text
Text.intercalate Text
"/"
      query :: Text
query =
        Req Request
request
          forall a b. a -> (a -> b) -> b
& forall ftype. Req ftype -> Url ftype
Servant._reqUrl
          forall a b. a -> (a -> b) -> b
& forall ftype. Url ftype -> [QueryArg ftype]
Servant._queryStr
          forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
            ( (\Text
x -> Text
x forall a. Semigroup a => a -> a -> a
<> Text
"=#{" forall a. Semigroup a => a -> a -> a
<> Text -> Text
underscore Text
x forall a. Semigroup a => a -> a -> a
<> Text
"}")
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. PathSegment -> Text
Servant.unPathSegment
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. Arg ftype -> PathSegment
Servant._argName
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall ftype. QueryArg ftype -> Arg ftype
Servant._queryArgName
            )
          forall a b. a -> (a -> b) -> b
& Text -> [Text] -> Text
Text.intercalate Text
"&"
      url :: Text
url = Text
"/" forall a. Semigroup a => a -> a -> a
<> Text
path forall a. Semigroup a => a -> a -> a
<> (if Text -> Bool
Text.null Text
query then Text
"" else Text
"?" forall a. Semigroup a => a -> a -> a
<> Text
query)
   in Text
"\"" forall a. Semigroup a => a -> a -> a
<> Text
url forall a. Semigroup a => a -> a -> a
<> Text
"\""

requestHeaders :: Servant.Req Request -> Text.Text
requestHeaders :: Req Request -> Text
requestHeaders Req Request
request =
  [ [Text
"{"],
    Req Request
request forall a b. a -> (a -> b) -> b
& Req Request -> [Text]
getHeaders forall a b. a -> (a -> b) -> b
& forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Text
x -> Text
"\"" forall a. Semigroup a => a -> a -> a
<> Text
x forall a. Semigroup a => a -> a -> a
<> Text
"\"=>" forall a. Semigroup a => a -> a -> a
<> Text -> Text
underscore Text
x),
    [Text
"}"]
  ]
    forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    forall a b. a -> (a -> b) -> b
& [Text] -> Text
Text.concat

requestBody :: Servant.Req Request -> Text.Text
requestBody :: Req Request -> Text
requestBody Req Request
request = if Req Request -> Bool
hasBody Req Request
request then Text
bodyArgument else Text
"nil"

functionBody :: Servant.Req Request -> Text.Text
functionBody :: Req Request -> Text
functionBody Req Request
request =
  [Text] -> Text
Text.concat
    [ Text
"excon.request(",
      Text
":method=>",
      Req Request -> Text
requestMethod Req Request
request,
      Text
",",
      Text
":path=>",
      Req Request -> Text
requestPath Req Request
request,
      Text
",",
      Text
":headers=>",
      Req Request -> Text
requestHeaders Req Request
request,
      Text
",",
      Text
":body=>",
      Req Request -> Text
requestBody Req Request
request,
      Text
")"
    ]

renderRequest :: Servant.Req Request -> Text.Text
renderRequest :: Req Request -> Text
renderRequest Req Request
request =
  [Text] -> Text
Text.concat
    [ Text
"def ",
      Req Request -> Text
functionName Req Request
request,
      Req Request -> Text
functionArguments Req Request
request,
      Req Request -> Text
functionBody Req Request
request,
      Text
"end"
    ]

requestsForAPI ::
  ( Servant.HasForeign Language Request api,
    Servant.GenerateList Request (Servant.Foreign Request api)
  ) =>
  Proxy.Proxy api ->
  [Servant.Req Request]
requestsForAPI :: forall api.
(HasForeign Language Request api,
 GenerateList Request (Foreign Request api)) =>
Proxy api -> [Req Request]
requestsForAPI Proxy api
api = Proxy api
api forall a b. a -> (a -> b) -> b
& forall {k} (lang :: k) ftype api.
(HasForeign lang ftype api,
 GenerateList ftype (Foreign ftype api)) =>
Proxy lang -> Proxy ftype -> Proxy api -> [Req ftype]
Servant.listFromAPI Proxy Language
languageProxy Proxy Request
requestProxy

rubyForAPI ::
  ( Servant.HasForeign Language Request api,
    Servant.GenerateList Request (Servant.Foreign Request api)
  ) =>
  Proxy.Proxy api ->
  Text.Text
rubyForAPI :: forall api.
(HasForeign Language Request api,
 GenerateList Request (Foreign Request api)) =>
Proxy api -> Text
rubyForAPI Proxy api
api = Proxy api
api forall a b. a -> (a -> b) -> b
& forall api.
(HasForeign Language Request api,
 GenerateList Request (Foreign Request api)) =>
Proxy api -> [Req Request]
requestsForAPI forall a b. a -> (a -> b) -> b
& [Req Request] -> Text
renderRequests