niki/vendor/github.com/sv-tools/openapi/spec/ref.go

112 lines
2.9 KiB
Go

package spec
import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
)
// Ref is a simple object to allow referencing other components in the OpenAPI document, internally and externally.
// The $ref string value contains a URI [RFC3986], which identifies the location of the value being referenced.
// See the rules for resolving Relative References.
//
// https://spec.openapis.org/oas/v3.1.0#reference-object
//
// Example:
//
// $ref: '#/components/schemas/Pet'
type Ref struct {
// REQUIRED.
// The reference identifier.
// This MUST be in the form of a URI.
Ref string `json:"$ref" yaml:"$ref"`
// A short summary which by default SHOULD override that of the referenced component.
// If the referenced object-type does not allow a summary field, then this field has no effect.
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
// A description which by default SHOULD override that of the referenced component.
// CommonMark syntax MAY be used for rich text representation.
// If the referenced object-type does not allow a description field, then this field has no effect.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
// NewRef creates an object of Ref type.
func NewRef(ref string) *Ref {
return &Ref{
Ref: ref,
}
}
// RefOrSpec holds either Ref or any OpenAPI spec type.
//
// NOTE: The Ref object takes precedent over Spec if using json or yaml Marshal and Unmarshal functions.
type RefOrSpec[T any] struct {
Ref *Ref `json:"-" yaml:"-"`
Spec *T `json:"-" yaml:"-"`
}
// NewRefOrSpec creates an object of RefOrSpec type for either Ref or Spec
func NewRefOrSpec[T any](ref *Ref, spec *T) *RefOrSpec[T] {
o := RefOrSpec[T]{}
switch {
case ref != nil:
o.Ref = ref
case spec != nil:
o.Spec = spec
}
return &o
}
// MarshalJSON implements json.Marshaler interface.
func (o *RefOrSpec[T]) MarshalJSON() ([]byte, error) {
var v any
if o.Ref != nil {
v = o.Ref
} else {
v = o.Spec
}
data, err := json.Marshal(&v)
if err != nil {
return nil, fmt.Errorf("%T: %w", o.Spec, err)
}
return data, nil
}
// UnmarshalJSON implements json.Unmarshaler interface.
func (o *RefOrSpec[T]) UnmarshalJSON(data []byte) error {
if json.Unmarshal(data, &o.Ref) == nil && o.Ref.Ref != "" {
o.Spec = nil
return nil
}
o.Ref = nil
if err := json.Unmarshal(data, &o.Spec); err != nil {
return fmt.Errorf("%T: %w", o.Spec, err)
}
return nil
}
// MarshalYAML implements yaml.Marshaler interface.
func (o *RefOrSpec[T]) MarshalYAML() (any, error) {
var v any
if o.Ref != nil {
v = o.Ref
} else {
v = o.Spec
}
return v, nil
}
// UnmarshalYAML implements yaml.Unmarshaler interface.
func (o *RefOrSpec[T]) UnmarshalYAML(node *yaml.Node) error {
if node.Decode(&o.Ref) == nil && o.Ref.Ref != "" {
return nil
}
o.Ref = nil
if err := node.Decode(&o.Spec); err != nil {
return fmt.Errorf("%T: %w", o.Spec, err)
}
return nil
}