Compare commits
4 Commits
v1.1.0.0
...
bb4375313e
Author | SHA1 | Date | |
---|---|---|---|
bb4375313e
|
|||
70dedb6911
|
|||
a96d4e6ef3
|
|||
3ce6e7da46
|
@ -6,6 +6,11 @@ The format is based on
|
||||
and this project adheres to
|
||||
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Partial schema printing: schema definition encoder.
|
||||
- `Semigroup` and `Monoid` instances for `AST.Document.Description`.
|
||||
|
||||
## [1.1.0.0] - 2022-12-24
|
||||
### Changed
|
||||
- Removed deprecated `Language.GraphQL.Error` functions: `addErr`, `addErrMsg`,
|
||||
@ -490,6 +495,7 @@ and this project adheres to
|
||||
### Added
|
||||
- Data types for the GraphQL language.
|
||||
|
||||
[Unreleased]: https://www.caraus.tech/projects/pub-graphql/repository/23/diff?rev=master&rev_to=v1.1.0.0
|
||||
[1.1.0.0]: https://www.caraus.tech/projects/pub-graphql/repository/23/diff?rev=v1.1.0.0&rev_to=v1.0.3.0
|
||||
[1.0.3.0]: https://www.caraus.tech/projects/pub-graphql/repository/23/diff?rev=v1.0.3.0&rev_to=v1.0.2.0
|
||||
[1.0.2.0]: https://www.caraus.tech/projects/pub-graphql/repository/23/diff?rev=v1.0.2.0&rev_to=v1.0.1.0
|
||||
|
@ -464,6 +464,14 @@ data SchemaExtension
|
||||
newtype Description = Description (Maybe Text)
|
||||
deriving (Eq, Show)
|
||||
|
||||
instance Semigroup Description
|
||||
where
|
||||
Description lhs <> Description rhs = Description $ lhs <> rhs
|
||||
|
||||
instance Monoid Description
|
||||
where
|
||||
mempty = Description mempty
|
||||
|
||||
-- ** Types
|
||||
|
||||
-- | Type definitions describe various user-defined types.
|
||||
|
@ -14,10 +14,11 @@ module Language.GraphQL.AST.Encoder
|
||||
, operationType
|
||||
, pretty
|
||||
, type'
|
||||
, typeSystemDefinition
|
||||
, value
|
||||
) where
|
||||
|
||||
import Data.Foldable (fold)
|
||||
import Data.Foldable (fold, Foldable (..))
|
||||
import qualified Data.List.NonEmpty as NonEmpty
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
@ -54,7 +55,95 @@ document formatter defs
|
||||
encodeDocument = foldr executableDefinition [] defs
|
||||
executableDefinition (Full.ExecutableDefinition executableDefinition') acc =
|
||||
definition formatter executableDefinition' : acc
|
||||
executableDefinition _ acc = acc
|
||||
executableDefinition (Full.TypeSystemDefinition typeSystemDefinition' _location) acc =
|
||||
typeSystemDefinition formatter typeSystemDefinition' : acc
|
||||
executableDefinition _ acc = acc -- TODO: TypeSystemExtension missing.
|
||||
|
||||
withLineBreak :: Formatter -> Lazy.Text.Text -> Lazy.Text.Text
|
||||
withLineBreak formatter encodeDefinition
|
||||
| Pretty _ <- formatter = Lazy.Text.snoc encodeDefinition '\n'
|
||||
| Minified <- formatter = encodeDefinition
|
||||
|
||||
-- | Converts a t'Full.TypeSystemDefinition' into a string.
|
||||
typeSystemDefinition :: Formatter -> Full.TypeSystemDefinition -> Lazy.Text
|
||||
typeSystemDefinition formatter = \case
|
||||
Full.SchemaDefinition operationDirectives operationTypeDefinitions' ->
|
||||
withLineBreak formatter
|
||||
$ optempty (directives formatter) operationDirectives
|
||||
<> "schema "
|
||||
<> bracesList formatter operationTypeDefinition (NonEmpty.toList operationTypeDefinitions')
|
||||
Full.TypeDefinition typeDefinition' -> typeDefinition formatter typeDefinition'
|
||||
_ -> "" -- TODO: DerictiveDefinition missing.
|
||||
where
|
||||
operationTypeDefinition (Full.OperationTypeDefinition operationType' namedType')
|
||||
= indentLine (incrementIndent formatter)
|
||||
<> operationType formatter operationType'
|
||||
<> colon formatter
|
||||
<> Lazy.Text.fromStrict namedType'
|
||||
|
||||
fieldDefinition :: Formatter -> Full.FieldDefinition -> Lazy.Text.Text
|
||||
fieldDefinition formatter fieldDefinition' =
|
||||
let Full.FieldDefinition description' name' arguments' type'' directives' = fieldDefinition'
|
||||
in optempty (description formatter) description'
|
||||
<> indentLine formatter
|
||||
<> Lazy.Text.fromStrict name'
|
||||
<> argumentsDefinition formatter arguments'
|
||||
<> colon formatter
|
||||
<> type' type''
|
||||
<> optempty (directives formatter) directives'
|
||||
|
||||
argumentsDefinition :: Formatter -> Full.ArgumentsDefinition -> Lazy.Text.Text
|
||||
argumentsDefinition formatter (Full.ArgumentsDefinition arguments') =
|
||||
parensCommas formatter (argumentDefinition formatter) arguments'
|
||||
|
||||
argumentDefinition :: Formatter -> Full.InputValueDefinition -> Lazy.Text.Text
|
||||
argumentDefinition formatter definition' =
|
||||
let Full.InputValueDefinition description' name' type'' defaultValue' directives' = definition'
|
||||
in optempty (description formatter) description'
|
||||
<> Lazy.Text.fromStrict name'
|
||||
<> colon formatter
|
||||
<> type' type''
|
||||
<> maybe mempty (defaultValue formatter . Full.node) defaultValue'
|
||||
<> directives formatter directives'
|
||||
|
||||
typeDefinition :: Formatter -> Full.TypeDefinition -> Lazy.Text
|
||||
typeDefinition formatter = \case
|
||||
Full.ScalarTypeDefinition description' name' directives'
|
||||
-> optempty (description formatter) description'
|
||||
<> "scalar "
|
||||
<> Lazy.Text.fromStrict name'
|
||||
<> optempty (directives formatter) directives'
|
||||
Full.ObjectTypeDefinition description' name' ifaces' directives' fields'
|
||||
-> optempty (description formatter) description'
|
||||
<> "type "
|
||||
<> Lazy.Text.fromStrict name'
|
||||
<> optempty (" " <>) (implementsInterfaces ifaces')
|
||||
<> optempty (directives formatter) directives'
|
||||
<> eitherFormat formatter " " ""
|
||||
<> bracesList formatter (fieldDefinition nextFormatter) fields'
|
||||
Full.InterfaceTypeDefinition description' name' directives' fields'
|
||||
-> optempty (description formatter) description'
|
||||
<> "interface "
|
||||
<> Lazy.Text.fromStrict name'
|
||||
<> optempty (directives formatter) directives'
|
||||
<> eitherFormat formatter " " ""
|
||||
<> bracesList formatter (fieldDefinition nextFormatter) fields'
|
||||
_typeDefinition' -> "" -- TODO: Types missing.
|
||||
where
|
||||
nextFormatter = incrementIndent formatter
|
||||
|
||||
implementsInterfaces :: Foldable t => Full.ImplementsInterfaces t -> Lazy.Text
|
||||
implementsInterfaces (Full.ImplementsInterfaces interfaces)
|
||||
| null interfaces = mempty
|
||||
| otherwise = Lazy.Text.fromStrict
|
||||
$ Text.append "implements"
|
||||
$ Text.intercalate " & "
|
||||
$ toList interfaces
|
||||
|
||||
description :: Formatter -> Full.Description -> Lazy.Text.Text
|
||||
description _formatter (Full.Description Nothing) = ""
|
||||
description formatter (Full.Description (Just description')) =
|
||||
stringValue formatter description'
|
||||
|
||||
-- | Converts a t'Full.ExecutableDefinition' into a string.
|
||||
definition :: Formatter -> Full.ExecutableDefinition -> Lazy.Text
|
||||
@ -100,7 +189,7 @@ variableDefinition formatter variableDefinition' =
|
||||
let Full.VariableDefinition variableName variableType defaultValue' _ =
|
||||
variableDefinition'
|
||||
in variable variableName
|
||||
<> eitherFormat formatter ": " ":"
|
||||
<> colon formatter
|
||||
<> type' variableType
|
||||
<> maybe mempty (defaultValue formatter . Full.node) defaultValue'
|
||||
|
||||
@ -127,20 +216,26 @@ indent :: (Integral a) => a -> Lazy.Text
|
||||
indent indentation = Lazy.Text.replicate (fromIntegral indentation) indentSymbol
|
||||
|
||||
selection :: Formatter -> Full.Selection -> Lazy.Text
|
||||
selection formatter = Lazy.Text.append indent' . encodeSelection
|
||||
selection formatter = Lazy.Text.append (indentLine formatter')
|
||||
. encodeSelection
|
||||
where
|
||||
encodeSelection (Full.FieldSelection fieldSelection) =
|
||||
field incrementIndent fieldSelection
|
||||
field formatter' fieldSelection
|
||||
encodeSelection (Full.InlineFragmentSelection fragmentSelection) =
|
||||
inlineFragment incrementIndent fragmentSelection
|
||||
inlineFragment formatter' fragmentSelection
|
||||
encodeSelection (Full.FragmentSpreadSelection fragmentSelection) =
|
||||
fragmentSpread incrementIndent fragmentSelection
|
||||
incrementIndent
|
||||
fragmentSpread formatter' fragmentSelection
|
||||
formatter' = incrementIndent formatter
|
||||
|
||||
indentLine :: Formatter -> Lazy.Text
|
||||
indentLine formatter
|
||||
| Pretty indentation <- formatter = indent indentation
|
||||
| otherwise = ""
|
||||
|
||||
incrementIndent :: Formatter -> Formatter
|
||||
incrementIndent formatter
|
||||
| Pretty indentation <- formatter = Pretty $ indentation + 1
|
||||
| otherwise = Minified
|
||||
indent'
|
||||
| Pretty indentation <- formatter = indent $ indentation + 1
|
||||
| otherwise = ""
|
||||
|
||||
colon :: Formatter -> Lazy.Text
|
||||
colon formatter = eitherFormat formatter ": " ":"
|
||||
@ -198,8 +293,10 @@ directive formatter (Full.Directive name args _)
|
||||
= "@" <> Lazy.Text.fromStrict name <> optempty (arguments formatter) args
|
||||
|
||||
directives :: Formatter -> [Full.Directive] -> Lazy.Text
|
||||
directives Minified = spaces (directive Minified)
|
||||
directives formatter = Lazy.Text.cons ' ' . spaces (directive formatter)
|
||||
directives Minified values = spaces (directive Minified) values
|
||||
directives formatter values
|
||||
| null values = ""
|
||||
| otherwise = Lazy.Text.cons ' ' $ spaces (directive formatter) values
|
||||
|
||||
-- | Converts a 'Full.Value' into a string.
|
||||
value :: Formatter -> Full.Value -> Lazy.Text
|
||||
|
@ -18,3 +18,9 @@ spec = do
|
||||
]
|
||||
expected = "{ field1: 1.2, field2: null }"
|
||||
in show object `shouldBe` expected
|
||||
|
||||
describe "Description" $
|
||||
it "keeps content when merging with no description" $
|
||||
let expected = Description $ Just "Left description"
|
||||
actual = expected <> Description Nothing
|
||||
in actual `shouldBe` expected
|
||||
|
@ -4,6 +4,7 @@ module Language.GraphQL.AST.EncoderSpec
|
||||
( spec
|
||||
) where
|
||||
|
||||
import Data.List.NonEmpty (NonEmpty(..))
|
||||
import qualified Language.GraphQL.AST.Document as Full
|
||||
import Language.GraphQL.AST.Encoder
|
||||
import Language.GraphQL.TH
|
||||
@ -178,3 +179,41 @@ spec = do
|
||||
it "produces lowercase mutation operation type" $
|
||||
let actual = operationType pretty Full.Mutation
|
||||
in actual `shouldBe` "mutation"
|
||||
|
||||
describe "typeSystemDefinition" $ do
|
||||
it "produces a schema with an indented operation type definition" $
|
||||
let queryType = Full.OperationTypeDefinition Full.Query "QueryRootType"
|
||||
mutationType = Full.OperationTypeDefinition Full.Mutation "MutationType"
|
||||
operations = queryType :| pure mutationType
|
||||
definition' = Full.SchemaDefinition [] operations
|
||||
expected = Text.Lazy.snoc [gql|
|
||||
schema {
|
||||
query: QueryRootType
|
||||
mutation: MutationType
|
||||
}
|
||||
|] '\n'
|
||||
actual = typeSystemDefinition pretty definition'
|
||||
in actual `shouldBe` expected
|
||||
|
||||
it "encodes a scalar type definition" $
|
||||
let uuidType = Full.ScalarTypeDefinition mempty "UUID" mempty
|
||||
definition' = Full.TypeDefinition uuidType
|
||||
expected = "scalar UUID"
|
||||
actual = typeSystemDefinition pretty definition'
|
||||
in actual `shouldBe` expected
|
||||
|
||||
it "encodes an interface definition" $
|
||||
let someType = Full.TypeNamed "String"
|
||||
argument = Full.InputValueDefinition mempty "arg" someType Nothing mempty
|
||||
arguments = Full.ArgumentsDefinition [argument]
|
||||
definition' = Full.TypeDefinition
|
||||
$ Full.InterfaceTypeDefinition mempty "UUID" mempty
|
||||
$ pure
|
||||
$ Full.FieldDefinition mempty "value" arguments someType mempty
|
||||
expected = [gql|
|
||||
interface UUID {
|
||||
value(arg: String): String
|
||||
}
|
||||
|]
|
||||
actual = typeSystemDefinition pretty definition'
|
||||
in actual `shouldBe` expected
|
||||
|
Reference in New Issue
Block a user