{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE NoImplicitPrelude #-}
module CLI.Generator
( processServerDocument,
processClientDocument,
BuildConfig (..),
)
where
import CLI.Config (ServiceOptions (..))
import Data.ByteString.Lazy.Char8 (ByteString, pack)
import Data.HashMap.Lazy (lookup)
import Data.Morpheus.Client
( SchemaSource,
parseClientTypeDeclarations,
)
import Data.Morpheus.Client.CodeGen.AST (ClientDeclaration (..), DERIVING_MODE (SCALAR_MODE))
import Data.Morpheus.CodeGen
( CodeGenConfig (..),
parseServerTypeDefinitions,
)
import Data.Morpheus.CodeGen.Internal.AST
import Data.Morpheus.CodeGen.Utils (Flag (..))
import Data.Morpheus.Internal.Ext (GQLResult)
import Data.Morpheus.Types.Internal.AST (unpackName)
import qualified Data.Set as S
import Prettyprinter
import Relude hiding (ByteString, print)
data BuildConfig = BuildConfig
{ root :: String,
buildOptions :: ServiceOptions
}
deriving (Show)
getExtensions :: [Flag] -> [Text]
getExtensions xs = [x | FlagLanguageExtension x <- xs]
resolveExternal :: ServiceOptions -> Text -> Maybe (Text, [Text])
resolveExternal ServiceOptions {optionExternals} name = (,[name]) <$> name `lookup` optionExternals
collectExternals :: ServiceOptions -> [Text] -> [(Text, [Text])]
collectExternals buildOptions exts = mapMaybe (resolveExternal buildOptions) (S.toList $ S.fromList exts)
getImports :: ServiceOptions -> [Flag] -> [(Text, [Text])]
getImports buildOptions flags = collectExternals buildOptions [x | FlagExternal x <- flags]
uniq :: (Ord a) => [a] -> [a]
uniq = S.toList . S.fromList
processServerDocument :: BuildConfig -> Text -> ByteString -> GQLResult ByteString
processServerDocument BuildConfig {..} moduleName schema = do
(types, flags) <- second uniq <$> parseServerTypeDefinitions CodeGenConfig {namespace = optionNamespace buildOptions} schema
pure
$ print
$ ModuleDefinition
{ moduleName,
imports =
[ ("Data.Morpheus.Server.CodeGen.Internal", ["*"]),
("Data.Morpheus.Server.Types", ["*"])
]
<> map (,["*"]) (optionImports buildOptions)
<> getImports buildOptions flags,
extensions =
[ "DeriveGeneric",
"DuplicateRecordFields",
"TypeFamilies"
]
<> getExtensions flags,
types
}
isScalars :: ClientDeclaration -> Bool
isScalars (InstanceDeclaration SCALAR_MODE _) = True
isScalars _ = False
processClientDocument ::
BuildConfig ->
SchemaSource ->
Maybe Text ->
Text ->
GQLResult (Maybe ByteString)
processClientDocument BuildConfig {..} schema query moduleName = do
(allTypes, flags) <- second uniq <$> parseClientTypeDeclarations schema query
let externalImports = collectExternals buildOptions [unpackName $ getFullName (typeClassTarget x) | InstanceDeclaration SCALAR_MODE x <- allTypes]
let types = filter (not . isScalars) allTypes
if null types
then pure Nothing
else
pure
$ Just
$ print
ModuleDefinition
{ moduleName,
imports =
[("Data.Morpheus.Client.CodeGen.Internal", ["*"])]
<> map (,["*"]) (optionImports buildOptions)
<> externalImports
<> getImports buildOptions flags,
extensions =
[ "DeriveGeneric",
"DuplicateRecordFields",
"OverloadedStrings",
"TypeFamilies"
]
<> getExtensions flags,
types
}
print :: (Pretty a) => a -> ByteString
print = pack . show . pretty