blob: a8ce156f229aac263e00f217e27bfbe62dd1eb1b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
{-# LANGUAGE OverloadedStrings #-}
module Data.GraphQL.Printer where
import Prelude hiding (unwords)
import Data.Monoid ((<>))
import Data.Text (Text, intercalate, pack, unwords)
import Data.GraphQL.AST
-- Uniplate could avoid boilerplate, but is it worth bringing the
-- extra dependency?
-- * Document
document :: Document -> Text
document (Document defs) = intercalate "\n\n" $ definition <$> defs
definition :: Definition -> Text
definition (DefinitionOperation x) = operationDefinition x
definition (DefinitionFragment x) = fragmentDefinition x
definition (DefinitionType x) = typeDefinition x
operationDefinition :: OperationDefinition -> Text
operationDefinition (Query n) = "query " <> node n
operationDefinition (Mutation n) = "mutation " <> node n
node :: Node -> Text
node (Node name vds ds ss) =
name
<> optempty variableDefinitions vds
<> optempty (("\SP" <>) . directives) ds
<> "\SP"
<> selectionSet ss
variableDefinitions :: [VariableDefinition] -> Text
variableDefinitions = parens . intercalate ", " . fmap variableDefinition
variableDefinition :: VariableDefinition -> Text
variableDefinition (VariableDefinition var ty dv) =
variable var <> ": " <> type_ ty <> maybe mempty defaultValue dv
defaultValue :: DefaultValue -> Text
defaultValue val = "= " <> value val
variable :: Variable -> Text
variable (Variable name) = "$" <> name
selectionSet :: SelectionSet -> Text
selectionSet = block . fmap selection
selection :: Selection -> Text
selection (SelectionField x) = field x
selection (SelectionInlineFragment x) = inlineFragment x
selection (SelectionFragmentSpread x) = fragmentSpread x
field :: Field -> Text
field (Field alias name args ds ss) =
optempty (<> ": ") alias
<> name
<> optempty arguments args
<> optempty (("\SP" <>) . directives) ds
<> optempty (("\SP" <>) . selectionSet) ss
arguments :: [Argument] -> Text
arguments = parens . intercalate ", " . fmap argument
argument :: Argument -> Text
argument (Argument name v) = name <> ": " <> value v
-- * Fragments
fragmentSpread :: FragmentSpread -> Text
fragmentSpread (FragmentSpread name ds) =
"..." <> name <> optempty (spaces . directives) ds
inlineFragment :: InlineFragment -> Text
inlineFragment (InlineFragment (NamedType tc) ds ss) =
"... on" <> tc
<> optempty (("\SP" <>) . directives) ds
<> optempty (("\SP" <>) . selectionSet) ss
fragmentDefinition :: FragmentDefinition -> Text
fragmentDefinition (FragmentDefinition name (NamedType tc) ds ss) =
"fragment " <> name <> " on " <> tc
<> optempty (("\SP" <>) . directives) ds
<> (("\SP" <>) . selectionSet) ss
-- * Values
value :: Value -> Text
value (ValueVariable x) = variable x
-- TODO: This will be replaced with `decimal` Buidler
value (ValueInt x) = pack $ show x
-- TODO: This will be replaced with `decimal` Buidler
value (ValueFloat x) = pack $ show x
value (ValueBoolean x) = booleanValue x
value (ValueString x) = stringValue x
value (ValueEnum x) = x
value (ValueList x) = listValue x
value (ValueObject x) = objectValue x
booleanValue :: Bool -> Text
booleanValue True = "true"
booleanValue False = "false"
-- TODO: Escape characters
stringValue :: StringValue -> Text
stringValue (StringValue x) = x
listValue :: ListValue -> Text
listValue (ListValue vs) = brackets . intercalate ", " $ value <$> vs
objectValue :: ObjectValue -> Text
objectValue (ObjectValue ofs) = block $ objectField <$> ofs
objectField :: ObjectField -> Text
objectField (ObjectField name v) = name <> ": " <> value v
-- * Directives
directives :: [Directive] -> Text
directives = withSpaces directive
directive :: Directive -> Text
directive (Directive name args) = "@" <> name <> optempty arguments args
-- * Type Reference
type_ :: Type -> Text
type_ (TypeNamed (NamedType x)) = x
type_ (TypeList x) = listType x
type_ (TypeNonNull x) = nonNullType x
namedType :: NamedType -> Text
namedType (NamedType name) = name
listType :: ListType -> Text
listType (ListType ty) = "[" <> type_ ty <> "]"
nonNullType :: NonNullType -> Text
nonNullType (NonNullTypeNamed (NamedType x)) = x <> "!"
nonNullType (NonNullTypeList x) = listType x <> "!"
typeDefinition :: TypeDefinition -> Text
typeDefinition (TypeDefinitionObject x) = objectTypeDefinition x
typeDefinition (TypeDefinitionInterface x) = interfaceTypeDefinition x
typeDefinition (TypeDefinitionUnion x) = unionTypeDefinition x
typeDefinition (TypeDefinitionScalar x) = scalarTypeDefinition x
typeDefinition (TypeDefinitionEnum x) = enumTypeDefinition x
typeDefinition (TypeDefinitionInputObject x) = inputObjectTypeDefinition x
typeDefinition (TypeDefinitionTypeExtension x) = typeExtensionDefinition x
objectTypeDefinition :: ObjectTypeDefinition -> Text
objectTypeDefinition (ObjectTypeDefinition name ifaces fds) =
"type " <> name
<> optempty (("\SP" <>) . interfaces) ifaces
<> optempty (("\SP" <>) . fieldDefinitions) fds
interfaces :: Interfaces -> Text
interfaces = ("implements " <>) . unwords . fmap namedType
fieldDefinitions :: [FieldDefinition] -> Text
fieldDefinitions = block . fmap fieldDefinition
fieldDefinition :: FieldDefinition -> Text
fieldDefinition (FieldDefinition name args ty) =
name <> optempty argumentsDefinition args
<> ": "
<> type_ ty
argumentsDefinition :: ArgumentsDefinition -> Text
argumentsDefinition = parens . intercalate ", " . fmap inputValueDefinition
inputValueDefinitions :: [InputValueDefinition] -> Text
inputValueDefinitions = block . fmap inputValueDefinition
inputValueDefinition :: InputValueDefinition -> Text
inputValueDefinition (InputValueDefinition name ty dv) =
name <> ": " <> type_ ty <> maybe mempty (("\SP" <>) . defaultValue) dv
interfaceTypeDefinition :: InterfaceTypeDefinition -> Text
interfaceTypeDefinition (InterfaceTypeDefinition name fds) =
"interface " <> name <> "\SP" <> fieldDefinitions fds
unionTypeDefinition :: UnionTypeDefinition -> Text
unionTypeDefinition (UnionTypeDefinition name ums) =
"union " <> name <> " = " <> unionMembers ums
unionMembers :: [NamedType] -> Text
unionMembers = intercalate " | " . fmap namedType
scalarTypeDefinition :: ScalarTypeDefinition -> Text
scalarTypeDefinition (ScalarTypeDefinition name) = "scalar " <> name
enumTypeDefinition :: EnumTypeDefinition -> Text
enumTypeDefinition (EnumTypeDefinition name evds) =
"enum " <> name
<> block (enumValueDefinition <$> evds)
enumValueDefinition :: EnumValueDefinition -> Text
enumValueDefinition (EnumValueDefinition name) = name
inputObjectTypeDefinition :: InputObjectTypeDefinition -> Text
inputObjectTypeDefinition (InputObjectTypeDefinition name ivds) =
"input " <> name <> "\SP" <> inputValueDefinitions ivds
typeExtensionDefinition :: TypeExtensionDefinition -> Text
typeExtensionDefinition (TypeExtensionDefinition otd) =
"extend " <> objectTypeDefinition otd
-- * Internal
spaces :: Text -> Text
spaces txt = "\SP" <> txt <> "\SP"
parens :: Text -> Text
parens txt = "(" <> txt <> ")"
brackets :: Text -> Text
brackets txt = "[" <> txt <> "]"
withSpaces :: (a -> Text) -> [a] -> Text
withSpaces f = intercalate "\SP" . fmap f
withCommas :: (a -> Text) -> [a] -> Text
withCommas f = intercalate ", " . fmap f
optempty :: (Eq a, Monoid a, Monoid b) => (a -> b) -> a -> b
optempty f xs = if xs == mempty then mempty else f xs
block :: [Text] -> Text
block txts = "{\n" <> intercalate " \n" txts <> "\n}"
|