...
1 package formatter
2
3 import (
4 "fmt"
5 "io"
6 "sort"
7 "strings"
8
9 "github.com/vektah/gqlparser/ast"
10 )
11
12 type Formatter interface {
13 FormatSchema(schema *ast.Schema)
14 FormatSchemaDocument(doc *ast.SchemaDocument)
15 FormatQueryDocument(doc *ast.QueryDocument)
16 }
17
18 func NewFormatter(w io.Writer) Formatter {
19 return &formatter{writer: w}
20 }
21
22 type formatter struct {
23 writer io.Writer
24
25 indent int
26 emitBuiltin bool
27
28 padNext bool
29 lineHead bool
30 }
31
32 func (f *formatter) writeString(s string) {
33 _, _ = f.writer.Write([]byte(s))
34 }
35
36 func (f *formatter) writeIndent() *formatter {
37 if f.lineHead {
38 f.writeString(strings.Repeat("\t", f.indent))
39 }
40 f.lineHead = false
41 f.padNext = false
42
43 return f
44 }
45
46 func (f *formatter) WriteNewline() *formatter {
47 f.writeString("\n")
48 f.lineHead = true
49 f.padNext = false
50
51 return f
52 }
53
54 func (f *formatter) WriteWord(word string) *formatter {
55 if f.lineHead {
56 f.writeIndent()
57 }
58 if f.padNext {
59 f.writeString(" ")
60 }
61 f.writeString(strings.TrimSpace(word))
62 f.padNext = true
63
64 return f
65 }
66
67 func (f *formatter) WriteString(s string) *formatter {
68 if f.lineHead {
69 f.writeIndent()
70 }
71 if f.padNext {
72 f.writeString(" ")
73 }
74 f.writeString(s)
75 f.padNext = false
76
77 return f
78 }
79
80 func (f *formatter) WriteDescription(s string) *formatter {
81 if s == "" {
82 return f
83 }
84
85 f.WriteString(`"""`).WriteNewline()
86
87 ss := strings.Split(s, "\n")
88 for _, s := range ss {
89 f.WriteString(s).WriteNewline()
90 }
91
92 f.WriteString(`"""`).WriteNewline()
93
94 return f
95 }
96
97 func (f *formatter) IncrementIndent() {
98 f.indent++
99 }
100
101 func (f *formatter) DecrementIndent() {
102 f.indent--
103 }
104
105 func (f *formatter) NoPadding() *formatter {
106 f.padNext = false
107
108 return f
109 }
110
111 func (f *formatter) NeedPadding() *formatter {
112 f.padNext = true
113
114 return f
115 }
116
117 func (f *formatter) FormatSchema(schema *ast.Schema) {
118 if schema == nil {
119 return
120 }
121
122 var inSchema bool
123 startSchema := func() {
124 if !inSchema {
125 inSchema = true
126
127 f.WriteWord("schema").WriteString("{").WriteNewline()
128 f.IncrementIndent()
129 }
130 }
131 if schema.Query != nil && schema.Query.Name != "Query" {
132 startSchema()
133 f.WriteWord("query").NoPadding().WriteString(":").NeedPadding()
134 f.WriteWord(schema.Query.Name).WriteNewline()
135 }
136 if schema.Mutation != nil && schema.Mutation.Name != "Mutation" {
137 startSchema()
138 f.WriteWord("mutation").NoPadding().WriteString(":").NeedPadding()
139 f.WriteWord(schema.Mutation.Name).WriteNewline()
140 }
141 if schema.Subscription != nil && schema.Subscription.Name != "Subscription" {
142 startSchema()
143 f.WriteWord("subscription").NoPadding().WriteString(":").NeedPadding()
144 f.WriteWord(schema.Subscription.Name).WriteNewline()
145 }
146 if inSchema {
147 f.DecrementIndent()
148 f.WriteString("}").WriteNewline()
149 }
150
151 directiveNames := make([]string, 0, len(schema.Directives))
152 for name := range schema.Directives {
153 directiveNames = append(directiveNames, name)
154 }
155 sort.Strings(directiveNames)
156 for _, name := range directiveNames {
157 f.FormatDirectiveDefinition(schema.Directives[name])
158 }
159
160 typeNames := make([]string, 0, len(schema.Types))
161 for name := range schema.Types {
162 typeNames = append(typeNames, name)
163 }
164 sort.Strings(typeNames)
165 for _, name := range typeNames {
166 f.FormatDefinition(schema.Types[name], false)
167 }
168 }
169
170 func (f *formatter) FormatSchemaDocument(doc *ast.SchemaDocument) {
171
172
173 if doc == nil {
174 return
175 }
176
177 f.FormatSchemaDefinitionList(doc.Schema, false)
178 f.FormatSchemaDefinitionList(doc.SchemaExtension, true)
179
180 f.FormatDirectiveDefinitionList(doc.Directives)
181
182 f.FormatDefinitionList(doc.Definitions, false)
183 f.FormatDefinitionList(doc.Extensions, true)
184 }
185
186 func (f *formatter) FormatQueryDocument(doc *ast.QueryDocument) {
187
188
189 if doc == nil {
190 return
191 }
192
193 f.FormatOperationList(doc.Operations)
194 f.FormatFragmentDefinitionList(doc.Fragments)
195 }
196
197 func (f *formatter) FormatSchemaDefinitionList(lists ast.SchemaDefinitionList, extension bool) {
198 if len(lists) == 0 {
199 return
200 }
201
202 if extension {
203 f.WriteWord("extend")
204 }
205 f.WriteWord("schema").WriteString("{").WriteNewline()
206 f.IncrementIndent()
207
208 for _, def := range lists {
209 f.FormatSchemaDefinition(def)
210 }
211
212 f.DecrementIndent()
213 f.WriteString("}").WriteNewline()
214 }
215
216 func (f *formatter) FormatSchemaDefinition(def *ast.SchemaDefinition) {
217 f.WriteDescription(def.Description)
218
219 f.FormatDirectiveList(def.Directives)
220
221 f.FormatOperationTypeDefinitionList(def.OperationTypes)
222 }
223
224 func (f *formatter) FormatOperationTypeDefinitionList(lists ast.OperationTypeDefinitionList) {
225 for _, def := range lists {
226 f.FormatOperationTypeDefinition(def)
227 }
228 }
229
230 func (f *formatter) FormatOperationTypeDefinition(def *ast.OperationTypeDefinition) {
231 f.WriteWord(string(def.Operation)).NoPadding().WriteString(":").NeedPadding()
232 f.WriteWord(def.Type)
233 f.WriteNewline()
234 }
235
236 func (f *formatter) FormatFieldList(fieldList ast.FieldList) {
237 if len(fieldList) == 0 {
238 return
239 }
240
241 f.WriteString("{").WriteNewline()
242 f.IncrementIndent()
243
244 for _, field := range fieldList {
245 f.FormatFieldDefinition(field)
246 }
247
248 f.DecrementIndent()
249 f.WriteString("}")
250 }
251
252 func (f *formatter) FormatFieldDefinition(field *ast.FieldDefinition) {
253 if !f.emitBuiltin && strings.HasPrefix(field.Name, "__") {
254 return
255 }
256
257 f.WriteDescription(field.Description)
258
259 f.WriteWord(field.Name).NoPadding()
260 f.FormatArgumentDefinitionList(field.Arguments)
261 f.NoPadding().WriteString(":").NeedPadding()
262 f.FormatType(field.Type)
263
264 if field.DefaultValue != nil {
265 f.WriteWord("=")
266 f.FormatValue(field.DefaultValue)
267 }
268
269 f.FormatDirectiveList(field.Directives)
270
271 f.WriteNewline()
272 }
273
274 func (f *formatter) FormatArgumentDefinitionList(lists ast.ArgumentDefinitionList) {
275 if len(lists) == 0 {
276 return
277 }
278
279 f.WriteString("(")
280 for idx, arg := range lists {
281 f.FormatArgumentDefinition(arg)
282
283 if idx != len(lists)-1 {
284 f.NoPadding().WriteWord(",")
285 }
286 }
287 f.NoPadding().WriteString(")").NeedPadding()
288 }
289
290 func (f *formatter) FormatArgumentDefinition(def *ast.ArgumentDefinition) {
291 f.WriteDescription(def.Description)
292
293 f.WriteWord(def.Name).NoPadding().WriteString(":").NeedPadding()
294 f.FormatType(def.Type)
295
296 if def.DefaultValue != nil {
297 f.WriteWord("=")
298 f.FormatValue(def.DefaultValue)
299 }
300 }
301
302 func (f *formatter) FormatDirectiveLocation(location ast.DirectiveLocation) {
303 f.WriteWord(string(location))
304 }
305
306 func (f *formatter) FormatDirectiveDefinitionList(lists ast.DirectiveDefinitionList) {
307 if len(lists) == 0 {
308 return
309 }
310
311 for _, dec := range lists {
312 f.FormatDirectiveDefinition(dec)
313 }
314 }
315
316 func (f *formatter) FormatDirectiveDefinition(def *ast.DirectiveDefinition) {
317 if !f.emitBuiltin {
318 if def.Position.Src.BuiltIn {
319 return
320 }
321 }
322
323 f.WriteDescription(def.Description)
324 f.WriteWord("directive").WriteString("@").WriteWord(def.Name)
325
326 if len(def.Arguments) != 0 {
327 f.NoPadding()
328 f.FormatArgumentDefinitionList(def.Arguments)
329 }
330
331 if len(def.Locations) != 0 {
332 f.WriteWord("on")
333
334 for idx, dirLoc := range def.Locations {
335 f.FormatDirectiveLocation(dirLoc)
336
337 if idx != len(def.Locations)-1 {
338 f.WriteWord("|")
339 }
340 }
341 }
342
343 f.WriteNewline()
344 }
345
346 func (f *formatter) FormatDefinitionList(lists ast.DefinitionList, extend bool) {
347 if len(lists) == 0 {
348 return
349 }
350
351 for _, dec := range lists {
352 f.FormatDefinition(dec, extend)
353 }
354 }
355
356 func (f *formatter) FormatDefinition(def *ast.Definition, extend bool) {
357 if !f.emitBuiltin && def.BuiltIn {
358 return
359 }
360
361 f.WriteDescription(def.Description)
362
363 if extend {
364 f.WriteWord("extend")
365 }
366
367 switch def.Kind {
368 case ast.Scalar:
369 f.WriteWord("scalar").WriteWord(def.Name)
370
371 case ast.Object:
372 f.WriteWord("type").WriteWord(def.Name)
373
374 case ast.Interface:
375 f.WriteWord("interface").WriteWord(def.Name)
376
377 case ast.Union:
378 f.WriteWord("union").WriteWord(def.Name)
379
380 case ast.Enum:
381 f.WriteWord("enum").WriteWord(def.Name)
382
383 case ast.InputObject:
384 f.WriteWord("input").WriteWord(def.Name)
385 }
386
387 if len(def.Interfaces) != 0 {
388 f.WriteWord("implements").WriteWord(strings.Join(def.Interfaces, " & "))
389 }
390
391 f.FormatDirectiveList(def.Directives)
392
393 if len(def.Types) != 0 {
394 f.WriteWord("=").WriteWord(strings.Join(def.Types, " | "))
395 }
396
397 f.FormatFieldList(def.Fields)
398
399 f.FormatEnumValueList(def.EnumValues)
400
401 f.WriteNewline()
402 }
403
404 func (f *formatter) FormatEnumValueList(lists ast.EnumValueList) {
405 if len(lists) == 0 {
406 return
407 }
408
409 f.WriteString("{").WriteNewline()
410 f.IncrementIndent()
411
412 for _, v := range lists {
413 f.FormatEnumValueDefinition(v)
414 }
415
416 f.DecrementIndent()
417 f.WriteString("}")
418 }
419
420 func (f *formatter) FormatEnumValueDefinition(def *ast.EnumValueDefinition) {
421 f.WriteDescription(def.Description)
422
423 f.WriteWord(def.Name)
424 f.FormatDirectiveList(def.Directives)
425
426 f.WriteNewline()
427 }
428
429 func (f *formatter) FormatOperationList(lists ast.OperationList) {
430 for _, def := range lists {
431 f.FormatOperationDefinition(def)
432 }
433 }
434
435 func (f *formatter) FormatOperationDefinition(def *ast.OperationDefinition) {
436 f.WriteWord(string(def.Operation))
437 if def.Name != "" {
438 f.WriteWord(def.Name)
439 }
440 f.FormatVariableDefinitionList(def.VariableDefinitions)
441 f.FormatDirectiveList(def.Directives)
442
443 if len(def.SelectionSet) != 0 {
444 f.FormatSelectionSet(def.SelectionSet)
445 f.WriteNewline()
446 }
447 }
448
449 func (f *formatter) FormatDirectiveList(lists ast.DirectiveList) {
450 if len(lists) == 0 {
451 return
452 }
453
454 for _, dir := range lists {
455 f.FormatDirective(dir)
456 }
457 }
458
459 func (f *formatter) FormatDirective(dir *ast.Directive) {
460 f.WriteString("@").WriteWord(dir.Name)
461 f.FormatArgumentList(dir.Arguments)
462 }
463
464 func (f *formatter) FormatArgumentList(lists ast.ArgumentList) {
465 if len(lists) == 0 {
466 return
467 }
468 f.NoPadding().WriteString("(")
469 for idx, arg := range lists {
470 f.FormatArgument(arg)
471
472 if idx != len(lists)-1 {
473 f.NoPadding().WriteWord(",")
474 }
475 }
476 f.WriteString(")").NeedPadding()
477 }
478
479 func (f *formatter) FormatArgument(arg *ast.Argument) {
480 f.WriteWord(arg.Name).NoPadding().WriteString(":").NeedPadding()
481 f.WriteString(arg.Value.String())
482 }
483
484 func (f *formatter) FormatFragmentDefinitionList(lists ast.FragmentDefinitionList) {
485 for _, def := range lists {
486 f.FormatFragmentDefinition(def)
487 }
488 }
489
490 func (f *formatter) FormatFragmentDefinition(def *ast.FragmentDefinition) {
491 f.WriteWord("fragment").WriteWord(def.Name)
492 f.FormatVariableDefinitionList(def.VariableDefinition)
493 f.WriteWord("on").WriteWord(def.TypeCondition)
494 f.FormatDirectiveList(def.Directives)
495
496 if len(def.SelectionSet) != 0 {
497 f.FormatSelectionSet(def.SelectionSet)
498 f.WriteNewline()
499 }
500 }
501
502 func (f *formatter) FormatVariableDefinitionList(lists ast.VariableDefinitionList) {
503 if len(lists) == 0 {
504 return
505 }
506
507 f.WriteString("(")
508 for idx, def := range lists {
509 f.FormatVariableDefinition(def)
510
511 if idx != len(lists)-1 {
512 f.NoPadding().WriteWord(",")
513 }
514 }
515 f.NoPadding().WriteString(")").NeedPadding()
516 }
517
518 func (f *formatter) FormatVariableDefinition(def *ast.VariableDefinition) {
519 f.WriteString("$").WriteWord(def.Variable).NoPadding().WriteString(":").NeedPadding()
520 f.FormatType(def.Type)
521
522 if def.DefaultValue != nil {
523 f.WriteWord("=")
524 f.FormatValue(def.DefaultValue)
525 }
526
527
528
529 }
530
531 func (f *formatter) FormatSelectionSet(sets ast.SelectionSet) {
532 if len(sets) == 0 {
533 return
534 }
535
536 f.WriteString("{").WriteNewline()
537 f.IncrementIndent()
538
539 for _, sel := range sets {
540 f.FormatSelection(sel)
541 }
542
543 f.DecrementIndent()
544 f.WriteString("}")
545 }
546
547 func (f *formatter) FormatSelection(selection ast.Selection) {
548 switch v := selection.(type) {
549 case *ast.Field:
550 f.FormatField(v)
551
552 case *ast.FragmentSpread:
553 f.FormatFragmentSpread(v)
554
555 case *ast.InlineFragment:
556 f.FormatInlineFragment(v)
557
558 default:
559 panic(fmt.Errorf("unknown Selection type: %T", selection))
560 }
561
562 f.WriteNewline()
563 }
564
565 func (f *formatter) FormatField(field *ast.Field) {
566 if field.Alias != "" && field.Alias != field.Name {
567 f.WriteWord(field.Alias).NoPadding().WriteString(":").NeedPadding()
568 }
569 f.WriteWord(field.Name)
570
571 if len(field.Arguments) != 0 {
572 f.NoPadding()
573 f.FormatArgumentList(field.Arguments)
574 f.NeedPadding()
575 }
576
577 f.FormatDirectiveList(field.Directives)
578
579 f.FormatSelectionSet(field.SelectionSet)
580 }
581
582 func (f *formatter) FormatFragmentSpread(spread *ast.FragmentSpread) {
583 f.WriteWord("...").WriteWord(spread.Name)
584
585 f.FormatDirectiveList(spread.Directives)
586 }
587
588 func (f *formatter) FormatInlineFragment(inline *ast.InlineFragment) {
589 f.WriteWord("...")
590 if inline.TypeCondition != "" {
591 f.WriteWord("on").WriteWord(inline.TypeCondition)
592 }
593
594 f.FormatDirectiveList(inline.Directives)
595
596 f.FormatSelectionSet(inline.SelectionSet)
597 }
598
599 func (f *formatter) FormatType(t *ast.Type) {
600 f.WriteWord(t.String())
601 }
602
603 func (f *formatter) FormatValue(value *ast.Value) {
604 f.WriteString(value.String())
605 }
606
View as plain text