fix: add involves edge from task to agent:nomos at creation
Plus sync vendor directory for Docker build compatibility.
This commit is contained in:
21
vendor/github.com/getkin/kin-openapi/LICENSE
generated
vendored
Normal file
21
vendor/github.com/getkin/kin-openapi/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018 the project authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
55
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
Normal file
55
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Callback is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callback-object
|
||||
type Callback struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
m map[string]*PathItem
|
||||
}
|
||||
|
||||
// NewCallback builds a Callback object with path items in insertion order.
|
||||
func NewCallback(opts ...NewCallbackOption) *Callback {
|
||||
Callback := NewCallbackWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(Callback)
|
||||
}
|
||||
return Callback
|
||||
}
|
||||
|
||||
// NewCallbackOption describes options to NewCallback func
|
||||
type NewCallbackOption func(*Callback)
|
||||
|
||||
// WithCallback adds Callback as an option to NewCallback
|
||||
func WithCallback(cb string, pathItem *PathItem) NewCallbackOption {
|
||||
return func(callback *Callback) {
|
||||
if p := pathItem; p != nil && cb != "" {
|
||||
callback.Set(cb, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if Callback does not comply with the OpenAPI spec.
|
||||
func (callback *Callback) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, key := range callback.Keys() {
|
||||
v := callback.Value(key)
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, callback.Extensions, callback.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Callbacks to a copy of data.
|
||||
func (callbacks *Callbacks) UnmarshalJSON(data []byte) (err error) {
|
||||
*callbacks, err = unmarshalStringMapP[CallbackRef](data)
|
||||
return
|
||||
}
|
||||
308
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
Normal file
308
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
type Callbacks map[string]*CallbackRef // Callbacks represents components' named callbacks
|
||||
type Examples map[string]*ExampleRef // Examples represents components' named examples
|
||||
type Headers map[string]*HeaderRef // Headers represents components' named headers
|
||||
type Links map[string]*LinkRef // Links represents components' named links
|
||||
type ParametersMap map[string]*ParameterRef // ParametersMap represents components' named parameters
|
||||
type RequestBodies map[string]*RequestBodyRef // RequestBodies represents components' named request bodies
|
||||
type ResponseBodies map[string]*ResponseRef // ResponseBodies represents components' named response bodies
|
||||
type Schemas map[string]*SchemaRef // Schemas represents components' named schemas
|
||||
type SecuritySchemes map[string]*SecuritySchemeRef // SecuritySchemes represents components' named security schemes
|
||||
|
||||
// Components is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#components-object
|
||||
type Components struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Schemas Schemas `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
Parameters ParametersMap `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
RequestBodies RequestBodies `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
||||
Responses ResponseBodies `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||
SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
|
||||
Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||
}
|
||||
|
||||
func NewComponents() Components {
|
||||
return Components{}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Components.
|
||||
func (components Components) MarshalJSON() ([]byte, error) {
|
||||
x, err := components.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Components.
|
||||
func (components Components) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 9+len(components.Extensions))
|
||||
maps.Copy(m, components.Extensions)
|
||||
if x := components.Schemas; len(x) != 0 {
|
||||
m["schemas"] = x
|
||||
}
|
||||
if x := components.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := components.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := components.RequestBodies; len(x) != 0 {
|
||||
m["requestBodies"] = x
|
||||
}
|
||||
if x := components.Responses; len(x) != 0 {
|
||||
m["responses"] = x
|
||||
}
|
||||
if x := components.SecuritySchemes; len(x) != 0 {
|
||||
m["securitySchemes"] = x
|
||||
}
|
||||
if x := components.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := components.Links; len(x) != 0 {
|
||||
m["links"] = x
|
||||
}
|
||||
if x := components.Callbacks; len(x) != 0 {
|
||||
m["callbacks"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Components to a copy of data.
|
||||
func (components *Components) UnmarshalJSON(data []byte) error {
|
||||
type ComponentsBis Components
|
||||
var x ComponentsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "schemas")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "requestBodies")
|
||||
delete(x.Extensions, "responses")
|
||||
delete(x.Extensions, "securitySchemes")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "links")
|
||||
delete(x.Extensions, "callbacks")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*components = Components(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Components does not comply with the OpenAPI spec.
|
||||
func (components *Components) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
validateMap := func(label string, names []string, validate func(k string) error) error {
|
||||
for _, k := range names {
|
||||
if idErr := ValidateIdentifier(k); idErr != nil {
|
||||
if err := me.emit(&ComponentValidationError{Section: label, Name: k, Cause: idErr}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip validating the component's value when its name is
|
||||
// invalid: any leaf error from validate(k) would surface as
|
||||
// "<bad-name>: <leaf-error>" and has no resolution path
|
||||
// until the name is fixed. The continue keeps the noise
|
||||
// per component bounded to a single, actionable finding.
|
||||
continue
|
||||
}
|
||||
wrap := func(e error) error { return &ComponentValidationError{Section: label, Name: k, Cause: e} }
|
||||
if err := me.emitWrapped(wrap, validate(k)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := validateMap("schema", componentNames(components.Schemas), func(k string) error {
|
||||
return components.Schemas[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("parameter", componentNames(components.Parameters), func(k string) error {
|
||||
return components.Parameters[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("request body", componentNames(components.RequestBodies), func(k string) error {
|
||||
return components.RequestBodies[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("response", componentNames(components.Responses), func(k string) error {
|
||||
return components.Responses[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("header", componentNames(components.Headers), func(k string) error {
|
||||
return components.Headers[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("security scheme", componentNames(components.SecuritySchemes), func(k string) error {
|
||||
return components.SecuritySchemes[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("example", componentNames(components.Examples), func(k string) error {
|
||||
return components.Examples[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("link", componentNames(components.Links), func(k string) error {
|
||||
return components.Links[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := validateMap("callback", componentNames(components.Callbacks), func(k string) error {
|
||||
return components.Callbacks[k].Validate(ctx)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, components.Extensions, components.Origin))
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Schemas)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Schemas) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no schema %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*ParametersMap)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m ParametersMap) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no parameter %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Headers)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Headers) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no header %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m RequestBodies) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no request body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*ResponseRef)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m ResponseBodies) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no response body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m SecuritySchemes) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no security scheme body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Examples)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Examples) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no example body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Links)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Links) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no link body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Callbacks)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Callbacks) JSONLookup(token string) (any, error) {
|
||||
if v, ok := m[token]; !ok || v == nil {
|
||||
return nil, fmt.Errorf("no callback body %q", token)
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
69
vendor/github.com/getkin/kin-openapi/openapi3/contact.go
generated
vendored
Normal file
69
vendor/github.com/getkin/kin-openapi/openapi3/contact.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Contact is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contact-object
|
||||
type Contact struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Contact.
|
||||
func (contact Contact) MarshalJSON() ([]byte, error) {
|
||||
x, err := contact.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Contact.
|
||||
func (contact Contact) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(contact.Extensions))
|
||||
maps.Copy(m, contact.Extensions)
|
||||
if x := contact.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := contact.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
if x := contact.Email; x != "" {
|
||||
m["email"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Contact to a copy of data.
|
||||
func (contact *Contact) UnmarshalJSON(data []byte) error {
|
||||
type ContactBis Contact
|
||||
var x ContactBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "url")
|
||||
delete(x.Extensions, "email")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*contact = Contact(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Contact does not comply with the OpenAPI spec.
|
||||
func (contact *Contact) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, contact.Extensions, contact.Origin)
|
||||
}
|
||||
123
vendor/github.com/getkin/kin-openapi/openapi3/content.go
generated
vendored
Normal file
123
vendor/github.com/getkin/kin-openapi/openapi3/content.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Content is specified by OpenAPI/Swagger 3.0 standard.
|
||||
type Content map[string]*MediaType
|
||||
|
||||
func NewContent() Content {
|
||||
return make(Content)
|
||||
}
|
||||
|
||||
func NewContentWithSchema(schema *Schema, consumes []string) Content {
|
||||
if len(consumes) == 0 {
|
||||
return Content{
|
||||
"*/*": NewMediaType().WithSchema(schema),
|
||||
}
|
||||
}
|
||||
content := make(map[string]*MediaType, len(consumes))
|
||||
for _, mediaType := range consumes {
|
||||
content[mediaType] = NewMediaType().WithSchema(schema)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func NewContentWithSchemaRef(schema *SchemaRef, consumes []string) Content {
|
||||
if len(consumes) == 0 {
|
||||
return Content{
|
||||
"*/*": NewMediaType().WithSchemaRef(schema),
|
||||
}
|
||||
}
|
||||
content := make(map[string]*MediaType, len(consumes))
|
||||
for _, mediaType := range consumes {
|
||||
content[mediaType] = NewMediaType().WithSchemaRef(schema)
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func NewContentWithJSONSchema(schema *Schema) Content {
|
||||
return Content{
|
||||
"application/json": NewMediaType().WithSchema(schema),
|
||||
}
|
||||
}
|
||||
func NewContentWithJSONSchemaRef(schema *SchemaRef) Content {
|
||||
return Content{
|
||||
"application/json": NewMediaType().WithSchemaRef(schema),
|
||||
}
|
||||
}
|
||||
|
||||
func NewContentWithFormDataSchema(schema *Schema) Content {
|
||||
return Content{
|
||||
"multipart/form-data": NewMediaType().WithSchema(schema),
|
||||
}
|
||||
}
|
||||
|
||||
func NewContentWithFormDataSchemaRef(schema *SchemaRef) Content {
|
||||
return Content{
|
||||
"multipart/form-data": NewMediaType().WithSchemaRef(schema),
|
||||
}
|
||||
}
|
||||
|
||||
func (content Content) Get(mime string) *MediaType {
|
||||
// If the mime is empty then short-circuit to the wildcard.
|
||||
// We do this here so that we catch only the specific case of
|
||||
// and empty mime rather than a present, but invalid, mime type.
|
||||
if mime == "" {
|
||||
return content["*/*"]
|
||||
}
|
||||
// Start by making the most specific match possible
|
||||
// by using the mime type in full.
|
||||
if v := content[mime]; v != nil {
|
||||
return v
|
||||
}
|
||||
// If an exact match is not found then we strip all
|
||||
// metadata from the mime type and only use the x/y
|
||||
// portion.
|
||||
i := strings.IndexByte(mime, ';')
|
||||
if i < 0 {
|
||||
// If there is no metadata then preserve the full mime type
|
||||
// string for later wildcard searches.
|
||||
i = len(mime)
|
||||
}
|
||||
mime = mime[:i]
|
||||
if v := content[mime]; v != nil {
|
||||
return v
|
||||
}
|
||||
// If the x/y pattern has no specific match then we
|
||||
// try the x/* pattern.
|
||||
i = strings.IndexByte(mime, '/')
|
||||
if i < 0 {
|
||||
// In the case that the given mime type is not valid because it is
|
||||
// missing the subtype we return nil so that this does not accidentally
|
||||
// resolve with the wildcard.
|
||||
return nil
|
||||
}
|
||||
mime = mime[:i] + "/*"
|
||||
if v := content[mime]; v != nil {
|
||||
return v
|
||||
}
|
||||
// Finally, the most generic match of */* is returned
|
||||
// as a catch-all.
|
||||
return content["*/*"]
|
||||
}
|
||||
|
||||
// Validate returns an error if Content does not comply with the OpenAPI spec.
|
||||
func (content Content) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, k := range componentNames(content) {
|
||||
if err := content[k].Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Content to a copy of data.
|
||||
func (content *Content) UnmarshalJSON(data []byte) (err error) {
|
||||
*content, err = unmarshalStringMapP[MediaType](data)
|
||||
return
|
||||
}
|
||||
76
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
Normal file
76
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Discriminator is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#discriminator-object
|
||||
type Discriminator struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
PropertyName string `json:"propertyName" yaml:"propertyName"` // required
|
||||
Mapping StringMap[MappingRef] `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
||||
}
|
||||
|
||||
// MappingRef is a ref to a Schema objects. Unlike SchemaRefs it is serialised
|
||||
// as a plain string instead of an object with a $ref key, as such it also does
|
||||
// not support extensions.
|
||||
type MappingRef SchemaRef
|
||||
|
||||
func (mr *MappingRef) UnmarshalText(data []byte) error {
|
||||
mr.Ref = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mr MappingRef) MarshalText() ([]byte, error) {
|
||||
return []byte(mr.Ref), nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Discriminator.
|
||||
func (discriminator Discriminator) MarshalJSON() ([]byte, error) {
|
||||
x, err := discriminator.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Discriminator.
|
||||
func (discriminator Discriminator) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 2+len(discriminator.Extensions))
|
||||
maps.Copy(m, discriminator.Extensions)
|
||||
m["propertyName"] = discriminator.PropertyName
|
||||
if x := discriminator.Mapping; len(x) != 0 {
|
||||
m["mapping"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Discriminator to a copy of data.
|
||||
func (discriminator *Discriminator) UnmarshalJSON(data []byte) error {
|
||||
type DiscriminatorBis Discriminator
|
||||
var x DiscriminatorBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "propertyName")
|
||||
delete(x.Extensions, "mapping")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*discriminator = Discriminator(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Discriminator does not comply with the OpenAPI spec.
|
||||
func (discriminator *Discriminator) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, discriminator.Extensions, discriminator.Origin)
|
||||
}
|
||||
25
vendor/github.com/getkin/kin-openapi/openapi3/doc.go
generated
vendored
Normal file
25
vendor/github.com/getkin/kin-openapi/openapi3/doc.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Package openapi3 parses and writes OpenAPI 3 specification documents.
|
||||
//
|
||||
// Supports both OpenAPI 3.0 and OpenAPI 3.1:
|
||||
// - OpenAPI 3.0.x: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md
|
||||
// - OpenAPI 3.1.x: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
|
||||
//
|
||||
// OpenAPI 3.1 Features:
|
||||
// - Type arrays with null support (e.g., ["string", "null"])
|
||||
// - JSON Schema 2020-12 keywords (const, examples, prefixItems, etc.)
|
||||
// - Webhooks for defining callback operations
|
||||
// - JSON Schema dialect specification
|
||||
// - SPDX license identifiers
|
||||
//
|
||||
// The implementation maintains 100% backward compatibility with OpenAPI 3.0.
|
||||
//
|
||||
// For OpenAPI 3.1 validation, use the JSON Schema 2020-12 validator option:
|
||||
//
|
||||
// schema.VisitJSON(value, openapi3.EnableJSONSchema2020())
|
||||
//
|
||||
// Version detection is available via helper methods:
|
||||
//
|
||||
// if doc.IsOpenAPI31OrLater() {
|
||||
// // Handle OpenAPI 3.1 specific features
|
||||
// }
|
||||
package openapi3
|
||||
151
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
Normal file
151
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Encoding is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#encoding-object
|
||||
type Encoding struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||
}
|
||||
|
||||
func NewEncoding() *Encoding {
|
||||
return &Encoding{}
|
||||
}
|
||||
|
||||
// Encodings is a map of encoding objects keyed by field name.
|
||||
type Encodings map[string]*Encoding
|
||||
|
||||
// UnmarshalJSON sets Encodings to a copy of data.
|
||||
func (encodings *Encodings) UnmarshalJSON(data []byte) (err error) {
|
||||
*encodings, err = unmarshalStringMapP[Encoding](data)
|
||||
return
|
||||
}
|
||||
|
||||
func (encoding *Encoding) WithHeader(name string, header *Header) *Encoding {
|
||||
return encoding.WithHeaderRef(name, &HeaderRef{
|
||||
Value: header,
|
||||
})
|
||||
}
|
||||
|
||||
func (encoding *Encoding) WithHeaderRef(name string, ref *HeaderRef) *Encoding {
|
||||
headers := encoding.Headers
|
||||
if headers == nil {
|
||||
headers = make(map[string]*HeaderRef)
|
||||
encoding.Headers = headers
|
||||
}
|
||||
headers[name] = ref
|
||||
return encoding
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Encoding.
|
||||
func (encoding Encoding) MarshalJSON() ([]byte, error) {
|
||||
x, err := encoding.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Encoding.
|
||||
func (encoding Encoding) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 5+len(encoding.Extensions))
|
||||
maps.Copy(m, encoding.Extensions)
|
||||
if x := encoding.ContentType; x != "" {
|
||||
m["contentType"] = x
|
||||
}
|
||||
if x := encoding.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := encoding.Style; x != "" {
|
||||
m["style"] = x
|
||||
}
|
||||
if x := encoding.Explode; x != nil {
|
||||
m["explode"] = x
|
||||
}
|
||||
if x := encoding.AllowReserved; x {
|
||||
m["allowReserved"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Encoding to a copy of data.
|
||||
func (encoding *Encoding) UnmarshalJSON(data []byte) error {
|
||||
type EncodingBis Encoding
|
||||
var x EncodingBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "contentType")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "style")
|
||||
delete(x.Extensions, "explode")
|
||||
delete(x.Extensions, "allowReserved")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*encoding = Encoding(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SerializationMethod returns a serialization method of request body.
|
||||
// When serialization method is not defined the method returns the default serialization method.
|
||||
func (encoding *Encoding) SerializationMethod() *SerializationMethod {
|
||||
sm := &SerializationMethod{Style: SerializationForm, Explode: true}
|
||||
if encoding != nil {
|
||||
if encoding.Style != "" {
|
||||
sm.Style = encoding.Style
|
||||
}
|
||||
if encoding.Explode != nil {
|
||||
sm.Explode = *encoding.Explode
|
||||
}
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
// Validate returns an error if Encoding does not comply with the OpenAPI spec.
|
||||
func (encoding *Encoding) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if encoding == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, k := range componentNames(encoding.Headers) {
|
||||
v := encoding.Headers[k]
|
||||
if err := ValidateIdentifier(k); err != nil {
|
||||
return nil
|
||||
}
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Validate a media types's serialization method.
|
||||
sm := encoding.SerializationMethod()
|
||||
switch {
|
||||
case sm.Style == SerializationForm && sm.Explode,
|
||||
sm.Style == SerializationForm && !sm.Explode,
|
||||
sm.Style == SerializationSpaceDelimited && sm.Explode,
|
||||
sm.Style == SerializationSpaceDelimited && !sm.Explode,
|
||||
sm.Style == SerializationPipeDelimited && sm.Explode,
|
||||
sm.Style == SerializationPipeDelimited && !sm.Explode,
|
||||
sm.Style == SerializationDeepObject && sm.Explode:
|
||||
default:
|
||||
return newInvalidSerializationMethod("media type", sm.Style, sm.Explode, encoding.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, encoding.Extensions, encoding.Origin)
|
||||
}
|
||||
82
vendor/github.com/getkin/kin-openapi/openapi3/error_collector.go
generated
vendored
Normal file
82
vendor/github.com/getkin/kin-openapi/openapi3/error_collector.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package openapi3
|
||||
|
||||
import "context"
|
||||
|
||||
// errCollector aggregates validation errors inside a Validate method.
|
||||
//
|
||||
// When multi-error mode is enabled (EnableMultiError), emit records the error
|
||||
// and returns nil so the caller continues to the next sibling; if the error is
|
||||
// itself a MultiError, its leaves are appended individually so the result is a
|
||||
// flat MultiError of fully-wrapped problems (this matches what most consumers
|
||||
// expect: one MultiError entry per independent problem).
|
||||
//
|
||||
// When multi-error mode is off, emit returns the error unchanged so the caller
|
||||
// fails fast, preserving the historical behavior byte-for-byte.
|
||||
//
|
||||
// emitWrapped applies wrap to err, distributing wrap over each leaf when err
|
||||
// is a MultiError. This is how validators attach per-section / per-path /
|
||||
// per-operation context to each aggregated leaf.
|
||||
//
|
||||
// result returns the accumulated MultiError, or nil if none were recorded.
|
||||
type errCollector struct {
|
||||
multi bool
|
||||
errs MultiError
|
||||
}
|
||||
|
||||
func newErrCollector(ctx context.Context) *errCollector {
|
||||
return &errCollector{multi: getValidationOptions(ctx).multiErrorEnabled}
|
||||
}
|
||||
|
||||
func (c *errCollector) emit(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !c.multi {
|
||||
return err
|
||||
}
|
||||
if me, ok := err.(MultiError); ok {
|
||||
for _, sub := range me {
|
||||
if e := c.emit(sub); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
c.errs = append(c.errs, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *errCollector) emitWrapped(wrap func(error) error, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !c.multi {
|
||||
return wrap(err)
|
||||
}
|
||||
if me, ok := err.(MultiError); ok {
|
||||
for _, sub := range me {
|
||||
if e := c.emitWrapped(wrap, sub); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return c.emit(wrap(err))
|
||||
}
|
||||
|
||||
func (c *errCollector) result() error {
|
||||
if len(c.errs) > 0 {
|
||||
return c.errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// finalize emits err (typically the last sibling validation in a container,
|
||||
// e.g. the extensions check) and returns the accumulated result. It collapses
|
||||
// the trailing emit-then-result pattern into a single line at each call site.
|
||||
func (c *errCollector) finalize(err error) error {
|
||||
if e := c.emit(err); e != nil {
|
||||
return e
|
||||
}
|
||||
return c.result()
|
||||
}
|
||||
69
vendor/github.com/getkin/kin-openapi/openapi3/errors.go
generated
vendored
Normal file
69
vendor/github.com/getkin/kin-openapi/openapi3/errors.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// MultiError is a collection of errors, intended for when
|
||||
// multiple issues need to be reported upstream
|
||||
type MultiError []error
|
||||
|
||||
func (me MultiError) Error() string {
|
||||
return spliceErr(" | ", me)
|
||||
}
|
||||
|
||||
func spliceErr(sep string, errs []error) string {
|
||||
buff := &bytes.Buffer{}
|
||||
for i, e := range errs {
|
||||
buff.WriteString(e.Error())
|
||||
if i != len(errs)-1 {
|
||||
buff.WriteString(sep)
|
||||
}
|
||||
}
|
||||
return buff.String()
|
||||
}
|
||||
|
||||
// Is allows you to determine if a generic error is in fact a MultiError using `errors.Is()`
|
||||
// It will also return true if any of the contained errors match target
|
||||
func (me MultiError) Is(target error) bool {
|
||||
if _, ok := target.(MultiError); ok {
|
||||
return true
|
||||
}
|
||||
for _, e := range me {
|
||||
if errors.Is(e, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// As allows you to use `errors.As()` to set target to the first error within the multi error that matches the target type
|
||||
func (me MultiError) As(target any) bool {
|
||||
for _, e := range me {
|
||||
if errors.As(e, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type multiErrorForOneOf MultiError
|
||||
|
||||
func (meo multiErrorForOneOf) Error() string {
|
||||
return spliceErr(" Or ", meo)
|
||||
}
|
||||
|
||||
func (meo multiErrorForOneOf) Unwrap() error {
|
||||
return MultiError(meo)
|
||||
}
|
||||
|
||||
type multiErrorForAllOf MultiError
|
||||
|
||||
func (mea multiErrorForAllOf) Error() string {
|
||||
return spliceErr(" And ", mea)
|
||||
}
|
||||
|
||||
func (mea multiErrorForAllOf) Unwrap() error {
|
||||
return MultiError(mea)
|
||||
}
|
||||
90
vendor/github.com/getkin/kin-openapi/openapi3/example.go
generated
vendored
Normal file
90
vendor/github.com/getkin/kin-openapi/openapi3/example.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Example is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#example-object
|
||||
type Example struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Value any `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
|
||||
}
|
||||
|
||||
func NewExample(value any) *Example {
|
||||
return &Example{Value: value}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Example.
|
||||
func (example Example) MarshalJSON() ([]byte, error) {
|
||||
x, err := example.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Example.
|
||||
func (example Example) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(example.Extensions))
|
||||
maps.Copy(m, example.Extensions)
|
||||
if x := example.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := example.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := example.Value; x != nil {
|
||||
m["value"] = x
|
||||
}
|
||||
if x := example.ExternalValue; x != "" {
|
||||
m["externalValue"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Example to a copy of data.
|
||||
func (example *Example) UnmarshalJSON(data []byte) error {
|
||||
type ExampleBis Example
|
||||
var x ExampleBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "value")
|
||||
delete(x.Extensions, "externalValue")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*example = Example(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Example does not comply with the OpenAPI spec.
|
||||
func (example *Example) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if example.Value != nil && example.ExternalValue != "" {
|
||||
return newExampleValueExternalValueExclusive(example.Origin)
|
||||
}
|
||||
if example.Value == nil && example.ExternalValue == "" {
|
||||
return newExampleValueOrExternalValueRequired(example.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, example.Extensions, example.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Examples to a copy of data.
|
||||
func (examples *Examples) UnmarshalJSON(data []byte) (err error) {
|
||||
*examples, err = unmarshalStringMapP[ExampleRef](data)
|
||||
return
|
||||
}
|
||||
20
vendor/github.com/getkin/kin-openapi/openapi3/example_validation.go
generated
vendored
Normal file
20
vendor/github.com/getkin/kin-openapi/openapi3/example_validation.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package openapi3
|
||||
|
||||
import "context"
|
||||
|
||||
func validateExampleValue(ctx context.Context, input any, schema *Schema) error {
|
||||
opts := []SchemaValidationOption{MultiErrors()}
|
||||
|
||||
vo := getValidationOptions(ctx)
|
||||
if vo.examplesValidationAsReq {
|
||||
opts = append(opts, VisitAsRequest())
|
||||
} else if vo.examplesValidationAsRes {
|
||||
opts = append(opts, VisitAsResponse())
|
||||
}
|
||||
|
||||
if vo.jsonSchema2020ValidationEnabled {
|
||||
opts = append(opts, EnableJSONSchema2020())
|
||||
}
|
||||
|
||||
return schema.VisitJSON(input, opts...)
|
||||
}
|
||||
36
vendor/github.com/getkin/kin-openapi/openapi3/extension.go
generated
vendored
Normal file
36
vendor/github.com/getkin/kin-openapi/openapi3/extension.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// validateExtensions reports any non-`x-` keys in the given extensions
|
||||
// map that are not explicitly allowed by the validation context. The
|
||||
// origin argument is attached to the resulting ExtraSiblingFieldsError
|
||||
// so callers can pin the finding to the parent object that carries the
|
||||
// unknown keys; pass nil when the parent has no Origin (the loader was
|
||||
// run with IncludeOrigin = false, or the parent was constructed
|
||||
// programmatically without an Origin set).
|
||||
func validateExtensions(ctx context.Context, extensions map[string]any, origin *Origin) error { // FIXME: newtype + Validate(...)
|
||||
allowed := getValidationOptions(ctx).extraSiblingFieldsAllowed
|
||||
|
||||
var unknowns []string
|
||||
for _, k := range componentNames(extensions) {
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
continue
|
||||
}
|
||||
if allowed != nil {
|
||||
if _, ok := allowed[k]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
unknowns = append(unknowns, k)
|
||||
}
|
||||
|
||||
if len(unknowns) != 0 {
|
||||
return newExtraSiblingFields(unknowns, origin)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
76
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
Normal file
76
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// ExternalDocs is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#external-documentation-object
|
||||
type ExternalDocs struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of ExternalDocs.
|
||||
func (e ExternalDocs) MarshalJSON() ([]byte, error) {
|
||||
x, err := e.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of ExternalDocs.
|
||||
func (e ExternalDocs) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 2+len(e.Extensions))
|
||||
maps.Copy(m, e.Extensions)
|
||||
if x := e.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := e.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ExternalDocs to a copy of data.
|
||||
func (e *ExternalDocs) UnmarshalJSON(data []byte) error {
|
||||
type ExternalDocsBis ExternalDocs
|
||||
var x ExternalDocsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "url")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*e = ExternalDocs(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if ExternalDocs does not comply with the OpenAPI spec.
|
||||
func (e *ExternalDocs) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if e.URL == "" {
|
||||
if err := me.emit(newExternalDocsURLRequired(e.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := url.Parse(e.URL); err != nil {
|
||||
if err := me.emit(&ExternalDocsURLValidationError{Cause: err}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, e.Extensions, e.Origin))
|
||||
}
|
||||
100
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
Normal file
100
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// Header is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#header-object
|
||||
type Header struct {
|
||||
Parameter
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Header)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (header Header) JSONLookup(token string) (any, error) {
|
||||
return header.Parameter.JSONLookup(token)
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Header.
|
||||
func (header Header) MarshalJSON() ([]byte, error) {
|
||||
return header.Parameter.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Header to a copy of data.
|
||||
func (header *Header) UnmarshalJSON(data []byte) error {
|
||||
return header.Parameter.UnmarshalJSON(data)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the JSON encoding of Header.
|
||||
func (header Header) MarshalYAML() (any, error) {
|
||||
return header.Parameter, nil
|
||||
}
|
||||
|
||||
// SerializationMethod returns a header's serialization method.
|
||||
func (header *Header) SerializationMethod() (*SerializationMethod, error) {
|
||||
style := header.Style
|
||||
if style == "" {
|
||||
style = SerializationSimple
|
||||
}
|
||||
explode := false
|
||||
if header.Explode != nil {
|
||||
explode = *header.Explode
|
||||
}
|
||||
return &SerializationMethod{Style: style, Explode: explode}, nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Header does not comply with the OpenAPI spec.
|
||||
func (header *Header) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if header.Name != "" {
|
||||
return newHeaderNameForbidden(header.Origin)
|
||||
}
|
||||
if header.In != "" {
|
||||
return newHeaderInForbidden(header.Origin)
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := header.SerializationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if smSupported := false ||
|
||||
sm.Style == SerializationSimple && !sm.Explode ||
|
||||
sm.Style == SerializationSimple && sm.Explode; !smSupported {
|
||||
e := newInvalidSerializationMethod("header", sm.Style, sm.Explode, header.Origin)
|
||||
return &HeaderFieldValidationError{Field: "schema", Cause: e}
|
||||
}
|
||||
|
||||
if (header.Schema == nil) == (len(header.Content) == 0) {
|
||||
return &HeaderFieldValidationError{Field: "schema",
|
||||
Cause: newHeaderContentSchemaExactlyOne(header, header.Origin)}
|
||||
}
|
||||
if schema := header.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return &HeaderFieldValidationError{Field: "schema", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if content := header.Content; content != nil {
|
||||
if len(content) > 1 {
|
||||
return &HeaderFieldValidationError{Field: "content",
|
||||
Cause: newHeaderContentSingleEntry(header.Origin)}
|
||||
}
|
||||
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return &HeaderFieldValidationError{Field: "content", Cause: err}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Headers to a copy of data.
|
||||
func (headers *Headers) UnmarshalJSON(data []byte) (err error) {
|
||||
*headers, err = unmarshalStringMapP[HeaderRef](data)
|
||||
return
|
||||
}
|
||||
275
vendor/github.com/getkin/kin-openapi/openapi3/helpers.go
generated
vendored
Normal file
275
vendor/github.com/getkin/kin-openapi/openapi3/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
const identifierChars = `a-zA-Z0-9._-`
|
||||
|
||||
// IdentifierRegExp verifies whether Component object key matches contains just 'identifierChars', according to OpenAPI v3.x.
|
||||
// InvalidIdentifierCharRegExp matches all characters not contained in 'identifierChars'.
|
||||
// However, to be able supporting legacy OpenAPI v2.x, there is a need to customize above pattern in order not to fail
|
||||
// converted v2-v3 validation
|
||||
var (
|
||||
IdentifierRegExp = regexp.MustCompile(`^[` + identifierChars + `]+$`)
|
||||
InvalidIdentifierCharRegExp = regexp.MustCompile(`[^` + identifierChars + `]`)
|
||||
)
|
||||
|
||||
// ValidateIdentifier returns an error if the given component name does not match [IdentifierRegExp].
|
||||
func ValidateIdentifier(value string) error {
|
||||
if IdentifierRegExp.MatchString(value) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("identifier %q is not supported by OpenAPIv3 standard (charset: [%q])", value, identifierChars)
|
||||
}
|
||||
|
||||
// Ptr is a helper for defining OpenAPI schemas.
|
||||
func Ptr[T any](value T) *T {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Float64Ptr is a helper for defining OpenAPI schemas.
|
||||
//
|
||||
// Deprecated: Use Ptr instead.
|
||||
func Float64Ptr(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// BoolPtr is a helper for defining OpenAPI schemas.
|
||||
//
|
||||
// Deprecated: Use Ptr instead.
|
||||
func BoolPtr(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Int64Ptr is a helper for defining OpenAPI schemas.
|
||||
//
|
||||
// Deprecated: Use Ptr instead.
|
||||
func Int64Ptr(value int64) *int64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Uint64Ptr is a helper for defining OpenAPI schemas.
|
||||
//
|
||||
// Deprecated: Use Ptr instead.
|
||||
func Uint64Ptr(value uint64) *uint64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// componentNames returns the map keys in a sorted slice.
|
||||
func componentNames[E any](s map[string]E) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
}
|
||||
slices.Sort(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// copyURI makes a copy of the pointer.
|
||||
func copyURI(u *url.URL) *url.URL {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := *u // shallow-copy
|
||||
return &c
|
||||
}
|
||||
|
||||
type ComponentRef interface {
|
||||
RefString() string
|
||||
RefPath() *url.URL
|
||||
CollectionName() string
|
||||
}
|
||||
|
||||
// refersToSameDocument returns if the $ref refers to the same document.
|
||||
//
|
||||
// Documents in different directories will have distinct $ref values that resolve to
|
||||
// the same document.
|
||||
// For example, consider the 3 files:
|
||||
//
|
||||
// /records.yaml
|
||||
// /root.yaml $ref: records.yaml
|
||||
// /schema/other.yaml $ref: ../records.yaml
|
||||
//
|
||||
// The records.yaml reference in the 2 latter refers to the same document.
|
||||
func refersToSameDocument(o1 ComponentRef, o2 ComponentRef) bool {
|
||||
if o1 == nil || o2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r1 := o1.RefPath()
|
||||
r2 := o2.RefPath()
|
||||
|
||||
if r1 == nil || r2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// refURL is relative to the working directory & base spec file.
|
||||
return referenceURIMatch(r1, r2)
|
||||
}
|
||||
|
||||
// referencesRootDocument returns if the $ref points to the root document of the OpenAPI spec.
|
||||
//
|
||||
// If the document has no location, perhaps loaded from data in memory, it always returns false.
|
||||
func referencesRootDocument(doc *T, ref ComponentRef) bool {
|
||||
if doc.url == nil || ref == nil || ref.RefPath() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
refURL := *ref.RefPath()
|
||||
refURL.Fragment = ""
|
||||
|
||||
// Check referenced element was in the root document.
|
||||
return referenceURIMatch(doc.url, &refURL)
|
||||
}
|
||||
|
||||
func referenceURIMatch(u1 *url.URL, u2 *url.URL) bool {
|
||||
s1, s2 := *u1, *u2
|
||||
if s1.Scheme == "" {
|
||||
s1.Scheme = "file"
|
||||
}
|
||||
if s2.Scheme == "" {
|
||||
s2.Scheme = "file"
|
||||
}
|
||||
|
||||
return s1.String() == s2.String()
|
||||
}
|
||||
|
||||
// ReferencesComponentInRootDocument returns if the given component reference references
|
||||
// the same document or element as another component reference in the root document's
|
||||
// '#/components/<type>'. If it does, it returns the name of it in the form
|
||||
// '#/components/<type>/NameXXX'
|
||||
//
|
||||
// Of course given a component from the root document will always match itself.
|
||||
//
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#reference-object
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#relative-references-in-urls
|
||||
//
|
||||
// Example. Take the spec with directory structure:
|
||||
//
|
||||
// openapi.yaml
|
||||
// schemas/
|
||||
// ├─ record.yaml
|
||||
// ├─ records.yaml
|
||||
//
|
||||
// In openapi.yaml we have:
|
||||
//
|
||||
// components:
|
||||
// schemas:
|
||||
// Record:
|
||||
// $ref: schemas/record.yaml
|
||||
//
|
||||
// Case 1: records.yml references a component in the root document
|
||||
//
|
||||
// $ref: ../openapi.yaml#/components/schemas/Record
|
||||
//
|
||||
// This would return...
|
||||
//
|
||||
// #/components/schemas/Record
|
||||
//
|
||||
// Case 2: records.yml indirectly refers to the same schema
|
||||
// as a schema the root document's '#/components/schemas'.
|
||||
//
|
||||
// $ref: ./record.yaml
|
||||
//
|
||||
// This would also return...
|
||||
//
|
||||
// #/components/schemas/Record
|
||||
func ReferencesComponentInRootDocument(doc *T, ref ComponentRef) (string, bool) {
|
||||
if ref == nil || ref.RefString() == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Case 1:
|
||||
// Something like: ../another-folder/document.json#/myElement
|
||||
if isRemoteReference(ref.RefString()) && isRootComponentReference(ref.RefString(), ref.CollectionName()) {
|
||||
// Determine if it is *this* root doc.
|
||||
if referencesRootDocument(doc, ref) {
|
||||
_, name, _ := strings.Cut(ref.RefString(), path.Join("#/components/", ref.CollectionName()))
|
||||
|
||||
return path.Join("#/components/", ref.CollectionName(), name), true
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no schemas defined in the root document return early.
|
||||
if doc.Components == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
collection, _, err := jsonpointer.GetForToken(doc.Components, ref.CollectionName())
|
||||
if err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
|
||||
var components map[string]ComponentRef
|
||||
|
||||
componentRefType := reflect.TypeFor[ComponentRef]()
|
||||
if t := reflect.TypeOf(collection); t.Kind() == reflect.Map &&
|
||||
t.Key().Kind() == reflect.String &&
|
||||
t.Elem().AssignableTo(componentRefType) {
|
||||
v := reflect.ValueOf(collection)
|
||||
|
||||
components = make(map[string]ComponentRef, v.Len())
|
||||
for _, key := range v.MapKeys() {
|
||||
strct := v.MapIndex(key)
|
||||
// Type assertion safe, already checked via reflection above.
|
||||
components[key.Interface().(string)] = strct.Interface().(ComponentRef)
|
||||
}
|
||||
} else {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Case 2:
|
||||
// Something like: ../openapi.yaml#/components/schemas/myElement
|
||||
for _, name := range componentNames(components) {
|
||||
s := components[name]
|
||||
// Must be a reference to a YAML file.
|
||||
if !isWholeDocumentReference(s.RefString()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Is the schema a ref to the same resource.
|
||||
if !refersToSameDocument(s, ref) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Transform the remote ref to the equivalent schema in the root document.
|
||||
return path.Join("#/components/", ref.CollectionName(), name), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// isElementReference takes a $ref value and checks if it references a specific element.
|
||||
func isElementReference(ref string) bool {
|
||||
return ref != "" && !isWholeDocumentReference(ref)
|
||||
}
|
||||
|
||||
// isSchemaReference takes a $ref value and checks if it references a schema element.
|
||||
func isRootComponentReference(ref string, compType string) bool {
|
||||
return isElementReference(ref) && strings.Contains(ref, path.Join("#/components/", compType))
|
||||
}
|
||||
|
||||
// isWholeDocumentReference takes a $ref value and checks if it is whole document reference.
|
||||
func isWholeDocumentReference(ref string) bool {
|
||||
return ref != "" && !strings.ContainsAny(ref, "#")
|
||||
}
|
||||
|
||||
// isRemoteReference takes a $ref value and checks if it is remote reference.
|
||||
func isRemoteReference(ref string) bool {
|
||||
return ref != "" && !strings.HasPrefix(ref, "#") && !isURLReference(ref)
|
||||
}
|
||||
|
||||
// isURLReference takes a $ref value and checks if it is URL reference.
|
||||
func isURLReference(ref string) bool {
|
||||
return strings.HasPrefix(ref, "http://") || strings.HasPrefix(ref, "https://") || strings.HasPrefix(ref, "//")
|
||||
}
|
||||
119
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
Normal file
119
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Info is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#info-object
|
||||
// and https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#info-object
|
||||
type Info struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Title string `json:"title" yaml:"title"` // Required
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` // OpenAPI >=3.1
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
|
||||
Contact *Contact `json:"contact,omitempty" yaml:"contact,omitempty"`
|
||||
License *License `json:"license,omitempty" yaml:"license,omitempty"`
|
||||
Version string `json:"version" yaml:"version"` // Required
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Info.
|
||||
func (info Info) MarshalJSON() ([]byte, error) {
|
||||
x, err := info.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Info.
|
||||
func (info *Info) MarshalYAML() (any, error) {
|
||||
if info == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, 7+len(info.Extensions))
|
||||
maps.Copy(m, info.Extensions)
|
||||
m["title"] = info.Title
|
||||
if x := info.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := info.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := info.TermsOfService; x != "" {
|
||||
m["termsOfService"] = x
|
||||
}
|
||||
if x := info.Contact; x != nil {
|
||||
m["contact"] = x
|
||||
}
|
||||
if x := info.License; x != nil {
|
||||
m["license"] = x
|
||||
}
|
||||
m["version"] = info.Version
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Info to a copy of data.
|
||||
func (info *Info) UnmarshalJSON(data []byte) error {
|
||||
type InfoBis Info
|
||||
var x InfoBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "title")
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "termsOfService")
|
||||
delete(x.Extensions, "contact")
|
||||
delete(x.Extensions, "license")
|
||||
delete(x.Extensions, "version")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*info = Info(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Info does not comply with the OpenAPI spec.
|
||||
func (info *Info) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if info.Summary != "" && !getValidationOptions(ctx).isOpenAPI31OrLater {
|
||||
if err := me.emit(newInfoSummaryFieldFor31Plus(info.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if contact := info.Contact; contact != nil {
|
||||
if err := me.emit(contact.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if license := info.License; license != nil {
|
||||
if err := me.emit(license.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if info.Version == "" {
|
||||
if err := me.emit(newInfoVersionRequired(info.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if info.Title == "" {
|
||||
if err := me.emit(newInfoTitleRequired(info.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, info.Extensions, info.Origin))
|
||||
}
|
||||
551
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
Normal file
551
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
Normal file
@@ -0,0 +1,551 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RefNameResolver maps a component to a name that is used as it's internalized name.
|
||||
//
|
||||
// The function should avoid name collisions (i.e. be a injective mapping).
|
||||
// It must only contain characters valid for fixed field names: [IdentifierRegExp].
|
||||
type RefNameResolver func(*T, ComponentRef) string
|
||||
|
||||
// DefaultRefResolver is a default implementation of refNameResolver for the
|
||||
// InternalizeRefs function.
|
||||
//
|
||||
// The external reference is internalized to (hopefully) a unique name. If
|
||||
// the external reference matches (by path) to another reference in the root
|
||||
// document then the name of that component is used.
|
||||
//
|
||||
// The transformation involves:
|
||||
// - Cutting the "#/components/<type>" part.
|
||||
// - Cutting the file extensions (.yaml/.json) from documents.
|
||||
// - Trimming the common directory with the root spec.
|
||||
// - Replace invalid characters with underscores.
|
||||
//
|
||||
// This is an injective mapping over a "reasonable" amount of the possible openapi
|
||||
// spec domain space but is not perfect. There might be edge cases.
|
||||
func DefaultRefNameResolver(doc *T, ref ComponentRef) string {
|
||||
if ref.RefString() == "" || ref.RefPath() == nil {
|
||||
panic("unable to resolve reference to name")
|
||||
}
|
||||
|
||||
name := ref.RefPath()
|
||||
|
||||
// If referring to a component in the root spec, no need to internalize just use
|
||||
// the existing component.
|
||||
// XXX(percivalalb): since this function call is iterating over components behind the
|
||||
// scenes during an internalization call it actually starts interating over
|
||||
// new & replaced internalized components. This might caused some edge cases,
|
||||
// haven't found one yet but this might need to actually be used on a frozen copy
|
||||
// of doc.
|
||||
if nameInRoot, found := ReferencesComponentInRootDocument(doc, ref); found {
|
||||
nameInRoot = strings.TrimPrefix(nameInRoot, "#")
|
||||
|
||||
rootCompURI := copyURI(doc.url)
|
||||
rootCompURI.Fragment = nameInRoot
|
||||
name = rootCompURI
|
||||
}
|
||||
|
||||
filePath, componentPath := name.Path, name.Fragment
|
||||
|
||||
// Cut out the "#/components/<type>" to make the names shorter.
|
||||
// XXX(percivalalb): This might cause collisions but is worth the brevity.
|
||||
if b, a, ok := strings.Cut(componentPath, path.Join("components", ref.CollectionName(), "")); ok {
|
||||
componentPath = path.Join(b, a)
|
||||
}
|
||||
|
||||
if filePath != "" {
|
||||
// If the path is the same as the root doc, just remove.
|
||||
if doc.url != nil && filePath == doc.url.Path {
|
||||
filePath = ""
|
||||
}
|
||||
|
||||
// Remove the path extensions to make this JSON/YAML agnostic.
|
||||
for ext := path.Ext(filePath); len(ext) > 0; ext = path.Ext(filePath) {
|
||||
filePath = strings.TrimSuffix(filePath, ext)
|
||||
}
|
||||
|
||||
// Trim the common prefix with the root doc path.
|
||||
if doc.url != nil {
|
||||
for commonDir := path.Dir(doc.url.Path); /*no common prefix*/ commonDir != "."; commonDir = path.Dir(commonDir) {
|
||||
if p, found := cutDirectories(filePath, commonDir); found {
|
||||
filePath = p
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var internalizedName string
|
||||
|
||||
// Trim .'s & slashes from start e.g. otherwise ./doc.yaml would end up as __doc
|
||||
if filePath != "" {
|
||||
internalizedName = strings.TrimLeft(filePath, "./")
|
||||
}
|
||||
|
||||
if componentPath != "" {
|
||||
if internalizedName != "" {
|
||||
internalizedName += "_"
|
||||
}
|
||||
|
||||
internalizedName += strings.TrimLeft(componentPath, "./")
|
||||
}
|
||||
|
||||
// Replace invalid characters in component fixed field names.
|
||||
internalizedName = InvalidIdentifierCharRegExp.ReplaceAllString(internalizedName, "_")
|
||||
|
||||
return internalizedName
|
||||
}
|
||||
|
||||
// cutDirectories removes the given directories from the start of the path if
|
||||
// the path is a child.
|
||||
func cutDirectories(p, dirs string) (string, bool) {
|
||||
if dirs == "" || p == "" {
|
||||
return p, false
|
||||
}
|
||||
|
||||
p = strings.TrimRight(p, "/")
|
||||
dirs = strings.TrimRight(dirs, "/")
|
||||
|
||||
var sb strings.Builder
|
||||
sb.Grow(len(ParameterInHeader))
|
||||
for segments := range strings.SplitSeq(p, "/") {
|
||||
sb.WriteString(segments)
|
||||
|
||||
if sb.String() == p {
|
||||
return strings.TrimPrefix(p, dirs), true
|
||||
}
|
||||
|
||||
sb.WriteRune('/')
|
||||
}
|
||||
|
||||
return p, false
|
||||
}
|
||||
|
||||
func isExternalRef(ref string, parentIsExternal bool) bool {
|
||||
return ref != "" && (!strings.HasPrefix(ref, "#/components/") || parentIsExternal)
|
||||
}
|
||||
|
||||
func (doc *T) addSchemaToSpec(s *SchemaRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if s == nil || !isExternalRef(s.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
|
||||
name := refNameResolver(doc, s)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Schemas[name]; ok {
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Schemas == nil {
|
||||
doc.Components.Schemas = make(Schemas)
|
||||
}
|
||||
doc.Components.Schemas[name] = s.Value.NewRef()
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addParameterToSpec(p *ParameterRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if p == nil || !isExternalRef(p.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(doc, p)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Parameters[name]; ok {
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Parameters == nil {
|
||||
doc.Components.Parameters = make(ParametersMap)
|
||||
}
|
||||
doc.Components.Parameters[name] = &ParameterRef{Value: p.Value}
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addHeaderToSpec(h *HeaderRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if h == nil || !isExternalRef(h.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(doc, h)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Headers[name]; ok {
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Headers == nil {
|
||||
doc.Components.Headers = make(Headers)
|
||||
}
|
||||
doc.Components.Headers[name] = &HeaderRef{Value: h.Value}
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addRequestBodyToSpec(r *RequestBodyRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if r == nil || !isExternalRef(r.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(doc, r)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.RequestBodies[name]; ok {
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.RequestBodies == nil {
|
||||
doc.Components.RequestBodies = make(RequestBodies)
|
||||
}
|
||||
doc.Components.RequestBodies[name] = &RequestBodyRef{Value: r.Value}
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addResponseToSpec(r *ResponseRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if r == nil || !isExternalRef(r.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(doc, r)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Responses[name]; ok {
|
||||
r.Ref = "#/components/responses/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Responses == nil {
|
||||
doc.Components.Responses = make(ResponseBodies)
|
||||
}
|
||||
doc.Components.Responses[name] = &ResponseRef{Value: r.Value}
|
||||
r.Ref = "#/components/responses/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addSecuritySchemeToSpec(ss *SecuritySchemeRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if ss == nil || !isExternalRef(ss.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(doc, ss)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.SecuritySchemes[name]; ok {
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.SecuritySchemes == nil {
|
||||
doc.Components.SecuritySchemes = make(SecuritySchemes)
|
||||
}
|
||||
doc.Components.SecuritySchemes[name] = &SecuritySchemeRef{Value: ss.Value}
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addExampleToSpec(e *ExampleRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if e == nil || !isExternalRef(e.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(doc, e)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Examples[name]; ok {
|
||||
e.Ref = "#/components/examples/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Examples == nil {
|
||||
doc.Components.Examples = make(Examples)
|
||||
}
|
||||
doc.Components.Examples[name] = &ExampleRef{Value: e.Value}
|
||||
e.Ref = "#/components/examples/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addLinkToSpec(l *LinkRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if l == nil || !isExternalRef(l.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(doc, l)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Links[name]; ok {
|
||||
l.Ref = "#/components/links/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Links == nil {
|
||||
doc.Components.Links = make(Links)
|
||||
}
|
||||
doc.Components.Links[name] = &LinkRef{Value: l.Value}
|
||||
l.Ref = "#/components/links/" + name
|
||||
|
||||
}
|
||||
|
||||
func (doc *T) addCallbackToSpec(c *CallbackRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if c == nil || !isExternalRef(c.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(doc, c)
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Callbacks == nil {
|
||||
doc.Components.Callbacks = make(Callbacks)
|
||||
}
|
||||
c.Ref = "#/components/callbacks/" + name
|
||||
doc.Components.Callbacks[name] = &CallbackRef{Value: c.Value}
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) derefSchema(s *Schema, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if s == nil || doc.isVisitedSchema(s) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, list := range []SchemaRefs{s.AllOf, s.AnyOf, s.OneOf} {
|
||||
for _, s2 := range list {
|
||||
isExternal := doc.addSchemaToSpec(s2, refNameResolver, parentIsExternal)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discriminator mapping values are special cases since they are not full
|
||||
// ref objects but are string references to schema objects.
|
||||
if s.Discriminator != nil {
|
||||
for _, k := range componentNames(s.Discriminator.Mapping) {
|
||||
mapRef := s.Discriminator.Mapping[k]
|
||||
s2 := (*SchemaRef)(&mapRef)
|
||||
isExternal := doc.addSchemaToSpec(s2, refNameResolver, parentIsExternal)
|
||||
doc.derefSchema(s2.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
s.Discriminator.Mapping[k] = MappingRef(*s2)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range componentNames(s.Properties) {
|
||||
s2 := s.Properties[name]
|
||||
isExternal := doc.addSchemaToSpec(s2, refNameResolver, parentIsExternal)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
for _, ref := range []*SchemaRef{s.Not, s.AdditionalProperties.Schema, s.Items} {
|
||||
isExternal := doc.addSchemaToSpec(ref, refNameResolver, parentIsExternal)
|
||||
if ref != nil {
|
||||
doc.derefSchema(ref.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefHeaders(hs Headers, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(hs) {
|
||||
h := hs[name]
|
||||
isExternal := doc.addHeaderToSpec(h, refNameResolver, parentIsExternal)
|
||||
if doc.isVisitedHeader(h.Value) {
|
||||
continue
|
||||
}
|
||||
doc.derefParameter(h.Value.Parameter, refNameResolver, parentIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefExamples(es Examples, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(es) {
|
||||
e := es[name]
|
||||
doc.addExampleToSpec(e, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefContent(c Content, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(c) {
|
||||
mediatype := c[name]
|
||||
isExternal := doc.addSchemaToSpec(mediatype.Schema, refNameResolver, parentIsExternal)
|
||||
if mediatype.Schema != nil {
|
||||
doc.derefSchema(mediatype.Schema.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
doc.derefExamples(mediatype.Examples, refNameResolver, parentIsExternal)
|
||||
for _, name := range componentNames(mediatype.Encoding) {
|
||||
e := mediatype.Encoding[name]
|
||||
doc.derefHeaders(e.Headers, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefLinks(ls Links, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(ls) {
|
||||
l := ls[name]
|
||||
doc.addLinkToSpec(l, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefResponse(r *ResponseRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
isExternal := doc.addResponseToSpec(r, refNameResolver, parentIsExternal)
|
||||
if v := r.Value; v != nil {
|
||||
doc.derefHeaders(v.Headers, refNameResolver, isExternal || parentIsExternal)
|
||||
doc.derefContent(v.Content, refNameResolver, isExternal || parentIsExternal)
|
||||
doc.derefLinks(v.Links, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefResponses(rs *Responses, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
doc.derefResponseBodies(rs.Map(), refNameResolver, parentIsExternal)
|
||||
}
|
||||
|
||||
func (doc *T) derefResponseBodies(es ResponseBodies, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(es) {
|
||||
e := es[name]
|
||||
doc.derefResponse(e, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefParameter(p Parameter, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
isExternal := doc.addSchemaToSpec(p.Schema, refNameResolver, parentIsExternal)
|
||||
doc.derefContent(p.Content, refNameResolver, parentIsExternal)
|
||||
if p.Schema != nil {
|
||||
doc.derefSchema(p.Schema.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefRequestBody(r RequestBody, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
doc.derefContent(r.Content, refNameResolver, parentIsExternal)
|
||||
}
|
||||
|
||||
func (doc *T) derefPaths(paths map[string]*PathItem, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(paths) {
|
||||
ops := paths[name]
|
||||
pathIsExternal := isExternalRef(ops.Ref, parentIsExternal)
|
||||
// inline full operations
|
||||
ops.Ref = ""
|
||||
|
||||
for _, param := range ops.Parameters {
|
||||
isExternal := doc.addParameterToSpec(param, refNameResolver, pathIsExternal)
|
||||
if param.Value != nil {
|
||||
doc.derefParameter(*param.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
|
||||
opsWithMethod := ops.Operations()
|
||||
for _, name := range componentNames(opsWithMethod) {
|
||||
op := opsWithMethod[name]
|
||||
isExternal := doc.addRequestBodyToSpec(op.RequestBody, refNameResolver, pathIsExternal)
|
||||
if op.RequestBody != nil && op.RequestBody.Value != nil {
|
||||
doc.derefRequestBody(*op.RequestBody.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
for _, name := range componentNames(op.Callbacks) {
|
||||
cb := op.Callbacks[name]
|
||||
isExternal := doc.addCallbackToSpec(cb, refNameResolver, pathIsExternal)
|
||||
if cb.Value != nil {
|
||||
cbValue := (*cb.Value).Map()
|
||||
doc.derefPaths(cbValue, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
doc.derefResponses(op.Responses, refNameResolver, pathIsExternal)
|
||||
for _, param := range op.Parameters {
|
||||
isExternal := doc.addParameterToSpec(param, refNameResolver, pathIsExternal)
|
||||
if param.Value != nil {
|
||||
doc.derefParameter(*param.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InternalizeRefs removes all references to external files from the spec and moves them
|
||||
// to the components section.
|
||||
//
|
||||
// refNameResolver takes in references to returns a name to store the reference under locally.
|
||||
// It MUST return a unique name for each reference type.
|
||||
// A default implementation is provided that will suffice for most use cases. See the function
|
||||
// documentation for more details.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// doc.InternalizeRefs(context.Background(), nil)
|
||||
func (doc *T) InternalizeRefs(ctx context.Context, refNameResolver func(*T, ComponentRef) string) {
|
||||
doc.resetVisited()
|
||||
|
||||
if refNameResolver == nil {
|
||||
refNameResolver = DefaultRefNameResolver
|
||||
}
|
||||
|
||||
if components := doc.Components; components != nil {
|
||||
for _, name := range componentNames(components.Schemas) {
|
||||
schema := components.Schemas[name]
|
||||
isExternal := doc.addSchemaToSpec(schema, refNameResolver, false)
|
||||
if schema != nil {
|
||||
schema.Ref = "" // always dereference the top level
|
||||
doc.derefSchema(schema.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
for _, name := range componentNames(components.Parameters) {
|
||||
p := components.Parameters[name]
|
||||
isExternal := doc.addParameterToSpec(p, refNameResolver, false)
|
||||
if p != nil && p.Value != nil {
|
||||
p.Ref = "" // always dereference the top level
|
||||
doc.derefParameter(*p.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
doc.derefHeaders(components.Headers, refNameResolver, false)
|
||||
for _, name := range componentNames(components.RequestBodies) {
|
||||
req := components.RequestBodies[name]
|
||||
isExternal := doc.addRequestBodyToSpec(req, refNameResolver, false)
|
||||
if req != nil && req.Value != nil {
|
||||
req.Ref = "" // always dereference the top level
|
||||
doc.derefRequestBody(*req.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
doc.derefResponseBodies(components.Responses, refNameResolver, false)
|
||||
for _, name := range componentNames(components.SecuritySchemes) {
|
||||
ss := components.SecuritySchemes[name]
|
||||
doc.addSecuritySchemeToSpec(ss, refNameResolver, false)
|
||||
}
|
||||
doc.derefExamples(components.Examples, refNameResolver, false)
|
||||
doc.derefLinks(components.Links, refNameResolver, false)
|
||||
|
||||
for _, name := range componentNames(components.Callbacks) {
|
||||
cb := components.Callbacks[name]
|
||||
isExternal := doc.addCallbackToSpec(cb, refNameResolver, false)
|
||||
if cb != nil && cb.Value != nil {
|
||||
cb.Ref = "" // always dereference the top level
|
||||
cbValue := (*cb.Value).Map()
|
||||
doc.derefPaths(cbValue, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc.derefPaths(doc.Paths.Map(), refNameResolver, false)
|
||||
}
|
||||
89
vendor/github.com/getkin/kin-openapi/openapi3/license.go
generated
vendored
Normal file
89
vendor/github.com/getkin/kin-openapi/openapi3/license.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// License is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#license-object
|
||||
// and https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#license-object
|
||||
type License struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Name string `json:"name" yaml:"name"` // Required
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
|
||||
// Identifier is an SPDX license expression for the API (OpenAPI 3.1)
|
||||
// Either url or identifier can be specified, not both
|
||||
Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"` // OpenAPI >=3.1
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of License.
|
||||
func (license License) MarshalJSON() ([]byte, error) {
|
||||
x, err := license.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of License.
|
||||
func (license License) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(license.Extensions))
|
||||
maps.Copy(m, license.Extensions)
|
||||
m["name"] = license.Name
|
||||
if x := license.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
if x := license.Identifier; x != "" {
|
||||
m["identifier"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets License to a copy of data.
|
||||
func (license *License) UnmarshalJSON(data []byte) error {
|
||||
type LicenseBis License
|
||||
var x LicenseBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "url")
|
||||
delete(x.Extensions, "identifier")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*license = License(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if License does not comply with the OpenAPI spec.
|
||||
func (license *License) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if license.Identifier != "" && !getValidationOptions(ctx).isOpenAPI31OrLater {
|
||||
if err := me.emit(newLicenseIdentifierFieldFor31Plus(license.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if license.Name == "" {
|
||||
if err := me.emit(newLicenseNameRequired(license.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if license.URL != "" && license.Identifier != "" {
|
||||
if err := me.emit(newLicenseURLIdentifierExclusive(license.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, license.Extensions, license.Origin))
|
||||
}
|
||||
99
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
Normal file
99
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Link is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#link-object
|
||||
type Link struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Parameters map[string]any `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
RequestBody any `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Link.
|
||||
func (link Link) MarshalJSON() ([]byte, error) {
|
||||
x, err := link.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Link.
|
||||
func (link Link) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 6+len(link.Extensions))
|
||||
maps.Copy(m, link.Extensions)
|
||||
|
||||
if x := link.OperationRef; x != "" {
|
||||
m["operationRef"] = x
|
||||
}
|
||||
if x := link.OperationID; x != "" {
|
||||
m["operationId"] = x
|
||||
}
|
||||
if x := link.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := link.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := link.Server; x != nil {
|
||||
m["server"] = x
|
||||
}
|
||||
if x := link.RequestBody; x != nil {
|
||||
m["requestBody"] = x
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Link to a copy of data.
|
||||
func (link *Link) UnmarshalJSON(data []byte) error {
|
||||
type LinkBis Link
|
||||
var x LinkBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "operationRef")
|
||||
delete(x.Extensions, "operationId")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "server")
|
||||
delete(x.Extensions, "requestBody")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*link = Link(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Link does not comply with the OpenAPI spec.
|
||||
func (link *Link) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if link.OperationID == "" && link.OperationRef == "" {
|
||||
return newLinkOperationIDOrRefRequired(link.Origin)
|
||||
}
|
||||
if link.OperationID != "" && link.OperationRef != "" {
|
||||
return newLinkOperationIDRefExclusive(link.OperationID, link.OperationRef, link.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, link.Extensions, link.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Links to a copy of data.
|
||||
func (links *Links) UnmarshalJSON(data []byte) (err error) {
|
||||
*links, err = unmarshalStringMapP[LinkRef](data)
|
||||
return
|
||||
}
|
||||
1503
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
Normal file
1503
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
117
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
Normal file
117
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ReadFromURIFunc defines a function which reads the contents of a resource
|
||||
// located at a URI.
|
||||
type ReadFromURIFunc func(loader *Loader, url *url.URL) ([]byte, error)
|
||||
|
||||
var uriMu = &sync.RWMutex{}
|
||||
|
||||
// ErrURINotSupported indicates the ReadFromURIFunc does not know how to handle a
|
||||
// given URI.
|
||||
var ErrURINotSupported = errors.New("unsupported URI")
|
||||
|
||||
// ReadFromURIs returns a ReadFromURIFunc which tries to read a URI using the
|
||||
// given reader functions, in the same order. If a reader function does not
|
||||
// support the URI and returns ErrURINotSupported, the next function is checked
|
||||
// until a match is found, or the URI is not supported by any.
|
||||
func ReadFromURIs(readers ...ReadFromURIFunc) ReadFromURIFunc {
|
||||
return func(loader *Loader, url *url.URL) ([]byte, error) {
|
||||
for i := range readers {
|
||||
buf, err := readers[i](loader, url)
|
||||
if err == ErrURINotSupported {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultReadFromURI returns a caching ReadFromURIFunc which can read remote
|
||||
// HTTP URIs and local file URIs.
|
||||
var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))
|
||||
|
||||
// ReadFromHTTP returns a ReadFromURIFunc which uses the given http.Client to
|
||||
// read the contents from a remote HTTP URI. This client may be customized to
|
||||
// implement timeouts, RFC 7234 caching, etc.
|
||||
func ReadFromHTTP(cl *http.Client) ReadFromURIFunc {
|
||||
return func(loader *Loader, location *url.URL) ([]byte, error) {
|
||||
if location.Scheme == "" || location.Host == "" {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
req, err := http.NewRequest("GET", location.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := cl.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode > 399 {
|
||||
return nil, fmt.Errorf("error loading %q: request returned status code %d", location.String(), resp.StatusCode)
|
||||
}
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
}
|
||||
|
||||
func is_file(location *url.URL) bool {
|
||||
return location.Path != "" &&
|
||||
location.Host == "" &&
|
||||
(location.Scheme == "" || location.Scheme == "file")
|
||||
}
|
||||
|
||||
// ReadFromFile is a ReadFromURIFunc which reads local file URIs.
|
||||
func ReadFromFile(loader *Loader, location *url.URL) ([]byte, error) {
|
||||
if !is_file(location) {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
return os.ReadFile(path.Clean(filepath.FromSlash(location.Path)))
|
||||
}
|
||||
|
||||
// URIMapCache returns a ReadFromURIFunc that caches the contents read from URI
|
||||
// locations in a simple map. This cache implementation is suitable for
|
||||
// short-lived processes such as command-line tools which process OpenAPI
|
||||
// documents.
|
||||
func URIMapCache(reader ReadFromURIFunc) ReadFromURIFunc {
|
||||
cache := map[string][]byte{}
|
||||
return func(loader *Loader, location *url.URL) (buf []byte, err error) {
|
||||
if location.Scheme == "" || location.Scheme == "file" {
|
||||
if !filepath.IsAbs(location.Path) {
|
||||
// Do not cache relative file paths; this can cause trouble if
|
||||
// the current working directory changes when processing
|
||||
// multiple top-level documents.
|
||||
return reader(loader, location)
|
||||
}
|
||||
}
|
||||
uri := location.String()
|
||||
var ok bool
|
||||
uriMu.RLock()
|
||||
if buf, ok = cache[uri]; ok {
|
||||
uriMu.RUnlock()
|
||||
return
|
||||
}
|
||||
uriMu.RUnlock()
|
||||
if buf, err = reader(loader, location); err != nil {
|
||||
return
|
||||
}
|
||||
uriMu.Lock()
|
||||
defer uriMu.Unlock()
|
||||
cache[uri] = buf
|
||||
return
|
||||
}
|
||||
}
|
||||
384
vendor/github.com/getkin/kin-openapi/openapi3/maplike.go
generated
vendored
Normal file
384
vendor/github.com/getkin/kin-openapi/openapi3/maplike.go
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// NewResponsesWithCapacity builds a responses object of the given capacity.
|
||||
func NewResponsesWithCapacity(cap int) *Responses {
|
||||
if cap == 0 {
|
||||
return &Responses{m: make(map[string]*ResponseRef)}
|
||||
}
|
||||
return &Responses{m: make(map[string]*ResponseRef, cap)}
|
||||
}
|
||||
|
||||
// Keys returns the responses keys in a fixed order
|
||||
func (responses *Responses) Keys() []string {
|
||||
return componentNames(responses.Map())
|
||||
}
|
||||
|
||||
// Value returns the responses for key or nil
|
||||
func (responses *Responses) Value(key string) *ResponseRef {
|
||||
if responses.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return responses.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'responses' with 'value'.
|
||||
// Note: 'responses' MUST be non-nil
|
||||
func (responses *Responses) Set(key string, value *ResponseRef) {
|
||||
if responses.m == nil {
|
||||
responses.m = make(map[string]*ResponseRef)
|
||||
}
|
||||
responses.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in responses excluding responses.Extensions.
|
||||
func (responses *Responses) Len() int {
|
||||
if responses == nil || responses.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(responses.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'responses'.
|
||||
func (responses *Responses) Delete(key string) {
|
||||
if responses != nil && responses.m != nil {
|
||||
delete(responses.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns responses as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (responses *Responses) Map() (m map[string]*ResponseRef) {
|
||||
if responses == nil || len(responses.m) == 0 {
|
||||
return make(map[string]*ResponseRef)
|
||||
}
|
||||
m = make(map[string]*ResponseRef, len(responses.m))
|
||||
maps.Copy(m, responses.m)
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Responses)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (responses Responses) JSONLookup(token string) (any, error) {
|
||||
if v := responses.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(responses.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v.Value, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Responses.
|
||||
func (responses *Responses) MarshalYAML() (any, error) {
|
||||
if responses == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, responses.Len()+len(responses.Extensions))
|
||||
maps.Copy(m, responses.Extensions)
|
||||
for _, k := range responses.Keys() {
|
||||
m[k] = responses.m[k]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Responses.
|
||||
func (responses *Responses) MarshalJSON() ([]byte, error) {
|
||||
responsesYaml, err := responses.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(responsesYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Responses to a copy of data.
|
||||
func (responses *Responses) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
x := Responses{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*ResponseRef, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range componentNames(m) {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv ResponseRef
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*responses = x
|
||||
return
|
||||
}
|
||||
|
||||
// NewCallbackWithCapacity builds a callback object of the given capacity.
|
||||
func NewCallbackWithCapacity(cap int) *Callback {
|
||||
if cap == 0 {
|
||||
return &Callback{m: make(map[string]*PathItem)}
|
||||
}
|
||||
return &Callback{m: make(map[string]*PathItem, cap)}
|
||||
}
|
||||
|
||||
// Keys returns the callback keys in a fixed order
|
||||
func (callback *Callback) Keys() []string {
|
||||
return componentNames(callback.Map())
|
||||
}
|
||||
|
||||
// Value returns the callback for key or nil
|
||||
func (callback *Callback) Value(key string) *PathItem {
|
||||
if callback.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return callback.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'callback' with 'value'.
|
||||
// Note: 'callback' MUST be non-nil
|
||||
func (callback *Callback) Set(key string, value *PathItem) {
|
||||
if callback.m == nil {
|
||||
callback.m = make(map[string]*PathItem)
|
||||
}
|
||||
callback.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in callback excluding callback.Extensions.
|
||||
func (callback *Callback) Len() int {
|
||||
if callback == nil || callback.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(callback.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'callback'.
|
||||
func (callback *Callback) Delete(key string) {
|
||||
if callback != nil && callback.m != nil {
|
||||
delete(callback.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns callback as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (callback *Callback) Map() (m map[string]*PathItem) {
|
||||
if callback == nil || len(callback.m) == 0 {
|
||||
return make(map[string]*PathItem)
|
||||
}
|
||||
m = make(map[string]*PathItem, len(callback.m))
|
||||
maps.Copy(m, callback.m)
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Callback)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (callback Callback) JSONLookup(token string) (any, error) {
|
||||
if v := callback.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(callback.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Callback.
|
||||
func (callback *Callback) MarshalYAML() (any, error) {
|
||||
if callback == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, callback.Len()+len(callback.Extensions))
|
||||
maps.Copy(m, callback.Extensions)
|
||||
for _, k := range callback.Keys() {
|
||||
m[k] = callback.m[k]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Callback.
|
||||
func (callback *Callback) MarshalJSON() ([]byte, error) {
|
||||
callbackYaml, err := callback.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(callbackYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Callback to a copy of data.
|
||||
func (callback *Callback) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
x := Callback{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*PathItem, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range componentNames(m) {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv PathItem
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*callback = x
|
||||
return
|
||||
}
|
||||
|
||||
// NewPathsWithCapacity builds a paths object of the given capacity.
|
||||
func NewPathsWithCapacity(cap int) *Paths {
|
||||
if cap == 0 {
|
||||
return &Paths{m: make(map[string]*PathItem)}
|
||||
}
|
||||
return &Paths{m: make(map[string]*PathItem, cap)}
|
||||
}
|
||||
|
||||
// Keys returns the paths keys in a fixed order
|
||||
func (paths *Paths) Keys() []string {
|
||||
return componentNames(paths.Map())
|
||||
}
|
||||
|
||||
// Value returns the paths for key or nil
|
||||
func (paths *Paths) Value(key string) *PathItem {
|
||||
if paths.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return paths.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'paths' with 'value'.
|
||||
// Note: 'paths' MUST be non-nil
|
||||
func (paths *Paths) Set(key string, value *PathItem) {
|
||||
if paths.m == nil {
|
||||
paths.m = make(map[string]*PathItem)
|
||||
}
|
||||
paths.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in paths excluding paths.Extensions.
|
||||
func (paths *Paths) Len() int {
|
||||
if paths == nil || paths.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(paths.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'paths'.
|
||||
func (paths *Paths) Delete(key string) {
|
||||
if paths != nil && paths.m != nil {
|
||||
delete(paths.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns paths as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (paths *Paths) Map() (m map[string]*PathItem) {
|
||||
if paths == nil || len(paths.m) == 0 {
|
||||
return make(map[string]*PathItem)
|
||||
}
|
||||
m = make(map[string]*PathItem, len(paths.m))
|
||||
maps.Copy(m, paths.m)
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Paths)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (paths Paths) JSONLookup(token string) (any, error) {
|
||||
if v := paths.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(paths.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Paths.
|
||||
func (paths *Paths) MarshalYAML() (any, error) {
|
||||
if paths == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, paths.Len()+len(paths.Extensions))
|
||||
maps.Copy(m, paths.Extensions)
|
||||
for _, k := range paths.Keys() {
|
||||
m[k] = paths.m[k]
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Paths.
|
||||
func (paths *Paths) MarshalJSON() ([]byte, error) {
|
||||
pathsYaml, err := paths.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(pathsYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Paths to a copy of data.
|
||||
func (paths *Paths) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
x := Paths{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*PathItem, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range componentNames(m) {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv PathItem
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*paths = x
|
||||
return
|
||||
}
|
||||
45
vendor/github.com/getkin/kin-openapi/openapi3/marsh.go
generated
vendored
Normal file
45
vendor/github.com/getkin/kin-openapi/openapi3/marsh.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/oasdiff/yaml"
|
||||
)
|
||||
|
||||
func unmarshalError(jsonUnmarshalErr error) error {
|
||||
if before, after, found := strings.Cut(jsonUnmarshalErr.Error(), "Bis"); found && before != "" && after != "" {
|
||||
before = strings.ReplaceAll(before, " Go struct ", " ")
|
||||
return fmt.Errorf("%s%s", before, strings.ReplaceAll(after, "Bis", ""))
|
||||
}
|
||||
return jsonUnmarshalErr
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, v any, includeOrigin bool, location *url.URL) error {
|
||||
var jsonErr, yamlErr error
|
||||
|
||||
// See https://github.com/getkin/kin-openapi/issues/680
|
||||
if jsonErr = json.Unmarshal(data, v); jsonErr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
|
||||
var file string
|
||||
if location != nil {
|
||||
file = location.String()
|
||||
}
|
||||
if tree, err := yaml.Unmarshal(data, v, yaml.DecodeOpts{
|
||||
Origin: yaml.OriginOpt{Enabled: includeOrigin, File: file},
|
||||
DisableTimestamps: true,
|
||||
}); err == nil {
|
||||
applyOrigins(v, tree)
|
||||
return nil
|
||||
} else {
|
||||
yamlErr = err
|
||||
}
|
||||
|
||||
// If both unmarshaling attempts fail, return a new error that includes both errors
|
||||
return fmt.Errorf("failed to unmarshal data: json error: %v, yaml error: %v", jsonErr, yamlErr)
|
||||
}
|
||||
174
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
Normal file
174
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// MediaType is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#media-type-object
|
||||
type MediaType struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Encoding Encodings `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*MediaType)(nil)
|
||||
|
||||
func NewMediaType() *MediaType {
|
||||
return &MediaType{}
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) WithSchema(schema *Schema) *MediaType {
|
||||
if schema == nil {
|
||||
mediaType.Schema = nil
|
||||
} else {
|
||||
mediaType.Schema = &SchemaRef{Value: schema}
|
||||
}
|
||||
return mediaType
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) WithSchemaRef(schema *SchemaRef) *MediaType {
|
||||
mediaType.Schema = schema
|
||||
return mediaType
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) WithExample(name string, value any) *MediaType {
|
||||
example := mediaType.Examples
|
||||
if example == nil {
|
||||
example = make(map[string]*ExampleRef)
|
||||
mediaType.Examples = example
|
||||
}
|
||||
example[name] = &ExampleRef{
|
||||
Value: NewExample(value),
|
||||
}
|
||||
return mediaType
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) WithEncoding(name string, enc *Encoding) *MediaType {
|
||||
encoding := mediaType.Encoding
|
||||
if encoding == nil {
|
||||
encoding = make(Encodings)
|
||||
mediaType.Encoding = encoding
|
||||
}
|
||||
encoding[name] = enc
|
||||
return mediaType
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of MediaType.
|
||||
func (mediaType MediaType) MarshalJSON() ([]byte, error) {
|
||||
x, err := mediaType.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of MediaType.
|
||||
func (mediaType MediaType) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(mediaType.Extensions))
|
||||
maps.Copy(m, mediaType.Extensions)
|
||||
if x := mediaType.Schema; x != nil {
|
||||
m["schema"] = x
|
||||
}
|
||||
if x := mediaType.Example; x != nil {
|
||||
m["example"] = x
|
||||
}
|
||||
if x := mediaType.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := mediaType.Encoding; len(x) != 0 {
|
||||
m["encoding"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets MediaType to a copy of data.
|
||||
func (mediaType *MediaType) UnmarshalJSON(data []byte) error {
|
||||
type MediaTypeBis MediaType
|
||||
var x MediaTypeBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "schema")
|
||||
delete(x.Extensions, "example")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "encoding")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
delete(x.Encoding, originKey)
|
||||
*mediaType = MediaType(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if MediaType does not comply with the OpenAPI spec.
|
||||
func (mediaType *MediaType) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if mediaType == nil {
|
||||
return nil
|
||||
}
|
||||
if schema := mediaType.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mediaType.Example != nil && mediaType.Examples != nil {
|
||||
return newMediaTypeExampleExamplesExclusive(mediaType.Origin)
|
||||
}
|
||||
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
if example := mediaType.Example; example != nil {
|
||||
if err := validateExampleValue(ctx, example, schema.Value); err != nil {
|
||||
return newSchemaValueError("example", err, mediaType.Origin)
|
||||
}
|
||||
}
|
||||
|
||||
if examples := mediaType.Examples; examples != nil {
|
||||
for _, k := range componentNames(examples) {
|
||||
v := examples[k]
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return &MediaTypeExampleValidationError{ExampleName: k, Cause: err}
|
||||
}
|
||||
if err := validateExampleValue(ctx, v.Value.Value, schema.Value); err != nil {
|
||||
return newSchemaValueError("example",
|
||||
&MediaTypeExampleValidationError{ExampleName: k, Cause: err},
|
||||
exampleValueOrigin(v.Value, mediaType.Origin))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, mediaType.Extensions, mediaType.Origin)
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (mediaType MediaType) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if mediaType.Schema != nil {
|
||||
if mediaType.Schema.Ref != "" {
|
||||
return &Ref{Ref: mediaType.Schema.Ref}, nil
|
||||
}
|
||||
return mediaType.Schema.Value, nil
|
||||
}
|
||||
case "example":
|
||||
return mediaType.Example, nil
|
||||
case "examples":
|
||||
return mediaType.Examples, nil
|
||||
case "encoding":
|
||||
return mediaType.Encoding, nil
|
||||
}
|
||||
v, _, err := jsonpointer.GetForToken(mediaType.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
391
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
Normal file
391
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/url"
|
||||
"slices"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// T is the root of an OpenAPI v3 document
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#openapi-object
|
||||
// and https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object
|
||||
type T struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
OpenAPI string `json:"openapi" yaml:"openapi"` // Required
|
||||
Components *Components `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
Info *Info `json:"info" yaml:"info"` // Required
|
||||
Paths *Paths `json:"paths" yaml:"paths"` // Required in 3.0, optional in 3.1
|
||||
Security SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
|
||||
Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||
Tags Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
Webhooks map[string]*PathItem `json:"webhooks,omitempty" yaml:"webhooks,omitempty"` // OpenAPI >=3.1
|
||||
JSONSchemaDialect string `json:"jsonSchemaDialect,omitempty" yaml:"jsonSchemaDialect,omitempty"` // OpenAPI >=3.1
|
||||
|
||||
visited visitedComponent
|
||||
url *url.URL
|
||||
|
||||
// Document-scoped format validators
|
||||
// These validators are automatically used by all schemas in this document
|
||||
stringFormats map[string]StringFormatValidator
|
||||
numberFormats map[string]NumberFormatValidator
|
||||
integerFormats map[string]IntegerFormatValidator
|
||||
}
|
||||
|
||||
// IsOpenAPI30 returns whether doc is an OpenAPI document version 3.0.x.
|
||||
// Returns true for 3, 3.0, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, ...
|
||||
// And false for 3.1.0, 3.2, ... and for invalid strings.
|
||||
func (doc *T) IsOpenAPI30() bool {
|
||||
return doc.OpenAPIMajorMinor() == "3.0"
|
||||
}
|
||||
|
||||
// IsOpenAPI31OrLater returns whether doc is an OpenAPI document version >=3.1.
|
||||
// Returns true for 3.1, 3.1.0, 3.1.1, 3.1.2, 3.2.0, ...
|
||||
// And false for cases where IsOpenAPI30 returns true and for invalid strings.
|
||||
func (doc *T) IsOpenAPI31OrLater() bool {
|
||||
return slices.Contains([]string{"3.1", "3.2"}, doc.OpenAPIMajorMinor())
|
||||
}
|
||||
|
||||
func errFieldFor31Plus(field string, origin *Origin) error {
|
||||
return newFieldFor31Plus(field, origin)
|
||||
}
|
||||
|
||||
func errValueOfFieldFor31Plus(value any, field string) error {
|
||||
return fmt.Errorf("value %q of field %s is for OpenAPI >=3.1", value, field)
|
||||
}
|
||||
|
||||
// OpenAPIMajorMinor returns 3.y of the OpenAPI "3.y" or "3.y.z" version of the document.
|
||||
// Returns the empty string for invalid OpenAPI version strings.
|
||||
func (doc *T) OpenAPIMajorMinor() string {
|
||||
if doc == nil {
|
||||
return ""
|
||||
}
|
||||
switch doc.OpenAPI {
|
||||
case "3", "3.0", "3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.0.4":
|
||||
return "3.0"
|
||||
case "3.1", "3.1.0", "3.1.1", "3.1.2":
|
||||
return "3.1"
|
||||
case "3.2", "3.2.0":
|
||||
return "3.2"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*T)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (doc *T) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "openapi":
|
||||
return doc.OpenAPI, nil
|
||||
case "components":
|
||||
return doc.Components, nil
|
||||
case "info":
|
||||
return doc.Info, nil
|
||||
case "paths":
|
||||
return doc.Paths, nil
|
||||
case "security":
|
||||
return doc.Security, nil
|
||||
case "servers":
|
||||
return doc.Servers, nil
|
||||
case "tags":
|
||||
return doc.Tags, nil
|
||||
case "externalDocs":
|
||||
return doc.ExternalDocs, nil
|
||||
case "webhooks":
|
||||
return doc.Webhooks, nil
|
||||
case "jsonSchemaDialect":
|
||||
return doc.JSONSchemaDialect, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(doc.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of T.
|
||||
func (doc *T) MarshalJSON() ([]byte, error) {
|
||||
x, err := doc.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of T.
|
||||
func (doc *T) MarshalYAML() (any, error) {
|
||||
if doc == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, 10+len(doc.Extensions))
|
||||
maps.Copy(m, doc.Extensions)
|
||||
m["openapi"] = doc.OpenAPI
|
||||
if x := doc.Components; x != nil {
|
||||
m["components"] = x
|
||||
}
|
||||
m["info"] = doc.Info
|
||||
m["paths"] = doc.Paths
|
||||
if x := doc.Security; len(x) != 0 {
|
||||
m["security"] = x
|
||||
}
|
||||
if x := doc.Servers; len(x) != 0 {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := doc.Tags; len(x) != 0 {
|
||||
m["tags"] = x
|
||||
}
|
||||
if x := doc.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
if x := doc.Webhooks; len(x) != 0 {
|
||||
m["webhooks"] = x
|
||||
}
|
||||
if x := doc.JSONSchemaDialect; x != "" {
|
||||
m["jsonSchemaDialect"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets T to a copy of data.
|
||||
func (doc *T) UnmarshalJSON(data []byte) error {
|
||||
type TBis T
|
||||
var x TBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "openapi")
|
||||
delete(x.Extensions, "components")
|
||||
delete(x.Extensions, "info")
|
||||
delete(x.Extensions, "paths")
|
||||
delete(x.Extensions, "security")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "tags")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
delete(x.Extensions, "webhooks")
|
||||
delete(x.Extensions, "jsonSchemaDialect")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
delete(x.Webhooks, originKey)
|
||||
*doc = T(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (doc *T) AddOperation(path string, method string, operation *Operation) {
|
||||
if doc.Paths == nil {
|
||||
doc.Paths = NewPaths()
|
||||
}
|
||||
pathItem := doc.Paths.Value(path)
|
||||
if pathItem == nil {
|
||||
pathItem = &PathItem{}
|
||||
doc.Paths.Set(path, pathItem)
|
||||
}
|
||||
pathItem.SetOperation(method, operation)
|
||||
}
|
||||
|
||||
func (doc *T) AddServer(server *Server) {
|
||||
doc.Servers = append(doc.Servers, server)
|
||||
}
|
||||
|
||||
func (doc *T) AddServers(servers ...*Server) {
|
||||
doc.Servers = append(doc.Servers, servers...)
|
||||
}
|
||||
|
||||
// SetStringFormatValidators sets document-scoped string format validators.
|
||||
// These validators are automatically used by all schemas in this document.
|
||||
func (doc *T) SetStringFormatValidators(validators map[string]StringFormatValidator) {
|
||||
doc.stringFormats = validators
|
||||
}
|
||||
|
||||
// SetStringFormatValidator sets a single document-scoped string format validator.
|
||||
func (doc *T) SetStringFormatValidator(name string, validator StringFormatValidator) {
|
||||
if doc.stringFormats == nil {
|
||||
doc.stringFormats = make(map[string]StringFormatValidator)
|
||||
}
|
||||
doc.stringFormats[name] = validator
|
||||
}
|
||||
|
||||
// SetNumberFormatValidators sets document-scoped number format validators.
|
||||
// These validators are automatically used by all schemas in this document.
|
||||
func (doc *T) SetNumberFormatValidators(validators map[string]NumberFormatValidator) {
|
||||
doc.numberFormats = validators
|
||||
}
|
||||
|
||||
// SetNumberFormatValidator sets a single document-scoped number format validator.
|
||||
func (doc *T) SetNumberFormatValidator(name string, validator NumberFormatValidator) {
|
||||
if doc.numberFormats == nil {
|
||||
doc.numberFormats = make(map[string]NumberFormatValidator)
|
||||
}
|
||||
doc.numberFormats[name] = validator
|
||||
}
|
||||
|
||||
// SetIntegerFormatValidators sets document-scoped integer format validators.
|
||||
// These validators are automatically used by all schemas in this document.
|
||||
func (doc *T) SetIntegerFormatValidators(validators map[string]IntegerFormatValidator) {
|
||||
doc.integerFormats = validators
|
||||
}
|
||||
|
||||
// SetIntegerFormatValidator sets a single document-scoped integer format validator.
|
||||
func (doc *T) SetIntegerFormatValidator(name string, validator IntegerFormatValidator) {
|
||||
if doc.integerFormats == nil {
|
||||
doc.integerFormats = make(map[string]IntegerFormatValidator)
|
||||
}
|
||||
doc.integerFormats[name] = validator
|
||||
}
|
||||
|
||||
// GetSchemaValidationOptions returns SchemaValidationOptions that include
|
||||
// this document's format validators. Use this when validating schemas from this document.
|
||||
func (doc *T) GetSchemaValidationOptions() []SchemaValidationOption {
|
||||
var opts []SchemaValidationOption
|
||||
if doc.stringFormats != nil {
|
||||
opts = append(opts, WithStringFormatValidators(doc.stringFormats))
|
||||
}
|
||||
if doc.numberFormats != nil {
|
||||
opts = append(opts, WithNumberFormatValidators(doc.numberFormats))
|
||||
}
|
||||
if doc.integerFormats != nil {
|
||||
opts = append(opts, WithIntegerFormatValidators(doc.integerFormats))
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
// Validate returns an error if T does not comply with the OpenAPI spec.
|
||||
// Validations Options can be provided to modify the validation behavior.
|
||||
//
|
||||
// By default, doc.OpenAPI's field dictates whether "JSON Schema Draft 2020-12" validation
|
||||
// is enabled.
|
||||
func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
if doc.IsOpenAPI31OrLater() {
|
||||
opts = append(opts, IsOpenAPI31OrLater())
|
||||
}
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if doc.OpenAPI == "" {
|
||||
if err := me.emit(newOpenAPIVersionRequired(doc.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Webhooks != nil && !doc.IsOpenAPI31OrLater() {
|
||||
if err := me.emit(newWebhooksFieldFor31Plus(doc.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if doc.JSONSchemaDialect != "" && !doc.IsOpenAPI31OrLater() {
|
||||
if err := me.emit(newJSONSchemaDialectFieldFor31Plus(doc.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrapSection := func(section string) func(error) error {
|
||||
return func(e error) error { return &SectionValidationError{Section: section, Cause: e} }
|
||||
}
|
||||
|
||||
var wrap func(error) error
|
||||
|
||||
wrap = wrapSection("components")
|
||||
if v := doc.Components; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("info")
|
||||
if v := doc.Info; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := me.emit(wrap(newInfoRequired(doc.Origin))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wrap = wrapSection("paths")
|
||||
if v := doc.Paths; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if doc.IsOpenAPI30() {
|
||||
if err := me.emit(wrap(newPathsRequired(doc.Origin))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("security")
|
||||
if v := doc.Security; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("servers")
|
||||
if v := doc.Servers; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("tags")
|
||||
if v := doc.Tags; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("external docs")
|
||||
if v := doc.ExternalDocs; v != nil {
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("webhooks")
|
||||
for _, name := range componentNames(doc.Webhooks) {
|
||||
pathItem := doc.Webhooks[name]
|
||||
if pathItem == nil {
|
||||
if err := me.emit(wrap(newWebhookNil(name))); err != nil {
|
||||
return err
|
||||
}
|
||||
// Nothing to descend into for a nil webhook; the nil itself
|
||||
// is the only finding under this name until the entry is
|
||||
// populated, so continue to the next webhook.
|
||||
continue
|
||||
}
|
||||
wrapWebhook := func(e error) error { return wrap(&WebhookValidationError{Name: name, Cause: e}) }
|
||||
if err := me.emitWrapped(wrapWebhook, pathItem.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
wrap = wrapSection("jsonSchemaDialect")
|
||||
if doc.JSONSchemaDialect != "" {
|
||||
u, err := url.Parse(doc.JSONSchemaDialect)
|
||||
if err != nil {
|
||||
if err = me.emit(wrap(err)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if u.Scheme == "" {
|
||||
if err := me.emit(wrap(newJSONSchemaDialectAbsoluteURIRequired(doc.Origin))); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, doc.Extensions, doc.Origin))
|
||||
}
|
||||
|
||||
// ValidateSchemaJSON validates data against a schema using this document's format validators.
|
||||
// This is a convenience method that automatically applies the document's format validators.
|
||||
func (doc *T) ValidateSchemaJSON(schema *Schema, value any, opts ...SchemaValidationOption) error {
|
||||
// Combine document's validators with any additional options
|
||||
allOpts := append(doc.GetSchemaValidationOptions(), opts...)
|
||||
return schema.VisitJSON(value, allOpts...)
|
||||
}
|
||||
222
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
Normal file
222
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// Operation represents "operation" specified by" OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object
|
||||
type Operation struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
// Optional tags for documentation.
|
||||
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||
|
||||
// Optional short summary.
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
|
||||
// Optional description. Should use CommonMark syntax.
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
||||
// Optional operation ID.
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
|
||||
// Optional parameters.
|
||||
Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
|
||||
// Optional body parameter.
|
||||
RequestBody *RequestBodyRef `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
|
||||
// Responses.
|
||||
Responses *Responses `json:"responses" yaml:"responses"` // Required
|
||||
|
||||
// Optional callbacks
|
||||
Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
|
||||
// Optional security requirements that overrides top-level security.
|
||||
Security *SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
|
||||
|
||||
// Optional servers that overrides top-level servers.
|
||||
Servers *Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Operation)(nil)
|
||||
|
||||
func NewOperation() *Operation {
|
||||
return &Operation{}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Operation.
|
||||
func (operation Operation) MarshalJSON() ([]byte, error) {
|
||||
x, err := operation.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Operation.
|
||||
func (operation Operation) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 12+len(operation.Extensions))
|
||||
maps.Copy(m, operation.Extensions)
|
||||
if x := operation.Tags; len(x) != 0 {
|
||||
m["tags"] = x
|
||||
}
|
||||
if x := operation.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := operation.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := operation.OperationID; x != "" {
|
||||
m["operationId"] = x
|
||||
}
|
||||
if x := operation.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := operation.RequestBody; x != nil {
|
||||
m["requestBody"] = x
|
||||
}
|
||||
m["responses"] = operation.Responses
|
||||
if x := operation.Callbacks; len(x) != 0 {
|
||||
m["callbacks"] = x
|
||||
}
|
||||
if x := operation.Deprecated; x {
|
||||
m["deprecated"] = x
|
||||
}
|
||||
if x := operation.Security; x != nil {
|
||||
m["security"] = x
|
||||
}
|
||||
if x := operation.Servers; x != nil {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := operation.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Operation to a copy of data.
|
||||
func (operation *Operation) UnmarshalJSON(data []byte) error {
|
||||
type OperationBis Operation
|
||||
var x OperationBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "tags")
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "operationId")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "requestBody")
|
||||
delete(x.Extensions, "responses")
|
||||
delete(x.Extensions, "callbacks")
|
||||
delete(x.Extensions, "deprecated")
|
||||
delete(x.Extensions, "security")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*operation = Operation(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (operation Operation) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "requestBody":
|
||||
if operation.RequestBody != nil {
|
||||
if operation.RequestBody.Ref != "" {
|
||||
return &Ref{Ref: operation.RequestBody.Ref}, nil
|
||||
}
|
||||
return operation.RequestBody.Value, nil
|
||||
}
|
||||
case "tags":
|
||||
return operation.Tags, nil
|
||||
case "summary":
|
||||
return operation.Summary, nil
|
||||
case "description":
|
||||
return operation.Description, nil
|
||||
case "operationID":
|
||||
return operation.OperationID, nil
|
||||
case "parameters":
|
||||
return operation.Parameters, nil
|
||||
case "responses":
|
||||
return operation.Responses, nil
|
||||
case "callbacks":
|
||||
return operation.Callbacks, nil
|
||||
case "deprecated":
|
||||
return operation.Deprecated, nil
|
||||
case "security":
|
||||
return operation.Security, nil
|
||||
case "servers":
|
||||
return operation.Servers, nil
|
||||
case "externalDocs":
|
||||
return operation.ExternalDocs, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(operation.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (operation *Operation) AddParameter(p *Parameter) {
|
||||
operation.Parameters = append(operation.Parameters, &ParameterRef{Value: p})
|
||||
}
|
||||
|
||||
func (operation *Operation) AddResponse(status int, response *Response) {
|
||||
code := "default"
|
||||
if 0 < status && status < 1000 {
|
||||
code = strconv.FormatInt(int64(status), 10)
|
||||
}
|
||||
if operation.Responses == nil {
|
||||
operation.Responses = NewResponses()
|
||||
}
|
||||
operation.Responses.Set(code, &ResponseRef{Value: response})
|
||||
}
|
||||
|
||||
// Validate returns an error if Operation does not comply with the OpenAPI spec.
|
||||
func (operation *Operation) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if v := operation.Parameters; v != nil {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v := operation.RequestBody; v != nil {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v := operation.Responses; v != nil {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := me.emit(newOperationResponsesRequired(operation.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v := operation.ExternalDocs; v != nil {
|
||||
wrap := func(e error) error { return &SectionValidationError{Section: "external docs", Cause: e} }
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, operation.Extensions, operation.Origin))
|
||||
}
|
||||
255
vendor/github.com/getkin/kin-openapi/openapi3/origin.go
generated
vendored
Normal file
255
vendor/github.com/getkin/kin-openapi/openapi3/origin.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/oasdiff/yaml"
|
||||
)
|
||||
|
||||
const originKey = "__origin__"
|
||||
|
||||
var originPtrType = reflect.TypeFor[*Origin]()
|
||||
|
||||
// Origin contains the origin of a collection.
|
||||
// Key is the location of the collection itself.
|
||||
// Fields is a map of the location of each scalar field in the collection.
|
||||
// Sequences is a map of the location of each item in sequence-valued fields.
|
||||
type Origin struct {
|
||||
Key *Location `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
Fields map[string]Location `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||
Sequences map[string][]Location `json:"sequences,omitempty" yaml:"sequences,omitempty"`
|
||||
}
|
||||
|
||||
// Location is a struct that contains the location of a field.
|
||||
type Location struct {
|
||||
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
Line int `json:"line,omitempty" yaml:"line,omitempty"`
|
||||
Column int `json:"column,omitempty" yaml:"column,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
}
|
||||
|
||||
// originFromSeq parses the compact []any sequence produced by yaml3's addOrigin.
|
||||
//
|
||||
// Format: [file, key_name, key_line, key_col, nf, f1_name, f1_delta, f1_col, ..., ns, s1_name, s1_count, s1_l0_delta, s1_c0, ...]
|
||||
func originFromSeq(s []any) *Origin {
|
||||
// Need at least: file, key_name, key_line, key_col, nf, ns
|
||||
if len(s) < 6 {
|
||||
return nil
|
||||
}
|
||||
file, _ := s[0].(string)
|
||||
keyName, _ := s[1].(string)
|
||||
keyLine := toInt(s[2])
|
||||
keyCol := toInt(s[3])
|
||||
|
||||
o := &Origin{
|
||||
Key: &Location{
|
||||
File: file,
|
||||
Line: keyLine,
|
||||
Column: keyCol,
|
||||
Name: keyName,
|
||||
},
|
||||
}
|
||||
|
||||
idx := 4
|
||||
nf := toInt(s[idx])
|
||||
idx++
|
||||
if nf > 0 && idx+nf*3 <= len(s) {
|
||||
o.Fields = make(map[string]Location, nf)
|
||||
for range nf {
|
||||
fname, _ := s[idx].(string)
|
||||
delta := toInt(s[idx+1])
|
||||
col := toInt(s[idx+2])
|
||||
o.Fields[fname] = Location{
|
||||
File: file,
|
||||
Line: keyLine + delta,
|
||||
Column: col,
|
||||
Name: fname,
|
||||
}
|
||||
idx += 3
|
||||
}
|
||||
}
|
||||
|
||||
if idx >= len(s) {
|
||||
return o
|
||||
}
|
||||
ns := toInt(s[idx])
|
||||
idx++
|
||||
if ns > 0 {
|
||||
o.Sequences = make(map[string][]Location, ns)
|
||||
for range ns {
|
||||
if idx >= len(s) {
|
||||
break
|
||||
}
|
||||
sname, _ := s[idx].(string)
|
||||
idx++
|
||||
if idx >= len(s) {
|
||||
break
|
||||
}
|
||||
count := toInt(s[idx])
|
||||
idx++
|
||||
locs := make([]Location, count)
|
||||
for j := 0; j < count && idx+2 < len(s); j++ {
|
||||
name, _ := s[idx].(string)
|
||||
delta := toInt(s[idx+1])
|
||||
col := toInt(s[idx+2])
|
||||
locs[j] = Location{File: file, Line: keyLine + delta, Column: col, Name: name}
|
||||
idx += 3
|
||||
}
|
||||
o.Sequences[sname] = locs
|
||||
}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// toInt converts numeric types to int. Handles int/uint64 from YAML decoding.
|
||||
func toInt(v any) int {
|
||||
switch n := v.(type) {
|
||||
case int:
|
||||
return n
|
||||
case uint64:
|
||||
return int(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// applyOrigins walks a Go struct tree and a parallel OriginTree, setting
|
||||
// Origin fields on each struct from the extracted origin data.
|
||||
func applyOrigins(v any, tree *yaml.OriginTree) {
|
||||
if tree == nil {
|
||||
return
|
||||
}
|
||||
applyOriginsToValue(reflect.ValueOf(v), tree)
|
||||
}
|
||||
|
||||
func applyOriginsToValue(val reflect.Value, tree *yaml.OriginTree) {
|
||||
// Keep track of the last pointer so we can pass it to struct handlers
|
||||
// (needed for calling methods like Map() on maplike types).
|
||||
var ptr reflect.Value
|
||||
for val.Kind() == reflect.Pointer || val.Kind() == reflect.Interface {
|
||||
if val.IsNil() {
|
||||
return
|
||||
}
|
||||
if val.Kind() == reflect.Pointer {
|
||||
ptr = val
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Struct:
|
||||
applyOriginsToStruct(val, ptr, tree)
|
||||
case reflect.Map:
|
||||
applyOriginsToMap(val, tree)
|
||||
case reflect.Slice:
|
||||
applyOriginsToSlice(val, tree)
|
||||
}
|
||||
}
|
||||
|
||||
func applyOriginsToStruct(val reflect.Value, ptr reflect.Value, tree *yaml.OriginTree) {
|
||||
typ := val.Type()
|
||||
|
||||
// Set Origin field for structs whose Origin field has a "-" json tag.
|
||||
if tree.Origin != nil {
|
||||
if sf, ok := typ.FieldByName("Origin"); ok && sf.Type == originPtrType {
|
||||
tag := sf.Tag.Get("json")
|
||||
if tag == "-" {
|
||||
if s, ok := tree.Origin.([]any); ok {
|
||||
val.FieldByName("Origin").Set(reflect.ValueOf(originFromSeq(s)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into exported struct fields using json tags
|
||||
for i := range typ.NumField() {
|
||||
sf := typ.Field(i)
|
||||
if !sf.IsExported() {
|
||||
continue
|
||||
}
|
||||
tag := jsonTagName(sf)
|
||||
if tag == "" || tag == "-" {
|
||||
continue
|
||||
}
|
||||
childTree := tree.Fields[tag]
|
||||
if childTree != nil {
|
||||
applyOriginsToValue(val.Field(i), childTree)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle wrapper types whose inner struct has no json tag:
|
||||
// - *Ref types (e.g. SchemaRef, ResponseRef) have a "Value" field
|
||||
// - BoolSchema (AdditionalProperties, UnevaluatedProperties, UnevaluatedItems) has a "Schema" field
|
||||
// The origin tree data applies to the inner struct, not a sub-key.
|
||||
for _, fieldName := range []string{"Value", "Schema"} {
|
||||
vf := val.FieldByName(fieldName)
|
||||
if !vf.IsValid() || vf.Kind() != reflect.Pointer || vf.IsNil() {
|
||||
continue
|
||||
}
|
||||
sf, _ := typ.FieldByName(fieldName)
|
||||
if sf.Tag.Get("json") == "" {
|
||||
applyOriginsToValue(vf, tree)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle "maplike" types (Paths, Responses, Callback) whose items are
|
||||
// stored in an unexported map accessible via a Map() method.
|
||||
// Use the original pointer (if available) since dereferenced values
|
||||
// are not addressable.
|
||||
receiver := val
|
||||
if ptr.IsValid() {
|
||||
receiver = ptr
|
||||
} else if val.CanAddr() {
|
||||
receiver = val.Addr()
|
||||
}
|
||||
if receiver.Kind() == reflect.Pointer {
|
||||
if mapMethod := receiver.MethodByName("Map"); mapMethod.IsValid() {
|
||||
results := mapMethod.Call(nil)
|
||||
if len(results) == 1 {
|
||||
applyOriginsToMap(results[0], tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func applyOriginsToMap(val reflect.Value, tree *yaml.OriginTree) {
|
||||
if tree.Fields == nil {
|
||||
return
|
||||
}
|
||||
for _, key := range val.MapKeys() {
|
||||
childTree := tree.Fields[key.String()]
|
||||
if childTree == nil {
|
||||
continue
|
||||
}
|
||||
elem := val.MapIndex(key)
|
||||
// Map values are not addressable. For pointer-typed values we can
|
||||
// recurse directly. For value types we must copy, apply, and set back.
|
||||
if elem.Kind() == reflect.Pointer || elem.Kind() == reflect.Interface {
|
||||
applyOriginsToValue(elem, childTree)
|
||||
} else if elem.Kind() == reflect.Struct {
|
||||
// Copy to a settable value
|
||||
cp := reflect.New(elem.Type()).Elem()
|
||||
cp.Set(elem)
|
||||
applyOriginsToStruct(cp, reflect.Value{}, childTree)
|
||||
val.SetMapIndex(key, cp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func applyOriginsToSlice(val reflect.Value, tree *yaml.OriginTree) {
|
||||
for i := 0; i < val.Len() && i < len(tree.Items); i++ {
|
||||
if tree.Items[i] != nil {
|
||||
applyOriginsToValue(val.Index(i), tree.Items[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// jsonTagName returns the JSON field name from a struct field's json tag.
|
||||
func jsonTagName(f reflect.StructField) string {
|
||||
tag := f.Tag.Get("json")
|
||||
if tag == "" {
|
||||
return ""
|
||||
}
|
||||
name, _, _ := strings.Cut(tag, ",")
|
||||
return name
|
||||
}
|
||||
417
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
Normal file
417
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// Parameters is specified by OpenAPI/Swagger 3.0 standard.
|
||||
type Parameters []*ParameterRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Parameters)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (p Parameters) JSONLookup(token string) (any, error) {
|
||||
index, err := strconv.Atoi(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if index < 0 || index >= len(p) {
|
||||
return nil, fmt.Errorf("index %d out of bounds of array of length %d", index, len(p))
|
||||
}
|
||||
|
||||
ref := p[index]
|
||||
if ref != nil && ref.Ref != "" {
|
||||
return &Ref{Ref: ref.Ref}, nil
|
||||
}
|
||||
return ref.Value, nil
|
||||
}
|
||||
|
||||
func NewParameters() Parameters {
|
||||
return make(Parameters, 0, 4)
|
||||
}
|
||||
|
||||
func (parameters Parameters) GetByInAndName(in string, name string) *Parameter {
|
||||
for _, item := range parameters {
|
||||
if v := item.Value; v != nil {
|
||||
if v.Name == name && v.In == in {
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Parameters does not comply with the OpenAPI spec.
|
||||
func (parameters Parameters) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
dupes := make(map[string]struct{})
|
||||
for _, parameterRef := range parameters {
|
||||
if v := parameterRef.Value; v != nil {
|
||||
key := v.In + ":" + v.Name
|
||||
if _, ok := dupes[key]; ok {
|
||||
return newDuplicateParameter(v.In, v.Name, v.Origin)
|
||||
}
|
||||
dupes[key] = struct{}{}
|
||||
}
|
||||
|
||||
if err := parameterRef.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parameter is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object
|
||||
type Parameter struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Parameter)(nil)
|
||||
|
||||
const (
|
||||
ParameterInPath = "path"
|
||||
ParameterInQuery = "query"
|
||||
ParameterInHeader = "header"
|
||||
ParameterInCookie = "cookie"
|
||||
)
|
||||
|
||||
func NewPathParameter(name string) *Parameter {
|
||||
return &Parameter{
|
||||
Name: name,
|
||||
In: ParameterInPath,
|
||||
Required: true,
|
||||
}
|
||||
}
|
||||
|
||||
func NewQueryParameter(name string) *Parameter {
|
||||
return &Parameter{
|
||||
Name: name,
|
||||
In: ParameterInQuery,
|
||||
}
|
||||
}
|
||||
|
||||
func NewHeaderParameter(name string) *Parameter {
|
||||
return &Parameter{
|
||||
Name: name,
|
||||
In: ParameterInHeader,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCookieParameter(name string) *Parameter {
|
||||
return &Parameter{
|
||||
Name: name,
|
||||
In: ParameterInCookie,
|
||||
}
|
||||
}
|
||||
|
||||
func (parameter *Parameter) WithDescription(value string) *Parameter {
|
||||
parameter.Description = value
|
||||
return parameter
|
||||
}
|
||||
|
||||
func (parameter *Parameter) WithRequired(value bool) *Parameter {
|
||||
parameter.Required = value
|
||||
return parameter
|
||||
}
|
||||
|
||||
func (parameter *Parameter) WithSchema(value *Schema) *Parameter {
|
||||
if value == nil {
|
||||
parameter.Schema = nil
|
||||
} else {
|
||||
parameter.Schema = &SchemaRef{
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
return parameter
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Parameter.
|
||||
func (parameter Parameter) MarshalJSON() ([]byte, error) {
|
||||
x, err := parameter.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Parameter.
|
||||
func (parameter Parameter) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 13+len(parameter.Extensions))
|
||||
maps.Copy(m, parameter.Extensions)
|
||||
|
||||
if x := parameter.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := parameter.In; x != "" {
|
||||
m["in"] = x
|
||||
}
|
||||
if x := parameter.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := parameter.Style; x != "" {
|
||||
m["style"] = x
|
||||
}
|
||||
if x := parameter.Explode; x != nil {
|
||||
m["explode"] = x
|
||||
}
|
||||
if x := parameter.AllowEmptyValue; x {
|
||||
m["allowEmptyValue"] = x
|
||||
}
|
||||
if x := parameter.AllowReserved; x {
|
||||
m["allowReserved"] = x
|
||||
}
|
||||
if x := parameter.Deprecated; x {
|
||||
m["deprecated"] = x
|
||||
}
|
||||
if x := parameter.Required; x {
|
||||
m["required"] = x
|
||||
}
|
||||
if x := parameter.Schema; x != nil {
|
||||
m["schema"] = x
|
||||
}
|
||||
if x := parameter.Example; x != nil {
|
||||
m["example"] = x
|
||||
}
|
||||
if x := parameter.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := parameter.Content; len(x) != 0 {
|
||||
m["content"] = x
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Parameter to a copy of data.
|
||||
func (parameter *Parameter) UnmarshalJSON(data []byte) error {
|
||||
type ParameterBis Parameter
|
||||
var x ParameterBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "in")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "style")
|
||||
delete(x.Extensions, "explode")
|
||||
delete(x.Extensions, "allowEmptyValue")
|
||||
delete(x.Extensions, "allowReserved")
|
||||
delete(x.Extensions, "deprecated")
|
||||
delete(x.Extensions, "required")
|
||||
delete(x.Extensions, "schema")
|
||||
delete(x.Extensions, "example")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "content")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
|
||||
*parameter = Parameter(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (parameter Parameter) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if parameter.Schema != nil {
|
||||
if parameter.Schema.Ref != "" {
|
||||
return &Ref{Ref: parameter.Schema.Ref}, nil
|
||||
}
|
||||
return parameter.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return parameter.Name, nil
|
||||
case "in":
|
||||
return parameter.In, nil
|
||||
case "description":
|
||||
return parameter.Description, nil
|
||||
case "style":
|
||||
return parameter.Style, nil
|
||||
case "explode":
|
||||
return parameter.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return parameter.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return parameter.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return parameter.Deprecated, nil
|
||||
case "required":
|
||||
return parameter.Required, nil
|
||||
case "example":
|
||||
return parameter.Example, nil
|
||||
case "examples":
|
||||
return parameter.Examples, nil
|
||||
case "content":
|
||||
return parameter.Content, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(parameter.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
// SerializationMethod returns a parameter's serialization method.
|
||||
// When a parameter's serialization method is not defined the method returns
|
||||
// the default serialization method corresponding to a parameter's location.
|
||||
func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error) {
|
||||
switch parameter.In {
|
||||
case ParameterInPath, ParameterInHeader:
|
||||
style := parameter.Style
|
||||
if style == "" {
|
||||
style = SerializationSimple
|
||||
}
|
||||
explode := false
|
||||
if parameter.Explode != nil {
|
||||
explode = *parameter.Explode
|
||||
}
|
||||
return &SerializationMethod{Style: style, Explode: explode}, nil
|
||||
case ParameterInQuery, ParameterInCookie:
|
||||
style := parameter.Style
|
||||
if style == "" {
|
||||
style = SerializationForm
|
||||
}
|
||||
explode := true
|
||||
if parameter.Explode != nil {
|
||||
explode = *parameter.Explode
|
||||
}
|
||||
return &SerializationMethod{Style: style, Explode: explode}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected parameter's 'in': %q", parameter.In)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if Parameter does not comply with the OpenAPI spec.
|
||||
func (parameter *Parameter) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if parameter.Name == "" {
|
||||
return newParameterNameRequired(parameter.Origin)
|
||||
}
|
||||
in := parameter.In
|
||||
switch in {
|
||||
case
|
||||
ParameterInPath,
|
||||
ParameterInQuery,
|
||||
ParameterInHeader,
|
||||
ParameterInCookie:
|
||||
default:
|
||||
return newInvalidParameterIn(parameter.In, parameter.Origin)
|
||||
}
|
||||
|
||||
if in == ParameterInPath && !parameter.Required {
|
||||
return newPathParameterRequired(parameter.Name, parameter.Origin)
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := parameter.SerializationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var smSupported bool
|
||||
switch {
|
||||
case parameter.In == ParameterInPath && sm.Style == SerializationSimple && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationSimple && sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationLabel && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationLabel && sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && sm.Explode,
|
||||
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationForm && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationForm && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationDeepObject && sm.Explode,
|
||||
|
||||
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
|
||||
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && sm.Explode,
|
||||
|
||||
parameter.In == ParameterInCookie && sm.Style == SerializationForm && !sm.Explode,
|
||||
parameter.In == ParameterInCookie && sm.Style == SerializationForm && sm.Explode:
|
||||
smSupported = true
|
||||
}
|
||||
if !smSupported {
|
||||
e := newInvalidSerializationMethod(in, sm.Style, sm.Explode, parameter.Origin)
|
||||
return &ParameterFieldValidationError{ParameterName: parameter.Name, Field: "schema", Cause: e}
|
||||
}
|
||||
|
||||
if (parameter.Schema == nil) == (len(parameter.Content) == 0) {
|
||||
return &ParameterFieldValidationError{ParameterName: parameter.Name, Field: "schema",
|
||||
Cause: newParameterContentSchemaExactlyOne(parameter.Origin)}
|
||||
}
|
||||
|
||||
if content := parameter.Content; content != nil {
|
||||
if len(content) > 1 {
|
||||
return &ParameterFieldValidationError{ParameterName: parameter.Name, Field: "content",
|
||||
Cause: newParameterContentSingleEntry(parameter.Origin)}
|
||||
}
|
||||
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return &ParameterFieldValidationError{ParameterName: parameter.Name, Field: "content", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if schema := parameter.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return &ParameterFieldValidationError{ParameterName: parameter.Name, Field: "schema", Cause: err}
|
||||
}
|
||||
if parameter.Example != nil && parameter.Examples != nil {
|
||||
return newParameterExampleAndExamplesExclusive(parameter.Name, parameter.Origin)
|
||||
}
|
||||
|
||||
if vo := getValidationOptions(ctx); vo.examplesValidationDisabled {
|
||||
return nil
|
||||
}
|
||||
if example := parameter.Example; example != nil {
|
||||
if err := validateExampleValue(ctx, example, schema.Value); err != nil {
|
||||
return newSchemaValueError("example", err, parameter.Origin)
|
||||
}
|
||||
} else if examples := parameter.Examples; examples != nil {
|
||||
for _, k := range componentNames(examples) {
|
||||
v := examples[k]
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return &ParameterExampleValidationError{ExampleName: k, Cause: err}
|
||||
}
|
||||
if err := validateExampleValue(ctx, v.Value.Value, schema.Value); err != nil {
|
||||
return newSchemaValueError("example",
|
||||
&ParameterExampleValidationError{ExampleName: k, Cause: err},
|
||||
exampleValueOrigin(v.Value, parameter.Origin))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, parameter.Extensions, parameter.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ParametersMap to a copy of data.
|
||||
func (parametersMap *ParametersMap) UnmarshalJSON(data []byte) (err error) {
|
||||
*parametersMap, err = unmarshalStringMapP[ParameterRef](data)
|
||||
return
|
||||
}
|
||||
244
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
Normal file
244
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// PathItem is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#path-item-object
|
||||
type PathItem struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Connect *Operation `json:"connect,omitempty" yaml:"connect,omitempty"`
|
||||
Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"`
|
||||
Get *Operation `json:"get,omitempty" yaml:"get,omitempty"`
|
||||
Head *Operation `json:"head,omitempty" yaml:"head,omitempty"`
|
||||
Options *Operation `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Post *Operation `json:"post,omitempty" yaml:"post,omitempty"`
|
||||
Put *Operation `json:"put,omitempty" yaml:"put,omitempty"`
|
||||
Trace *Operation `json:"trace,omitempty" yaml:"trace,omitempty"`
|
||||
Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||
Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of PathItem.
|
||||
func (pathItem PathItem) MarshalJSON() ([]byte, error) {
|
||||
x, err := pathItem.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of PathItem.
|
||||
func (pathItem PathItem) MarshalYAML() (any, error) {
|
||||
if ref := pathItem.Ref; ref != "" {
|
||||
return Ref{Ref: ref}, nil
|
||||
}
|
||||
|
||||
m := make(map[string]any, 13+len(pathItem.Extensions))
|
||||
maps.Copy(m, pathItem.Extensions)
|
||||
if x := pathItem.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := pathItem.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := pathItem.Connect; x != nil {
|
||||
m["connect"] = x
|
||||
}
|
||||
if x := pathItem.Delete; x != nil {
|
||||
m["delete"] = x
|
||||
}
|
||||
if x := pathItem.Get; x != nil {
|
||||
m["get"] = x
|
||||
}
|
||||
if x := pathItem.Head; x != nil {
|
||||
m["head"] = x
|
||||
}
|
||||
if x := pathItem.Options; x != nil {
|
||||
m["options"] = x
|
||||
}
|
||||
if x := pathItem.Patch; x != nil {
|
||||
m["patch"] = x
|
||||
}
|
||||
if x := pathItem.Post; x != nil {
|
||||
m["post"] = x
|
||||
}
|
||||
if x := pathItem.Put; x != nil {
|
||||
m["put"] = x
|
||||
}
|
||||
if x := pathItem.Trace; x != nil {
|
||||
m["trace"] = x
|
||||
}
|
||||
if x := pathItem.Servers; len(x) != 0 {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := pathItem.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets PathItem to a copy of data.
|
||||
func (pathItem *PathItem) UnmarshalJSON(data []byte) error {
|
||||
type PathItemBis PathItem
|
||||
var x PathItemBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "$ref")
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "connect")
|
||||
delete(x.Extensions, "delete")
|
||||
delete(x.Extensions, "get")
|
||||
delete(x.Extensions, "head")
|
||||
delete(x.Extensions, "options")
|
||||
delete(x.Extensions, "patch")
|
||||
delete(x.Extensions, "post")
|
||||
delete(x.Extensions, "put")
|
||||
delete(x.Extensions, "trace")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "parameters")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*pathItem = PathItem(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pathItem *PathItem) Operations() map[string]*Operation {
|
||||
operations := make(map[string]*Operation)
|
||||
if v := pathItem.Connect; v != nil {
|
||||
operations[http.MethodConnect] = v
|
||||
}
|
||||
if v := pathItem.Delete; v != nil {
|
||||
operations[http.MethodDelete] = v
|
||||
}
|
||||
if v := pathItem.Get; v != nil {
|
||||
operations[http.MethodGet] = v
|
||||
}
|
||||
if v := pathItem.Head; v != nil {
|
||||
operations[http.MethodHead] = v
|
||||
}
|
||||
if v := pathItem.Options; v != nil {
|
||||
operations[http.MethodOptions] = v
|
||||
}
|
||||
if v := pathItem.Patch; v != nil {
|
||||
operations[http.MethodPatch] = v
|
||||
}
|
||||
if v := pathItem.Post; v != nil {
|
||||
operations[http.MethodPost] = v
|
||||
}
|
||||
if v := pathItem.Put; v != nil {
|
||||
operations[http.MethodPut] = v
|
||||
}
|
||||
if v := pathItem.Trace; v != nil {
|
||||
operations[http.MethodTrace] = v
|
||||
}
|
||||
return operations
|
||||
}
|
||||
|
||||
func (pathItem *PathItem) GetOperation(method string) *Operation {
|
||||
switch method {
|
||||
case http.MethodConnect:
|
||||
return pathItem.Connect
|
||||
case http.MethodDelete:
|
||||
return pathItem.Delete
|
||||
case http.MethodGet:
|
||||
return pathItem.Get
|
||||
case http.MethodHead:
|
||||
return pathItem.Head
|
||||
case http.MethodOptions:
|
||||
return pathItem.Options
|
||||
case http.MethodPatch:
|
||||
return pathItem.Patch
|
||||
case http.MethodPost:
|
||||
return pathItem.Post
|
||||
case http.MethodPut:
|
||||
return pathItem.Put
|
||||
case http.MethodTrace:
|
||||
return pathItem.Trace
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported HTTP method %q", method))
|
||||
}
|
||||
}
|
||||
|
||||
func (pathItem *PathItem) SetOperation(method string, operation *Operation) {
|
||||
switch method {
|
||||
case http.MethodConnect:
|
||||
pathItem.Connect = operation
|
||||
case http.MethodDelete:
|
||||
pathItem.Delete = operation
|
||||
case http.MethodGet:
|
||||
pathItem.Get = operation
|
||||
case http.MethodHead:
|
||||
pathItem.Head = operation
|
||||
case http.MethodOptions:
|
||||
pathItem.Options = operation
|
||||
case http.MethodPatch:
|
||||
pathItem.Patch = operation
|
||||
case http.MethodPost:
|
||||
pathItem.Post = operation
|
||||
case http.MethodPut:
|
||||
pathItem.Put = operation
|
||||
case http.MethodTrace:
|
||||
pathItem.Trace = operation
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported HTTP method %q", method))
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if PathItem does not comply with the OpenAPI spec.
|
||||
func (pathItem *PathItem) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
operations := pathItem.Operations()
|
||||
|
||||
for _, method := range componentNames(operations) {
|
||||
operation := operations[method]
|
||||
wrapOp := func(e error) error { return &OperationValidationError{Method: method, Cause: e} }
|
||||
if err := me.emitWrapped(wrapOp, operation.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v := pathItem.Parameters; v != nil {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, pathItem.Extensions, pathItem.Origin))
|
||||
}
|
||||
|
||||
// isEmpty's introduced in 546590b1
|
||||
func (pathItem *PathItem) isEmpty() bool {
|
||||
// NOTE: ignores pathItem.Extensions
|
||||
// NOTE: ignores pathItem.Ref
|
||||
return pathItem.Summary == "" &&
|
||||
pathItem.Description == "" &&
|
||||
pathItem.Connect == nil &&
|
||||
pathItem.Delete == nil &&
|
||||
pathItem.Get == nil &&
|
||||
pathItem.Head == nil &&
|
||||
pathItem.Options == nil &&
|
||||
pathItem.Patch == nil &&
|
||||
pathItem.Post == nil &&
|
||||
pathItem.Put == nil &&
|
||||
pathItem.Trace == nil &&
|
||||
len(pathItem.Servers) == 0 &&
|
||||
len(pathItem.Parameters) == 0
|
||||
}
|
||||
275
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
Normal file
275
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Paths is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#paths-object
|
||||
type Paths struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
m map[string]*PathItem
|
||||
}
|
||||
|
||||
// NewPaths builds a paths object with path items in insertion order.
|
||||
func NewPaths(opts ...NewPathsOption) *Paths {
|
||||
paths := NewPathsWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(paths)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// NewPathsOption describes options to NewPaths func
|
||||
type NewPathsOption func(*Paths)
|
||||
|
||||
// WithPath adds a named path item
|
||||
func WithPath(path string, pathItem *PathItem) NewPathsOption {
|
||||
return func(paths *Paths) {
|
||||
if p := pathItem; p != nil && path != "" {
|
||||
paths.Set(path, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if Paths does not comply with the OpenAPI spec.
|
||||
func (paths *Paths) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
normalizedPaths := make(map[string]string, paths.Len())
|
||||
|
||||
for _, path := range paths.Keys() {
|
||||
pathItem := paths.Value(path)
|
||||
if path == "" || path[0] != '/' {
|
||||
if err := me.emit(newPathMustStartWithSlash(path, paths.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip validating operations under a malformed path key: any
|
||||
// findings below would be addressed under a path that has no
|
||||
// resolution path until the key itself is fixed.
|
||||
continue
|
||||
}
|
||||
|
||||
if pathItem == nil {
|
||||
pathItem = &PathItem{}
|
||||
paths.Set(path, pathItem)
|
||||
}
|
||||
|
||||
normalizedPath, _, varsInPath := normalizeTemplatedPath(path)
|
||||
if oldPath, ok := normalizedPaths[normalizedPath]; ok {
|
||||
if err := me.emit(newConflictingPaths(path, oldPath, paths.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip validating operations under a duplicate path: the
|
||||
// first occurrence already validated its operations under the
|
||||
// canonical path, so re-running would surface duplicate-but-
|
||||
// identical findings without new information.
|
||||
continue
|
||||
}
|
||||
normalizedPaths[normalizedPath] = path
|
||||
|
||||
var commonParams []string
|
||||
for _, parameterRef := range pathItem.Parameters {
|
||||
if parameterRef != nil {
|
||||
if parameter := parameterRef.Value; parameter != nil && parameter.In == ParameterInPath {
|
||||
commonParams = append(commonParams, parameter.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
operations := pathItem.Operations()
|
||||
for _, method := range componentNames(operations) {
|
||||
operation := operations[method]
|
||||
var setParams []string
|
||||
for _, parameterRef := range operation.Parameters {
|
||||
if parameterRef != nil {
|
||||
if parameter := parameterRef.Value; parameter != nil && parameter.In == ParameterInPath {
|
||||
setParams = append(setParams, parameter.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if expected := len(setParams) + len(commonParams); expected != len(varsInPath) {
|
||||
expected -= len(varsInPath)
|
||||
if expected < 0 {
|
||||
expected *= -1
|
||||
}
|
||||
missing := make(map[string]struct{}, expected)
|
||||
definedParams := append(setParams, commonParams...)
|
||||
for _, name := range definedParams {
|
||||
if _, ok := varsInPath[name]; !ok {
|
||||
missing[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, name := range componentNames(varsInPath) {
|
||||
if slices.Contains(definedParams, name) {
|
||||
break
|
||||
}
|
||||
missing[name] = struct{}{}
|
||||
}
|
||||
if len(missing) != 0 {
|
||||
if err := me.emit(&PathParametersError{
|
||||
Path: path,
|
||||
Method: method,
|
||||
Missing: componentNames(missing),
|
||||
Origin: pathItem.Origin,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrapPath := func(e error) error { return &PathValidationError{Path: path, Cause: e} }
|
||||
if err := me.emitWrapped(wrapPath, pathItem.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := me.emit(paths.validateUniqueOperationIDs()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, paths.Extensions, paths.Origin))
|
||||
}
|
||||
|
||||
// InMatchingOrder returns paths in the order they are matched against URLs.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#paths-object
|
||||
// When matching URLs, concrete (non-templated) paths would be matched
|
||||
// before their templated counterparts.
|
||||
func (paths *Paths) InMatchingOrder() []string {
|
||||
// NOTE: sorting by number of variables ASC then by descending lexicographical
|
||||
// order seems to be a good heuristic.
|
||||
if paths.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
vars := make(map[int][]string)
|
||||
max := 0
|
||||
for path := range paths.Map() {
|
||||
count := strings.Count(path, "}")
|
||||
vars[count] = append(vars[count], path)
|
||||
if count > max {
|
||||
max = count
|
||||
}
|
||||
}
|
||||
|
||||
ordered := make([]string, 0, paths.Len())
|
||||
for c := 0; c <= max; c++ {
|
||||
if ps, ok := vars[c]; ok {
|
||||
slices.SortFunc(ps, func(a, b string) int { return cmp.Compare(b, a) })
|
||||
ordered = append(ordered, ps...)
|
||||
}
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
|
||||
// Find returns a path that matches the key.
|
||||
//
|
||||
// The method ignores differences in template variable names (except possible "*" suffix).
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// paths := openapi3.Paths {
|
||||
// "/person/{personName}": &openapi3.PathItem{},
|
||||
// }
|
||||
// pathItem := path.Find("/person/{name}")
|
||||
//
|
||||
// would return the correct path item.
|
||||
func (paths *Paths) Find(key string) *PathItem {
|
||||
// Try directly access the map
|
||||
pathItem := paths.Value(key)
|
||||
if pathItem != nil {
|
||||
return pathItem
|
||||
}
|
||||
|
||||
normalizedPath, expected, _ := normalizeTemplatedPath(key)
|
||||
pathsMap := paths.Map()
|
||||
for _, path := range componentNames(pathsMap) {
|
||||
pathNormalized, got, _ := normalizeTemplatedPath(path)
|
||||
if got == expected && pathNormalized == normalizedPath {
|
||||
return pathsMap[path]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (paths *Paths) validateUniqueOperationIDs() error {
|
||||
operationIDs := make(map[string]string)
|
||||
pathsMap := paths.Map()
|
||||
for _, urlPath := range componentNames(pathsMap) {
|
||||
pathItem := pathsMap[urlPath]
|
||||
if pathItem == nil {
|
||||
continue
|
||||
}
|
||||
operations := pathItem.Operations()
|
||||
for _, httpMethod := range componentNames(operations) {
|
||||
operation := operations[httpMethod]
|
||||
if operation == nil || operation.OperationID == "" {
|
||||
continue
|
||||
}
|
||||
endpoint := httpMethod + " " + urlPath
|
||||
if endpointDup, ok := operationIDs[operation.OperationID]; ok {
|
||||
if endpoint > endpointDup { // For make error message a bit more deterministic. May be useful for tests.
|
||||
endpoint, endpointDup = endpointDup, endpoint
|
||||
}
|
||||
return newDuplicateOperationID(endpoint, endpointDup, operation.OperationID, operation.Origin)
|
||||
}
|
||||
operationIDs[operation.OperationID] = endpoint
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeTemplatedPath(path string) (string, uint, map[string]struct{}) {
|
||||
if strings.IndexByte(path, '{') < 0 {
|
||||
return path, 0, nil
|
||||
}
|
||||
|
||||
var buffTpl strings.Builder
|
||||
buffTpl.Grow(len(path))
|
||||
|
||||
var (
|
||||
cc rune
|
||||
count uint
|
||||
isVariable bool
|
||||
vars = make(map[string]struct{})
|
||||
buffVar strings.Builder
|
||||
)
|
||||
for i, c := range path {
|
||||
if isVariable {
|
||||
if c == '}' {
|
||||
// End path variable
|
||||
isVariable = false
|
||||
|
||||
vars[buffVar.String()] = struct{}{}
|
||||
buffVar = strings.Builder{}
|
||||
|
||||
// First append possible '*' before this character
|
||||
// The character '}' will be appended
|
||||
if i > 0 && cc == '*' {
|
||||
buffTpl.WriteRune(cc)
|
||||
}
|
||||
} else {
|
||||
buffVar.WriteRune(c)
|
||||
continue
|
||||
}
|
||||
|
||||
} else if c == '{' {
|
||||
// Begin path variable
|
||||
isVariable = true
|
||||
|
||||
// The character '{' will be appended
|
||||
count++
|
||||
}
|
||||
|
||||
// Append the character
|
||||
buffTpl.WriteRune(c)
|
||||
cc = c
|
||||
}
|
||||
return buffTpl.String(), count, vars
|
||||
}
|
||||
42
vendor/github.com/getkin/kin-openapi/openapi3/ref.go
generated
vendored
Normal file
42
vendor/github.com/getkin/kin-openapi/openapi3/ref.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
//go:generate go run refsgenerator.go
|
||||
|
||||
// Ref is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#reference-object
|
||||
type Ref struct {
|
||||
Ref string `json:"$ref" yaml:"$ref"`
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Ref.
|
||||
func (x Ref) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 1+len(x.Extensions))
|
||||
maps.Copy(m, x.Extensions)
|
||||
if x := x.Ref; x != "" {
|
||||
m["$ref"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Ref.
|
||||
func (x Ref) MarshalJSON() ([]byte, error) {
|
||||
y, err := x.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(y)
|
||||
}
|
||||
|
||||
// Validate returns an error if Extensions does not comply with the OpenAPI spec.
|
||||
func (e *Ref) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
return validateExtensions(ctx, e.Extensions, e.Origin)
|
||||
}
|
||||
1310
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
Normal file
1310
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
vendor/github.com/getkin/kin-openapi/openapi3/refs.tmpl
generated
vendored
Normal file
183
vendor/github.com/getkin/kin-openapi/openapi3/refs.tmpl
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Code generated by go generate using refs.tmpl; DO NOT EDIT refs.go.
|
||||
package {{ .Package }}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
{{ range $type := .Types }}
|
||||
// {{ $type.Name }}Ref represents either a {{ $type.Name }} or a $ref to a {{ $type.Name }}.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type {{ $type.Name }}Ref struct {
|
||||
// Extensions only captures fields starting with 'x-' as no other fields
|
||||
// are allowed by the openapi spec.
|
||||
Extensions map[string]any
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Ref string
|
||||
Value *{{ $type.Name }}
|
||||
extra []string
|
||||
{{- if eq $type.Name "Schema" }}
|
||||
// sibling holds keyword siblings of a $ref (OAS 3.1 / JSON Schema 2020-12).
|
||||
// It is populated during unmarshal and applied to Value after $ref resolution.
|
||||
sibling *Schema
|
||||
{{- end }}
|
||||
|
||||
refPath *url.URL
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*{{ $type.Name }}Ref)(nil)
|
||||
|
||||
func (x *{{ $type.Name }}Ref) isEmpty() bool { return x == nil || x.Ref == "" && x.Value == nil }
|
||||
|
||||
// RefString returns the $ref value.
|
||||
func (x *{{ $type.Name }}Ref) RefString() string { return x.Ref }
|
||||
|
||||
// CollectionName returns the JSON string used for a collection of these components.
|
||||
func (x *{{ $type.Name }}Ref) CollectionName() string { return "{{ $type.CollectionName }}" }
|
||||
|
||||
// RefPath returns the path of the $ref relative to the root document.
|
||||
func (x *{{ $type.Name }}Ref) RefPath() *url.URL { return copyURI(x.refPath) }
|
||||
|
||||
func (x *{{ $type.Name }}Ref) setRefPath(u *url.URL) {
|
||||
// Once the refPath is set don't override. References can be loaded
|
||||
// multiple times not all with access to the correct path info.
|
||||
if x.refPath != nil {
|
||||
return
|
||||
}
|
||||
|
||||
x.refPath = copyURI(u)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of {{ $type.Name }}Ref.
|
||||
func (x {{ $type.Name }}Ref) MarshalYAML() (any, error) {
|
||||
if ref := x.Ref; ref != "" {
|
||||
return &Ref{Ref: ref, Extensions: x.Extensions}, nil
|
||||
}
|
||||
return x.Value.MarshalYAML()
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of {{ $type.Name }}Ref.
|
||||
func (x {{ $type.Name }}Ref) MarshalJSON() ([]byte, error) {
|
||||
y, err := x.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(y)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets {{ $type.Name }}Ref to a copy of data.
|
||||
func (x *{{ $type.Name }}Ref) UnmarshalJSON(data []byte) error {
|
||||
var refOnly Ref
|
||||
if err := json.Unmarshal(data, &refOnly); err == nil && refOnly.Ref != "" {
|
||||
extra := map[string]any{}
|
||||
_ = json.Unmarshal(data, &extra)
|
||||
delete(extra, "$ref")
|
||||
x.Ref = refOnly.Ref
|
||||
x.Origin = refOnly.Origin
|
||||
if len(extra) != 0 {
|
||||
x.extra = componentNames(extra)
|
||||
{{- if eq $type.Name "Schema" }}
|
||||
// OAS 3.1 / JSON Schema 2020-12: sibling keywords alongside $ref are valid
|
||||
// and must be merged with the resolved reference. Parse the full object so
|
||||
// the sibling fields are available after $ref resolution in resolveSchemaRef.
|
||||
hasSiblings := false
|
||||
for k := range extra {
|
||||
if !strings.HasPrefix(k, "x-") {
|
||||
hasSiblings = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasSiblings {
|
||||
var sibling Schema
|
||||
if err := json.Unmarshal(data, &sibling); err == nil {
|
||||
x.sibling = &sibling
|
||||
}
|
||||
}
|
||||
{{- end }}
|
||||
for k := range extra {
|
||||
if !strings.HasPrefix(k, "x-") {
|
||||
delete(extra, k)
|
||||
}
|
||||
}
|
||||
if len(extra) != 0 {
|
||||
x.Extensions = extra
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(data, &x.Value)
|
||||
}
|
||||
|
||||
// validateExtras returns an error if {{ $type.Name }}Ref has sibling fields
|
||||
// alongside $ref that are not allowed by the validation options.
|
||||
func (x *{{ $type.Name }}Ref) validateExtras(ctx context.Context) error {
|
||||
validationOpts := getValidationOptions(ctx)
|
||||
var extras []string
|
||||
|
||||
allowed := validationOpts.extraSiblingFieldsAllowed
|
||||
if allowed == nil {
|
||||
allowed = make(map[string]struct{})
|
||||
}
|
||||
for _, ex := range x.extra {
|
||||
if _, ok := allowed[ex]; !ok {
|
||||
if _, ok := x.Extensions[ex]; !ok {
|
||||
extras = append(extras, ex)
|
||||
}
|
||||
// extras in the Extensions checked below
|
||||
}
|
||||
}
|
||||
|
||||
if validationOpts.schemaExtensionsInRefProhibited {
|
||||
for _, ex := range componentNames(x.Extensions) {
|
||||
if _, ok := allowed[ex]; !ok {
|
||||
extras = append(extras, ex)
|
||||
}
|
||||
// extras in the Extensions checked below
|
||||
}
|
||||
}
|
||||
|
||||
if len(extras) != 0 {
|
||||
{{- if eq $type.Name "Schema" }}
|
||||
if !validationOpts.isOpenAPI31OrLater {
|
||||
return newExtraSiblingFields(extras, x.Origin)
|
||||
}
|
||||
{{- else }}
|
||||
return newExtraSiblingFields(extras, x.Origin)
|
||||
{{- end }}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if {{ $type.Name }}Ref does not comply with the OpenAPI spec.
|
||||
func (x *{{ $type.Name }}Ref) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
if err := x.validateExtras(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v := x.Value; v != nil {
|
||||
return v.Validate(ctx)
|
||||
}
|
||||
|
||||
return newUnresolvedRef(x.Ref, x.Origin)
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (x *{{ $type.Name }}Ref) JSONLookup(token string) (any, error) {
|
||||
if token == "$ref" {
|
||||
return x.Ref, nil
|
||||
}
|
||||
|
||||
if v, ok := x.Extensions[token]; ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
ptr, _, err := jsonpointer.GetForToken(x.Value, token)
|
||||
return ptr, err
|
||||
}
|
||||
{{ end -}}
|
||||
62
vendor/github.com/getkin/kin-openapi/openapi3/refs_test.tmpl
generated
vendored
Normal file
62
vendor/github.com/getkin/kin-openapi/openapi3/refs_test.tmpl
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
package {{ .Package }}_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
{{ range $type := .Types }}
|
||||
func Test{{ $type.Name }}Ref_Extensions(t *testing.T) {
|
||||
data := []byte(`{"$ref":"#/components/schemas/Pet","something":"integer","x-order":1}`)
|
||||
expectMarshalJson := []byte(`{"$ref":"#/components/schemas/Pet","x-order":1}`)
|
||||
|
||||
ref := openapi3.{{ $type.Name }}Ref{}
|
||||
err := json.Unmarshal(data, &ref)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// captures extension
|
||||
assert.Equal(t, "#/components/schemas/Pet", ref.Ref)
|
||||
assert.Equal(t, float64(1), ref.Extensions["x-order"])
|
||||
|
||||
// does not capture non-extensions
|
||||
assert.Nil(t, ref.Extensions["something"])
|
||||
|
||||
// validation
|
||||
err = ref.Validate(t.Context())
|
||||
require.EqualError(t, err, "extra sibling fields: [something]")
|
||||
|
||||
err = ref.Validate(t.Context(), openapi3.ProhibitExtensionsWithRef())
|
||||
require.EqualError(t, err, "extra sibling fields: [something x-order]")
|
||||
|
||||
err = ref.Validate(t.Context(), openapi3.AllowExtraSiblingFields("something"))
|
||||
assert.ErrorContains(t, err, "found unresolved ref") // expected since value not defined
|
||||
|
||||
// Verify round trip JSON
|
||||
// Compare as string to make error message more readable if different
|
||||
outJson, err := ref.MarshalJSON()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, string(outJson), string(expectMarshalJson), "MarshalJSON output is not the same as input data")
|
||||
|
||||
// non-extension not json lookable
|
||||
_, err = ref.JSONLookup("something")
|
||||
assert.Error(t, err)
|
||||
{{ if ne $type.Name "Header" }}
|
||||
t.Run("extentions in value", func(t *testing.T) {
|
||||
ref.Value = &openapi3.{{ $type.Name }}{Extensions: map[string]any{}}
|
||||
ref.Value.Extensions["x-order"] = 2.0
|
||||
|
||||
// prefers the value next to the \$ref over the one in the \$ref.
|
||||
v, err := ref.JSONLookup("x-order")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, float64(1), v)
|
||||
})
|
||||
{{ else }}
|
||||
// Header does not have its own extensions.
|
||||
{{ end -}}
|
||||
}
|
||||
{{ end -}}
|
||||
143
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
Normal file
143
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// RequestBody is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#request-body-object
|
||||
type RequestBody struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Content Content `json:"content" yaml:"content"`
|
||||
}
|
||||
|
||||
func NewRequestBody() *RequestBody {
|
||||
return &RequestBody{}
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithDescription(value string) *RequestBody {
|
||||
requestBody.Description = value
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithRequired(value bool) *RequestBody {
|
||||
requestBody.Required = value
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithContent(content Content) *RequestBody {
|
||||
requestBody.Content = content
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithSchemaRef(value *SchemaRef, consumes []string) *RequestBody {
|
||||
requestBody.Content = NewContentWithSchemaRef(value, consumes)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithSchema(value *Schema, consumes []string) *RequestBody {
|
||||
requestBody.Content = NewContentWithSchema(value, consumes)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithJSONSchemaRef(value *SchemaRef) *RequestBody {
|
||||
requestBody.Content = NewContentWithJSONSchemaRef(value)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithJSONSchema(value *Schema) *RequestBody {
|
||||
requestBody.Content = NewContentWithJSONSchema(value)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithFormDataSchemaRef(value *SchemaRef) *RequestBody {
|
||||
requestBody.Content = NewContentWithFormDataSchemaRef(value)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) WithFormDataSchema(value *Schema) *RequestBody {
|
||||
requestBody.Content = NewContentWithFormDataSchema(value)
|
||||
return requestBody
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType {
|
||||
m := requestBody.Content
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return m[mediaType]
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of RequestBody.
|
||||
func (requestBody RequestBody) MarshalJSON() ([]byte, error) {
|
||||
x, err := requestBody.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of RequestBody.
|
||||
func (requestBody RequestBody) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(requestBody.Extensions))
|
||||
maps.Copy(m, requestBody.Extensions)
|
||||
if x := requestBody.Description; x != "" {
|
||||
m["description"] = requestBody.Description
|
||||
}
|
||||
if x := requestBody.Required; x {
|
||||
m["required"] = x
|
||||
}
|
||||
if x := requestBody.Content; true {
|
||||
m["content"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets RequestBody to a copy of data.
|
||||
func (requestBody *RequestBody) UnmarshalJSON(data []byte) error {
|
||||
type RequestBodyBis RequestBody
|
||||
var x RequestBodyBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "required")
|
||||
delete(x.Extensions, "content")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*requestBody = RequestBody(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if RequestBody does not comply with the OpenAPI spec.
|
||||
func (requestBody *RequestBody) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if requestBody.Content == nil {
|
||||
return newRequestBodyContentRequired(requestBody.Origin)
|
||||
}
|
||||
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
vo.examplesValidationAsReq, vo.examplesValidationAsRes = true, false
|
||||
}
|
||||
|
||||
if err := requestBody.Content.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, requestBody.Extensions, requestBody.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets RequestBodies to a copy of data.
|
||||
func (requestBodies *RequestBodies) UnmarshalJSON(data []byte) (err error) {
|
||||
*requestBodies, err = unmarshalStringMapP[RequestBodyRef](data)
|
||||
return
|
||||
}
|
||||
219
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
Normal file
219
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Responses is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responses-object
|
||||
type Responses struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
m map[string]*ResponseRef
|
||||
}
|
||||
|
||||
// NewResponses builds a responses object with response objects in insertion order.
|
||||
// Given no arguments, NewResponses returns an empty responses object.
|
||||
func NewResponses(opts ...NewResponsesOption) *Responses {
|
||||
responses := NewResponsesWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(responses)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// NewResponsesOption describes options to NewResponses func
|
||||
type NewResponsesOption func(*Responses)
|
||||
|
||||
// WithStatus adds a status code keyed ResponseRef
|
||||
func WithStatus(status int, responseRef *ResponseRef) NewResponsesOption {
|
||||
return func(responses *Responses) {
|
||||
if r := responseRef; r != nil {
|
||||
code := strconv.FormatInt(int64(status), 10)
|
||||
responses.Set(code, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithName adds a name-keyed Response
|
||||
func WithName(name string, response *Response) NewResponsesOption {
|
||||
return func(responses *Responses) {
|
||||
if r := response; r != nil && name != "" {
|
||||
responses.Set(name, &ResponseRef{Value: r})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default returns the default response
|
||||
func (responses *Responses) Default() *ResponseRef {
|
||||
return responses.Value("default")
|
||||
}
|
||||
|
||||
// Status returns a ResponseRef for the given status
|
||||
// If an exact match isn't initially found a patterned field is checked using
|
||||
// the first digit to determine the range (eg: 201 to 2XX)
|
||||
// See https://spec.openapis.org/oas/v3.0.3#patterned-fields-0
|
||||
func (responses *Responses) Status(status int) *ResponseRef {
|
||||
st := strconv.FormatInt(int64(status), 10)
|
||||
if rref := responses.Value(st); rref != nil {
|
||||
return rref
|
||||
}
|
||||
if 99 < status && status < 600 {
|
||||
st = string(st[0]) + "XX"
|
||||
switch st {
|
||||
case "1XX", "2XX", "3XX", "4XX", "5XX":
|
||||
return responses.Value(st)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Responses does not comply with the OpenAPI spec.
|
||||
func (responses *Responses) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if responses.Len() == 0 {
|
||||
if err := me.emit(newResponsesNonEmptyRequired(responses.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Fall through so validateExtensions still runs and any extension
|
||||
// errors aggregate with the empty-responses finding under multi mode.
|
||||
}
|
||||
|
||||
for _, key := range responses.Keys() {
|
||||
v := responses.Value(key)
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, responses.Extensions, responses.Origin))
|
||||
}
|
||||
|
||||
// Response is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#response-object
|
||||
type Response struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
|
||||
}
|
||||
|
||||
func NewResponse() *Response {
|
||||
return &Response{}
|
||||
}
|
||||
|
||||
func (response *Response) WithDescription(value string) *Response {
|
||||
response.Description = &value
|
||||
return response
|
||||
}
|
||||
|
||||
func (response *Response) WithContent(content Content) *Response {
|
||||
response.Content = content
|
||||
return response
|
||||
}
|
||||
|
||||
func (response *Response) WithJSONSchema(schema *Schema) *Response {
|
||||
response.Content = NewContentWithJSONSchema(schema)
|
||||
return response
|
||||
}
|
||||
|
||||
func (response *Response) WithJSONSchemaRef(schema *SchemaRef) *Response {
|
||||
response.Content = NewContentWithJSONSchemaRef(schema)
|
||||
return response
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Response.
|
||||
func (response Response) MarshalJSON() ([]byte, error) {
|
||||
x, err := response.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Response.
|
||||
func (response Response) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(response.Extensions))
|
||||
maps.Copy(m, response.Extensions)
|
||||
if x := response.Description; x != nil {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := response.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := response.Content; len(x) != 0 {
|
||||
m["content"] = x
|
||||
}
|
||||
if x := response.Links; len(x) != 0 {
|
||||
m["links"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Response to a copy of data.
|
||||
func (response *Response) UnmarshalJSON(data []byte) error {
|
||||
type ResponseBis Response
|
||||
var x ResponseBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "content")
|
||||
delete(x.Extensions, "links")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*response = Response(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Response does not comply with the OpenAPI spec.
|
||||
func (response *Response) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if response.Description == nil {
|
||||
return newResponseDescriptionRequired(response.Origin)
|
||||
}
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
vo.examplesValidationAsReq, vo.examplesValidationAsRes = false, true
|
||||
}
|
||||
|
||||
if content := response.Content; content != nil {
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range componentNames(response.Headers) {
|
||||
header := response.Headers[name]
|
||||
if err := header.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range componentNames(response.Links) {
|
||||
link := response.Links[name]
|
||||
if err := link.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, response.Extensions, response.Origin)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ResponseBodies to a copy of data.
|
||||
func (responseBodies *ResponseBodies) UnmarshalJSON(data []byte) (err error) {
|
||||
*responseBodies, err = unmarshalStringMapP[ResponseRef](data)
|
||||
return
|
||||
}
|
||||
3182
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
Normal file
3182
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
172
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
Normal file
172
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/netip"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// FormatValidator is an interface for custom format validators.
|
||||
type FormatValidator[T any] interface {
|
||||
Validate(value T) error
|
||||
}
|
||||
|
||||
// StringFormatValidator is a type alias for FormatValidator[string]
|
||||
type StringFormatValidator = FormatValidator[string]
|
||||
|
||||
// NumberFormatValidator is a type alias for FormatValidator[float64]
|
||||
type NumberFormatValidator = FormatValidator[float64]
|
||||
|
||||
// IntegerFormatValidator is a type alias for FormatValidator[int64]
|
||||
type IntegerFormatValidator = FormatValidator[int64]
|
||||
|
||||
var (
|
||||
// SchemaStringFormats is a map of custom string format validators.
|
||||
SchemaStringFormats = make(map[string]StringFormatValidator)
|
||||
// SchemaNumberFormats is a map of custom number format validators.
|
||||
SchemaNumberFormats = make(map[string]NumberFormatValidator)
|
||||
// SchemaIntegerFormats is a map of custom integer format validators.
|
||||
SchemaIntegerFormats = make(map[string]IntegerFormatValidator)
|
||||
)
|
||||
|
||||
const (
|
||||
// FormatOfStringForUUIDOfRFC4122 is an optional predefined format for UUID v1-v5 as specified by RFC4122
|
||||
FormatOfStringForUUIDOfRFC4122 = `^(?:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$`
|
||||
|
||||
// FormatOfStringForEmail pattern catches only some suspiciously wrong-looking email addresses.
|
||||
// Use DefineStringFormat(...) if you need something stricter.
|
||||
FormatOfStringForEmail = `^[^@]+@[^@<>",\s]+$`
|
||||
|
||||
// FormatOfStringByte is a regexp for base64-encoded characters, for example, "U3dhZ2dlciByb2Nrcw=="
|
||||
FormatOfStringByte = `(^$|^[a-zA-Z0-9+/\-_]*=*$)`
|
||||
|
||||
// FormatOfStringDate is a RFC3339 date format regexp, for example "2017-07-21".
|
||||
FormatOfStringDate = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])$`
|
||||
|
||||
// FormatOfStringDateTime is a RFC3339 date-time format regexp, for example "2017-07-21T17:32:28Z".
|
||||
FormatOfStringDateTime = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})$`
|
||||
)
|
||||
|
||||
func init() {
|
||||
DefineStringFormatValidator("byte", NewRegexpFormatValidator(FormatOfStringByte))
|
||||
DefineStringFormatValidator("date", NewRegexpFormatValidator(FormatOfStringDate))
|
||||
DefineStringFormatValidator("date-time", NewRegexpFormatValidator(FormatOfStringDateTime))
|
||||
DefineIntegerFormatValidator("int32", NewRangeFormatValidator(int64(math.MinInt32), int64(math.MaxInt32)))
|
||||
DefineIntegerFormatValidator("int64", NewRangeFormatValidator(int64(math.MinInt64), int64(math.MaxInt64)))
|
||||
}
|
||||
|
||||
// DefineIPv4Format opts in ipv4 format validation on top of OAS 3 spec
|
||||
func DefineIPv4Format() {
|
||||
DefineStringFormatValidator("ipv4", NewIPValidator(true))
|
||||
}
|
||||
|
||||
// DefineIPv6Format opts in ipv6 format validation on top of OAS 3 spec
|
||||
func DefineIPv6Format() {
|
||||
DefineStringFormatValidator("ipv6", NewIPValidator(false))
|
||||
}
|
||||
|
||||
type stringRegexpFormatValidator struct {
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
func (s stringRegexpFormatValidator) Validate(value string) error {
|
||||
if !s.re.MatchString(value) {
|
||||
return fmt.Errorf(`string doesn't match pattern "%s"`, s.re.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type callbackValidator[T any] struct {
|
||||
fn func(T) error
|
||||
}
|
||||
|
||||
func (c callbackValidator[T]) Validate(value T) error {
|
||||
return c.fn(value)
|
||||
}
|
||||
|
||||
type rangeFormat[T int64 | float64] struct {
|
||||
min, max T
|
||||
}
|
||||
|
||||
func (r rangeFormat[T]) Validate(value T) error {
|
||||
if value < r.min || value > r.max {
|
||||
return fmt.Errorf("value should be between %v and %v", r.min, r.max)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRangeFormatValidator creates a new FormatValidator that validates the value is within a given range.
|
||||
func NewRangeFormatValidator[T int64 | float64](min, max T) FormatValidator[T] {
|
||||
return rangeFormat[T]{min: min, max: max}
|
||||
}
|
||||
|
||||
// NewRegexpFormatValidator creates a new FormatValidator that uses a regular expression to validate the value.
|
||||
func NewRegexpFormatValidator(pattern string) StringFormatValidator {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("string regexp format has invalid pattern %q: %w", pattern, err)
|
||||
panic(err)
|
||||
}
|
||||
return stringRegexpFormatValidator{re: re}
|
||||
}
|
||||
|
||||
// NewCallbackValidator creates a new FormatValidator that uses a callback function to validate the value.
|
||||
func NewCallbackValidator[T any](fn func(T) error) FormatValidator[T] {
|
||||
return callbackValidator[T]{fn: fn}
|
||||
}
|
||||
|
||||
// DefineStringFormatValidator defines a custom format validator for a given string format.
|
||||
func DefineStringFormatValidator(name string, validator StringFormatValidator) {
|
||||
SchemaStringFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineNumberFormatValidator defines a custom format validator for a given number format.
|
||||
func DefineNumberFormatValidator(name string, validator NumberFormatValidator) {
|
||||
SchemaNumberFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineIntegerFormatValidator defines a custom format validator for a given integer format.
|
||||
func DefineIntegerFormatValidator(name string, validator IntegerFormatValidator) {
|
||||
SchemaIntegerFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineStringFormat defines a regexp pattern for a given string format
|
||||
//
|
||||
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern)) instead.
|
||||
func DefineStringFormat(name string, pattern string) {
|
||||
DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern))
|
||||
}
|
||||
|
||||
// DefineStringFormatCallback defines a callback function for a given string format
|
||||
//
|
||||
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewCallbackValidator(fn)) instead.
|
||||
func DefineStringFormatCallback(name string, callback func(string) error) {
|
||||
DefineStringFormatValidator(name, NewCallbackValidator(callback))
|
||||
}
|
||||
|
||||
// NewIPValidator creates a new FormatValidator that validates the value is an IP address.
|
||||
func NewIPValidator(isIPv4 bool) FormatValidator[string] {
|
||||
return callbackValidator[string]{fn: func(ip string) error {
|
||||
addr, err := netip.ParseAddr(ip)
|
||||
if err != nil {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IP address",
|
||||
}
|
||||
}
|
||||
if isIPv4 && !addr.Is4() {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv4 address (it's IPv6)",
|
||||
}
|
||||
}
|
||||
if !isIPv4 && !addr.Is6() {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv6 address (it's IPv4)",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}}
|
||||
}
|
||||
212
vendor/github.com/getkin/kin-openapi/openapi3/schema_jsonschema_validator.go
generated
vendored
Normal file
212
vendor/github.com/getkin/kin-openapi/openapi3/schema_jsonschema_validator.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/santhosh-tekuri/jsonschema/v6"
|
||||
)
|
||||
|
||||
// jsonSchemaValidator wraps the santhosh-tekuri/jsonschema validator
|
||||
type jsonSchemaValidator struct {
|
||||
compiler *jsonschema.Compiler
|
||||
schema *jsonschema.Schema
|
||||
}
|
||||
|
||||
// newJSONSchemaValidator creates a new validator using JSON Schema 2020-12
|
||||
func newJSONSchemaValidator(schema *Schema) (*jsonSchemaValidator, error) {
|
||||
// Convert OpenAPI Schema to JSON Schema format
|
||||
schemaBytes, err := json.Marshal(schema)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal schema: %w", err)
|
||||
}
|
||||
|
||||
var schemaMap map[string]any
|
||||
if err := json.Unmarshal(schemaBytes, &schemaMap); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal schema: %w", err)
|
||||
}
|
||||
|
||||
// OpenAPI 3.1 specific transformations
|
||||
transformOpenAPIToJSONSchema(schemaMap)
|
||||
|
||||
// Create compiler
|
||||
compiler := jsonschema.NewCompiler()
|
||||
compiler.DefaultDraft(jsonschema.Draft2020)
|
||||
|
||||
// Add the schema
|
||||
schemaURL := "https://example.com/schema.json"
|
||||
if err := compiler.AddResource(schemaURL, schemaMap); err != nil {
|
||||
return nil, fmt.Errorf("failed to add schema resource: %w", err)
|
||||
}
|
||||
|
||||
// Compile the schema
|
||||
compiledSchema, err := compiler.Compile(schemaURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compile schema: %w", err)
|
||||
}
|
||||
|
||||
return &jsonSchemaValidator{
|
||||
compiler: compiler,
|
||||
schema: compiledSchema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// transformOpenAPIToJSONSchema converts OpenAPI 3.0/3.1 specific keywords to JSON Schema format
|
||||
func transformOpenAPIToJSONSchema(schema map[string]any) {
|
||||
// Handle nullable - in OpenAPI 3.0, nullable is a boolean flag
|
||||
// In OpenAPI 3.1 / JSON Schema 2020-12, we use type arrays
|
||||
if nullable, ok := schema["nullable"].(bool); ok && nullable {
|
||||
if typeVal, ok := schema["type"].(string); ok {
|
||||
// Convert to type array with null
|
||||
schema["type"] = []string{typeVal, "null"}
|
||||
} else if _, hasType := schema["type"]; !hasType {
|
||||
// nullable: true without type - add "null" to allow null values
|
||||
schema["type"] = []string{"null"}
|
||||
}
|
||||
delete(schema, "nullable")
|
||||
}
|
||||
|
||||
// Handle exclusiveMinimum/exclusiveMaximum
|
||||
// In OpenAPI 3.0, these are booleans alongside minimum/maximum
|
||||
// In JSON Schema 2020-12, they are numeric values
|
||||
if exclusiveMin, ok := schema["exclusiveMinimum"].(bool); ok {
|
||||
if exclusiveMin {
|
||||
if schemaMin, ok := schema["minimum"].(float64); ok {
|
||||
schema["exclusiveMinimum"] = schemaMin
|
||||
delete(schema, "minimum")
|
||||
} else {
|
||||
delete(schema, "exclusiveMinimum")
|
||||
}
|
||||
} else {
|
||||
// exclusiveMinimum: false means inclusive, which is the JSON Schema default
|
||||
delete(schema, "exclusiveMinimum")
|
||||
}
|
||||
}
|
||||
if exclusiveMax, ok := schema["exclusiveMaximum"].(bool); ok {
|
||||
if exclusiveMax {
|
||||
if schemaMax, ok := schema["maximum"].(float64); ok {
|
||||
schema["exclusiveMaximum"] = schemaMax
|
||||
delete(schema, "maximum")
|
||||
} else {
|
||||
delete(schema, "exclusiveMaximum")
|
||||
}
|
||||
} else {
|
||||
// exclusiveMaximum: false means inclusive, which is the JSON Schema default
|
||||
delete(schema, "exclusiveMaximum")
|
||||
}
|
||||
}
|
||||
|
||||
// Remove OpenAPI-specific keywords that aren't in JSON Schema
|
||||
delete(schema, "discriminator")
|
||||
delete(schema, "xml")
|
||||
delete(schema, "externalDocs")
|
||||
delete(schema, "example") // Use "examples" in 2020-12
|
||||
|
||||
// Recursively transform nested schemas (single schema fields)
|
||||
for _, key := range []string{
|
||||
"additionalProperties", "items", "not",
|
||||
// OpenAPI 3.1 / JSON Schema 2020-12 fields
|
||||
"contains", "propertyNames", "unevaluatedItems", "unevaluatedProperties",
|
||||
"if", "then", "else", "contentSchema",
|
||||
} {
|
||||
if val, ok := schema[key]; ok {
|
||||
if nestedSchema, ok := val.(map[string]any); ok {
|
||||
transformOpenAPIToJSONSchema(nestedSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transform schema arrays (oneOf, anyOf, allOf, prefixItems)
|
||||
for _, key := range []string{"oneOf", "anyOf", "allOf", "prefixItems"} {
|
||||
if val, ok := schema[key].([]any); ok {
|
||||
for _, item := range val {
|
||||
if nestedSchema, ok := item.(map[string]any); ok {
|
||||
transformOpenAPIToJSONSchema(nestedSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transform schema maps (properties, patternProperties, dependentSchemas, $defs)
|
||||
for _, key := range []string{"properties", "patternProperties", "dependentSchemas", "$defs"} {
|
||||
if props, ok := schema[key].(map[string]any); ok {
|
||||
for _, propVal := range props {
|
||||
if propSchema, ok := propVal.(map[string]any); ok {
|
||||
transformOpenAPIToJSONSchema(propSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate validates a value against the compiled JSON Schema
|
||||
func (v *jsonSchemaValidator) validate(value any) error {
|
||||
if err := v.schema.Validate(value); err != nil {
|
||||
// Convert jsonschema error to SchemaError
|
||||
return convertJSONSchemaError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertJSONSchemaError converts a jsonschema validation error to OpenAPI SchemaError format
|
||||
func convertJSONSchemaError(err error) error {
|
||||
// TODO: Go 1.26
|
||||
// if err, ok := errors.AsType[*jsonschema.ValidationError](err); ok {
|
||||
// return formatValidationError(err, "")
|
||||
var validationErr *jsonschema.ValidationError
|
||||
if errors.As(err, &validationErr) {
|
||||
return formatValidationError(validationErr, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// formatValidationError recursively formats validation errors
|
||||
func formatValidationError(verr *jsonschema.ValidationError, parentPath string) error {
|
||||
// Build the path from InstanceLocation slice
|
||||
path := "/" + strings.Join(verr.InstanceLocation, "/")
|
||||
if parentPath != "" && path != "/" {
|
||||
path = parentPath + path
|
||||
} else if path == "/" {
|
||||
path = parentPath
|
||||
}
|
||||
|
||||
// Build error message using the Error() method
|
||||
var msg strings.Builder
|
||||
if path != "" {
|
||||
fmt.Fprintf(&msg, `error at "%s": `, path)
|
||||
}
|
||||
msg.WriteString(verr.Error())
|
||||
|
||||
// If there are sub-errors, format them too
|
||||
if len(verr.Causes) > 0 {
|
||||
var subErrors MultiError
|
||||
for _, cause := range verr.Causes {
|
||||
if subErr := formatValidationError(cause, path); subErr != nil {
|
||||
subErrors = append(subErrors, subErr)
|
||||
}
|
||||
}
|
||||
if len(subErrors) > 0 {
|
||||
return &SchemaError{
|
||||
Reason: msg.String(),
|
||||
Origin: fmt.Errorf("validation failed due to: %w", subErrors),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &SchemaError{
|
||||
Reason: msg.String(),
|
||||
}
|
||||
}
|
||||
|
||||
// useJSONSchema2020 validates using the JSON Schema 2020-12 validator
|
||||
func (schema *Schema) useJSONSchema2020(settings *schemaValidationSettings, value any) error {
|
||||
validator, err := newJSONSchemaValidator(schema)
|
||||
if err != nil {
|
||||
// Fall back to built-in validator if compilation fails
|
||||
return schema.visitJSON(settings, value)
|
||||
}
|
||||
|
||||
return validator.validate(value)
|
||||
}
|
||||
36
vendor/github.com/getkin/kin-openapi/openapi3/schema_pattern.go
generated
vendored
Normal file
36
vendor/github.com/getkin/kin-openapi/openapi3/schema_pattern.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var patRewriteCodepoints = regexp.MustCompile(`(?P<replaced_with_slash_x>\\u)(?P<code>[0-9A-F]{4})`)
|
||||
|
||||
// See https://pkg.go.dev/regexp/syntax
|
||||
func intoGoRegexp(re string) string {
|
||||
return patRewriteCodepoints.ReplaceAllString(re, `\x{${code}}`)
|
||||
}
|
||||
|
||||
// NOTE: racey WRT [writes to schema.Pattern] vs [reads schema.Pattern then writes to compiledPatterns]
|
||||
func (schema *Schema) compilePattern(c RegexCompilerFunc) (cp RegexMatcher, err error) {
|
||||
pattern := schema.Pattern
|
||||
if c != nil {
|
||||
cp, err = c(pattern)
|
||||
} else {
|
||||
cp, err = regexp.Compile(intoGoRegexp(pattern))
|
||||
}
|
||||
if err != nil {
|
||||
schemaErr := &SchemaError{
|
||||
Schema: schema,
|
||||
SchemaField: "pattern",
|
||||
Origin: err,
|
||||
Reason: fmt.Sprintf("cannot compile pattern %q: %v", pattern, err),
|
||||
}
|
||||
err = newSchemaPatternRegexError(pattern, schemaErr, schema.Origin)
|
||||
return
|
||||
}
|
||||
|
||||
compiledPatterns.Store(pattern, cp)
|
||||
return
|
||||
}
|
||||
168
vendor/github.com/getkin/kin-openapi/openapi3/schema_validation_settings.go
generated
vendored
Normal file
168
vendor/github.com/getkin/kin-openapi/openapi3/schema_validation_settings.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SchemaValidationOption describes options a user has when validating request / response bodies.
|
||||
type SchemaValidationOption func(*schemaValidationSettings)
|
||||
|
||||
type RegexCompilerFunc func(expr string) (RegexMatcher, error)
|
||||
|
||||
type RegexMatcher interface {
|
||||
MatchString(s string) bool
|
||||
}
|
||||
|
||||
type schemaValidationSettings struct {
|
||||
failfast bool
|
||||
multiError bool
|
||||
asreq, asrep bool // exclusive (XOR) fields
|
||||
formatValidationEnabled bool
|
||||
patternValidationDisabled bool
|
||||
readOnlyValidationDisabled bool
|
||||
writeOnlyValidationDisabled bool
|
||||
useJSONSchema2020 bool // Use JSON Schema 2020-12 validator for OpenAPI 3.1
|
||||
|
||||
regexCompiler RegexCompilerFunc
|
||||
|
||||
onceSettingDefaults sync.Once
|
||||
defaultsSet func()
|
||||
|
||||
customizeMessageError func(err *SchemaError) string
|
||||
|
||||
// Per-validation format validators (checked before global ones)
|
||||
stringFormats map[string]StringFormatValidator
|
||||
numberFormats map[string]NumberFormatValidator
|
||||
integerFormats map[string]IntegerFormatValidator
|
||||
}
|
||||
|
||||
// FailFast returns schema validation errors quicker.
|
||||
func FailFast() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.failfast = true }
|
||||
}
|
||||
|
||||
func MultiErrors() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.multiError = true }
|
||||
}
|
||||
|
||||
func VisitAsRequest() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.asreq, s.asrep = true, false }
|
||||
}
|
||||
|
||||
func VisitAsResponse() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.asreq, s.asrep = false, true }
|
||||
}
|
||||
|
||||
// EnableFormatValidation setting makes Validate not return an error when validating documents that mention schema formats that are not defined by the OpenAPIv3 specification.
|
||||
func EnableFormatValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.formatValidationEnabled = true }
|
||||
}
|
||||
|
||||
// DisablePatternValidation setting makes Validate not return an error when validating patterns that are not supported by the Go regexp engine.
|
||||
func DisablePatternValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.patternValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DisableReadOnlyValidation setting makes Validate not return an error when validating properties marked as read-only
|
||||
func DisableReadOnlyValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.readOnlyValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DisableWriteOnlyValidation setting makes Validate not return an error when validating properties marked as write-only
|
||||
func DisableWriteOnlyValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.writeOnlyValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DefaultsSet executes the given callback (once) IFF schema validation set default values.
|
||||
func DefaultsSet(f func()) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.defaultsSet = f }
|
||||
}
|
||||
|
||||
// SetSchemaErrorMessageCustomizer allows to override the schema error message.
|
||||
// If the passed function returns an empty string, it returns to the previous Error() implementation.
|
||||
func SetSchemaErrorMessageCustomizer(f func(err *SchemaError) string) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.customizeMessageError = f }
|
||||
}
|
||||
|
||||
// SetSchemaRegexCompiler allows to override the regex implementation used to validate field "pattern".
|
||||
func SetSchemaRegexCompiler(c RegexCompilerFunc) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.regexCompiler = c }
|
||||
}
|
||||
|
||||
// WithStringFormatValidators adds per-validation string format validators.
|
||||
// These validators are checked before global SchemaStringFormats and allow
|
||||
// different validations for the same format name across different specs.
|
||||
func WithStringFormatValidators(validators map[string]StringFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
s.stringFormats = validators
|
||||
}
|
||||
}
|
||||
|
||||
// WithStringFormatValidator adds a single per-validation string format validator.
|
||||
// This validator is checked before global SchemaStringFormats and allows
|
||||
// different validations for the same format name across different specs.
|
||||
func WithStringFormatValidator(name string, validator StringFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
if s.stringFormats == nil {
|
||||
s.stringFormats = make(map[string]StringFormatValidator)
|
||||
}
|
||||
s.stringFormats[name] = validator
|
||||
}
|
||||
}
|
||||
|
||||
// WithNumberFormatValidators adds per-validation number format validators.
|
||||
// These validators are checked before global SchemaNumberFormats and allow
|
||||
// different validations for the same format name across different specs.
|
||||
func WithNumberFormatValidators(validators map[string]NumberFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
s.numberFormats = validators
|
||||
}
|
||||
}
|
||||
|
||||
// WithNumberFormatValidator adds a single per-validation number format validator.
|
||||
// This validator is checked before global SchemaNumberFormats and allows
|
||||
// different validations for the same format name across different specs.
|
||||
func WithNumberFormatValidator(name string, validator NumberFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
if s.numberFormats == nil {
|
||||
s.numberFormats = make(map[string]NumberFormatValidator)
|
||||
}
|
||||
s.numberFormats[name] = validator
|
||||
}
|
||||
}
|
||||
|
||||
// WithIntegerFormatValidators adds per-validation integer format validators.
|
||||
// These validators are checked before global SchemaIntegerFormats and allow
|
||||
// different validations for the same format name across different specs.
|
||||
func WithIntegerFormatValidators(validators map[string]IntegerFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
s.integerFormats = validators
|
||||
}
|
||||
}
|
||||
|
||||
// WithIntegerFormatValidator adds a single per-validation integer format validator.
|
||||
// This validator is checked before global SchemaIntegerFormats and allows
|
||||
// different validations for the same format name across different specs.
|
||||
func WithIntegerFormatValidator(name string, validator IntegerFormatValidator) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) {
|
||||
if s.integerFormats == nil {
|
||||
s.integerFormats = make(map[string]IntegerFormatValidator)
|
||||
}
|
||||
s.integerFormats[name] = validator
|
||||
}
|
||||
}
|
||||
|
||||
// EnableJSONSchema2020 enables JSON Schema 2020-12 compliant validation.
|
||||
// This enables support for OpenAPI 3.1 and JSON Schema 2020-12 features.
|
||||
// When enabled, validation uses the jsonschema library instead of the built-in validator.
|
||||
func EnableJSONSchema2020() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.useJSONSchema2020 = true }
|
||||
}
|
||||
|
||||
func newSchemaValidationSettings(opts ...SchemaValidationOption) *schemaValidationSettings {
|
||||
settings := &schemaValidationSettings{}
|
||||
for _, opt := range opts {
|
||||
opt(settings)
|
||||
}
|
||||
return settings
|
||||
}
|
||||
57
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
Normal file
57
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type SecurityRequirements []SecurityRequirement
|
||||
|
||||
func NewSecurityRequirements() *SecurityRequirements {
|
||||
return &SecurityRequirements{}
|
||||
}
|
||||
|
||||
func (srs *SecurityRequirements) With(securityRequirement SecurityRequirement) *SecurityRequirements {
|
||||
*srs = append(*srs, securityRequirement)
|
||||
return srs
|
||||
}
|
||||
|
||||
// Validate returns an error if SecurityRequirements does not comply with the OpenAPI spec.
|
||||
func (srs SecurityRequirements) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, security := range srs {
|
||||
if err := security.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SecurityRequirement is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object
|
||||
type SecurityRequirement map[string][]string
|
||||
|
||||
func NewSecurityRequirement() SecurityRequirement {
|
||||
return make(SecurityRequirement)
|
||||
}
|
||||
|
||||
func (security SecurityRequirement) Authenticate(provider string, scopes ...string) SecurityRequirement {
|
||||
if len(scopes) == 0 {
|
||||
scopes = []string{} // Forces the variable to be encoded as an array instead of null
|
||||
}
|
||||
security[provider] = scopes
|
||||
return security
|
||||
}
|
||||
|
||||
// Validate returns an error if SecurityRequirement does not comply with the OpenAPI spec.
|
||||
func (security *SecurityRequirement) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
// ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecurityRequirement to a copy of data.
|
||||
func (security *SecurityRequirement) UnmarshalJSON(data []byte) (err error) {
|
||||
*security, err = unmarshalStringMap[[]string](data)
|
||||
return
|
||||
}
|
||||
434
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
Normal file
434
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/url"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// SecurityScheme is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object
|
||||
// and https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#security-scheme-object
|
||||
type SecurityScheme struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
|
||||
BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
|
||||
Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
|
||||
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"`
|
||||
}
|
||||
|
||||
func NewSecurityScheme() *SecurityScheme {
|
||||
return &SecurityScheme{}
|
||||
}
|
||||
|
||||
func NewCSRFSecurityScheme() *SecurityScheme {
|
||||
return &SecurityScheme{
|
||||
Type: "apiKey",
|
||||
In: "header",
|
||||
Name: "X-XSRF-TOKEN",
|
||||
}
|
||||
}
|
||||
|
||||
func NewOIDCSecurityScheme(oidcUrl string) *SecurityScheme {
|
||||
return &SecurityScheme{
|
||||
Type: "openIdConnect",
|
||||
OpenIdConnectUrl: oidcUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func NewJWTSecurityScheme() *SecurityScheme {
|
||||
return &SecurityScheme{
|
||||
Type: "http",
|
||||
Scheme: "bearer",
|
||||
BearerFormat: "JWT",
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of SecurityScheme.
|
||||
func (ss SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
x, err := ss.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of SecurityScheme.
|
||||
func (ss SecurityScheme) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 8+len(ss.Extensions))
|
||||
maps.Copy(m, ss.Extensions)
|
||||
if x := ss.Type; x != "" {
|
||||
m["type"] = x
|
||||
}
|
||||
if x := ss.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := ss.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := ss.In; x != "" {
|
||||
m["in"] = x
|
||||
}
|
||||
if x := ss.Scheme; x != "" {
|
||||
m["scheme"] = x
|
||||
}
|
||||
if x := ss.BearerFormat; x != "" {
|
||||
m["bearerFormat"] = x
|
||||
}
|
||||
if x := ss.Flows; x != nil {
|
||||
m["flows"] = x
|
||||
}
|
||||
if x := ss.OpenIdConnectUrl; x != "" {
|
||||
m["openIdConnectUrl"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecurityScheme to a copy of data.
|
||||
func (ss *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
type SecuritySchemeBis SecurityScheme
|
||||
var x SecuritySchemeBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "type")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "in")
|
||||
delete(x.Extensions, "scheme")
|
||||
delete(x.Extensions, "bearerFormat")
|
||||
delete(x.Extensions, "flows")
|
||||
delete(x.Extensions, "openIdConnectUrl")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*ss = SecurityScheme(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithType(value string) *SecurityScheme {
|
||||
ss.Type = value
|
||||
return ss
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithDescription(value string) *SecurityScheme {
|
||||
ss.Description = value
|
||||
return ss
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithName(value string) *SecurityScheme {
|
||||
ss.Name = value
|
||||
return ss
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithIn(value string) *SecurityScheme {
|
||||
ss.In = value
|
||||
return ss
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithScheme(value string) *SecurityScheme {
|
||||
ss.Scheme = value
|
||||
return ss
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithBearerFormat(value string) *SecurityScheme {
|
||||
ss.BearerFormat = value
|
||||
return ss
|
||||
}
|
||||
|
||||
// Validate returns an error if SecurityScheme does not comply with the OpenAPI spec.
|
||||
func (ss *SecurityScheme) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
hasIn := false
|
||||
hasBearerFormat := false
|
||||
hasFlow := false
|
||||
switch ss.Type {
|
||||
case "apiKey":
|
||||
hasIn = true
|
||||
case "http":
|
||||
scheme := ss.Scheme
|
||||
switch scheme {
|
||||
case "bearer":
|
||||
hasBearerFormat = true
|
||||
case "basic", "negotiate", "digest":
|
||||
default:
|
||||
return newInvalidHTTPScheme(scheme, ss.Origin)
|
||||
}
|
||||
case "oauth2":
|
||||
hasFlow = true
|
||||
case "openIdConnect":
|
||||
if ss.OpenIdConnectUrl == "" {
|
||||
return newOpenIDConnectURLRequired(ss.Name, ss.Origin)
|
||||
}
|
||||
case "mutualTLS":
|
||||
if !getValidationOptions(ctx).isOpenAPI31OrLater {
|
||||
return errValueOfFieldFor31Plus(ss.Type, "type")
|
||||
}
|
||||
default:
|
||||
return newInvalidSecuritySchemeType(ss.Type, ss.Origin)
|
||||
}
|
||||
|
||||
// Validate "in" and "name"
|
||||
if hasIn {
|
||||
switch ss.In {
|
||||
case "query", "header", "cookie":
|
||||
default:
|
||||
return newAPIKeyInInvalid(ss.In, ss.Origin)
|
||||
}
|
||||
if ss.Name == "" {
|
||||
return newAPIKeySecuritySchemeNameRequired(ss.Origin)
|
||||
}
|
||||
} else if len(ss.In) > 0 {
|
||||
return newSecuritySchemeInForbidden(ss.Type, ss.Origin)
|
||||
} else if len(ss.Name) > 0 {
|
||||
return newSecuritySchemeNameForbidden(ss.Type, ss.Origin)
|
||||
}
|
||||
|
||||
// Validate "format"
|
||||
// "bearerFormat" is an arbitrary string so we only check if the scheme supports it
|
||||
if !hasBearerFormat && len(ss.BearerFormat) > 0 {
|
||||
return newSecuritySchemeBearerFormatForbidden(ss.Type, ss.Origin)
|
||||
}
|
||||
|
||||
// Validate "flow"
|
||||
if hasFlow {
|
||||
flow := ss.Flows
|
||||
if flow == nil {
|
||||
return newSecuritySchemeFlowsRequired(ss.Type, ss.Origin)
|
||||
}
|
||||
if err := flow.Validate(ctx); err != nil {
|
||||
return &SecuritySchemeFlowValidationError{Cause: err}
|
||||
}
|
||||
} else if ss.Flows != nil {
|
||||
return newSecuritySchemeFlowsForbidden(ss.Type, ss.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, ss.Extensions, ss.Origin)
|
||||
}
|
||||
|
||||
// OAuthFlows is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flows-object
|
||||
type OAuthFlows struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||
AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"`
|
||||
}
|
||||
|
||||
type oAuthFlowType int
|
||||
|
||||
const (
|
||||
oAuthFlowTypeImplicit oAuthFlowType = iota
|
||||
oAuthFlowTypePassword
|
||||
oAuthFlowTypeClientCredentials
|
||||
oAuthFlowAuthorizationCode
|
||||
)
|
||||
|
||||
// MarshalJSON returns the JSON encoding of OAuthFlows.
|
||||
func (flows OAuthFlows) MarshalJSON() ([]byte, error) {
|
||||
x, err := flows.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of OAuthFlows.
|
||||
func (flows OAuthFlows) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(flows.Extensions))
|
||||
maps.Copy(m, flows.Extensions)
|
||||
if x := flows.Implicit; x != nil {
|
||||
m["implicit"] = x
|
||||
}
|
||||
if x := flows.Password; x != nil {
|
||||
m["password"] = x
|
||||
}
|
||||
if x := flows.ClientCredentials; x != nil {
|
||||
m["clientCredentials"] = x
|
||||
}
|
||||
if x := flows.AuthorizationCode; x != nil {
|
||||
m["authorizationCode"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets OAuthFlows to a copy of data.
|
||||
func (flows *OAuthFlows) UnmarshalJSON(data []byte) error {
|
||||
type OAuthFlowsBis OAuthFlows
|
||||
var x OAuthFlowsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "implicit")
|
||||
delete(x.Extensions, "password")
|
||||
delete(x.Extensions, "clientCredentials")
|
||||
delete(x.Extensions, "authorizationCode")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*flows = OAuthFlows(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
|
||||
func (flows *OAuthFlows) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := flows.Implicit; v != nil {
|
||||
if err := v.validate(ctx, oAuthFlowTypeImplicit, opts...); err != nil {
|
||||
return &OAuthFlowValidationError{FlowKind: "implicit", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.Password; v != nil {
|
||||
if err := v.validate(ctx, oAuthFlowTypePassword, opts...); err != nil {
|
||||
return &OAuthFlowValidationError{FlowKind: "password", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.ClientCredentials; v != nil {
|
||||
if err := v.validate(ctx, oAuthFlowTypeClientCredentials, opts...); err != nil {
|
||||
return &OAuthFlowValidationError{FlowKind: "clientCredentials", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.AuthorizationCode; v != nil {
|
||||
if err := v.validate(ctx, oAuthFlowAuthorizationCode, opts...); err != nil {
|
||||
return &OAuthFlowValidationError{FlowKind: "authorizationCode", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, flows.Extensions, flows.Origin)
|
||||
}
|
||||
|
||||
// OAuthFlow is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flow-object
|
||||
type OAuthFlow struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||
Scopes StringMap[string] `json:"scopes" yaml:"scopes"` // required
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of OAuthFlow.
|
||||
func (flow OAuthFlow) MarshalJSON() ([]byte, error) {
|
||||
x, err := flow.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of OAuthFlow.
|
||||
func (flow OAuthFlow) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(flow.Extensions))
|
||||
maps.Copy(m, flow.Extensions)
|
||||
if x := flow.AuthorizationURL; x != "" {
|
||||
m["authorizationUrl"] = x
|
||||
}
|
||||
if x := flow.TokenURL; x != "" {
|
||||
m["tokenUrl"] = x
|
||||
}
|
||||
if x := flow.RefreshURL; x != "" {
|
||||
m["refreshUrl"] = x
|
||||
}
|
||||
m["scopes"] = flow.Scopes
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets OAuthFlow to a copy of data.
|
||||
func (flow *OAuthFlow) UnmarshalJSON(data []byte) error {
|
||||
type OAuthFlowBis OAuthFlow
|
||||
var x OAuthFlowBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, "authorizationUrl")
|
||||
delete(x.Extensions, "tokenUrl")
|
||||
delete(x.Extensions, "refreshUrl")
|
||||
delete(x.Extensions, "scopes")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*flow = OAuthFlow(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
|
||||
func (flow *OAuthFlow) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := flow.RefreshURL; v != "" {
|
||||
if _, err := url.Parse(v); err != nil {
|
||||
return &OAuthFlowFieldValidationError{Field: "refreshUrl", Cause: err}
|
||||
}
|
||||
}
|
||||
|
||||
if flow.Scopes == nil {
|
||||
return newOAuthFlowScopesRequired(flow.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, flow.Extensions, flow.Origin)
|
||||
}
|
||||
|
||||
func (flow *OAuthFlow) validate(ctx context.Context, typ oAuthFlowType, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
typeIn := func(types ...oAuthFlowType) bool {
|
||||
return slices.Contains(types, typ)
|
||||
}
|
||||
|
||||
if in := typeIn(oAuthFlowTypeImplicit, oAuthFlowAuthorizationCode); true {
|
||||
switch {
|
||||
case flow.AuthorizationURL == "" && in:
|
||||
return newOAuthFlowAuthorizationURLRequired(flow.Origin)
|
||||
case flow.AuthorizationURL != "" && !in:
|
||||
return newOAuthFlowAuthorizationURLForbidden(flow.Origin)
|
||||
case flow.AuthorizationURL != "":
|
||||
if _, err := url.Parse(flow.AuthorizationURL); err != nil {
|
||||
return fmt.Errorf("field 'authorizationUrl' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if in := typeIn(oAuthFlowTypePassword, oAuthFlowTypeClientCredentials, oAuthFlowAuthorizationCode); true {
|
||||
switch {
|
||||
case flow.TokenURL == "" && in:
|
||||
return newOAuthFlowTokenURLRequired(flow.Origin)
|
||||
case flow.TokenURL != "" && !in:
|
||||
return newOAuthFlowTokenURLForbidden(flow.Origin)
|
||||
case flow.TokenURL != "":
|
||||
if _, err := url.Parse(flow.TokenURL); err != nil {
|
||||
return fmt.Errorf("field 'tokenUrl' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flow.Validate(ctx, opts...)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecuritySchemes to a copy of data.
|
||||
func (securitySchemes *SecuritySchemes) UnmarshalJSON(data []byte) (err error) {
|
||||
*securitySchemes, err = unmarshalStringMapP[SecuritySchemeRef](data)
|
||||
return
|
||||
}
|
||||
17
vendor/github.com/getkin/kin-openapi/openapi3/serialization_method.go
generated
vendored
Normal file
17
vendor/github.com/getkin/kin-openapi/openapi3/serialization_method.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package openapi3
|
||||
|
||||
const (
|
||||
SerializationSimple = "simple"
|
||||
SerializationLabel = "label"
|
||||
SerializationMatrix = "matrix"
|
||||
SerializationForm = "form"
|
||||
SerializationSpaceDelimited = "spaceDelimited"
|
||||
SerializationPipeDelimited = "pipeDelimited"
|
||||
SerializationDeepObject = "deepObject"
|
||||
)
|
||||
|
||||
// SerializationMethod describes a serialization method of HTTP request's parameters and body.
|
||||
type SerializationMethod struct {
|
||||
Style string
|
||||
Explode bool
|
||||
}
|
||||
318
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
Normal file
318
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"maps"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Servers is specified by OpenAPI/Swagger standard version 3.
|
||||
type Servers []*Server
|
||||
|
||||
// Validate returns an error if Servers does not comply with the OpenAPI spec.
|
||||
func (servers Servers) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
for _, v := range servers {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return me.result()
|
||||
}
|
||||
|
||||
// BasePath returns the base path of the first server in the list, or /.
|
||||
func (servers Servers) BasePath() (string, error) {
|
||||
for _, server := range servers {
|
||||
return server.BasePath()
|
||||
}
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
func (servers Servers) MatchURL(parsedURL *url.URL) (*Server, []string, string) {
|
||||
rawURL := parsedURL.String()
|
||||
if i := strings.IndexByte(rawURL, '?'); i >= 0 {
|
||||
rawURL = rawURL[:i]
|
||||
}
|
||||
for _, server := range servers {
|
||||
pathParams, remaining, ok := server.MatchRawURL(rawURL)
|
||||
if ok {
|
||||
return server, pathParams, remaining
|
||||
}
|
||||
}
|
||||
return nil, nil, ""
|
||||
}
|
||||
|
||||
// Server is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object
|
||||
type Server struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
URL string `json:"url" yaml:"url"` // Required
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Variables ServerVariables `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||
}
|
||||
|
||||
// BasePath returns the base path extracted from the default values of variables, if any.
|
||||
// Assumes a valid struct (per Validate()).
|
||||
func (server *Server) BasePath() (string, error) {
|
||||
if server == nil {
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
uri := server.URL
|
||||
for _, name := range componentNames(server.Variables) {
|
||||
uri = strings.ReplaceAll(uri, "{"+name+"}", server.Variables[name].Default)
|
||||
}
|
||||
|
||||
u, err := url.ParseRequestURI(uri)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bp := u.Path; bp != "" {
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Server.
|
||||
func (server Server) MarshalJSON() ([]byte, error) {
|
||||
x, err := server.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Server.
|
||||
func (server Server) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(server.Extensions))
|
||||
maps.Copy(m, server.Extensions)
|
||||
m["url"] = server.URL
|
||||
if x := server.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := server.Variables; len(x) != 0 {
|
||||
m["variables"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Server to a copy of data.
|
||||
func (server *Server) UnmarshalJSON(data []byte) error {
|
||||
type ServerBis Server
|
||||
var x ServerBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "url")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "variables")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
delete(x.Variables, originKey)
|
||||
*server = Server(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (server Server) ParameterNames() ([]string, error) {
|
||||
pattern := server.URL
|
||||
var params []string
|
||||
for len(pattern) > 0 {
|
||||
i := strings.IndexByte(pattern, '{')
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
pattern = pattern[i+1:]
|
||||
i = strings.IndexByte(pattern, '}')
|
||||
if i < 0 {
|
||||
return nil, errors.New("missing '}'")
|
||||
}
|
||||
params = append(params, strings.TrimSpace(pattern[:i]))
|
||||
pattern = pattern[i+1:]
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (server Server) MatchRawURL(input string) ([]string, string, bool) {
|
||||
pattern := server.URL
|
||||
var params []string
|
||||
for len(pattern) > 0 {
|
||||
c := pattern[0]
|
||||
if len(pattern) == 1 && c == '/' {
|
||||
break
|
||||
}
|
||||
if c == '{' {
|
||||
// Find end of pattern
|
||||
i := strings.IndexByte(pattern, '}')
|
||||
if i < 0 {
|
||||
return nil, "", false
|
||||
}
|
||||
pattern = pattern[i+1:]
|
||||
|
||||
// Find next matching pattern character or next '/' whichever comes first
|
||||
np := -1
|
||||
if len(pattern) > 0 {
|
||||
np = strings.IndexByte(input, pattern[0])
|
||||
}
|
||||
ns := strings.IndexByte(input, '/')
|
||||
|
||||
if np < 0 {
|
||||
i = ns
|
||||
} else if ns < 0 {
|
||||
i = np
|
||||
} else {
|
||||
i = min(np, ns)
|
||||
}
|
||||
if i < 0 {
|
||||
i = len(input)
|
||||
}
|
||||
params = append(params, input[:i])
|
||||
input = input[i:]
|
||||
continue
|
||||
}
|
||||
if len(input) == 0 || input[0] != c {
|
||||
return nil, "", false
|
||||
}
|
||||
pattern = pattern[1:]
|
||||
input = input[1:]
|
||||
}
|
||||
if input == "" {
|
||||
input = "/"
|
||||
}
|
||||
if input[0] != '/' {
|
||||
return nil, "", false
|
||||
}
|
||||
return params, input, true
|
||||
}
|
||||
|
||||
// Validate returns an error if Server does not comply with the OpenAPI spec.
|
||||
func (server *Server) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if server.URL == "" {
|
||||
if err := me.emit(newServerURLRequired(server.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opening, closing := strings.Count(server.URL, "{"), strings.Count(server.URL, "}")
|
||||
if opening != closing {
|
||||
if err := me.emit(newServerURLMismatchedBraces(server.URL, server.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if opening != len(server.Variables) {
|
||||
if err := me.emit(newServerURLUndeclaredVariables(server.URL, server.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range componentNames(server.Variables) {
|
||||
v := server.Variables[name]
|
||||
if !strings.Contains(server.URL, "{"+name+"}") {
|
||||
if err := me.emit(newServerURLUndeclaredVariables(server.URL, server.Origin)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Variable name doesn't appear in the URL template; descending
|
||||
// into its Validate would surface findings under a variable
|
||||
// the URL never references, with no resolution path until the
|
||||
// URL is fixed.
|
||||
continue
|
||||
}
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, server.Extensions, server.Origin))
|
||||
}
|
||||
|
||||
// ServerVariable is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-variable-object
|
||||
// ServerVariables is a map of ServerVariable objects keyed by variable name.
|
||||
type ServerVariables map[string]*ServerVariable
|
||||
|
||||
// UnmarshalJSON sets ServerVariables to a copy of data.
|
||||
func (serverVariables *ServerVariables) UnmarshalJSON(data []byte) (err error) {
|
||||
*serverVariables, err = unmarshalStringMapP[ServerVariable](data)
|
||||
return
|
||||
}
|
||||
|
||||
type ServerVariable struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||
Default string `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of ServerVariable.
|
||||
func (serverVariable ServerVariable) MarshalJSON() ([]byte, error) {
|
||||
x, err := serverVariable.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of ServerVariable.
|
||||
func (serverVariable ServerVariable) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(serverVariable.Extensions))
|
||||
maps.Copy(m, serverVariable.Extensions)
|
||||
if x := serverVariable.Enum; len(x) != 0 {
|
||||
m["enum"] = x
|
||||
}
|
||||
if x := serverVariable.Default; x != "" {
|
||||
m["default"] = x
|
||||
}
|
||||
if x := serverVariable.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ServerVariable to a copy of data.
|
||||
func (serverVariable *ServerVariable) UnmarshalJSON(data []byte) error {
|
||||
type ServerVariableBis ServerVariable
|
||||
var x ServerVariableBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "enum")
|
||||
delete(x.Extensions, "default")
|
||||
delete(x.Extensions, "description")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*serverVariable = ServerVariable(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if ServerVariable does not comply with the OpenAPI spec.
|
||||
func (serverVariable *ServerVariable) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if serverVariable.Default == "" {
|
||||
data, err := serverVariable.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return newServerVariableDefaultRequired(string(data), serverVariable.Origin)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, serverVariable.Extensions, serverVariable.Origin)
|
||||
}
|
||||
64
vendor/github.com/getkin/kin-openapi/openapi3/stringmap.go
generated
vendored
Normal file
64
vendor/github.com/getkin/kin-openapi/openapi3/stringmap.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package openapi3
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// StringMap is a map[string]string that ignores the origin in the underlying json representation.
|
||||
type StringMap[V any] map[string]V
|
||||
|
||||
// UnmarshalJSON sets StringMap to a copy of data.
|
||||
func (stringMap *StringMap[V]) UnmarshalJSON(data []byte) (err error) {
|
||||
*stringMap, err = unmarshalStringMap[V](data)
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalStringMapP unmarshals given json into a map[string]*V
|
||||
func unmarshalStringMapP[V any](data []byte) (map[string]*V, error) {
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]*V, len(m))
|
||||
for _, k := range componentNames(m) {
|
||||
value, err := deepCast[V](m[k])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[k] = value
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// unmarshalStringMap unmarshals given json into a map[string]V
|
||||
func unmarshalStringMap[V any](data []byte) (map[string]V, error) {
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]V, len(m))
|
||||
for _, k := range componentNames(m) {
|
||||
value, err := deepCast[V](m[k])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[k] = *value
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// deepCast casts any value to a value of type V.
|
||||
func deepCast[V any](value any) (*V, error) {
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result V
|
||||
if err = json.Unmarshal(data, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
101
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
Normal file
101
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// Tags is specified by OpenAPI/Swagger 3.0 standard.
|
||||
type Tags []*Tag
|
||||
|
||||
func (tags Tags) Get(name string) *Tag {
|
||||
for _, tag := range tags {
|
||||
if tag.Name == name {
|
||||
return tag
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Tags does not comply with the OpenAPI spec.
|
||||
func (tags Tags) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
for _, v := range tags {
|
||||
if err := me.emit(v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return me.result()
|
||||
}
|
||||
|
||||
// Tag is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#tag-object
|
||||
type Tag struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Tag.
|
||||
func (t Tag) MarshalJSON() ([]byte, error) {
|
||||
x, err := t.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Tag.
|
||||
func (t Tag) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(t.Extensions))
|
||||
maps.Copy(m, t.Extensions)
|
||||
if x := t.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := t.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := t.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Tag to a copy of data.
|
||||
func (t *Tag) UnmarshalJSON(data []byte) error {
|
||||
type TagBis Tag
|
||||
var x TagBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*t = Tag(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Tag does not comply with the OpenAPI spec.
|
||||
func (t *Tag) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
me := newErrCollector(ctx)
|
||||
|
||||
if v := t.ExternalDocs; v != nil {
|
||||
wrap := func(e error) error { return &SectionValidationError{Section: "external docs", Cause: e} }
|
||||
if err := me.emitWrapped(wrap, v.Validate(ctx)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return me.finalize(validateExtensions(ctx, t.Extensions, t.Origin))
|
||||
}
|
||||
1568
vendor/github.com/getkin/kin-openapi/openapi3/validation_error.go
generated
vendored
Normal file
1568
vendor/github.com/getkin/kin-openapi/openapi3/validation_error.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
252
vendor/github.com/getkin/kin-openapi/openapi3/validation_error_context.go
generated
vendored
Normal file
252
vendor/github.com/getkin/kin-openapi/openapi3/validation_error_context.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Context wrappers are the 4th category of typed validation errors,
|
||||
// alongside the Base / Cluster / Leaf model documented at the top of
|
||||
// validation_error.go.
|
||||
//
|
||||
// A context wrapper carries scope (which section, path, operation,
|
||||
// component, parameter, OAuth flow, ...) around an inner error chain.
|
||||
// It does NOT itself report a validation failure — the actual error
|
||||
// lives in Cause and is reachable via errors.Unwrap / errors.As.
|
||||
//
|
||||
// Use a context wrapper to extract "where the error happened" without
|
||||
// parsing the rendered message. Combine with errors.As against the
|
||||
// inner cluster or leaf to also extract "what category" and "exactly
|
||||
// which case." A canonical error chain looks like:
|
||||
//
|
||||
// ComponentValidationError{Section, Name} // context wrapper: WHERE
|
||||
// -> RequiredFieldError{Field} // cluster: WHAT CATEGORY
|
||||
// -> SomeFieldRequired{Message} // leaf: EXACTLY WHICH CASE
|
||||
//
|
||||
// Two scopes of context wrapper live in this file:
|
||||
//
|
||||
// - Document-wide wrappers — SectionValidationError,
|
||||
// PathValidationError, OperationValidationError. Cover entire
|
||||
// top-level scopes of the document.
|
||||
// - Narrow-scope wrappers — ComponentValidationError,
|
||||
// ExternalDocsURLValidationError, HeaderFieldValidationError,
|
||||
// MediaTypeExampleValidationError, WebhookValidationError,
|
||||
// ParameterFieldValidationError, ParameterExampleValidationError,
|
||||
// SecuritySchemeFlowValidationError, OAuthFlowValidationError,
|
||||
// OAuthFlowFieldValidationError. Cover a specific validation
|
||||
// surface inside a section.
|
||||
//
|
||||
// Both scopes follow the same shape:
|
||||
//
|
||||
// - One or more discriminator fields naming the scope (Section,
|
||||
// Path, ParameterName + Field, etc.).
|
||||
// - A Cause error that holds the wrapped inner error.
|
||||
// - Unwrap() returns Cause so errors.As walks transparently to the
|
||||
// inner cluster or leaf.
|
||||
//
|
||||
// Error() formats vary per wrapper: each preserves the original
|
||||
// fmt.Errorf-with-%w message format byte-for-byte for backward
|
||||
// compatibility, so existing string-matching consumers see identical
|
||||
// output. There is no canonical "<context>: <cause>" format across
|
||||
// wrappers — read each type's Error() if the exact string matters.
|
||||
|
||||
package openapi3
|
||||
|
||||
import "fmt"
|
||||
|
||||
// SectionValidationError wraps an error originating inside one of the
|
||||
// top-level OpenAPI document sections (info, paths, components,
|
||||
// security, servers, tags, externalDocs, webhooks, jsonSchemaDialect).
|
||||
// Section is the OpenAPI field name as it appears in the document
|
||||
// root.
|
||||
//
|
||||
// Use errors.As(err, &sve) to extract the section context from a
|
||||
// validation error chain without parsing the rendered message.
|
||||
type SectionValidationError struct {
|
||||
Section string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *SectionValidationError) Error() string {
|
||||
return fmt.Sprintf("invalid %s: %v", e.Section, e.Cause)
|
||||
}
|
||||
|
||||
func (e *SectionValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// PathValidationError wraps an error originating inside a specific path.
|
||||
// Path is the path template as it appears in the document (e.g.
|
||||
// "/users/{id}").
|
||||
//
|
||||
// Use errors.As(err, &pve) to extract the path from a validation
|
||||
// error chain without parsing the rendered message.
|
||||
type PathValidationError struct {
|
||||
Path string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *PathValidationError) Error() string {
|
||||
return fmt.Sprintf("invalid path %s: %v", e.Path, e.Cause)
|
||||
}
|
||||
|
||||
func (e *PathValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// OperationValidationError wraps an error originating inside a specific
|
||||
// HTTP-method operation under a path. Method is the uppercase method
|
||||
// (GET, POST, etc.).
|
||||
//
|
||||
// Use errors.As(err, &ove) to extract the method from a validation
|
||||
// error chain without parsing the rendered message.
|
||||
type OperationValidationError struct {
|
||||
Method string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *OperationValidationError) Error() string {
|
||||
return fmt.Sprintf("invalid operation %s: %v", e.Method, e.Cause)
|
||||
}
|
||||
|
||||
func (e *OperationValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// Below: narrow-scope context wrappers covering specific validation
|
||||
// surfaces inside a section. See the file-level header above for the
|
||||
// full inventory and how these relate to the document-wide wrappers
|
||||
// above.
|
||||
|
||||
// ComponentValidationError wraps validation errors inside the
|
||||
// Components container, carrying which sub-section (Schemas,
|
||||
// Parameters, etc.) and which component name failed.
|
||||
type ComponentValidationError struct {
|
||||
// Section is the lowercase singular form of the component bucket
|
||||
// ("schema", "parameter", "header", "request body", "response",
|
||||
// "security scheme", "example", "link", "callback").
|
||||
Section string
|
||||
// Name is the component map key.
|
||||
Name string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *ComponentValidationError) Error() string {
|
||||
return fmt.Sprintf("%s %q: %v", e.Section, e.Name, e.Cause)
|
||||
}
|
||||
|
||||
func (e *ComponentValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// ExternalDocsURLValidationError wraps the URL parse failure on an
|
||||
// ExternalDocs object.
|
||||
type ExternalDocsURLValidationError struct {
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *ExternalDocsURLValidationError) Error() string {
|
||||
return fmt.Sprintf("url is incorrect: %v", e.Cause)
|
||||
}
|
||||
|
||||
func (e *ExternalDocsURLValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// HeaderFieldValidationError wraps validation errors on a Header's
|
||||
// `schema` or `content` sub-objects. Field discriminates the two.
|
||||
type HeaderFieldValidationError struct {
|
||||
// Field is "schema" or "content".
|
||||
Field string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *HeaderFieldValidationError) Error() string {
|
||||
return fmt.Sprintf("header %s is invalid: %v", e.Field, e.Cause)
|
||||
}
|
||||
|
||||
func (e *HeaderFieldValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// MediaTypeExampleValidationError wraps validation errors on a named
|
||||
// example inside a MediaType.examples map.
|
||||
type MediaTypeExampleValidationError struct {
|
||||
// ExampleName is the example map key.
|
||||
ExampleName string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *MediaTypeExampleValidationError) Error() string {
|
||||
return fmt.Sprintf("example %s: %v", e.ExampleName, e.Cause)
|
||||
}
|
||||
|
||||
func (e *MediaTypeExampleValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// WebhookValidationError wraps validation errors on a named webhook
|
||||
// at the document root (OpenAPI 3.1+).
|
||||
type WebhookValidationError struct {
|
||||
// Name is the webhook map key.
|
||||
Name string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *WebhookValidationError) Error() string {
|
||||
return fmt.Sprintf("webhook %q: %v", e.Name, e.Cause)
|
||||
}
|
||||
|
||||
func (e *WebhookValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// ParameterFieldValidationError wraps validation errors on a
|
||||
// parameter's `schema` or `content` sub-objects. Field discriminates.
|
||||
type ParameterFieldValidationError struct {
|
||||
// ParameterName is the parameter's `name:` value.
|
||||
ParameterName string
|
||||
// Field is "schema" or "content".
|
||||
Field string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *ParameterFieldValidationError) Error() string {
|
||||
return fmt.Sprintf("parameter %q %s is invalid: %v", e.ParameterName, e.Field, e.Cause)
|
||||
}
|
||||
|
||||
func (e *ParameterFieldValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// ParameterExampleValidationError wraps validation errors on a named
|
||||
// example inside a parameter's examples map.
|
||||
type ParameterExampleValidationError struct {
|
||||
// ExampleName is the example map key.
|
||||
ExampleName string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *ParameterExampleValidationError) Error() string {
|
||||
return fmt.Sprintf("%s: %v", e.ExampleName, e.Cause)
|
||||
}
|
||||
|
||||
func (e *ParameterExampleValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// SecuritySchemeFlowValidationError wraps validation errors on the
|
||||
// outer flows object of an oauth2 security scheme.
|
||||
type SecuritySchemeFlowValidationError struct {
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *SecuritySchemeFlowValidationError) Error() string {
|
||||
return fmt.Sprintf("security scheme 'flow' is invalid: %v", e.Cause)
|
||||
}
|
||||
|
||||
func (e *SecuritySchemeFlowValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// OAuthFlowValidationError wraps validation errors on a specific
|
||||
// OAuth flow inside OAuthFlows.
|
||||
type OAuthFlowValidationError struct {
|
||||
// FlowKind is one of "implicit", "password", "clientCredentials",
|
||||
// "authorizationCode".
|
||||
FlowKind string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *OAuthFlowValidationError) Error() string {
|
||||
return fmt.Sprintf("the OAuth flow %q is invalid: %v", e.FlowKind, e.Cause)
|
||||
}
|
||||
|
||||
func (e *OAuthFlowValidationError) Unwrap() error { return e.Cause }
|
||||
|
||||
// OAuthFlowFieldValidationError wraps validation errors on a specific
|
||||
// field inside an OAuthFlow object. Field discriminates which URL
|
||||
// field failed.
|
||||
type OAuthFlowFieldValidationError struct {
|
||||
// Field is the offending field name ("refreshUrl" is the only
|
||||
// site today; future URL fields can reuse the same wrapper).
|
||||
Field string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *OAuthFlowFieldValidationError) Error() string {
|
||||
return fmt.Sprintf("field %q is invalid: %v", e.Field, e.Cause)
|
||||
}
|
||||
|
||||
func (e *OAuthFlowFieldValidationError) Unwrap() error { return e.Cause }
|
||||
172
vendor/github.com/getkin/kin-openapi/openapi3/validation_options.go
generated
vendored
Normal file
172
vendor/github.com/getkin/kin-openapi/openapi3/validation_options.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package openapi3
|
||||
|
||||
import "context"
|
||||
|
||||
// ValidationOption allows the modification of how the OpenAPI document is validated.
|
||||
type ValidationOption func(options *ValidationOptions)
|
||||
|
||||
// ValidationOptions provides configuration for validating OpenAPI documents.
|
||||
type ValidationOptions struct {
|
||||
examplesValidationAsReq, examplesValidationAsRes bool
|
||||
examplesValidationDisabled bool
|
||||
schemaDefaultsValidationDisabled bool
|
||||
schemaFormatValidationEnabled bool
|
||||
schemaPatternValidationDisabled bool
|
||||
schemaExtensionsInRefProhibited bool
|
||||
jsonSchema2020ValidationEnabled bool
|
||||
isOpenAPI31OrLater bool
|
||||
multiErrorEnabled bool
|
||||
regexCompilerFunc RegexCompilerFunc
|
||||
extraSiblingFieldsAllowed map[string]struct{}
|
||||
}
|
||||
|
||||
type validationOptionsKey struct{}
|
||||
|
||||
// AllowExtraSiblingFields called as AllowExtraSiblingFields("description") makes Validate not return an error when said field appears next to a $ref.
|
||||
func AllowExtraSiblingFields(fields ...string) ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
if options.extraSiblingFieldsAllowed == nil && len(fields) != 0 {
|
||||
options.extraSiblingFieldsAllowed = make(map[string]struct{}, len(fields))
|
||||
}
|
||||
for _, field := range fields {
|
||||
options.extraSiblingFieldsAllowed[field] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsOpenAPI31OrLater enables "JSON Schema Draft 2020-12"-compliant validation (for OpenAPI 3.1 documents).
|
||||
func IsOpenAPI31OrLater() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.isOpenAPI31OrLater = true // To distinguish from v3.0
|
||||
options.jsonSchema2020ValidationEnabled = true // TODO: use even for v3.0
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaFormatValidation makes Validate not return an error when validating documents that mention schema formats that are not defined by the OpenAPIv3 specification.
|
||||
// By default, schema format validation is disabled.
|
||||
func EnableSchemaFormatValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaFormatValidationEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaFormatValidation does the opposite of EnableSchemaFormatValidation.
|
||||
// By default, schema format validation is disabled.
|
||||
func DisableSchemaFormatValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaFormatValidationEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaPatternValidation does the opposite of DisableSchemaPatternValidation.
|
||||
// By default, schema pattern validation is enabled.
|
||||
func EnableSchemaPatternValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaPatternValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaPatternValidation makes Validate not return an error when validating patterns that are not supported by the Go regexp engine.
|
||||
func DisableSchemaPatternValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaPatternValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaDefaultsValidation does the opposite of DisableSchemaDefaultsValidation.
|
||||
// By default, schema default values are validated against their schema.
|
||||
func EnableSchemaDefaultsValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaDefaultsValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaDefaultsValidation disables schemas' default field validation.
|
||||
// By default, schema default values are validated against their schema.
|
||||
func DisableSchemaDefaultsValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaDefaultsValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// EnableExamplesValidation does the opposite of DisableExamplesValidation.
|
||||
// By default, all schema examples are validated.
|
||||
func EnableExamplesValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.examplesValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableExamplesValidation disables all example schema validation.
|
||||
// By default, all schema examples are validated.
|
||||
func DisableExamplesValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.examplesValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// AllowExtensionsWithRef allows extensions (fields starting with 'x-')
|
||||
// as siblings for $ref fields. This is the default.
|
||||
// Non-extension fields are prohibited unless allowed explicitly with the
|
||||
// AllowExtraSiblingFields option.
|
||||
func AllowExtensionsWithRef() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaExtensionsInRefProhibited = false
|
||||
}
|
||||
}
|
||||
|
||||
// ProhibitExtensionsWithRef causes the validation to return an
|
||||
// error if extensions (fields starting with 'x-') are found as
|
||||
// siblings for $ref fields. Non-extension fields are prohibited
|
||||
// unless allowed explicitly with the AllowExtraSiblingFields option.
|
||||
func ProhibitExtensionsWithRef() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaExtensionsInRefProhibited = true
|
||||
}
|
||||
}
|
||||
|
||||
// EnableMultiError makes Validate aggregate independent validation errors and
|
||||
// return them together as a MultiError instead of returning the first error
|
||||
// and stopping. By default, Validate is fail-fast.
|
||||
//
|
||||
// Not every validator reports more than one error yet. Some, such as Schema,
|
||||
// run checks that build on earlier ones, so continuing past a failure can hit
|
||||
// a nil dereference or produce nonsense secondary errors.
|
||||
// We will keep converting more validators in follow-up changes as each one
|
||||
// is analyzed.
|
||||
//
|
||||
// To pull a specific error type out of the result, use errors.As(err, &target).
|
||||
// It walks into the MultiError automatically, so the same call works whether
|
||||
// Validate returned one error or many.
|
||||
func EnableMultiError() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.multiErrorEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// SetRegexCompiler allows to override the regex implementation used to validate
|
||||
// field "pattern".
|
||||
func SetRegexCompiler(c RegexCompilerFunc) ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.regexCompilerFunc = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithValidationOptions allows adding validation options to a context object that can be used when validating any OpenAPI type.
|
||||
func WithValidationOptions(ctx context.Context, opts ...ValidationOption) context.Context {
|
||||
if len(opts) == 0 {
|
||||
return ctx
|
||||
}
|
||||
options := &ValidationOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
return context.WithValue(ctx, validationOptionsKey{}, options)
|
||||
}
|
||||
|
||||
func getValidationOptions(ctx context.Context) *ValidationOptions {
|
||||
if options, ok := ctx.Value(validationOptionsKey{}).(*ValidationOptions); ok {
|
||||
return options
|
||||
}
|
||||
return &ValidationOptions{}
|
||||
}
|
||||
41
vendor/github.com/getkin/kin-openapi/openapi3/visited.go
generated
vendored
Normal file
41
vendor/github.com/getkin/kin-openapi/openapi3/visited.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package openapi3
|
||||
|
||||
func newVisited() visitedComponent {
|
||||
return visitedComponent{
|
||||
header: make(map[*Header]struct{}),
|
||||
schema: make(map[*Schema]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
type visitedComponent struct {
|
||||
header map[*Header]struct{}
|
||||
schema map[*Schema]struct{}
|
||||
}
|
||||
|
||||
// resetVisited clears visitedComponent map
|
||||
// should be called before recursion over doc *T
|
||||
func (doc *T) resetVisited() {
|
||||
doc.visited = newVisited()
|
||||
}
|
||||
|
||||
// isVisitedHeader returns `true` if the *Header pointer was already visited
|
||||
// otherwise it returns `false`
|
||||
func (doc *T) isVisitedHeader(h *Header) bool {
|
||||
if _, ok := doc.visited.header[h]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
doc.visited.header[h] = struct{}{}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVisitedHeader returns `true` if the *Schema pointer was already visited
|
||||
// otherwise it returns `false`
|
||||
func (doc *T) isVisitedSchema(s *Schema) bool {
|
||||
if _, ok := doc.visited.schema[s]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
doc.visited.schema[s] = struct{}{}
|
||||
return false
|
||||
}
|
||||
78
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
Normal file
78
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// XML is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xml-object
|
||||
type XML struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
Attribute bool `json:"attribute,omitempty" yaml:"attribute,omitempty"`
|
||||
Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of XML.
|
||||
func (xml XML) MarshalJSON() ([]byte, error) {
|
||||
x, err := xml.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of XML.
|
||||
func (xml XML) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 5+len(xml.Extensions))
|
||||
maps.Copy(m, xml.Extensions)
|
||||
if x := xml.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := xml.Namespace; x != "" {
|
||||
m["namespace"] = x
|
||||
}
|
||||
if x := xml.Prefix; x != "" {
|
||||
m["prefix"] = x
|
||||
}
|
||||
if x := xml.Attribute; x {
|
||||
m["attribute"] = x
|
||||
}
|
||||
if x := xml.Wrapped; x {
|
||||
m["wrapped"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets XML to a copy of data.
|
||||
func (xml *XML) UnmarshalJSON(data []byte) error {
|
||||
type XMLBis XML
|
||||
var x XMLBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "namespace")
|
||||
delete(x.Extensions, "prefix")
|
||||
delete(x.Extensions, "attribute")
|
||||
delete(x.Extensions, "wrapped")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*xml = XML(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if XML does not comply with the OpenAPI spec.
|
||||
func (xml *XML) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, xml.Extensions, xml.Origin)
|
||||
}
|
||||
Reference in New Issue
Block a user