servant-typescript-0.1.0.0: src/Servant/TypeScript/Types.hs
module Servant.TypeScript.Types where
import Control.Lens
import Data.Aeson.TypeScript.Recursive
import Data.Aeson.TypeScript.TH
import Data.String.Interpolate
import qualified Data.Text as T
import Servant.Foreign.Internal as FI
import qualified Servant.TypeScript.GetFunctions as GetFunctions
import Servant.TypeScript.Util
-- | Foreign type for getting TS types
data LangTS
instance (TypeScript a) => HasForeignType LangTS T.Text a where
typeFor _proxyLang _proxyFtype proxyA = T.pack $ getTypeScriptType proxyA
-- | Foreign type for getting TS declarations
data LangTSDecls
instance (TypeScript a) => HasForeignType LangTSDecls [TSDeclaration] a where
typeFor _proxyLang _proxyFtype proxyA = getTypeScriptDeclarationsRecursively proxyA
data ServantTypeScriptOptions = ServantTypeScriptOptions {
-- | Extra TypeScript types to include in the @d.ts@ file.
--
-- Useful if you want to expose types that don't appear in your API, for whatever reason.
extraTypes :: [TSType]
-- | Determine to which output file the client function for the given request is mapped.
--
-- Useful to break up larger APIs into separate files based on criteria like route prefixes.
--
-- It's fine if the file key contains sub-directories; they will be created as needed.
--
-- A good approach is to split on @case req ^. (reqFuncName . _FunctionName) of ...@.
--
-- Default implementation is @const "client.ts"@.
, getFileKey :: Req T.Text -> FilePath
-- | Mangle a given request into a corresponding client function name.
-- By default, just prepends the HTTP method to the camel-cased route.
, getFunctionName :: Req T.Text -> T.Text
-- | Given a list of requests, output a complete TypeScript module with the (exported) client functions,
-- ready to be consumed by your TypeScript app.
--
-- For example, you can import dependencies at the top
-- to use in your functions. The default version relies on the NPM "query-string" package to construct
-- URLs. It uses the built-in @window.fetch@ by default, but allows you to pass your own @fetch@ function
-- instead (useful for server-side rendering etc.). The default client functions return @Promise@s with
-- the given return value, and on failure they reject the promise with a value of interface
-- @{ status: number; text: string; }@.
--
-- If you want to write your own 'getFunctions', check out the 'Servant.TypeScript.GetFunctions' module for
-- inspiration.
--
-- The first argument passed to 'getFunctions' is the 'getFunctionName' function.
, getFunctions :: (Req T.Text -> T.Text) -> [Req T.Text] -> T.Text
}
-- | Reasonable default options.
defaultServantTypeScriptOptions :: ServantTypeScriptOptions
defaultServantTypeScriptOptions = ServantTypeScriptOptions {
extraTypes = []
, getFileKey = const "client.ts"
, getFunctionName = \req -> case req ^. (reqFuncName . _FunctionName) of
(method:xs) -> toCamelList $ fmap snakeToCamel (method:xs)
_ -> error [i|Case not handled in getFunctionName: '#{req}'|]
, getFunctions = GetFunctions.getFunctions
}