func (g openAPITypeWriter) validatePatchTags(m *types.Member, parent *types.Type) error {
	for _, tagKey := range tempPatchTags {
		structTagValue := reflect.StructTag(m.Tags).Get(tagKey)
		commentTagValue, err := getSingleTagsValue(m.CommentLines, tagKey)
		if err != nil {
			return err
		}
		if structTagValue != commentTagValue {
			return fmt.Errorf("Tags in comment and struct should match for member (%s) of (%s)",
				m.Name, parent.Name.String())
		}
	}
	return nil
}
TODO(#44005): Move this validation outside of this generator (probably to policy verifier)
package generators
import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"k8s.io/gengo/generator"
	"k8s.io/gengo/namer"
	"k8s.io/gengo/types"
	openapi "k8s.io/kube-openapi/pkg/common"
	"k8s.io/klog/v2"
)
const tagName = "k8s:openapi-gen"
const tagOptional = "optional"
const tagDefault = "default"
const (
	tagValueTrue  = "true"
	tagValueFalse = "false"
)
var tempPatchTags = [...]string{
	"patchMergeKey",
	"patchStrategy",
}
func getOpenAPITagValue(comments []string) []string {
	return types.ExtractCommentTags("+", comments)[tagName]
}
func getSingleTagsValue(comments []string, tag string) (string, error) {
	tags, ok := types.ExtractCommentTags("+", comments)[tag]
	if !ok || len(tags) == 0 {
		return "", nil
	}
	if len(tags) > 1 {
		return "", fmt.Errorf("multiple values are not allowed for tag %s", tag)
	}
	return tags[0], nil
}
func hasOpenAPITagValue(comments []string, value string) bool {
	tagValues := getOpenAPITagValue(comments)
	for _, val := range tagValues {
		if val == value {
			return true
		}
	}
	return false
}
func hasOptionalTag(m *types.Member) bool {
	hasOptionalCommentTag := types.ExtractCommentTags(
		"+", m.CommentLines)[tagOptional] != nil
	hasOptionalJsonTag := strings.Contains(
		reflect.StructTag(m.Tags).Get("json"), "omitempty")
	return hasOptionalCommentTag || hasOptionalJsonTag
}
func apiTypeFilterFunc(c *generator.Context, t *types.Type) bool {
	if strings.HasPrefix(t.Name.Name, "codecSelfer") {
		return false
	}
	pkg := c.Universe.Package(t.Name.Package)
	if hasOpenAPITagValue(pkg.Comments, tagValueTrue) {
		return !hasOpenAPITagValue(t.CommentLines, tagValueFalse)
	}
	if hasOpenAPITagValue(t.CommentLines, tagValueTrue) {
		return true
	}
	return false
}
const (
	specPackagePath          = "k8s.io/kube-openapi/pkg/validation/spec"
	openAPICommonPackagePath = "k8s.io/kube-openapi/pkg/common"
)
type openAPIGen struct {
	generator.DefaultGen
	targetPackage string
	imports       namer.ImportTracker
}
func newOpenAPIGen(sanitizedName string, targetPackage string) generator.Generator {
	return &openAPIGen{
		DefaultGen: generator.DefaultGen{
			OptionalName: sanitizedName,
		},
		imports:       generator.NewImportTracker(),
		targetPackage: targetPackage,
	}
}
const nameTmpl = "schema_$.type|private$"
func (g *openAPIGen) Namers(c *generator.Context) namer.NameSystems {
	return namer.NameSystems{
		"raw": namer.NewRawNamer(g.targetPackage, g.imports),
		"private": &namer.NameStrategy{
			Join: func(pre string, in []string, post string) string {
				return strings.Join(in, "_")
			},
			PrependPackageNames: 4,  
		},
	}
}
func (g *openAPIGen) isOtherPackage(pkg string) bool {
	if pkg == g.targetPackage {
		return false
	}
	if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
		return false
	}
	return true
}
func (g *openAPIGen) Imports(c *generator.Context) []string {
	importLines := []string{}
	for _, singleImport := range g.imports.ImportLines() {
		importLines = append(importLines, singleImport)
	}
	return importLines
}
func argsFromType(t *types.Type) generator.Args {
	return generator.Args{
		"type":              t,
		"ReferenceCallback": types.Ref(openAPICommonPackagePath, "ReferenceCallback"),
		"OpenAPIDefinition": types.Ref(openAPICommonPackagePath, "OpenAPIDefinition"),
		"SpecSchemaType":    types.Ref(specPackagePath, "Schema"),
	}
}
func (g *openAPIGen) Init(c *generator.Context, w io.Writer) error {
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	sw.Do("func GetOpenAPIDefinitions(ref $.ReferenceCallback|raw$) map[string]$.OpenAPIDefinition|raw$ {\n", argsFromType(nil))
	sw.Do("return map[string]$.OpenAPIDefinition|raw${\n", argsFromType(nil))
	for _, t := range c.Order {
		err := newOpenAPITypeWriter(sw, c).generateCall(t)
		if err != nil {
			return err
		}
	}
	sw.Do("}\n", nil)
	sw.Do("}\n\n", nil)
	return sw.Error()
}
func (g *openAPIGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
	klog.V(5).Infof("generating for type %v", t)
	sw := generator.NewSnippetWriter(w, c, "$", "$")
	err := newOpenAPITypeWriter(sw, c).generate(t)
	if err != nil {
		return err
	}
	return sw.Error()
}
func getJsonTags(m *types.Member) []string {
	jsonTag := reflect.StructTag(m.Tags).Get("json")
	if jsonTag == "" {
		return []string{}
	}
	return strings.Split(jsonTag, ",")
}
func getReferableName(m *types.Member) string {
	jsonTags := getJsonTags(m)
	if len(jsonTags) > 0 {
		if jsonTags[0] == "-" {
			return ""
		} else {
			return jsonTags[0]
		}
	} else {
		return m.Name
	}
}
func shouldInlineMembers(m *types.Member) bool {
	jsonTags := getJsonTags(m)
	return len(jsonTags) > 1 && jsonTags[1] == "inline"
}
type openAPITypeWriter struct {
	*generator.SnippetWriter
	context                *generator.Context
	refTypes               map[string]*types.Type
	enumContext            *enumContext
	GetDefinitionInterface *types.Type
}
func newOpenAPITypeWriter(sw *generator.SnippetWriter, c *generator.Context) openAPITypeWriter {
	return openAPITypeWriter{
		SnippetWriter: sw,
		context:       c,
		refTypes:      map[string]*types.Type{},
		enumContext:   newEnumContext(c),
	}
}
func methodReturnsValue(mt *types.Type, pkg, name string) bool {
	if len(mt.Signature.Parameters) != 0 || len(mt.Signature.Results) != 1 {
		return false
	}
	r := mt.Signature.Results[0]
	return r.Name.Name == name && r.Name.Package == pkg
}
func hasOpenAPIV3DefinitionMethod(t *types.Type) bool {
	for mn, mt := range t.Methods {
		if mn != "OpenAPIV3Definition" {
			continue
		}
		return methodReturnsValue(mt, openAPICommonPackagePath, "OpenAPIDefinition")
	}
	return false
}
func hasOpenAPIDefinitionMethod(t *types.Type) bool {
	for mn, mt := range t.Methods {
		if mn != "OpenAPIDefinition" {
			continue
		}
		return methodReturnsValue(mt, openAPICommonPackagePath, "OpenAPIDefinition")
	}
	return false
}
func hasOpenAPIDefinitionMethods(t *types.Type) bool {
	var hasSchemaTypeMethod, hasOpenAPISchemaFormat bool
	for mn, mt := range t.Methods {
		switch mn {
		case "OpenAPISchemaType":
			hasSchemaTypeMethod = methodReturnsValue(mt, "", "[]string")
		case "OpenAPISchemaFormat":
			hasOpenAPISchemaFormat = methodReturnsValue(mt, "", "string")
		}
	}
	return hasSchemaTypeMethod && hasOpenAPISchemaFormat
}
func typeShortName(t *types.Type) string {
	return filepath.Base(t.Name.Package) + "." + t.Name.Name
}
func (g openAPITypeWriter) generateMembers(t *types.Type, required []string) ([]string, error) {
	var err error
	for t.Kind == types.Pointer {  
		t = t.Elem
	}
	for _, m := range t.Members {
		if hasOpenAPITagValue(m.CommentLines, tagValueFalse) {
			continue
		}
		if shouldInlineMembers(&m) {
			required, err = g.generateMembers(m.Type, required)
			if err != nil {
				return required, err
			}
			continue
		}
		name := getReferableName(&m)
		if name == "" {
			continue
		}
		if !hasOptionalTag(&m) {
			required = append(required, name)
		}
		if err = g.generateProperty(&m, t); err != nil {
			klog.Errorf("Error when generating: %v, %v\n", name, m)
			return required, err
		}
	}
	return required, nil
}
func (g openAPITypeWriter) generateCall(t *types.Type) error {
	switch t.Kind {
	case types.Struct:
		args := argsFromType(t)
		g.Do("\"$.$\": ", t.Name)
		hasV2Definition := hasOpenAPIDefinitionMethod(t)
		hasV2DefinitionTypeAndFormat := hasOpenAPIDefinitionMethods(t)
		hasV3Definition := hasOpenAPIV3DefinitionMethod(t)
		switch {
		case hasV2DefinitionTypeAndFormat:
			g.Do(nameTmpl+"(ref),\n", args)
		case hasV2Definition && hasV3Definition:
			g.Do("common.EmbedOpenAPIDefinitionIntoV2Extension($.type|raw${}.OpenAPIV3Definition(), $.type|raw${}.OpenAPIDefinition()),\n", args)
		case hasV2Definition:
			g.Do("$.type|raw${}.OpenAPIDefinition(),\n", args)
		case hasV3Definition:
			g.Do("$.type|raw${}.OpenAPIV3Definition(),\n", args)
		default:
			g.Do(nameTmpl+"(ref),\n", args)
		}
	}
	return g.Error()
}
func (g openAPITypeWriter) generate(t *types.Type) error {
	switch t.Kind {
	case types.Struct:
		hasV2Definition := hasOpenAPIDefinitionMethod(t)
		hasV2DefinitionTypeAndFormat := hasOpenAPIDefinitionMethods(t)
		hasV3Definition := hasOpenAPIV3DefinitionMethod(t)
		if hasV2Definition || (hasV3Definition && !hasV2DefinitionTypeAndFormat) {
			return nil
		}
		args := argsFromType(t)
		g.Do("func "+nameTmpl+"(ref $.ReferenceCallback|raw$) $.OpenAPIDefinition|raw$ {\n", args)
		switch {
		case hasV2DefinitionTypeAndFormat && hasV3Definition:
			g.Do("return common.EmbedOpenAPIDefinitionIntoV2Extension($.type|raw${}.OpenAPIV3Definition(), $.OpenAPIDefinition|raw${\n"+
				"Schema: spec.Schema{\n"+
				"SchemaProps: spec.SchemaProps{\n", args)
			g.generateDescription(t.CommentLines)
			g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
				"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
				"},\n"+
				"},\n"+
				"})\n}\n\n", args)
			return nil
		case hasV2DefinitionTypeAndFormat:
			g.Do("return $.OpenAPIDefinition|raw${\n"+
				"Schema: spec.Schema{\n"+
				"SchemaProps: spec.SchemaProps{\n", args)
			g.generateDescription(t.CommentLines)
			g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
				"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
				"},\n"+
				"},\n"+
				"}\n}\n\n", args)
			return nil
		}
		g.Do("return $.OpenAPIDefinition|raw${\nSchema: spec.Schema{\nSchemaProps: spec.SchemaProps{\n", args)
		g.generateDescription(t.CommentLines)
		g.Do("Type: []string{\"object\"},\n", nil)
		propertiesBuf := bytes.Buffer{}
		bsw := g
		bsw.SnippetWriter = generator.NewSnippetWriter(&propertiesBuf, g.context, "$", "$")
		required, err := bsw.generateMembers(t, []string{})
		if err != nil {
			return err
		}
		if propertiesBuf.Len() > 0 {
			g.Do("Properties: map[string]$.SpecSchemaType|raw${\n", args)
			g.Do(strings.Replace(propertiesBuf.String(), "$", "$\"$\"$", -1), nil)  
			g.Do("},\n", nil)
		}
		if len(required) > 0 {
			g.Do("Required: []string{\"$.$\"},\n", strings.Join(required, "\",\""))
		}
		g.Do("},\n", nil)
		if err := g.generateStructExtensions(t); err != nil {
			return err
		}
		g.Do("},\n", nil)
		keys := []string{}
		for k := range g.refTypes {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		deps := []string{}
		for _, k := range keys {
			v := g.refTypes[k]
			if t, _ := openapi.OpenAPITypeFormat(v.String()); t != "" {
				continue
			}
			deps = append(deps, k)
		}
		if len(deps) > 0 {
			g.Do("Dependencies: []string{\n", args)
			for _, k := range deps {
				g.Do("\"$.$\",", k)
			}
			g.Do("},\n", nil)
		}
		g.Do("}\n}\n\n", nil)
	}
	return nil
}
func (g openAPITypeWriter) generateStructExtensions(t *types.Type) error {
	extensions, errors := parseExtensions(t.CommentLines)
	if len(errors) > 0 {
		for _, e := range errors {
			klog.Errorf("[%s]: %s\n", t.String(), e)
		}
	}
	unions, errors := parseUnions(t)
	if len(errors) > 0 {
		for _, e := range errors {
			klog.Errorf("[%s]: %s\n", t.String(), e)
		}
	}
	g.emitExtensions(extensions, unions)
	return nil
}
func (g openAPITypeWriter) generateMemberExtensions(m *types.Member, parent *types.Type) error {
	extensions, parseErrors := parseExtensions(m.CommentLines)
	validationErrors := validateMemberExtensions(extensions, m)
	errors := append(parseErrors, validationErrors...)
	if len(errors) > 0 {
		errorPrefix := fmt.Sprintf("[%s] %s:", parent.String(), m.String())
		for _, e := range errors {
			klog.V(2).Infof("%s %s\n", errorPrefix, e)
		}
	}
	g.emitExtensions(extensions, nil)
	return nil
}
func (g openAPITypeWriter) emitExtensions(extensions []extension, unions []union) {
	if len(extensions) == 0 && len(unions) == 0 {
		return
	}
	g.Do("VendorExtensible: spec.VendorExtensible{\nExtensions: spec.Extensions{\n", nil)
	for _, extension := range extensions {
		g.Do("\"$.$\": ", extension.xName)
		if extension.hasMultipleValues() || extension.isAlwaysArrayFormat() {
			g.Do("[]interface{}{\n", nil)
		}
		for _, value := range extension.values {
			g.Do("\"$.$\",\n", value)
		}
		if extension.hasMultipleValues() || extension.isAlwaysArrayFormat() {
			g.Do("},\n", nil)
		}
	}
	if len(unions) > 0 {
		g.Do("\"x-kubernetes-unions\": []interface{}{\n", nil)
		for _, u := range unions {
			u.emit(g)
		}
		g.Do("},\n", nil)
	}
	g.Do("},\n},\n", nil)
}