{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Morpheus.Parsing.Document.TypeSystem
( parseSchema
)
where
import Data.Text ( Text )
import Text.Megaparsec ( label
, sepBy1
, (<|>)
, eof
, manyTill
)
import Data.Morpheus.Parsing.Internal.Internal
( Parser
, processParser
)
import Data.Morpheus.Parsing.Internal.Pattern
( fieldsDefinition
, optionalDirectives
, typDeclaration
, enumValueDefinition
, inputFieldsDefinition
)
import Data.Morpheus.Parsing.Internal.Terms
( keyword
, operator
, optDescription
, parseName
, pipeLiteral
, sepByAnd
, collection
, spaceAndComments
)
import Data.Morpheus.Types.Internal.AST
( DataFingerprint(..)
, TypeContent(..)
, TypeDefinition(..)
, Name
, Description
, Meta(..)
, ScalarDefinition(..)
)
import Data.Morpheus.Types.Internal.Resolving
( Eventless )
scalarTypeDefinition :: Maybe Description -> Parser TypeDefinition
scalarTypeDefinition metaDescription = label "ScalarTypeDefinition" $ do
typeName <- typDeclaration "scalar"
metaDirectives <- optionalDirectives
pure TypeDefinition
{ typeName
, typeMeta = Just Meta { metaDescription, metaDirectives }
, typeFingerprint = DataFingerprint typeName []
, typeContent = DataScalar $ ScalarDefinition pure
}
objectTypeDefinition :: Maybe Description -> Parser TypeDefinition
objectTypeDefinition metaDescription = label "ObjectTypeDefinition" $ do
typeName <- typDeclaration "type"
objectImplements <- optionalImplementsInterfaces
metaDirectives <- optionalDirectives
objectFields <- fieldsDefinition
pure TypeDefinition
{ typeName
, typeMeta = Just Meta { metaDescription, metaDirectives }
, typeFingerprint = DataFingerprint typeName []
, typeContent = DataObject { objectImplements, objectFields }
}
optionalImplementsInterfaces :: Parser [Name]
optionalImplementsInterfaces = implements <|> pure []
where
implements =
label "ImplementsInterfaces" $ keyword "implements" *> sepByAnd parseName
interfaceTypeDefinition :: Maybe Description -> Parser TypeDefinition
interfaceTypeDefinition metaDescription = label "InterfaceTypeDefinition" $ do
typeName <- typDeclaration "interface"
metaDirectives <- optionalDirectives
fields <- fieldsDefinition
pure TypeDefinition
{ typeName
, typeMeta = Just Meta { metaDescription, metaDirectives }
, typeFingerprint = DataFingerprint typeName []
, typeContent = DataInterface fields
}
unionTypeDefinition :: Maybe Description -> Parser TypeDefinition
unionTypeDefinition metaDescription = label "UnionTypeDefinition" $ do
typeName <- typDeclaration "union"
metaDirectives <- optionalDirectives
memberTypes <- unionMemberTypes
pure TypeDefinition
{ typeName
, typeMeta = Just Meta { metaDescription, metaDirectives }
, typeFingerprint = DataFingerprint typeName []
, typeContent = DataUnion memberTypes
}
where unionMemberTypes = operator '=' *> parseName `sepBy1` pipeLiteral
enumTypeDefinition :: Maybe Description -> Parser TypeDefinition
enumTypeDefinition metaDescription = label "EnumTypeDefinition" $ do
typeName <- typDeclaration "enum"
metaDirectives <- optionalDirectives
enumValuesDefinitions <- collection enumValueDefinition
pure TypeDefinition
{ typeName
, typeContent = DataEnum enumValuesDefinitions
, typeFingerprint = DataFingerprint typeName []
, typeMeta = Just Meta { metaDescription, metaDirectives }
}
inputObjectTypeDefinition :: Maybe Description -> Parser TypeDefinition
inputObjectTypeDefinition metaDescription =
label "InputObjectTypeDefinition" $ do
typeName <- typDeclaration "input"
metaDirectives <- optionalDirectives
fields <- inputFieldsDefinition
pure TypeDefinition
{ typeName
, typeContent = DataInputObject fields
, typeFingerprint = DataFingerprint typeName []
, typeMeta = Just Meta { metaDescription, metaDirectives }
}
parseDataType :: Parser TypeDefinition
parseDataType = label "TypeDefinition" $ do
description <- optDescription
inputObjectTypeDefinition description
<|> unionTypeDefinition description
<|> enumTypeDefinition description
<|> scalarTypeDefinition description
<|> objectTypeDefinition description
<|> interfaceTypeDefinition description
parseSchema :: Text -> Eventless [TypeDefinition]
parseSchema = processParser request
where
request = label "DocumentTypes" $ do
spaceAndComments
manyTill parseDataType eof