123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package proto
- import (
- "fmt"
- "sort"
- "strings"
- )
- // Defines openapi types.
- const (
- Integer = "integer"
- Number = "number"
- String = "string"
- Boolean = "boolean"
- // These types are private as they should never leak, and are
- // represented by actual structs.
- array = "array"
- object = "object"
- )
- // Models interface describe a model provider. They can give you the
- // schema for a specific model.
- type Models interface {
- LookupModel(string) Schema
- ListModels() []string
- }
- // SchemaVisitor is an interface that you need to implement if you want
- // to "visit" an openapi schema. A dispatch on the Schema type will call
- // the appropriate function based on its actual type:
- // - Array is a list of one and only one given subtype
- // - Map is a map of string to one and only one given subtype
- // - Primitive can be string, integer, number and boolean.
- // - Kind is an object with specific fields mapping to specific types.
- // - Reference is a link to another definition.
- type SchemaVisitor interface {
- VisitArray(*Array)
- VisitMap(*Map)
- VisitPrimitive(*Primitive)
- VisitKind(*Kind)
- VisitReference(Reference)
- }
- // SchemaVisitorArbitrary is an additional visitor interface which handles
- // arbitrary types. For backwards compatibility, it's a separate interface
- // which is checked for at runtime.
- type SchemaVisitorArbitrary interface {
- SchemaVisitor
- VisitArbitrary(*Arbitrary)
- }
- // Schema is the base definition of an openapi type.
- type Schema interface {
- // Giving a visitor here will let you visit the actual type.
- Accept(SchemaVisitor)
- // Pretty print the name of the type.
- GetName() string
- // Describes how to access this field.
- GetPath() *Path
- // Describes the field.
- GetDescription() string
- // Returns type extensions.
- GetExtensions() map[string]interface{}
- }
- // Path helps us keep track of type paths
- type Path struct {
- parent *Path
- key string
- }
- func NewPath(key string) Path {
- return Path{key: key}
- }
- func (p *Path) Get() []string {
- if p == nil {
- return []string{}
- }
- if p.key == "" {
- return p.parent.Get()
- }
- return append(p.parent.Get(), p.key)
- }
- func (p *Path) Len() int {
- return len(p.Get())
- }
- func (p *Path) String() string {
- return strings.Join(p.Get(), "")
- }
- // ArrayPath appends an array index and creates a new path
- func (p *Path) ArrayPath(i int) Path {
- return Path{
- parent: p,
- key: fmt.Sprintf("[%d]", i),
- }
- }
- // FieldPath appends a field name and creates a new path
- func (p *Path) FieldPath(field string) Path {
- return Path{
- parent: p,
- key: fmt.Sprintf(".%s", field),
- }
- }
- // BaseSchema holds data used by each types of schema.
- type BaseSchema struct {
- Description string
- Extensions map[string]interface{}
- Path Path
- }
- func (b *BaseSchema) GetDescription() string {
- return b.Description
- }
- func (b *BaseSchema) GetExtensions() map[string]interface{} {
- return b.Extensions
- }
- func (b *BaseSchema) GetPath() *Path {
- return &b.Path
- }
- // Array must have all its element of the same `SubType`.
- type Array struct {
- BaseSchema
- SubType Schema
- }
- var _ Schema = &Array{}
- func (a *Array) Accept(v SchemaVisitor) {
- v.VisitArray(a)
- }
- func (a *Array) GetName() string {
- return fmt.Sprintf("Array of %s", a.SubType.GetName())
- }
- // Kind is a complex object. It can have multiple different
- // subtypes for each field, as defined in the `Fields` field. Mandatory
- // fields are listed in `RequiredFields`. The key of the object is
- // always of type `string`.
- type Kind struct {
- BaseSchema
- // Lists names of required fields.
- RequiredFields []string
- // Maps field names to types.
- Fields map[string]Schema
- // FieldOrder reports the canonical order for the fields.
- FieldOrder []string
- }
- var _ Schema = &Kind{}
- func (k *Kind) Accept(v SchemaVisitor) {
- v.VisitKind(k)
- }
- func (k *Kind) GetName() string {
- properties := []string{}
- for key := range k.Fields {
- properties = append(properties, key)
- }
- return fmt.Sprintf("Kind(%v)", properties)
- }
- // IsRequired returns true if `field` is a required field for this type.
- func (k *Kind) IsRequired(field string) bool {
- for _, f := range k.RequiredFields {
- if f == field {
- return true
- }
- }
- return false
- }
- // Keys returns a alphabetically sorted list of keys.
- func (k *Kind) Keys() []string {
- keys := make([]string, 0)
- for key := range k.Fields {
- keys = append(keys, key)
- }
- sort.Strings(keys)
- return keys
- }
- // Map is an object who values must all be of the same `SubType`.
- // The key of the object is always of type `string`.
- type Map struct {
- BaseSchema
- SubType Schema
- }
- var _ Schema = &Map{}
- func (m *Map) Accept(v SchemaVisitor) {
- v.VisitMap(m)
- }
- func (m *Map) GetName() string {
- return fmt.Sprintf("Map of %s", m.SubType.GetName())
- }
- // Primitive is a literal. There can be multiple types of primitives,
- // and this subtype can be visited through the `subType` field.
- type Primitive struct {
- BaseSchema
- // Type of a primitive must be one of: integer, number, string, boolean.
- Type string
- Format string
- }
- var _ Schema = &Primitive{}
- func (p *Primitive) Accept(v SchemaVisitor) {
- v.VisitPrimitive(p)
- }
- func (p *Primitive) GetName() string {
- if p.Format == "" {
- return p.Type
- }
- return fmt.Sprintf("%s (%s)", p.Type, p.Format)
- }
- // Arbitrary is a value of any type (primitive, object or array)
- type Arbitrary struct {
- BaseSchema
- }
- var _ Schema = &Arbitrary{}
- func (a *Arbitrary) Accept(v SchemaVisitor) {
- if visitor, ok := v.(SchemaVisitorArbitrary); ok {
- visitor.VisitArbitrary(a)
- }
- }
- func (a *Arbitrary) GetName() string {
- return "Arbitrary value (primitive, object or array)"
- }
- // Reference implementation depends on the type of document.
- type Reference interface {
- Schema
- Reference() string
- SubSchema() Schema
- }
|