printer.go

  1package printer
  2
  3import (
  4	"fmt"
  5	"strings"
  6
  7	"github.com/graphql-go/graphql/language/ast"
  8	"github.com/graphql-go/graphql/language/visitor"
  9	"reflect"
 10)
 11
 12func getMapValue(m map[string]interface{}, key string) interface{} {
 13	tokens := strings.Split(key, ".")
 14	valMap := m
 15	for _, token := range tokens {
 16		v, ok := valMap[token]
 17		if !ok {
 18			return nil
 19		}
 20		switch v := v.(type) {
 21		case []interface{}:
 22			return v
 23		case map[string]interface{}:
 24			valMap = v
 25			continue
 26		default:
 27			return v
 28		}
 29	}
 30	return valMap
 31}
 32func getMapSliceValue(m map[string]interface{}, key string) []interface{} {
 33	tokens := strings.Split(key, ".")
 34	valMap := m
 35	for _, token := range tokens {
 36		v, ok := valMap[token]
 37		if !ok {
 38			return []interface{}{}
 39		}
 40		switch v := v.(type) {
 41		case []interface{}:
 42			return v
 43		default:
 44			return []interface{}{}
 45		}
 46	}
 47	return []interface{}{}
 48}
 49func getMapValueString(m map[string]interface{}, key string) string {
 50	tokens := strings.Split(key, ".")
 51	valMap := m
 52	for _, token := range tokens {
 53		v, ok := valMap[token]
 54		if !ok {
 55			return ""
 56		}
 57		if v == nil {
 58			return ""
 59		}
 60		switch v := v.(type) {
 61		case map[string]interface{}:
 62			valMap = v
 63			continue
 64		case string:
 65			return v
 66		default:
 67			return fmt.Sprintf("%v", v)
 68		}
 69	}
 70	return ""
 71}
 72
 73func toSliceString(slice interface{}) []string {
 74	if slice == nil {
 75		return []string{}
 76	}
 77	res := []string{}
 78	switch reflect.TypeOf(slice).Kind() {
 79	case reflect.Slice:
 80		s := reflect.ValueOf(slice)
 81		for i := 0; i < s.Len(); i++ {
 82			elem := s.Index(i)
 83			elemInterface := elem.Interface()
 84			if elem, ok := elemInterface.(string); ok {
 85				res = append(res, elem)
 86			}
 87		}
 88		return res
 89	default:
 90		return res
 91	}
 92}
 93
 94func join(str []string, sep string) string {
 95	ss := []string{}
 96	// filter out empty strings
 97	for _, s := range str {
 98		if s == "" {
 99			continue
100		}
101		ss = append(ss, s)
102	}
103	return strings.Join(ss, sep)
104}
105
106func wrap(start, maybeString, end string) string {
107	if maybeString == "" {
108		return maybeString
109	}
110	return start + maybeString + end
111}
112
113// Given array, print each item on its own line, wrapped in an indented "{ }" block.
114func block(maybeArray interface{}) string {
115	s := toSliceString(maybeArray)
116	if len(s) == 0 {
117		return "{}"
118	}
119	return indent("{\n"+join(s, "\n")) + "\n}"
120}
121
122func indent(maybeString interface{}) string {
123	if maybeString == nil {
124		return ""
125	}
126	switch str := maybeString.(type) {
127	case string:
128		return strings.Replace(str, "\n", "\n  ", -1)
129	}
130	return ""
131}
132
133var printDocASTReducer = map[string]visitor.VisitFunc{
134	"Name": func(p visitor.VisitFuncParams) (string, interface{}) {
135		switch node := p.Node.(type) {
136		case *ast.Name:
137			return visitor.ActionUpdate, node.Value
138		case map[string]interface{}:
139			return visitor.ActionUpdate, getMapValue(node, "Value")
140		}
141		return visitor.ActionNoChange, nil
142	},
143	"Variable": func(p visitor.VisitFuncParams) (string, interface{}) {
144		switch node := p.Node.(type) {
145		case *ast.Variable:
146			return visitor.ActionUpdate, fmt.Sprintf("$%v", node.Name)
147		case map[string]interface{}:
148			return visitor.ActionUpdate, "$" + getMapValueString(node, "Name")
149		}
150		return visitor.ActionNoChange, nil
151	},
152
153	// Document
154	"Document": func(p visitor.VisitFuncParams) (string, interface{}) {
155		switch node := p.Node.(type) {
156		case *ast.Document:
157			definitions := toSliceString(node.Definitions)
158			return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
159		case map[string]interface{}:
160			definitions := toSliceString(getMapValue(node, "Definitions"))
161			return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
162		}
163		return visitor.ActionNoChange, nil
164	},
165	"OperationDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
166		switch node := p.Node.(type) {
167		case *ast.OperationDefinition:
168			op := string(node.Operation)
169			name := fmt.Sprintf("%v", node.Name)
170
171			varDefs := wrap("(", join(toSliceString(node.VariableDefinitions), ", "), ")")
172			directives := join(toSliceString(node.Directives), " ")
173			selectionSet := fmt.Sprintf("%v", node.SelectionSet)
174			// Anonymous queries with no directives or variable definitions can use
175			// the query short form.
176			str := ""
177			if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
178				str = selectionSet
179			} else {
180				str = join([]string{
181					op,
182					join([]string{name, varDefs}, ""),
183					directives,
184					selectionSet,
185				}, " ")
186			}
187			return visitor.ActionUpdate, str
188		case map[string]interface{}:
189
190			op := getMapValueString(node, "Operation")
191			name := getMapValueString(node, "Name")
192
193			varDefs := wrap("(", join(toSliceString(getMapValue(node, "VariableDefinitions")), ", "), ")")
194			directives := join(toSliceString(getMapValue(node, "Directives")), " ")
195			selectionSet := getMapValueString(node, "SelectionSet")
196			str := ""
197			if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
198				str = selectionSet
199			} else {
200				str = join([]string{
201					op,
202					join([]string{name, varDefs}, ""),
203					directives,
204					selectionSet,
205				}, " ")
206			}
207			return visitor.ActionUpdate, str
208		}
209		return visitor.ActionNoChange, nil
210	},
211	"VariableDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
212		switch node := p.Node.(type) {
213		case *ast.VariableDefinition:
214			variable := fmt.Sprintf("%v", node.Variable)
215			ttype := fmt.Sprintf("%v", node.Type)
216			defaultValue := fmt.Sprintf("%v", node.DefaultValue)
217
218			return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
219		case map[string]interface{}:
220
221			variable := getMapValueString(node, "Variable")
222			ttype := getMapValueString(node, "Type")
223			defaultValue := getMapValueString(node, "DefaultValue")
224
225			return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
226
227		}
228		return visitor.ActionNoChange, nil
229	},
230	"SelectionSet": func(p visitor.VisitFuncParams) (string, interface{}) {
231		switch node := p.Node.(type) {
232		case *ast.SelectionSet:
233			str := block(node.Selections)
234			return visitor.ActionUpdate, str
235		case map[string]interface{}:
236			selections := getMapValue(node, "Selections")
237			str := block(selections)
238			return visitor.ActionUpdate, str
239
240		}
241		return visitor.ActionNoChange, nil
242	},
243	"Field": func(p visitor.VisitFuncParams) (string, interface{}) {
244		switch node := p.Node.(type) {
245		case *ast.Argument:
246			name := fmt.Sprintf("%v", node.Name)
247			value := fmt.Sprintf("%v", node.Value)
248			return visitor.ActionUpdate, name + ": " + value
249		case map[string]interface{}:
250
251			alias := getMapValueString(node, "Alias")
252			name := getMapValueString(node, "Name")
253			args := toSliceString(getMapValue(node, "Arguments"))
254			directives := toSliceString(getMapValue(node, "Directives"))
255			selectionSet := getMapValueString(node, "SelectionSet")
256
257			str := join(
258				[]string{
259					wrap("", alias, ": ") + name + wrap("(", join(args, ", "), ")"),
260					join(directives, " "),
261					selectionSet,
262				},
263				" ",
264			)
265			return visitor.ActionUpdate, str
266		}
267		return visitor.ActionNoChange, nil
268	},
269	"Argument": func(p visitor.VisitFuncParams) (string, interface{}) {
270		switch node := p.Node.(type) {
271		case *ast.FragmentSpread:
272			name := fmt.Sprintf("%v", node.Name)
273			directives := toSliceString(node.Directives)
274			return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
275		case map[string]interface{}:
276			name := getMapValueString(node, "Name")
277			value := getMapValueString(node, "Value")
278			return visitor.ActionUpdate, name + ": " + value
279		}
280		return visitor.ActionNoChange, nil
281	},
282
283	// Fragments
284	"FragmentSpread": func(p visitor.VisitFuncParams) (string, interface{}) {
285		switch node := p.Node.(type) {
286		case *ast.InlineFragment:
287			typeCondition := fmt.Sprintf("%v", node.TypeCondition)
288			directives := toSliceString(node.Directives)
289			selectionSet := fmt.Sprintf("%v", node.SelectionSet)
290			return visitor.ActionUpdate, "... on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
291		case map[string]interface{}:
292			name := getMapValueString(node, "Name")
293			directives := toSliceString(getMapValue(node, "Directives"))
294			return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
295		}
296		return visitor.ActionNoChange, nil
297	},
298	"InlineFragment": func(p visitor.VisitFuncParams) (string, interface{}) {
299		switch node := p.Node.(type) {
300		case map[string]interface{}:
301			typeCondition := getMapValueString(node, "TypeCondition")
302			directives := toSliceString(getMapValue(node, "Directives"))
303			selectionSet := getMapValueString(node, "SelectionSet")
304			return visitor.ActionUpdate,
305				join([]string{
306					"...",
307					wrap("on ", typeCondition, ""),
308					join(directives, " "),
309					selectionSet,
310				}, " ")
311		}
312		return visitor.ActionNoChange, nil
313	},
314	"FragmentDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
315		switch node := p.Node.(type) {
316		case *ast.FragmentDefinition:
317			name := fmt.Sprintf("%v", node.Name)
318			typeCondition := fmt.Sprintf("%v", node.TypeCondition)
319			directives := toSliceString(node.Directives)
320			selectionSet := fmt.Sprintf("%v", node.SelectionSet)
321			return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
322		case map[string]interface{}:
323			name := getMapValueString(node, "Name")
324			typeCondition := getMapValueString(node, "TypeCondition")
325			directives := toSliceString(getMapValue(node, "Directives"))
326			selectionSet := getMapValueString(node, "SelectionSet")
327			return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
328		}
329		return visitor.ActionNoChange, nil
330	},
331
332	// Value
333	"IntValue": func(p visitor.VisitFuncParams) (string, interface{}) {
334		switch node := p.Node.(type) {
335		case *ast.IntValue:
336			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
337		case map[string]interface{}:
338			return visitor.ActionUpdate, getMapValueString(node, "Value")
339		}
340		return visitor.ActionNoChange, nil
341	},
342	"FloatValue": func(p visitor.VisitFuncParams) (string, interface{}) {
343		switch node := p.Node.(type) {
344		case *ast.FloatValue:
345			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
346		case map[string]interface{}:
347			return visitor.ActionUpdate, getMapValueString(node, "Value")
348		}
349		return visitor.ActionNoChange, nil
350	},
351	"StringValue": func(p visitor.VisitFuncParams) (string, interface{}) {
352		switch node := p.Node.(type) {
353		case *ast.StringValue:
354			return visitor.ActionUpdate, `"` + fmt.Sprintf("%v", node.Value) + `"`
355		case map[string]interface{}:
356			return visitor.ActionUpdate, `"` + getMapValueString(node, "Value") + `"`
357		}
358		return visitor.ActionNoChange, nil
359	},
360	"BooleanValue": func(p visitor.VisitFuncParams) (string, interface{}) {
361		switch node := p.Node.(type) {
362		case *ast.BooleanValue:
363			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
364		case map[string]interface{}:
365			return visitor.ActionUpdate, getMapValueString(node, "Value")
366		}
367		return visitor.ActionNoChange, nil
368	},
369	"EnumValue": func(p visitor.VisitFuncParams) (string, interface{}) {
370		switch node := p.Node.(type) {
371		case *ast.EnumValue:
372			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
373		case map[string]interface{}:
374			return visitor.ActionUpdate, getMapValueString(node, "Value")
375		}
376		return visitor.ActionNoChange, nil
377	},
378	"ListValue": func(p visitor.VisitFuncParams) (string, interface{}) {
379		switch node := p.Node.(type) {
380		case *ast.ListValue:
381			return visitor.ActionUpdate, "[" + join(toSliceString(node.Values), ", ") + "]"
382		case map[string]interface{}:
383			return visitor.ActionUpdate, "[" + join(toSliceString(getMapValue(node, "Values")), ", ") + "]"
384		}
385		return visitor.ActionNoChange, nil
386	},
387	"ObjectValue": func(p visitor.VisitFuncParams) (string, interface{}) {
388		switch node := p.Node.(type) {
389		case *ast.ObjectValue:
390			return visitor.ActionUpdate, "{" + join(toSliceString(node.Fields), ", ") + "}"
391		case map[string]interface{}:
392			return visitor.ActionUpdate, "{" + join(toSliceString(getMapValue(node, "Fields")), ", ") + "}"
393		}
394		return visitor.ActionNoChange, nil
395	},
396	"ObjectField": func(p visitor.VisitFuncParams) (string, interface{}) {
397		switch node := p.Node.(type) {
398		case *ast.ObjectField:
399			name := fmt.Sprintf("%v", node.Name)
400			value := fmt.Sprintf("%v", node.Value)
401			return visitor.ActionUpdate, name + ": " + value
402		case map[string]interface{}:
403			name := getMapValueString(node, "Name")
404			value := getMapValueString(node, "Value")
405			return visitor.ActionUpdate, name + ": " + value
406		}
407		return visitor.ActionNoChange, nil
408	},
409
410	// Directive
411	"Directive": func(p visitor.VisitFuncParams) (string, interface{}) {
412		switch node := p.Node.(type) {
413		case *ast.Directive:
414			name := fmt.Sprintf("%v", node.Name)
415			args := toSliceString(node.Arguments)
416			return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
417		case map[string]interface{}:
418			name := getMapValueString(node, "Name")
419			args := toSliceString(getMapValue(node, "Arguments"))
420			return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
421		}
422		return visitor.ActionNoChange, nil
423	},
424
425	// Type
426	"Named": func(p visitor.VisitFuncParams) (string, interface{}) {
427		switch node := p.Node.(type) {
428		case *ast.Named:
429			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Name)
430		case map[string]interface{}:
431			return visitor.ActionUpdate, getMapValueString(node, "Name")
432		}
433		return visitor.ActionNoChange, nil
434	},
435	"List": func(p visitor.VisitFuncParams) (string, interface{}) {
436		switch node := p.Node.(type) {
437		case *ast.List:
438			return visitor.ActionUpdate, "[" + fmt.Sprintf("%v", node.Type) + "]"
439		case map[string]interface{}:
440			return visitor.ActionUpdate, "[" + getMapValueString(node, "Type") + "]"
441		}
442		return visitor.ActionNoChange, nil
443	},
444	"NonNull": func(p visitor.VisitFuncParams) (string, interface{}) {
445		switch node := p.Node.(type) {
446		case *ast.NonNull:
447			return visitor.ActionUpdate, fmt.Sprintf("%v", node.Type) + "!"
448		case map[string]interface{}:
449			return visitor.ActionUpdate, getMapValueString(node, "Type") + "!"
450		}
451		return visitor.ActionNoChange, nil
452	},
453
454	// Type System Definitions
455	"SchemaDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
456		switch node := p.Node.(type) {
457		case *ast.SchemaDefinition:
458			directives := []string{}
459			for _, directive := range node.Directives {
460				directives = append(directives, fmt.Sprintf("%v", directive.Name))
461			}
462			str := join([]string{
463				"schema",
464				join(directives, " "),
465				block(node.OperationTypes),
466			}, " ")
467			return visitor.ActionUpdate, str
468		case map[string]interface{}:
469			operationTypes := toSliceString(getMapValue(node, "OperationTypes"))
470			directives := []string{}
471			for _, directive := range getMapSliceValue(node, "Directives") {
472				directives = append(directives, fmt.Sprintf("%v", directive))
473			}
474			str := join([]string{
475				"schema",
476				join(directives, " "),
477				block(operationTypes),
478			}, " ")
479			return visitor.ActionUpdate, str
480		}
481		return visitor.ActionNoChange, nil
482	},
483	"OperationTypeDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
484		switch node := p.Node.(type) {
485		case *ast.OperationTypeDefinition:
486			str := fmt.Sprintf("%v: %v", node.Operation, node.Type)
487			return visitor.ActionUpdate, str
488		case map[string]interface{}:
489			operation := getMapValueString(node, "Operation")
490			ttype := getMapValueString(node, "Type")
491			str := fmt.Sprintf("%v: %v", operation, ttype)
492			return visitor.ActionUpdate, str
493		}
494		return visitor.ActionNoChange, nil
495	},
496	"ScalarDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
497		switch node := p.Node.(type) {
498		case *ast.ScalarDefinition:
499			directives := []string{}
500			for _, directive := range node.Directives {
501				directives = append(directives, fmt.Sprintf("%v", directive.Name))
502			}
503			str := join([]string{
504				"scalar",
505				fmt.Sprintf("%v", node.Name),
506				join(directives, " "),
507			}, " ")
508			return visitor.ActionUpdate, str
509		case map[string]interface{}:
510			name := getMapValueString(node, "Name")
511			directives := []string{}
512			for _, directive := range getMapSliceValue(node, "Directives") {
513				directives = append(directives, fmt.Sprintf("%v", directive))
514			}
515			str := join([]string{
516				"scalar",
517				name,
518				join(directives, " "),
519			}, " ")
520			return visitor.ActionUpdate, str
521		}
522		return visitor.ActionNoChange, nil
523	},
524	"ObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
525		switch node := p.Node.(type) {
526		case *ast.ObjectDefinition:
527			name := fmt.Sprintf("%v", node.Name)
528			interfaces := toSliceString(node.Interfaces)
529			fields := node.Fields
530			directives := []string{}
531			for _, directive := range node.Directives {
532				directives = append(directives, fmt.Sprintf("%v", directive.Name))
533			}
534			str := join([]string{
535				"type",
536				name,
537				wrap("implements ", join(interfaces, ", "), ""),
538				join(directives, " "),
539				block(fields),
540			}, " ")
541			return visitor.ActionUpdate, str
542		case map[string]interface{}:
543			name := getMapValueString(node, "Name")
544			interfaces := toSliceString(getMapValue(node, "Interfaces"))
545			fields := getMapValue(node, "Fields")
546			directives := []string{}
547			for _, directive := range getMapSliceValue(node, "Directives") {
548				directives = append(directives, fmt.Sprintf("%v", directive))
549			}
550			str := join([]string{
551				"type",
552				name,
553				wrap("implements ", join(interfaces, ", "), ""),
554				join(directives, " "),
555				block(fields),
556			}, " ")
557			return visitor.ActionUpdate, str
558		}
559		return visitor.ActionNoChange, nil
560	},
561	"FieldDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
562		switch node := p.Node.(type) {
563		case *ast.FieldDefinition:
564			name := fmt.Sprintf("%v", node.Name)
565			ttype := fmt.Sprintf("%v", node.Type)
566			args := toSliceString(node.Arguments)
567			directives := []string{}
568			for _, directive := range node.Directives {
569				directives = append(directives, fmt.Sprintf("%v", directive.Name))
570			}
571			str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + wrap(" ", join(directives, " "), "")
572			return visitor.ActionUpdate, str
573		case map[string]interface{}:
574			name := getMapValueString(node, "Name")
575			ttype := getMapValueString(node, "Type")
576			args := toSliceString(getMapValue(node, "Arguments"))
577			directives := []string{}
578			for _, directive := range getMapSliceValue(node, "Directives") {
579				directives = append(directives, fmt.Sprintf("%v", directive))
580			}
581			str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + wrap(" ", join(directives, " "), "")
582			return visitor.ActionUpdate, str
583		}
584		return visitor.ActionNoChange, nil
585	},
586	"InputValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
587		switch node := p.Node.(type) {
588		case *ast.InputValueDefinition:
589			name := fmt.Sprintf("%v", node.Name)
590			ttype := fmt.Sprintf("%v", node.Type)
591			defaultValue := fmt.Sprintf("%v", node.DefaultValue)
592			directives := []string{}
593			for _, directive := range node.Directives {
594				directives = append(directives, fmt.Sprintf("%v", directive.Name))
595			}
596			str := join([]string{
597				name + ": " + ttype,
598				wrap("= ", defaultValue, ""),
599				join(directives, " "),
600			}, " ")
601
602			return visitor.ActionUpdate, str
603		case map[string]interface{}:
604			name := getMapValueString(node, "Name")
605			ttype := getMapValueString(node, "Type")
606			defaultValue := getMapValueString(node, "DefaultValue")
607			directives := []string{}
608			for _, directive := range getMapSliceValue(node, "Directives") {
609				directives = append(directives, fmt.Sprintf("%v", directive))
610			}
611			str := join([]string{
612				name + ": " + ttype,
613				wrap("= ", defaultValue, ""),
614				join(directives, " "),
615			}, " ")
616			return visitor.ActionUpdate, str
617		}
618		return visitor.ActionNoChange, nil
619	},
620	"InterfaceDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
621		switch node := p.Node.(type) {
622		case *ast.InterfaceDefinition:
623			name := fmt.Sprintf("%v", node.Name)
624			fields := node.Fields
625			directives := []string{}
626			for _, directive := range node.Directives {
627				directives = append(directives, fmt.Sprintf("%v", directive.Name))
628			}
629			str := join([]string{
630				"interface",
631				name,
632				join(directives, " "),
633				block(fields),
634			}, " ")
635			return visitor.ActionUpdate, str
636		case map[string]interface{}:
637			name := getMapValueString(node, "Name")
638			fields := getMapValue(node, "Fields")
639			directives := []string{}
640			for _, directive := range getMapSliceValue(node, "Directives") {
641				directives = append(directives, fmt.Sprintf("%v", directive))
642			}
643			str := join([]string{
644				"interface",
645				name,
646				join(directives, " "),
647				block(fields),
648			}, " ")
649			return visitor.ActionUpdate, str
650		}
651		return visitor.ActionNoChange, nil
652	},
653	"UnionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
654		switch node := p.Node.(type) {
655		case *ast.UnionDefinition:
656			name := fmt.Sprintf("%v", node.Name)
657			types := toSliceString(node.Types)
658			directives := []string{}
659			for _, directive := range node.Directives {
660				directives = append(directives, fmt.Sprintf("%v", directive.Name))
661			}
662			str := join([]string{
663				"union",
664				name,
665				join(directives, " "),
666				"= " + join(types, " | "),
667			}, " ")
668			return visitor.ActionUpdate, str
669		case map[string]interface{}:
670			name := getMapValueString(node, "Name")
671			types := toSliceString(getMapValue(node, "Types"))
672			directives := []string{}
673			for _, directive := range getMapSliceValue(node, "Directives") {
674				directives = append(directives, fmt.Sprintf("%v", directive))
675			}
676			str := join([]string{
677				"union",
678				name,
679				join(directives, " "),
680				"= " + join(types, " | "),
681			}, " ")
682			return visitor.ActionUpdate, str
683		}
684		return visitor.ActionNoChange, nil
685	},
686	"EnumDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
687		switch node := p.Node.(type) {
688		case *ast.EnumDefinition:
689			name := fmt.Sprintf("%v", node.Name)
690			values := node.Values
691			directives := []string{}
692			for _, directive := range node.Directives {
693				directives = append(directives, fmt.Sprintf("%v", directive.Name))
694			}
695			str := join([]string{
696				"enum",
697				name,
698				join(directives, " "),
699				block(values),
700			}, " ")
701			return visitor.ActionUpdate, str
702		case map[string]interface{}:
703			name := getMapValueString(node, "Name")
704			values := getMapValue(node, "Values")
705			directives := []string{}
706			for _, directive := range getMapSliceValue(node, "Directives") {
707				directives = append(directives, fmt.Sprintf("%v", directive))
708			}
709			str := join([]string{
710				"enum",
711				name,
712				join(directives, " "),
713				block(values),
714			}, " ")
715			return visitor.ActionUpdate, str
716		}
717		return visitor.ActionNoChange, nil
718	},
719	"EnumValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
720		switch node := p.Node.(type) {
721		case *ast.EnumValueDefinition:
722			name := fmt.Sprintf("%v", node.Name)
723			directives := []string{}
724			for _, directive := range node.Directives {
725				directives = append(directives, fmt.Sprintf("%v", directive.Name))
726			}
727			str := join([]string{
728				name,
729				join(directives, " "),
730			}, " ")
731			return visitor.ActionUpdate, str
732		case map[string]interface{}:
733			name := getMapValueString(node, "Name")
734			directives := []string{}
735			for _, directive := range getMapSliceValue(node, "Directives") {
736				directives = append(directives, fmt.Sprintf("%v", directive))
737			}
738			str := join([]string{
739				name,
740				join(directives, " "),
741			}, " ")
742			return visitor.ActionUpdate, str
743		}
744		return visitor.ActionNoChange, nil
745	},
746	"InputObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
747		switch node := p.Node.(type) {
748		case *ast.InputObjectDefinition:
749			name := fmt.Sprintf("%v", node.Name)
750			fields := node.Fields
751			directives := []string{}
752			for _, directive := range node.Directives {
753				directives = append(directives, fmt.Sprintf("%v", directive.Name))
754			}
755			str := join([]string{
756				"input",
757				name,
758				join(directives, " "),
759				block(fields),
760			}, " ")
761			return visitor.ActionUpdate, str
762		case map[string]interface{}:
763			name := getMapValueString(node, "Name")
764			fields := getMapValue(node, "Fields")
765			directives := []string{}
766			for _, directive := range getMapSliceValue(node, "Directives") {
767				directives = append(directives, fmt.Sprintf("%v", directive))
768			}
769			str := join([]string{
770				"input",
771				name,
772				join(directives, " "),
773				block(fields),
774			}, " ")
775			return visitor.ActionUpdate, str
776		}
777		return visitor.ActionNoChange, nil
778	},
779	"TypeExtensionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
780		switch node := p.Node.(type) {
781		case *ast.TypeExtensionDefinition:
782			definition := fmt.Sprintf("%v", node.Definition)
783			str := "extend " + definition
784			return visitor.ActionUpdate, str
785		case map[string]interface{}:
786			definition := getMapValueString(node, "Definition")
787			str := "extend " + definition
788			return visitor.ActionUpdate, str
789		}
790		return visitor.ActionNoChange, nil
791	},
792	"DirectiveDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
793		switch node := p.Node.(type) {
794		case *ast.DirectiveDefinition:
795			args := wrap("(", join(toSliceString(node.Arguments), ", "), ")")
796			str := fmt.Sprintf("directive @%v%v on %v", node.Name, args, join(toSliceString(node.Locations), " | "))
797			return visitor.ActionUpdate, str
798		case map[string]interface{}:
799			name := getMapValueString(node, "Name")
800			locations := toSliceString(getMapValue(node, "Locations"))
801			args := toSliceString(getMapValue(node, "Arguments"))
802			argsStr := wrap("(", join(args, ", "), ")")
803			str := fmt.Sprintf("directive @%v%v on %v", name, argsStr, join(locations, " | "))
804			return visitor.ActionUpdate, str
805		}
806		return visitor.ActionNoChange, nil
807	},
808}
809
810func Print(astNode ast.Node) (printed interface{}) {
811	defer func() interface{} {
812		if r := recover(); r != nil {
813			return fmt.Sprintf("%v", astNode)
814		}
815		return printed
816	}()
817	printed = visitor.Visit(astNode, &visitor.VisitorOptions{
818		LeaveKindMap: printDocASTReducer,
819	}, nil)
820	return printed
821}