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 }