func (d *dumper) dumpValue(value Value) {
	switch value.Kind {
	case ValueKindVariable:
		io.WriteString(d.w, "$")
		io.WriteString(d.w, value.StringValue)
	case ValueKindInt:
		io.WriteString(d.w, strconv.Itoa(value.IntValue))
	case ValueKindFloat:
		io.WriteString(d.w, fmt.Sprintf("%g", value.FloatValue))
	case ValueKindString:
		hasLF := strings.Contains(value.StringValue, "\n")
		if hasLF {
			indent := strings.Repeat(indentation, d.depth)
			escaped := escapeGraphQLBlockString(value.StringValue)
			lines := strings.Split(escaped, "\n")
			buf := bytes.Buffer{}
			for i, line := range lines {
				buf.WriteString(indent)
				buf.WriteString(indentation)  
				buf.WriteString(line)
				if i != len(lines)-1 {
					buf.WriteRune('\n')
				}
			}
			io.WriteString(d.w, `"""`)
			io.WriteString(d.w, "\n")
			io.WriteString(d.w, buf.String())
			io.WriteString(d.w, "\n")
			io.WriteString(d.w, indent)
			io.WriteString(d.w, `"""`)
		} else {
			io.WriteString(d.w, `"`)
			io.WriteString(d.w, escapeGraphQLString(value.StringValue))
			io.WriteString(d.w, `"`)
		}
	case ValueKindBoolean:
		if value.BooleanValue {
			io.WriteString(d.w, "true")
		} else {
			io.WriteString(d.w, "false")
		}
	case ValueKindNull:
		io.WriteString(d.w, "null")
	case ValueKindEnum:
		io.WriteString(d.w, value.StringValue)
	case ValueKindList:
		io.WriteString(d.w, "[")
		vals := len(value.ListValue)
		for i, v := range value.ListValue {
			d.dumpValue(v)
			if i < vals-1 {
				io.WriteString(d.w, ", ")
			}
		}
		io.WriteString(d.w, "]")
	case ValueKindObject:
		io.WriteString(d.w, "{ ")
		vals := len(value.ObjectValue)
		for i, v := range value.ObjectValue {
			io.WriteString(d.w, v.Name)
			io.WriteString(d.w, ": ")
			d.dumpValue(v.Value)
			if i < vals-1 {
				io.WriteString(d.w, ", ")
			}
		}
		io.WriteString(d.w, " }")
	}
}
2.9 Input Values
package ast
import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"unicode/utf8"
)
func Fdump(w io.Writer, doc Document) {
	dmpr := dumper{defs: doc.Definitions.Len(), w: w}
	dmpr.dumpDefinitions(doc.Definitions)
}
func Dump(doc Document) {
	Fdump(os.Stdout, doc)
}
func Sdump(doc Document) string {
	buf := bytes.Buffer{}
	Fdump(&buf, doc)
	return buf.String()
}
const indentation = "  "
type dumper struct {
	defs  int
	depth int
	w     io.Writer
}
func (d *dumper) dumpDefinitions(definitions *Definitions) {
	definitions.ForEach(func(definition Definition, i int) {
		if i != 0 {
			io.WriteString(d.w, "\n")
		}
		d.dumpDefinition(definition)
		if i < d.defs-1 {
			io.WriteString(d.w, "\n")
		}
	})
}
func (d *dumper) dumpDefinition(definition Definition) {
	switch definition.Kind {
	case DefinitionKindExecutable:
		d.dumpExecutableDefinition(definition.ExecutableDefinition)
	case DefinitionKindTypeSystem:
		d.dumpTypeSystemDefinition(definition.TypeSystemDefinition)
	case DefinitionKindTypeSystemExtension:
		d.dumpTypeSystemExtension(definition.TypeSystemExtension)
	}
}
func (d *dumper) dumpExecutableDefinition(def *ExecutableDefinition) {
	switch def.Kind {
	case ExecutableDefinitionKindOperation:
		d.dumpOperationDefinition(def.OperationDefinition)
	case ExecutableDefinitionKindFragment:
		d.dumpFragmentDefinition(def.FragmentDefinition)
	}
}
func (d *dumper) dumpOperationDefinition(def *OperationDefinition) {
	var shorthand bool
	if d.defs == 1 {
		shorthand = true
	}
	switch def.Kind {
	case OperationDefinitionKindQuery:
		if !shorthand || def.Name != "" {
			io.WriteString(d.w, "query ")
		}
	case OperationDefinitionKindMutation:
		io.WriteString(d.w, "mutation ")
	case OperationDefinitionKindSubscription:
		io.WriteString(d.w, "subscription ")
	}
	if def.Name != "" {
		io.WriteString(d.w, def.Name)
	}
	if def.VariableDefinitions != nil {
		d.dumpVariableDefinitions(def.VariableDefinitions)
	}
	if def.Directives != nil {
		io.WriteString(d.w, " ")
		d.dumpDirectives(def.Directives)
	}
	if !shorthand {
		io.WriteString(d.w, " ")
	}
	d.dumpSelections(def.SelectionSet)
}
func (d *dumper) dumpSelections(selections *Selections) {
	io.WriteString(d.w, "{\n")
	selections.ForEach(func(selection Selection, _ int) {
		d.dumpSelection(selection)
		io.WriteString(d.w, "\n")
	})
	io.WriteString(d.w, strings.Repeat(indentation, d.depth))
	io.WriteString(d.w, "}")
}
func (d *dumper) dumpSelection(selection Selection) {
	d.depth++
	switch selection.Kind {
	case SelectionKindField:
		d.dumpFieldSelection(selection)
	case SelectionKindFragmentSpread:
		d.dumpFragmentSpread(selection)
	case SelectionKindInlineFragment:
		d.dumpInlineFragment(selection)
	}
	d.depth--
}
func (d *dumper) dumpFieldSelection(selection Selection) {
	indent := strings.Repeat(indentation, d.depth)
	io.WriteString(d.w, indent)
	if selection.Alias != "" {
		io.WriteString(d.w, selection.Alias)
		io.WriteString(d.w, ": ")
	}
	io.WriteString(d.w, selection.Name)
	d.dumpArguments(selection.Arguments)
	if selection.Directives != nil {
		io.WriteString(d.w, " ")
		d.dumpDirectives(selection.Directives)
	}
	if selection.SelectionSet != nil {
		io.WriteString(d.w, " ")
		d.dumpSelections(selection.SelectionSet)
	}
}
func (d *dumper) dumpArguments(args *Arguments) {
	argsLen := args.Len()
	if argsLen == 0 {
		return
	}
	io.WriteString(d.w, "(")
	args.ForEach(func(arg Argument, i int) {
		d.dumpArgument(arg)
		if i < argsLen-1 {
			io.WriteString(d.w, ", ")
		}
	})
	io.WriteString(d.w, ")")
}
func (d *dumper) dumpArgument(arg Argument) {
	io.WriteString(d.w, arg.Name)
	io.WriteString(d.w, ": ")
	d.dumpValue(arg.Value)
}
func (d *dumper) dumpFragmentSpread(selection Selection) {
	indent := strings.Repeat(indentation, d.depth)
	io.WriteString(d.w, indent)
	io.WriteString(d.w, "...")
	io.WriteString(d.w, selection.Name)
	if selection.Directives != nil {
		io.WriteString(d.w, " ")
		d.dumpDirectives(selection.Directives)
	}
}
func (d *dumper) dumpInlineFragment(selection Selection) {
	indent := strings.Repeat(indentation, d.depth)
	io.WriteString(d.w, indent)
	io.WriteString(d.w, "...")
	if selection.TypeCondition != nil {
		io.WriteString(d.w, " ")
		io.WriteString(d.w, "on")
		io.WriteString(d.w, " ")
		io.WriteString(d.w, selection.TypeCondition.NamedType.NamedType)
	}
	if selection.Directives != nil {
		io.WriteString(d.w, " ")
		d.dumpDirectives(selection.Directives)
	}
	io.WriteString(d.w, " ")
	d.dumpSelections(selection.SelectionSet)
}
func (d *dumper) dumpFragmentDefinition(def *FragmentDefinition) {
	io.WriteString(d.w, "fragment")
	io.WriteString(d.w, " ")
	io.WriteString(d.w, def.Name)
	io.WriteString(d.w, " ")
	io.WriteString(d.w, "on")
	io.WriteString(d.w, " ")
	io.WriteString(d.w, def.TypeCondition.NamedType.NamedType)
	if def.Directives != nil {
		io.WriteString(d.w, " ")
		d.dumpDirectives(def.Directives)
	}
	io.WriteString(d.w, " ")
	d.dumpSelections(def.SelectionSet)
}