morpheus-graphql-code-gen 0.20.1 → 0.21.0
raw patch · 9 files changed
+349/−165 lines, 9 filesdep ~morpheus-graphql-coredep ~prettyprinterPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: morpheus-graphql-core, prettyprinter
API changes (from Hackage documentation)
- Data.Morpheus.CodeGen.Internal.AST: [gqlTypeDirectives] :: GQLTypeDefinition -> Map Text (Directives CONST)
- Data.Morpheus.CodeGen.Internal.AST: [gql] :: ServerTypeDefinition -> Maybe GQLTypeDefinition
+ Data.Morpheus.CodeGen.Internal.AST: DirectiveTypeDefinition :: ServerConstructorDefinition -> [DerivingClass] -> [DirectiveLocation] -> GQLTypeDefinition -> ServerTypeDefinition
+ Data.Morpheus.CodeGen.Internal.AST: EnumDirectiveUsage :: TypeName -> TypeValue -> ServerDirectiveUsage
+ Data.Morpheus.CodeGen.Internal.AST: FieldDirectiveUsage :: FieldName -> TypeValue -> ServerDirectiveUsage
+ Data.Morpheus.CodeGen.Internal.AST: TypeDirectiveUsage :: TypeValue -> ServerDirectiveUsage
+ Data.Morpheus.CodeGen.Internal.AST: TypeValueBool :: Bool -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: TypeValueList :: [TypeValue] -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: TypeValueNumber :: Double -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: TypeValueObject :: TypeName -> [(FieldName, TypeValue)] -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: TypeValueString :: Text -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: TypedValueMaybe :: Maybe TypeValue -> TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: [directiveConstructor] :: ServerTypeDefinition -> ServerConstructorDefinition
+ Data.Morpheus.CodeGen.Internal.AST: [directiveDerives] :: ServerTypeDefinition -> [DerivingClass]
+ Data.Morpheus.CodeGen.Internal.AST: [directiveGQLType] :: ServerTypeDefinition -> GQLTypeDefinition
+ Data.Morpheus.CodeGen.Internal.AST: [directiveLocations] :: ServerTypeDefinition -> [DirectiveLocation]
+ Data.Morpheus.CodeGen.Internal.AST: [gqlTypeDirectiveUses] :: GQLTypeDefinition -> [ServerDirectiveUsage]
+ Data.Morpheus.CodeGen.Internal.AST: [typeGQLType] :: ServerTypeDefinition -> Maybe GQLTypeDefinition
+ Data.Morpheus.CodeGen.Internal.AST: data ServerDirectiveUsage
+ Data.Morpheus.CodeGen.Internal.AST: data TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: instance GHC.Show.Show Data.Morpheus.CodeGen.Internal.AST.ServerDirectiveUsage
+ Data.Morpheus.CodeGen.Internal.AST: instance GHC.Show.Show Data.Morpheus.CodeGen.Internal.AST.TypeValue
+ Data.Morpheus.CodeGen.Internal.AST: instance Prettyprinter.Internal.Pretty Data.Morpheus.CodeGen.Internal.AST.TypeValue
- Data.Morpheus.CodeGen.Internal.AST: GQLTypeDefinition :: Kind -> Maybe Text -> Map Text Description -> Map Text (Directives CONST) -> Map Text (Value CONST) -> GQLTypeDefinition
+ Data.Morpheus.CodeGen.Internal.AST: GQLTypeDefinition :: Kind -> Maybe Text -> Map Text Description -> [ServerDirectiveUsage] -> Map Text (Value CONST) -> GQLTypeDefinition
Files
- app/Main.hs +3/−3
- morpheus-graphql-code-gen.cabal +6/−6
- src/Data/Morpheus/CodeGen/Internal/AST.hs +44/−6
- src/Data/Morpheus/CodeGen/Internal/Name.hs +4/−3
- src/Data/Morpheus/CodeGen/Interpreting/Transform.hs +239/−108
- src/Data/Morpheus/CodeGen/Printing/GQLType.hs +21/−24
- src/Data/Morpheus/CodeGen/Printing/Render.hs +8/−7
- src/Data/Morpheus/CodeGen/Printing/Terms.hs +4/−3
- src/Data/Morpheus/CodeGen/Printing/Type.hs +20/−5
app/Main.hs view
@@ -6,11 +6,11 @@ ) where +import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as L ( readFile, writeFile, )-import Data.ByteString.Lazy (ByteString) import Data.Char import Data.Morpheus.CodeGen ( CodeGenConfig (..),@@ -48,13 +48,13 @@ import qualified Paths_morpheus_graphql_code_gen as CLI import Relude hiding (ByteString) import System.FilePath.Posix- ( (</>),- dropExtensions,+ ( dropExtensions, makeRelative, normalise, replaceExtensions, splitDirectories, splitFileName,+ (</>), ) currentVersion :: String
morpheus-graphql-code-gen.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.35.0. -- -- see: https://github.com/sol/hpack name: morpheus-graphql-code-gen-version: 0.20.1+version: 0.21.0 synopsis: Morpheus GraphQL CLI description: code generator for Morpheus GraphQL category: web, graphql, cli@@ -46,8 +46,8 @@ base >=4.7.0 && <5.0.0 , bytestring >=0.10.4 && <0.12.0 , containers >=0.4.2.1 && <0.7.0- , morpheus-graphql-core >=0.20.0 && <0.21.0- , prettyprinter >=1.2.0 && <2.0.0+ , morpheus-graphql-core >=0.21.0 && <0.22.0+ , prettyprinter >=1.7.0 && <2.0.0 , relude >=0.3.0 && <2.0.0 , template-haskell >=2.0.0 && <3.0.0 , text >=1.2.3 && <1.3.0@@ -67,9 +67,9 @@ , containers >=0.4.2.1 && <0.7.0 , filepath >=1.1.0 && <1.5.0 , morpheus-graphql-code-gen- , morpheus-graphql-core >=0.20.0 && <0.21.0+ , morpheus-graphql-core >=0.21.0 && <0.22.0 , optparse-applicative >=0.12.0 && <0.18.0- , prettyprinter >=1.2.0 && <2.0.0+ , prettyprinter >=1.7.0 && <2.0.0 , relude >=0.3.0 && <2.0.0 , template-haskell >=2.0.0 && <3.0.0 , text >=1.2.3 && <1.3.0
src/Data/Morpheus/CodeGen/Internal/AST.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} module Data.Morpheus.CodeGen.Internal.AST@@ -16,24 +17,24 @@ ServerConstructorDefinition (..), ServerFieldDefinition (..), Kind (..),+ ServerDirectiveUsage (..),+ TypeValue (..), ) where import Data.Morpheus.Types.Internal.AST ( CONST, Description,- Directives,+ DirectiveLocation (..), FieldName, TypeKind (..),- TypeKind, TypeName,- TypeName, TypeRef (..),- TypeRef, TypeWrapper (..), Value, unpackName, )+import Prettyprinter (Doc, Pretty (..), punctuate, vsep, (<+>)) import Relude data ModuleDefinition = ModuleDefinition@@ -66,11 +67,42 @@ data Kind = Scalar | Type deriving (Show) +data TypeValue+ = TypeValueObject TypeName [(FieldName, TypeValue)]+ | TypeValueNumber Double+ | TypeValueString Text+ | TypeValueBool Bool+ | TypeValueList [TypeValue]+ | TypedValueMaybe (Maybe TypeValue)+ deriving (Show)++renderField :: (FieldName, TypeValue) -> Doc n+renderField (fName, fValue) = pretty (unpackName fName :: Text) <> "=" <+> pretty fValue++instance Pretty TypeValue where+ pretty (TypeValueObject name xs) =+ pretty (unpackName name :: Text)+ <+> "{"+ <+> vsep (punctuate "," (map renderField xs))+ <+> "}"+ pretty (TypeValueNumber x) = pretty x+ pretty (TypeValueString x) = pretty (show x :: String)+ pretty (TypeValueBool x) = pretty x+ pretty (TypedValueMaybe (Just x)) = "Just" <+> pretty x+ pretty (TypedValueMaybe Nothing) = "Nothing"+ pretty (TypeValueList xs) = prettyList xs++data ServerDirectiveUsage+ = TypeDirectiveUsage TypeValue+ | FieldDirectiveUsage FieldName TypeValue+ | EnumDirectiveUsage TypeName TypeValue+ deriving (Show)+ data GQLTypeDefinition = GQLTypeDefinition { gqlKind :: Kind, gqlTypeDescription :: Maybe Text, gqlTypeDescriptions :: Map Text Description,- gqlTypeDirectives :: Map Text (Directives CONST),+ gqlTypeDirectiveUses :: [ServerDirectiveUsage], gqlTypeDefaultValues :: Map Text (Value CONST) } deriving (Show)@@ -88,7 +120,13 @@ tCons :: [ServerConstructorDefinition], tKind :: TypeKind, derives :: [DerivingClass],- gql :: Maybe GQLTypeDefinition+ typeGQLType :: Maybe GQLTypeDefinition+ }+ | DirectiveTypeDefinition+ { directiveConstructor :: ServerConstructorDefinition,+ directiveDerives :: [DerivingClass],+ directiveLocations :: [DirectiveLocation],+ directiveGQLType :: GQLTypeDefinition } | ServerInterfaceDefinition TypeName
src/Data/Morpheus/CodeGen/Internal/Name.hs view
@@ -12,13 +12,13 @@ ( toLower, toUpper, )-import qualified Data.Morpheus.Types.Internal.AST as N import Data.Morpheus.Types.Internal.AST ( FieldName, TypeName, packName, unpackName, )+import qualified Data.Morpheus.Types.Internal.AST as N import qualified Data.Text as T import Relude hiding ( ToString (..),@@ -35,8 +35,9 @@ camelCaseTypeName :: [N.Name t] -> TypeName -> TypeName camelCaseTypeName list name =- packName $ T.concat $- map (capitalize . unpackName) (list <> [coerce name])+ packName $+ T.concat $+ map (capitalize . unpackName) (list <> [coerce name]) toHaskellTypeName :: TypeName -> Text toHaskellTypeName "String" = "Text"
src/Data/Morpheus/CodeGen/Interpreting/Transform.hs view
@@ -24,8 +24,10 @@ GQLTypeDefinition (..), Kind (..), ServerConstructorDefinition (..),+ ServerDirectiveUsage (..), ServerFieldDefinition (..), ServerTypeDefinition (..),+ TypeValue (..), ) import Data.Morpheus.CodeGen.Internal.Name ( camelCaseFieldName,@@ -35,18 +37,19 @@ ( ToName (toName), camelCaseTypeName, )-import Data.Morpheus.Core- ( parseTypeDefinitions,- )+import Data.Morpheus.Core (internalSchema, parseDefinitions, render) import Data.Morpheus.Error (gqlWarnings, renderGQLErrors) import Data.Morpheus.Internal.Ext (GQLResult, Result (..))+import Data.Morpheus.Internal.Utils (IsMap, selectOr) import Data.Morpheus.Types.Internal.AST ( ANY,+ Argument (..), ArgumentDefinition (..), CONST, DataEnumValue (..), Description,- Directives,+ Directive (Directive, directiveArgs, directiveName),+ DirectiveDefinition (..), FieldContent (..), FieldDefinition (..), FieldName,@@ -54,7 +57,9 @@ GQLError, IN, OUT,+ ObjectEntry (..), OperationType (Subscription),+ RawTypeDefinition (..), TRUE, Token, TypeContent (..),@@ -63,13 +68,14 @@ TypeName, TypeRef (..), UnionMember (..),- Value, isPossibleInterfaceType, isResolverType, kindOf, lookupWith, unpackName, )+import qualified Data.Morpheus.Types.Internal.AST as AST+import qualified Data.Morpheus.Types.Internal.AST as V import Language.Haskell.TH ( Dec (..), Info (..),@@ -109,39 +115,72 @@ data TypeContext s = TypeContext { toArgsTypeName :: FieldName -> TypeName,- schema :: [TypeDefinition ANY s],- currentTypeName :: TypeName,- hasNamespace :: Bool,- currentKind :: Maybe TypeKind+ typeDefinitions :: [TypeDefinition ANY s],+ directiveDefinitions :: [DirectiveDefinition s],+ currentTypeName :: Maybe TypeName,+ currentKind :: Maybe TypeKind,+ hasNamespace :: Bool } parseServerTypeDefinitions :: CodeGenMonad m => CodeGenConfig -> ByteString -> m [ServerTypeDefinition] parseServerTypeDefinitions ctx txt =- case parseTypeDefinitions txt of+ case parseDefinitions txt of Failure errors -> fail (renderGQLErrors errors)- Success {result = schema, warnings} -> printWarnings warnings >> toTHDefinitions (namespace ctx) schema+ Success {result, warnings} -> printWarnings warnings >> toTHDefinitions (namespace ctx) result toTHDefinitions :: CodeGenMonad m => Bool ->- [TypeDefinition ANY CONST] ->+ [RawTypeDefinition] -> m [ServerTypeDefinition]-toTHDefinitions namespace schema = concat <$> traverse generateTypes schema+toTHDefinitions namespace defs = concat <$> traverse generateTypes defs where- generateTypes :: CodeGenMonad m => TypeDefinition ANY CONST -> m [ServerTypeDefinition]- generateTypes typeDef =+ typeDefinitions = [td | RawTypeDefinition td <- defs]+ directiveDefinitions = [td | RawDirectiveDefinition td <- defs]+ generateTypes :: CodeGenMonad m => RawTypeDefinition -> m [ServerTypeDefinition]+ generateTypes (RawTypeDefinition typeDef) = runReaderT (genTypeDefinition typeDef) TypeContext { toArgsTypeName = mkArgsTypeName namespace (typeName typeDef),- schema,- currentTypeName = typeName typeDef,+ typeDefinitions,+ directiveDefinitions,+ currentTypeName = Just (typeName typeDef), currentKind = Just (kindOf typeDef), hasNamespace = namespace }+ generateTypes (RawDirectiveDefinition DirectiveDefinition {..}) =+ runReaderT+ ( do+ fields <- traverse renderDataField (argument <$> toList directiveDefinitionArgs)+ pure+ [ DirectiveTypeDefinition+ { directiveConstructor = ServerConstructorDefinition (coerce directiveDefinitionName) fields,+ directiveDerives = [SHOW, GENERIC],+ directiveLocations = directiveDefinitionLocations,+ directiveGQLType =+ GQLTypeDefinition+ { gqlKind = Type,+ gqlTypeDescription = Nothing,+ gqlTypeDescriptions = mempty,+ gqlTypeDefaultValues = mempty,+ gqlTypeDirectiveUses = []+ }+ }+ ]+ )+ TypeContext+ { toArgsTypeName = coerce,+ typeDefinitions,+ currentTypeName = Just (coerce directiveDefinitionName),+ directiveDefinitions,+ currentKind = Nothing,+ hasNamespace = namespace+ }+ generateTypes _ = pure [] -inType :: MonadReader (TypeContext s) m => TypeName -> m a -> m a-inType currentTypeName = local (\x -> x {currentTypeName, currentKind = Nothing})+inType :: MonadReader (TypeContext s) m => Maybe TypeName -> m a -> m a+inType name = local (\x -> x {currentTypeName = name, currentKind = Nothing}) mkInterfaceName :: TypeName -> TypeName mkInterfaceName = ("Interface" <>)@@ -158,32 +197,39 @@ { typeName = originalTypeName, typeContent, typeDescription- } = withType <$> genTypeContent originalTypeName typeContent+ } = genTypeContent originalTypeName typeContent >>= withType where typeName = case typeContent of DataInterface {} -> mkInterfaceName originalTypeName _ -> originalTypeName tKind = kindOf typeDef tName = toHaskellTypeName typeName- gql =- Just- GQLTypeDefinition- { gqlTypeDescription = typeDescription,- gqlTypeDescriptions = getDesc typeDef,- gqlTypeDirectives = getDirs typeDef,- gqlKind = derivingKind tKind,- gqlTypeDefaultValues =- fromList- $ mapMaybe getDefaultValue- $ getInputFields typeDef- }+ deriveGQL = do+ gqlTypeDescriptions <- getDesc typeDef+ gqlTypeDirectiveUses <- getDirs typeDef+ pure $+ Just+ GQLTypeDefinition+ { gqlTypeDescription = typeDescription,+ gqlTypeDescriptions,+ gqlTypeDirectiveUses,+ gqlKind = derivingKind tKind,+ gqlTypeDefaultValues =+ fromList $+ mapMaybe getDefaultValue $+ getInputFields typeDef+ } typeParameters | isResolverType tKind = ["m"] | otherwise = [] derives = derivesClasses (isResolverType tKind) -------------------------- withType (ConsIN tCons) = [ServerTypeDefinition {..}]- withType (ConsOUT others tCons) = ServerTypeDefinition {..} : others+ withType (ConsIN tCons) = do+ typeGQLType <- deriveGQL+ pure [ServerTypeDefinition {..}]+ withType (ConsOUT others tCons) = do+ typeGQLType <- deriveGQL+ pure (ServerTypeDefinition {..} : others) derivingKind :: TypeKind -> Kind derivingKind KindScalar = Scalar@@ -226,10 +272,10 @@ fieldContent, fieldType = TypeRef {typeConName, typeWrappers} } = do- isParametrized <- lift . isParametrizedResolverType typeConName =<< asks schema+ isParametrized <- lift . isParametrizedResolverType typeConName =<< asks typeDefinitions genName <- asks toArgsTypeName kind <- asks currentKind- fieldName <- genFieldName fName+ fieldName <- renderFieldName fName pure ServerFieldDefinition { fieldType = toHaskellTypeName typeConName,@@ -262,7 +308,7 @@ genInterfaceUnion :: Monad m => TypeName -> ServerQ m [ServerTypeDefinition] genInterfaceUnion interfaceName = mkInterface . map typeName . mapMaybe (isPossibleInterfaceType interfaceName)- <$> asks schema+ <$> asks typeDefinitions where tKind = KindUnion mkInterface [] = []@@ -275,18 +321,18 @@ tKind, typeParameters = ["m"], derives = derivesClasses True,- gql = Nothing+ typeGQLType = Nothing } ] mkGuardWithPossibleType = ServerInterfaceDefinition interfaceName (mkInterfaceName interfaceName) tName = mkPossibleTypesName interfaceName -genFieldName :: Monad m => FieldName -> ServerQ m FieldName-genFieldName fieldName = do+renderFieldName :: Monad m => FieldName -> ServerQ m FieldName+renderFieldName fieldName = do TypeContext {hasNamespace, currentTypeName} <- ask pure $ if hasNamespace- then camelCaseFieldName currentTypeName fieldName+ then maybe fieldName (`camelCaseFieldName` fieldName) currentTypeName else fieldName mkConsEnum :: Monad m => TypeName -> DataEnumValue CONST -> ServerQ m ServerConstructorDefinition@@ -301,19 +347,12 @@ constructorFields = [] } -toNonResolverServerField :: Monad m => FieldDefinition c CONST -> ServerQ m ServerFieldDefinition-toNonResolverServerField- FieldDefinition- { fieldType = TypeRef {typeConName, typeWrappers},- fieldName = fName- } = do- fieldName <- genFieldName fName- pure $- ServerFieldDefinition- { fieldType = toHaskellTypeName typeConName,- fieldName,- wrappers = [GQL_WRAPPER typeWrappers]- }+renderDataField :: Monad m => FieldDefinition c CONST -> ServerQ m ServerFieldDefinition+renderDataField FieldDefinition {fieldType = TypeRef {typeConName, typeWrappers}, fieldName = fName} = do+ fieldName <- renderFieldName fName+ let wrappers = [GQL_WRAPPER typeWrappers]+ let fieldType = toHaskellTypeName typeConName+ pure ServerFieldDefinition {..} genTypeContent :: CodeGenMonad m =>@@ -323,7 +362,7 @@ genTypeContent _ DataScalar {} = pure (ConsIN []) genTypeContent typeName (DataEnum tags) = ConsIN <$> traverse (mkConsEnum typeName) tags genTypeContent typeName (DataInputObject fields) =- ConsIN . mkObjectCons typeName <$> traverse toNonResolverServerField (toList fields)+ ConsIN . mkObjectCons typeName <$> traverse renderDataField (toList fields) genTypeContent _ DataInputUnion {} = fail "Input Unions not Supported" genTypeContent typeName DataInterface {interfaceFields} = ConsOUT@@ -331,13 +370,14 @@ <*> ( do let interfaceName = mkInterfaceName typeName inType- interfaceName+ (Just interfaceName) ( mkObjectCons interfaceName <$> traverse mkObjectField (toList interfaceFields) ) ) genTypeContent typeName DataObject {objectFields} =- ConsOUT <$> genArgumentTypes objectFields+ ConsOUT+ <$> genArgumentTypes objectFields <*> ( mkObjectCons typeName <$> traverse mkObjectField (toList objectFields) )@@ -371,52 +411,54 @@ fieldContent = Just (FieldArgs arguments) } | length arguments > 1 = do- tName <- (fieldName &) <$> asks toArgsTypeName- inType tName $ do- let argumentFields = argument <$> toList arguments- fields <- traverse toNonResolverServerField argumentFields- let tKind = KindInputObject- pure- [ ServerTypeDefinition- { tName = toHaskellTypeName tName,- tKind,- tCons = mkObjectCons tName fields,- derives = derivesClasses False,- typeParameters = [],- gql =- Just- ( GQLTypeDefinition- { gqlKind = Type,- gqlTypeDescription = Nothing,- gqlTypeDescriptions = fromList (mapMaybe mkFieldDescription argumentFields),- gqlTypeDirectives = fromList (mkFieldDirective <$> argumentFields),- gqlTypeDefaultValues = fromList (mapMaybe getDefaultValue argumentFields)- }- )- }- ]+ tName <- (fieldName &) <$> asks toArgsTypeName+ inType (Just tName) $ do+ let argumentFields = argument <$> toList arguments+ fields <- traverse renderDataField argumentFields+ let tKind = KindInputObject+ pure+ [ ServerTypeDefinition+ { tName = toHaskellTypeName tName,+ tKind,+ tCons = mkObjectCons tName fields,+ derives = derivesClasses False,+ typeParameters = [],+ typeGQLType =+ Just+ ( GQLTypeDefinition+ { gqlKind = Type,+ gqlTypeDescription = Nothing,+ gqlTypeDescriptions = fromList (mapMaybe mkFieldDescription argumentFields),+ gqlTypeDefaultValues = fromList (mapMaybe getDefaultValue argumentFields),+ gqlTypeDirectiveUses = []+ }+ )+ }+ ] genArgumentType _ = pure [] mkFieldDescription :: FieldDefinition cat s -> Maybe (Text, Description) mkFieldDescription FieldDefinition {..} = (unpackName fieldName,) <$> fieldDescription -mkFieldDirective :: FieldDefinition cat s -> (Text, Directives s)-mkFieldDirective FieldDefinition {..} = (unpackName fieldName, fieldDirectives)- --- -getDesc :: TypeDefinition c s -> Map Token Description-getDesc = fromList . get+getDesc :: MonadFail m => TypeDefinition c CONST -> ServerQ m (Map Token Description)+getDesc = fmap fromList . get -getDirs :: TypeDefinition c s -> Map Token (Directives s)-getDirs = fromList . get+getDirs :: MonadFail m => TypeDefinition c CONST -> ServerQ m [ServerDirectiveUsage]+getDirs x = do+ contentD <- map snd <$> get x+ typeD <- traverse transform (toList $ AST.typeDirectives x)+ pure (contentD <> typeD)+ where+ transform v = TypeDirectiveUsage <$> directiveTypeValue v class Meta a v where- get :: a -> [(Token, v)]+ get :: MonadFail m => a -> ServerQ m [(Token, v)] instance (Meta a v) => Meta (Maybe a) v where get (Just x) = get x- get _ = []+ get _ = pure [] instance ( Meta (FieldsDefinition IN s) v,@@ -437,41 +479,130 @@ get DataObject {objectFields} = get objectFields get DataInputObject {inputObjectFields} = get inputObjectFields get DataInterface {interfaceFields} = get interfaceFields- get DataEnum {enumMembers} = concatMap get enumMembers- get _ = []+ get DataEnum {enumMembers} = concat <$> traverse get enumMembers+ get _ = pure [] -instance Meta (DataEnumValue s) Description where- get DataEnumValue {enumName, enumDescription = Just x} = [(unpackName enumName, x)]- get _ = []+instance Meta (DataEnumValue CONST) Description where+ get DataEnumValue {enumName, enumDescription = Just x} = pure [(unpackName enumName, x)]+ get _ = pure [] -instance Meta (DataEnumValue s) (Directives s) where+instance Meta (DataEnumValue CONST) ServerDirectiveUsage where get DataEnumValue {enumName, enumDirectives}- | null enumDirectives = []- | otherwise = [(unpackName enumName, enumDirectives)]+ | null enumDirectives = pure []+ | otherwise = traverse transform (toList enumDirectives)+ where+ transform x = (unpackName enumName,) . EnumDirectiveUsage enumName <$> directiveTypeValue x instance- Meta (FieldDefinition c s) v =>- Meta (FieldsDefinition c s) v+ Meta (FieldDefinition c CONST) v =>+ Meta (FieldsDefinition c CONST) v where- get = concatMap get . toList+ get = fmap concat . traverse get . toList -instance Meta (FieldDefinition c s) Description where- get FieldDefinition {fieldName, fieldDescription = Just x} = [(unpackName fieldName, x)]- get _ = []+instance Meta (FieldDefinition c CONST) Description where+ get FieldDefinition {fieldName, fieldDescription = Just x} = pure [(unpackName fieldName, x)]+ get _ = pure [] -instance Meta (FieldDefinition c s) (Directives s) where+instance Meta (FieldDefinition c CONST) ServerDirectiveUsage where get FieldDefinition {fieldName, fieldDirectives}- | null fieldDirectives = []- | otherwise = [(unpackName fieldName, fieldDirectives)]+ | null fieldDirectives = pure []+ | otherwise = traverse transform (toList fieldDirectives)+ where+ transform x = (unpackName fieldName,) . FieldDirectiveUsage fieldName <$> directiveTypeValue x getInputFields :: TypeDefinition c s -> [FieldDefinition IN s] getInputFields TypeDefinition {typeContent = DataInputObject {inputObjectFields}} = toList inputObjectFields getInputFields _ = [] -getDefaultValue :: FieldDefinition c s -> Maybe (Text, Value s)+getDefaultValue :: FieldDefinition c s -> Maybe (Text, V.Value s) getDefaultValue FieldDefinition { fieldName, fieldContent = Just DefaultInputValue {defaultInputValue} } = Just (unpackName fieldName, defaultInputValue) getDefaultValue _ = Nothing++nativeDirectives :: V.DirectivesDefinition CONST+nativeDirectives = AST.directiveDefinitions internalSchema++getDirective :: (MonadReader (TypeContext CONST) m, MonadFail m) => FieldName -> m (DirectiveDefinition CONST)+getDirective directiveName = do+ dirs <- asks directiveDefinitions+ case find (\DirectiveDefinition {directiveDefinitionName} -> directiveDefinitionName == directiveName) dirs of+ Just dir -> pure dir+ _ -> selectOr (fail $ "unknown directive" <> show directiveName) pure directiveName nativeDirectives++directiveTypeValue :: MonadFail m => Directive CONST -> ServerQ m TypeValue+directiveTypeValue Directive {..} = inType typeContext $ do+ dirs <- getDirective directiveName+ TypeValueObject typename <$> traverse (renderArgumentValue directiveArgs) (toList $ directiveDefinitionArgs dirs)+ where+ (typeContext, typename) = renderDirectiveTypeName directiveName++renderDirectiveTypeName :: FieldName -> (Maybe TypeName, TypeName)+renderDirectiveTypeName "deprecated" = (Nothing, "Deprecated")+renderDirectiveTypeName name = (Just (coerce name), coerce name)++renderArgumentValue ::+ (IsMap FieldName c, MonadFail m) =>+ c (Argument CONST) ->+ ArgumentDefinition s ->+ ReaderT (TypeContext CONST) m (FieldName, TypeValue)+renderArgumentValue args ArgumentDefinition {..} = do+ let dirName = AST.fieldName argument+ gqlValue <- selectOr (pure AST.Null) (pure . argumentValue) dirName args+ typeValue <- mapWrappedValue (AST.fieldType argument) gqlValue+ fName <- renderFieldName dirName+ pure (fName, typeValue)++notFound :: MonadFail m => String -> String -> m a+notFound name at = fail $ "can't found " <> name <> "at " <> at <> "!"++lookupType :: MonadFail m => TypeName -> ServerQ m (TypeDefinition ANY CONST)+lookupType name = do+ types <- asks typeDefinitions+ case find (\t -> typeName t == name) types of+ Just x -> pure x+ Nothing -> notFound (show name) "type definitions"++lookupValueFieldType :: MonadFail m => TypeName -> FieldName -> ServerQ m TypeRef+lookupValueFieldType name fieldName = do+ TypeDefinition {typeContent} <- lookupType name+ case typeContent of+ DataInputObject fields -> do+ FieldDefinition {fieldType} <- selectOr (notFound (show fieldName) (show name)) pure fieldName fields+ pure fieldType+ _ -> notFound "input object" (show name)++mapField :: MonadFail m => TypeName -> ObjectEntry CONST -> ServerQ m (FieldName, TypeValue)+mapField tName ObjectEntry {..} = do+ t <- lookupValueFieldType tName entryName+ value <- mapWrappedValue t entryValue+ pure (entryName, value)++expected :: MonadFail m => String -> V.Value CONST -> ServerQ m TypeValue+expected typ value = fail ("expected " <> typ <> ", found " <> show (render value) <> "!")++mapWrappedValue :: MonadFail m => TypeRef -> V.Value CONST -> ServerQ m TypeValue+mapWrappedValue (TypeRef name (AST.BaseType isRequired)) value+ | isRequired = mapValue name value+ | value == V.Null = pure (TypedValueMaybe Nothing)+ | otherwise = TypedValueMaybe . Just <$> mapValue name value+mapWrappedValue (TypeRef name (AST.TypeList elems isRequired)) d = case d of+ V.Null | not isRequired -> pure (TypedValueMaybe Nothing)+ (V.List xs) -> TypedValueMaybe . Just . TypeValueList <$> traverse (mapWrappedValue (TypeRef name elems)) xs+ value -> expected "list" value++mapValue :: MonadFail m => TypeName -> V.Value CONST -> ServerQ m TypeValue+mapValue name (V.List xs) = TypeValueList <$> traverse (mapValue name) xs+mapValue _ (V.Enum name) = pure $ TypeValueObject name []+mapValue name (V.Object fields) = TypeValueObject name <$> traverse (mapField name) (toList fields)+mapValue _ (V.Scalar x) = mapScalarValue x+mapValue t v = expected (show t) v++mapScalarValue :: MonadFail m => V.ScalarValue -> ServerQ m TypeValue+mapScalarValue (V.Int x) = pure $ TypeValueNumber (fromIntegral x)+mapScalarValue (V.Float x) = pure $ TypeValueNumber x+mapScalarValue (V.String x) = pure $ TypeValueString x+mapScalarValue (V.Boolean x) = pure $ TypeValueBool x+mapScalarValue (V.Value _) = fail "JSON objects are not supported!"
src/Data/Morpheus/CodeGen/Printing/GQLType.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NoImplicitPrelude #-} module Data.Morpheus.CodeGen.Printing.GQLType@@ -10,6 +10,7 @@ import Data.Morpheus.CodeGen.Internal.AST ( GQLTypeDefinition (..), Kind (..),+ ServerDirectiveUsage (..), ServerTypeDefinition (..), TypeKind, )@@ -17,36 +18,29 @@ ( optional, parametrizedType, )-import Data.Text.Prettyprint.Doc- ( Doc,- Pretty (pretty),- indent,- line,- tupled,- vsep,- (<+>),- )+import Prettyprinter import Relude hiding (optional, show) import Prelude (show) renderTypeableConstraints :: [Text] -> Doc n renderTypeableConstraints xs = tupled (map (("Typeable" <+>) . pretty) xs) <+> "=>" --- TODO: fill namespace options-defineTypeOptions :: Text -> TypeKind -> Doc n-defineTypeOptions tName kind = ""+defineTypeOptions :: Bool -> Text -> TypeKind -> Doc n+defineTypeOptions namespaces tName kind+ | namespaces = "typeOptions _ = dropNamespaceOptions " <> pretty tName <> " (" <> pretty (show kind) <> ")"+ | otherwise = "typeOptions _ options = options" renderGQLType :: ServerTypeDefinition -> Doc n-renderGQLType ServerTypeDefinition {tName, typeParameters, tKind, gql} =+renderGQLType ServerTypeDefinition {..} = "instance" <> optional renderTypeableConstraints typeParameters <+> "GQLType" <+> typeHead <+> "where"- <> line- <> indent 2 (vsep (renderMethods typeHead gql <> [options]))+ <> line+ <> indent 2 (vsep (renderMethods typeHead typeGQLType <> [options])) where- options = defineTypeOptions tName tKind+ options = defineTypeOptions False tName tKind typeHead = if null typeParameters then parametrizedType tName typeParameters@@ -57,16 +51,19 @@ renderMethods _ Nothing = [] renderMethods typeHead- ( Just- GQLTypeDefinition- { gqlTypeDescription,- gqlTypeDescriptions,- gqlKind- }- ) =+ (Just GQLTypeDefinition {..}) = ["type KIND" <+> typeHead <+> "=" <+> renderKind gqlKind] <> ["description _ =" <+> pretty (show gqlTypeDescription) | not (null gqlTypeDescription)] <> ["getDescriptions _ =" <+> pretty (show gqlTypeDescriptions) | not (null gqlTypeDescriptions)]+ <> ["directives _=" <+> renderDirectiveUsages gqlTypeDirectiveUses | not (null gqlTypeDirectiveUses)]++renderDirectiveUsages :: [ServerDirectiveUsage] -> Doc n+renderDirectiveUsages = align . vsep . punctuate " <>" . map renderDirectiveUsage++renderDirectiveUsage :: ServerDirectiveUsage -> Doc n+renderDirectiveUsage (TypeDirectiveUsage value) = "typeDirective" <+> pretty value+renderDirectiveUsage (FieldDirectiveUsage place value) = "fieldDirective" <+> pretty (show place) <+> pretty value+renderDirectiveUsage (EnumDirectiveUsage place value) = "enumDirective" <+> pretty (show place) <+> pretty value renderKind :: Kind -> Doc n renderKind Type = "TYPE"
src/Data/Morpheus/CodeGen/Printing/Render.hs view
@@ -27,7 +27,7 @@ ( fromStrict, ) import Data.Text.Lazy.Encoding (encodeUtf8)-import Data.Text.Prettyprint.Doc+import Prettyprinter ( Doc, line, pretty,@@ -49,6 +49,7 @@ [ ("Data.Data", ["Typeable"]), ("Data.Morpheus.Kind", ["TYPE"]), ("Data.Morpheus.Types", []),+ ("Data.Morpheus", []), ("Data.Text", ["Text"]), ("GHC.Generics", ["Generic"]), ("Data.Map", ["fromList", "empty"])@@ -78,9 +79,9 @@ <> "module" <+> pretty moduleName <+> "where"- <> line- <> line- <> vsep (map renderImport imports)- <> line- <> line- <> either (error . show) id (renderTypes types)+ <> line+ <> line+ <> vsep (map renderImport imports)+ <> line+ <> line+ <> either (error . show) id (renderTypes types)
src/Data/Morpheus/CodeGen/Printing/Terms.hs view
@@ -22,7 +22,7 @@ unpackName, ) import qualified Data.Text as T-import Data.Text.Prettyprint.Doc+import Prettyprinter ( Doc, hsep, list,@@ -73,5 +73,6 @@ renderImport :: (Text, [Text]) -> Doc ann renderImport (src, ls) =- "import" <+> pretty src- <> optional (tupled . map pretty) ls+ "import"+ <+> pretty src+ <> optional (tupled . map pretty) ls
src/Data/Morpheus/CodeGen/Printing/Type.hs view
@@ -31,7 +31,7 @@ renderType, renderWrapped, )-import Data.Text.Prettyprint.Doc+import Prettyprinter ( Doc, comma, enclose,@@ -74,14 +74,29 @@ pure $ "data" <+> parametrizedType tName typeParameters- <> cons- <> line- <> indent 2 derivations- <> line+ <> cons+ <> line+ <> indent 2 derivations+ <> line renderConstructors [cons] = (" =" <+>) <$> render cons renderConstructors conses = nest 2 . (line <>) . vsep . prefixVariants <$> traverse render conses prefixVariants (x : xs) = "=" <+> x : map ("|" <+>) xs prefixVariants [] = []+ render typeDef@DirectiveTypeDefinition {directiveConstructor, directiveDerives} = do+ typeRendering <- renderTypeDef+ pure $ label name <> vsep [typeRendering, renderGQLType typeDef]+ where+ renderTypeDef = do+ cons <- (" =" <+>) <$> render directiveConstructor+ derivations <- renderDeriving directiveDerives+ pure $+ "data"+ <+> parametrizedType name []+ <> cons+ <> line+ <> indent 2 derivations+ <> line+ name = unpackName (constructorName directiveConstructor) renderDeriving :: [DerivingClass] -> Result (Doc n) renderDeriving list = ("deriving" <+>) . tupled <$> traverse render list