2019-01-18 01:50:10 +00:00
|
|
|
/*
|
|
|
|
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
|
2021-05-15 10:08:31 +00:00
|
|
|
// Default for that schema.
|
|
|
|
GetDefault() interface{}
|
2019-01-18 01:50:10 +00:00
|
|
|
// 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{}
|
2021-05-15 10:08:31 +00:00
|
|
|
Default interface{}
|
2019-01-18 01:50:10 +00:00
|
|
|
|
|
|
|
Path Path
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BaseSchema) GetDescription() string {
|
|
|
|
return b.Description
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BaseSchema) GetExtensions() map[string]interface{} {
|
|
|
|
return b.Extensions
|
|
|
|
}
|
|
|
|
|
2021-05-15 10:08:31 +00:00
|
|
|
func (b *BaseSchema) GetDefault() interface{} {
|
|
|
|
return b.Default
|
|
|
|
}
|
|
|
|
|
2019-01-18 01:50:10 +00:00
|
|
|
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
|
|
|
|
}
|