func (g *generator) addOperation(op *ast.OperationDefinition) error {
	if op.Name == "" {
		return errorf(op.Position, "operations must have operation-names")
	}
	queryDoc := &ast.QueryDocument{
		Operations: ast.OperationList{op},
		Fragments:  g.usedFragments(op),
	}
	g.preprocessQueryDocument(queryDoc)
	var builder strings.Builder
	f := formatter.NewFormatter(&builder)
	f.FormatQueryDocument(queryDoc)
	commentLines, directive, err := g.parsePrecedingComment(op, nil, op.Position, nil)
	if err != nil {
		return err
	}
	inputType, err := g.convertArguments(op, directive)
	if err != nil {
		return err
	}
	responseType, err := g.convertOperation(op, directive)
	if err != nil {
		return err
	}
	var docComment string
	if len(commentLines) > 0 {
		docComment = "// " + strings.ReplaceAll(commentLines, "\n", "\n// ")
	}
	sourceFilename := op.Position.Src.Name
	if i := strings.LastIndex(sourceFilename, ":"); i != -1 {
		sourceFilename = sourceFilename[:i]
	}
	g.Operations = append(g.Operations, &operation{
		Type: op.Operation,
		Name: op.Name,
		Doc:  docComment,
		Body:           "\n" + builder.String(),
		Input:          inputType,
		ResponseName:   responseType.Reference(),
		SourceFilename: sourceFilename,
		Config:         g.Config,  
	})
	return nil
}
addOperation adds to g.Operations the information needed to generate a
genqlient entrypoint function for the given operation.  It also adds to
g.typeMap any types referenced by the operation, except for types belonging
to named fragments, which are added separately by Generate via
convertFragment.
package generate
import (
	"bytes"
	"encoding/json"
	"go/format"
	"io"
	"sort"
	"strings"
	"text/template"
	"github.com/vektah/gqlparser/v2/ast"
	"github.com/vektah/gqlparser/v2/formatter"
	"github.com/vektah/gqlparser/v2/validator"
	"golang.org/x/tools/imports"
)
type generator struct {
	Config *Config
	Operations []*operation
	typeMap map[string]goType
	imports     map[string]string
	usedAliases map[string]bool
	importsLocked bool
	templateCache map[string]*template.Template
	schema *ast.Schema
	fragments map[string]*ast.FragmentDefinition
}
type operation struct {
	Type ast.Operation `json:"-"`
	Name string `json:"operationName"`
	Doc string `json:"-"`
	Body string `json:"query"`
	Input *goStructType `json:"-"`
	ResponseName string `json:"-"`
	SourceFilename string `json:"sourceLocation"`
	Config *Config `json:"-"`
}
type exportedOperations struct {
	Operations []*operation `json:"operations"`
}
func newGenerator(
	config *Config,
	schema *ast.Schema,
	fragments ast.FragmentDefinitionList,
) *generator {
	g := generator{
		Config:        config,
		typeMap:       map[string]goType{},
		imports:       map[string]string{},
		usedAliases:   map[string]bool{},
		templateCache: map[string]*template.Template{},
		schema:        schema,
		fragments:     make(map[string]*ast.FragmentDefinition, len(fragments)),
	}
	for _, fragment := range fragments {
		g.fragments[fragment.Name] = fragment
	}
	return &g
}
func (g *generator) WriteTypes(w io.Writer) error {
	names := make([]string, 0, len(g.typeMap))
	for name := range g.typeMap {
		names = append(names, name)
	}
	sort.Strings(names)
	for _, name := range names {
		err := g.typeMap[name].WriteDefinition(w, g)
		if err != nil {
			return err
		}
		_, err = io.WriteString(w, "\n\n")
		if err != nil {
			return err
		}
	}
	return nil
}
func (g *generator) usedFragments(op *ast.OperationDefinition) ast.FragmentDefinitionList {
	var retval, queue ast.FragmentDefinitionList
	seen := map[string]bool{}
	var observers validator.Events
	observers.OnFragmentSpread(func(_ *validator.Walker, fragmentSpread *ast.FragmentSpread) {
		if seen[fragmentSpread.Name] {
			return
		}
		def := g.fragments[fragmentSpread.Name]
		seen[fragmentSpread.Name] = true
		retval = append(retval, def)
		queue = append(queue, def)
	})
	doc := ast.QueryDocument{Operations: ast.OperationList{op}}
	validator.Walk(g.schema, &doc, &observers)
	for len(queue) > 0 {
		doc = ast.QueryDocument{Fragments: ast.FragmentDefinitionList{queue[0]}}
		validator.Walk(g.schema, &doc, &observers)  
		queue = queue[1:]
	}
	return retval
}
func (g *generator) preprocessQueryDocument(doc *ast.QueryDocument) {
	var observers validator.Events
	observers.OnField(func(_ *validator.Walker, field *ast.Field) {
		fieldType := g.schema.Types[field.Definition.Type.Name()]
		if fieldType.Kind != ast.Interface && fieldType.Kind != ast.Union {
			return  
		}
		hasTypename := false
		for _, selection := range field.SelectionSet {
			subField, ok := selection.(*ast.Field)
			if ok && subField.Name == "__typename" {
				hasTypename = true
			}
		}
		if !hasTypename {
			field.SelectionSet = append(ast.SelectionSet{
				&ast.Field{
					Alias: "__typename", Name: "__typename",
					Definition: &ast.FieldDefinition{
						Name: "__typename",
						Type: ast.NamedType("String", nil  ),
					},
					ObjectDefinition: fieldType,
				},
			}, field.SelectionSet...)
		}
	})
	validator.Walk(g.schema, doc, &observers)
}