func (d *Definitions) ParseSchema(s *openapi_v2.Schema, path *Path) (Schema, error) {
	if s.GetXRef() != "" {
		return d.parseReference(s, path)
	}
	objectTypes := s.GetType().GetValue()
	switch len(objectTypes) {
	case 0:
		if s.GetProperties() != nil {
			return d.parseKind(s, path)
		} else {
			return d.parseArbitrary(s, path)
		}
	case 1:
		t := objectTypes[0]
		switch t {
		case object:
			if s.GetProperties() != nil {
				return d.parseKind(s, path)
			} else {
				return d.parseMap(s, path)
			}
		case array:
			return d.parseArray(s, path)
		}
		return d.parsePrimitive(s, path)
	default:
		return nil, newSchemaError(path, "definitions with multiple types aren't supported")
	}
}
ParseSchema creates a walkable Schema from an openapi schema. While
this function is public, it doesn't leak through the interface.
package proto
import (
	"fmt"
	"sort"
	"strings"
	"github.com/googleapis/gnostic/OpenAPIv2"
	"gopkg.in/yaml.v2"
)
func newSchemaError(path *Path, format string, a ...interface{}) error {
	err := fmt.Sprintf(format, a...)
	if path.Len() == 0 {
		return fmt.Errorf("SchemaError: %v", err)
	}
	return fmt.Errorf("SchemaError(%v): %v", path, err)
}
func VendorExtensionToMap(e []*openapi_v2.NamedAny) map[string]interface{} {
	values := map[string]interface{}{}
	for _, na := range e {
		if na.GetName() == "" || na.GetValue() == nil {
			continue
		}
		if na.GetValue().GetYaml() == "" {
			continue
		}
		var value interface{}
		err := yaml.Unmarshal([]byte(na.GetValue().GetYaml()), &value)
		if err != nil {
			continue
		}
		values[na.GetName()] = value
	}
	return values
}
type Definitions struct {
	models map[string]Schema
}
var _ Models = &Definitions{}
func NewOpenAPIData(doc *openapi_v2.Document) (Models, error) {
	definitions := Definitions{
		models: map[string]Schema{},
	}
	for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
		definitions.models[namedSchema.GetName()] = nil
	}
	for _, namedSchema := range doc.GetDefinitions().GetAdditionalProperties() {
		path := NewPath(namedSchema.GetName())
		schema, err := definitions.ParseSchema(namedSchema.GetValue(), &path)
		if err != nil {
			return nil, err
		}
		definitions.models[namedSchema.GetName()] = schema
	}
	return &definitions, nil
}
func (d *Definitions) parseReference(s *openapi_v2.Schema, path *Path) (Schema, error) {
	if len(s.GetProperties().GetAdditionalProperties()) > 0 {
		return nil, newSchemaError(path, "unallowed embedded type definition")
	}
	if len(s.GetType().GetValue()) > 0 {
		return nil, newSchemaError(path, "definition reference can't have a type")
	}
	if !strings.HasPrefix(s.GetXRef(), "#/definitions/") {
		return nil, newSchemaError(path, "unallowed reference to non-definition %q", s.GetXRef())
	}
	reference := strings.TrimPrefix(s.GetXRef(), "#/definitions/")
	if _, ok := d.models[reference]; !ok {
		return nil, newSchemaError(path, "unknown model in reference: %q", reference)
	}
	return &Ref{
		BaseSchema:  d.parseBaseSchema(s, path),
		reference:   reference,
		definitions: d,
	}, nil
}
func (d *Definitions) parseBaseSchema(s *openapi_v2.Schema, path *Path) BaseSchema {
	return BaseSchema{
		Description: s.GetDescription(),
		Extensions:  VendorExtensionToMap(s.GetVendorExtension()),
		Path:        *path,
	}
}
func (d *Definitions) parseMap(s *openapi_v2.Schema, path *Path) (Schema, error) {
	if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
		return nil, newSchemaError(path, "invalid object type")
	}
	var sub Schema
	if s.GetAdditionalProperties().GetSchema() == nil {
		sub = &Arbitrary{
			BaseSchema: d.parseBaseSchema(s, path),
		}
	} else {
		var err error
		sub, err = d.ParseSchema(s.GetAdditionalProperties().GetSchema(), path)
		if err != nil {
			return nil, err
		}
	}
	return &Map{
		BaseSchema: d.parseBaseSchema(s, path),
		SubType:    sub,
	}, nil
}
func (d *Definitions) parsePrimitive(s *openapi_v2.Schema, path *Path) (Schema, error) {
	var t string
	if len(s.GetType().GetValue()) > 1 {
		return nil, newSchemaError(path, "primitive can't have more than 1 type")
	}
	if len(s.GetType().GetValue()) == 1 {
		t = s.GetType().GetValue()[0]
	}
	switch t {
	case String:  
	case Number:  
	case Integer:  
	case Boolean:  
	default:
		return nil, newSchemaError(path, "Unknown primitive type: %q", t)
	}
	return &Primitive{
		BaseSchema: d.parseBaseSchema(s, path),
		Type:       t,
		Format:     s.GetFormat(),
	}, nil
}
func (d *Definitions) parseArray(s *openapi_v2.Schema, path *Path) (Schema, error) {
	if len(s.GetType().GetValue()) != 1 {
		return nil, newSchemaError(path, "array should have exactly one type")
	}
	if s.GetType().GetValue()[0] != array {
		return nil, newSchemaError(path, `array should have type "array"`)
	}
	if len(s.GetItems().GetSchema()) != 1 {
		return nil, newSchemaError(path, "array should have exactly one sub-item")
	}
	sub, err := d.ParseSchema(s.GetItems().GetSchema()[0], path)
	if err != nil {
		return nil, err
	}
	return &Array{
		BaseSchema: d.parseBaseSchema(s, path),
		SubType:    sub,
	}, nil
}
func (d *Definitions) parseKind(s *openapi_v2.Schema, path *Path) (Schema, error) {
	if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
		return nil, newSchemaError(path, "invalid object type")
	}
	if s.GetProperties() == nil {
		return nil, newSchemaError(path, "object doesn't have properties")
	}
	fields := map[string]Schema{}
	fieldOrder := []string{}
	for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
		var err error
		name := namedSchema.GetName()
		path := path.FieldPath(name)
		fields[name], err = d.ParseSchema(namedSchema.GetValue(), &path)
		if err != nil {
			return nil, err
		}
		fieldOrder = append(fieldOrder, name)
	}
	return &Kind{
		BaseSchema:     d.parseBaseSchema(s, path),
		RequiredFields: s.GetRequired(),
		Fields:         fields,
		FieldOrder:     fieldOrder,
	}, nil
}
func (d *Definitions) parseArbitrary(s *openapi_v2.Schema, path *Path) (Schema, error) {
	return &Arbitrary{
		BaseSchema: d.parseBaseSchema(s, path),
	}, nil
}