Large update to support v3 rendering.

This commit is contained in:
Dave Shanley
2023-03-11 15:43:32 -05:00
parent 000eada3f4
commit 3101a7c9b7
65 changed files with 605 additions and 133 deletions

View File

@@ -34,6 +34,11 @@ func (c *Contact) GoLow() *low.Contact {
return c.low
}
// GoLowUntyped will return the low-level Contact instance that was used to create the high-level one, with no type
func (c *Contact) GoLowUntyped() any {
return c.low
}
func (c *Contact) Render() ([]byte, error) {
return yaml.Marshal(c)
}

View File

@@ -41,6 +41,11 @@ func (d *Discriminator) GoLow() *low.Discriminator {
return d.low
}
// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type
func (d *Discriminator) GoLowUntyped() any {
return d.low
}
// Render will return a YAML representation of the Discriminator object as a byte slice.
func (d *Discriminator) Render() ([]byte, error) {
return yaml.Marshal(d)

View File

@@ -38,6 +38,11 @@ func (e *Example) GoLow() *low.Example {
return e.low
}
// GoLowUntyped will return the low-level Example instance that was used to create the high-level one, with no type
func (e *Example) GoLowUntyped() any {
return e.low
}
// Render will return a YAML representation of the Example object as a byte slice.
func (e *Example) Render() ([]byte, error) {
return yaml.Marshal(e)

View File

@@ -40,6 +40,11 @@ func (e *ExternalDoc) GoLow() *low.ExternalDoc {
return e.low
}
// GoLowUntyped will return the low-level ExternalDoc instance that was used to create the high-level one, with no type
func (e *ExternalDoc) GoLowUntyped() any {
return e.low
}
func (e *ExternalDoc) GetExtensions() map[string]any {
return e.Extensions
}

View File

@@ -64,6 +64,11 @@ func (i *Info) GoLow() *low.Info {
return i.low
}
// GoLowUntyped will return the low-level Info instance that was used to create the high-level one, with no type
func (i *Info) GoLowUntyped() any {
return i.low
}
// Render will return a YAML representation of the Info object as a byte slice.
func (i *Info) Render() ([]byte, error) {
return yaml.Marshal(i)

View File

@@ -36,6 +36,11 @@ func (l *License) GoLow() *low.License {
return l.low
}
// GoLowUntyped will return the low-level License instance that was used to create the high-level one, with no type
func (l *License) GoLowUntyped() any {
return l.low
}
// Render will return a YAML representation of the License object as a byte slice.
func (l *License) Render() ([]byte, error) {
return yaml.Marshal(l)

View File

@@ -444,6 +444,11 @@ func (s *Schema) GoLow() *base.Schema {
return s.low
}
// GoLowUntyped will return the low-level Schema instance that was used to create the high-level one, with no type
func (s *Schema) GoLowUntyped() any {
return s.low
}
// Render will return a YAML representation of the Schema object as a byte slice.
func (s *Schema) Render() ([]byte, error) {
return yaml.Marshal(s)

View File

@@ -96,6 +96,13 @@ func (sp *SchemaProxy) GoLow() *base.SchemaProxy {
return sp.schema.Value
}
func (sp *SchemaProxy) GoLowUntyped() any {
if sp.schema == nil {
return nil
}
return sp.schema.Value
}
// Render will return a YAML representation of the Schema object as a byte slice.
func (sp *SchemaProxy) Render() ([]byte, error) {
return yaml.Marshal(sp)

View File

@@ -43,6 +43,11 @@ func (s *SecurityRequirement) GoLow() *base.SecurityRequirement {
return s.low
}
// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type
func (s *SecurityRequirement) GoLowUntyped() any {
return s.low
}
// Render will return a YAML representation of the SecurityRequirement object as a byte slice.
func (s *SecurityRequirement) Render() ([]byte, error) {
return yaml.Marshal(s)

View File

@@ -45,6 +45,11 @@ func (t *Tag) GoLow() *low.Tag {
return t.low
}
// GoLowUntyped will return the low-level Tag instance that was used to create the high-level one, with no type
func (t *Tag) GoLowUntyped() any {
return t.low
}
// Render will return a YAML representation of the Info object as a byte slice.
func (t *Tag) Render() ([]byte, error) {
return yaml.Marshal(t)
@@ -58,28 +63,3 @@ func (t *Tag) MarshalYAML() (interface{}, error) {
nb := high.NewNodeBuilder(t, t.low)
return nb.Render(), nil
}
// Experimental mutation API.
//func (t *Tag) SetName(value string) {
// t.GoLow().Name.ValueNode.Value = value
//}
//func (t *Tag) SetDescription(value string) {
// t.GoLow().Description.ValueNode.Value = value
//}
//func (t *Tag) MarshalYAML() (interface{}, error) {
// m := make(map[string]interface{})
// for i := range t.Extensions {
// m[i] = t.Extensions[i]
// }
// if t.Name != "" {
// m[NameLabel] = t.Name
// }
// if t.Description != "" {
// m[DescriptionLabel] = t.Description
// }
// if t.ExternalDocs != nil {
// m[ExternalDocsLabel] = t.ExternalDocs
// }
// return m, nil
//}

View File

@@ -46,6 +46,11 @@ func (x *XML) GoLow() *low.XML {
return x.low
}
// GoLowUntyped will return the low-level XML instance that was used to create the high-level one, with no type
func (x *XML) GoLowUntyped() any {
return x.low
}
// Render will return a YAML representation of the XML object as a byte slice.
func (x *XML) Render() ([]byte, error) {
return yaml.Marshal(x)

View File

@@ -150,6 +150,16 @@ func (n *NodeBuilder) add(key string) {
case reflect.Struct:
y := value.Interface()
if nb, ok := y.(low.HasValueNodeUntyped); ok {
if nb.IsReference() {
if jk, kj := y.(low.HasKeyNode); kj {
nodeEntry.Line = jk.GetKeyNode().Line
break
}
panic("this should not break.")
}
if nb.GetValueNode() != nil {
nodeEntry.Line = nb.GetValueNode().Line
} else {
@@ -169,13 +179,32 @@ func (n *NodeBuilder) add(key string) {
}
}
func (n *NodeBuilder) renderReference() []*yaml.Node {
if fg, ok := n.Low.(low.IsReferenced); ok {
nodes := make([]*yaml.Node, 2)
nodes[0] = CreateStringNode("$ref")
nodes[1] = CreateStringNode(fg.GetReference())
return nodes
}
return nil
}
// Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined
func (n *NodeBuilder) Render() *yaml.Node {
// order nodes by line number, retain original order
m := CreateEmptyMapNode()
if fg, ok := n.Low.(low.IsReferenced); ok {
if fg.IsReference() {
m.Content = append(m.Content, n.renderReference()...)
return m
}
}
sort.Slice(n.Nodes, func(i, j int) bool {
return n.Nodes[i].Line < n.Nodes[j].Line
})
m := CreateEmptyMapNode()
for i := range n.Nodes {
node := n.Nodes[i]
n.AddYAMLNode(m, node.Tag, node.Key, node.Value)
@@ -296,7 +325,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
Tag: uu.(string),
Key: uu.(string),
Line: 9999 + j,
Value: fg.MapIndex(ky).Interface(),
Value: m.MapIndex(k).Interface(),
})
}
}
@@ -379,6 +408,32 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
}
var rawNode yaml.Node
m := reflect.ValueOf(value)
sl := CreateEmptySequenceNode()
for i := 0; i < m.Len(); i++ {
sqi := m.Index(i).Interface()
if glu, ok := sqi.(GoesLowUntyped); ok {
if glu.GoLowUntyped().(low.IsReferenced).IsReference() {
rt := CreateEmptyMapNode()
nodes := make([]*yaml.Node, 2)
nodes[0] = CreateStringNode("$ref")
nodes[1] = CreateStringNode(glu.GoLowUntyped().(low.IsReferenced).GetReference())
rt.Content = append(rt.Content, nodes...)
sl.Content = append(sl.Content, rt)
}
}
}
if len(sl.Content) > 0 {
valueNode = sl
break
}
err := rawNode.Encode(value)
if err != nil {
return parent
@@ -399,6 +454,15 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
case reflect.Ptr:
if r, ok := value.(Renderable); ok {
if gl, lg := value.(GoesLowUntyped); lg {
if gl.GoLowUntyped().(low.IsReferenced).IsReference() {
rvn := CreateEmptyMapNode()
rvn.Content = append(rvn.Content, CreateStringNode("$ref"))
rvn.Content = append(rvn.Content, CreateStringNode(gl.GoLowUntyped().(low.IsReferenced).GetReference()))
valueNode = rvn
break
}
}
rawRender, _ := r.MarshalYAML()
if rawRender != nil {
valueNode = rawRender.(*yaml.Node)
@@ -469,6 +533,14 @@ func CreateEmptyMapNode() *yaml.Node {
return n
}
func CreateEmptySequenceNode() *yaml.Node {
n := &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
}
return n
}
func CreateStringNode(str string) *yaml.Node {
n := &yaml.Node{
Kind: yaml.ScalarNode,

View File

@@ -26,6 +26,15 @@ type GoesLow[T any] interface {
GoLow() T
}
// GoesLowUnTyped is used to represent any high-level model. All high level models meet this interface and can be used to
// extract low-level models from any high-level model.
type GoesLowUntyped interface {
// GoLow returns the low-level object that was used to create the high-level object. This allows consumers
// to dive-down into the plumbing API at any point in the model.
GoLowUntyped() any
}
// ExtractExtensions is a convenience method for converting low-level extension definitions, to a high level map[string]any
// definition that is easier to consume in applications.
func ExtractExtensions(extensions map[low.KeyReference[string]]low.ValueReference[any]) map[string]any {

View File

@@ -43,6 +43,11 @@ func (c *Callback) GoLow() *low.Callback {
return c.low
}
// GoLowUntyped will return the low-level Callback instance that was used to create the high-level one, with no type
func (c *Callback) GoLowUntyped() any {
return c.low
}
// Render will return a YAML representation of the Callback object as a byte slice.
func (c *Callback) Render() ([]byte, error) {
return yaml.Marshal(c)

View File

@@ -30,14 +30,14 @@ const (
// will have no effect on the API unless they are explicitly referenced from properties outside the components object.
// - https://spec.openapis.org/oas/v3.1.0#components-object
type Components struct {
//Schemas map[string]*highbase.SchemaProxy `json:"schemas,omitempty" yaml:"schemas,omitempty"`
Schemas map[string]*highbase.SchemaProxy `json:"-" yaml:"-"`
Responses map[string]*Response `json:"-" yaml:"-"`
//Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Parameters map[string]*Parameter `json:"-" yaml:"-"`
//Parameters map[string]*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
//Examples map[string]*highbase.Example `json:"examples,omitempty" yaml:"examples,omitempty"`
Examples map[string]*highbase.Example `json:"-" yaml:"-"`
Schemas map[string]*highbase.SchemaProxy `json:"schemas,omitempty" yaml:"schemas,omitempty"`
//Schemas map[string]*highbase.SchemaProxy `json:"-" yaml:"-"`
//Responses map[string]*Response `json:"-" yaml:"-"`
Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"`
//Parameters map[string]*Parameter `json:"-" yaml:"-"`
Parameters map[string]*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Examples map[string]*highbase.Example `json:"examples,omitempty" yaml:"examples,omitempty"`
//Examples map[string]*highbase.Example `json:"-" yaml:"-"`
RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"`
SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`

View File

@@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/url"
"os"
"strings"
"testing"
"github.com/pb33f/libopenapi/datamodel"
@@ -490,14 +491,149 @@ func TestDocument_MarshalYAML(t *testing.T) {
os.WriteFile("rendered.yaml", r, 0644)
// re-parse the document
//TODO: pick up in the morning here, trying to figure out why headers are being rendered (UseOil)
info, _ := datamodel.ExtractSpecInfo(r)
lDoc, e := lowv3.CreateDocumentFromConfig(info, datamodel.NewOpenDocumentConfiguration())
assert.Nil(t, e)
highDoc := NewDocument(lDoc)
assert.Equal(t, "3.1.0", highDoc.Version)
assert.Len(t, highDoc.Paths.PathItems, 1)
assert.Len(t, highDoc.Paths.PathItems, 5)
}
func TestDocument_MarshalYAML_TestRefs(t *testing.T) {
// create a new document
yml := `openapi: 3.1.0
paths:
x-milky-milk: milky
/burgers:
x-burger-meta: meaty
post:
operationId: createBurger
tags:
- Burgers
summary: Create a new burger
description: A new burger for our menu, yummy yum yum.
responses:
"200":
headers:
UseOil:
$ref: '#/components/headers/UseOil'
description: A tasty burger for you to eat.
content:
application/json:
schema:
$ref: '#/components/schemas/Burger'
examples:
quarterPounder:
$ref: '#/components/examples/QuarterPounder'
filetOFish:
summary: a cripsy fish sammich filled with ocean goodness.
value:
name: Filet-O-Fish
numPatties: 1
components:
headers:
UseOil:
description: this is a header example for UseOil
schema:
type: string
schemas:
Burger:
type: object
description: The tastiest food on the planet you would love to eat everyday
required:
- name
- numPatties
properties:
name:
type: string
description: The name of your tasty burger - burger names are listed in our menus
example: Big Mac
numPatties:
type: integer
description: The number of burger patties used
example: "2"
examples:
QuarterPounder:
summary: A juicy two hander sammich
value:
name: Quarter Pounder with Cheese
numPatties: 1`
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
lowDoc, err = lowv3.CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: true,
AllowRemoteReferences: true,
})
if err != nil {
panic("broken something")
}
h := NewDocument(lowDoc)
// render the document to YAML and it should be identical.
r, _ := h.Render()
assert.Equal(t, yml, strings.TrimSpace(string(r)))
}
func TestDocument_MarshalYAML_TestParamRefs(t *testing.T) {
// create a new document
yml := `openapi: 3.1.0
paths:
"/burgers/{burgerId}":
get:
operationId: locateBurger
tags:
- Burgers
summary: Search a burger by ID - returns the burger with that identifier
description: Look up a tasty burger take it and enjoy it
parameters:
- $ref: "#/components/parameters/BurgerId"
- $ref: "#/components/parameters/BurgerHeader"
components:
parameters:
BurgerHeader:
in: header
name: burgerHeader
schema:
properties:
burgerTheme:
type: string
description: something about a theme goes in here?
burgerTime:
type: number
description: number of burgers ordered so far this year.
BurgerId:
in: path
name: burgerId
schema:
type: string
example: big-mac
description: the name of the burger. use this to order your tasty burger
required: true
`
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
var err []error
lowDoc, err = lowv3.CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
AllowFileReferences: true,
AllowRemoteReferences: true,
})
if err != nil {
panic("broken something")
}
h := NewDocument(lowDoc)
// render the document to YAML and it should be identical.
r, _ := h.Render()
assert.Equal(t, yml, strings.TrimSpace(string(r)))
}

View File

@@ -38,6 +38,11 @@ func (e *Encoding) GoLow() *low.Encoding {
return e.low
}
// GoLowUntyped will return the low-level Encoding instance that was used to create the high-level one, with no type
func (e *Encoding) GoLowUntyped() any {
return e.low
}
// Render will return a YAML representation of the Encoding object as a byte slice.
func (e *Encoding) Render() ([]byte, error) {
return yaml.Marshal(e)

View File

@@ -59,6 +59,11 @@ func (h *Header) GoLow() *low.Header {
return h.low
}
// GoLowUntyped will return the low-level Header instance that was used to create the high-level one, with no type
func (h *Header) GoLowUntyped() any {
return h.low
}
// ExtractHeaders will extract a hard to navigate low-level Header map, into simple high-level one.
func ExtractHeaders(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Header]) map[string]*Header {
extracted := make(map[string]*Header)

View File

@@ -57,6 +57,11 @@ func (l *Link) GoLow() *low.Link {
return l.low
}
// GoLowUntyped will return the low-level Link instance that was used to create the high-level one, with no type
func (l *Link) GoLowUntyped() any {
return l.low
}
// Render will return a YAML representation of the Link object as a byte slice.
func (l *Link) Render() ([]byte, error) {
return yaml.Marshal(l)

View File

@@ -44,6 +44,11 @@ func (m *MediaType) GoLow() *low.MediaType {
return m.low
}
// GoLowUntyped will return the low-level MediaType instance that was used to create the high-level one, with no type
func (m *MediaType) GoLowUntyped() any {
return m.low
}
// Render will return a YAML representation of the MediaType object as a byte slice.
func (m *MediaType) Render() ([]byte, error) {
return yaml.Marshal(m)

View File

@@ -41,6 +41,11 @@ func (o *OAuthFlow) GoLow() *low.OAuthFlow {
return o.low
}
// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type
func (o *OAuthFlow) GoLowUntyped() any {
return o.low
}
// Render will return a YAML representation of the OAuthFlow object as a byte slice.
func (o *OAuthFlow) Render() ([]byte, error) {
return yaml.Marshal(o)

View File

@@ -48,6 +48,11 @@ func (o *OAuthFlows) GoLow() *low.OAuthFlows {
return o.low
}
// GoLowUntyped will return the low-level OAuthFlows instance that was used to create the high-level one, with no type
func (o *OAuthFlows) GoLowUntyped() any {
return o.low
}
// Render will return a YAML representation of the OAuthFlows object as a byte slice.
func (o *OAuthFlows) Render() ([]byte, error) {
return yaml.Marshal(o)

View File

@@ -91,6 +91,11 @@ func (o *Operation) GoLow() *low.Operation {
return o.low
}
// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type
func (o *Operation) GoLowUntyped() any {
return o.low
}
// Render will return a YAML representation of the Operation object as a byte slice.
func (o *Operation) Render() ([]byte, error) {
return yaml.Marshal(o)

View File

@@ -62,6 +62,11 @@ func (p *Parameter) GoLow() *low.Parameter {
return p.low
}
// GoLowUntyped will return the low-level Discriminator instance that was used to create the high-level one, with no type
func (p *Parameter) GoLowUntyped() any {
return p.low
}
// Render will return a YAML representation of the Encoding object as a byte slice.
func (p *Parameter) Render() ([]byte, error) {
return yaml.Marshal(p)

View File

@@ -124,6 +124,11 @@ func (p *PathItem) GoLow() *low.PathItem {
return p.low
}
// GoLowUntyped will return the low-level PathItem instance that was used to create the high-level one, with no type
func (p *PathItem) GoLowUntyped() any {
return p.low
}
func (p *PathItem) GetOperations() map[string]*Operation {
o := make(map[string]*Operation)
if p.Get != nil {

View File

@@ -58,6 +58,11 @@ func (p *Paths) GoLow() *low.Paths {
return p.low
}
// GoLowUntyped will return the low-level Paths instance that was used to create the high-level one, with no type
func (p *Paths) GoLowUntyped() any {
return p.low
}
// Render will return a YAML representation of the Paths object as a byte slice.
func (p *Paths) Render() ([]byte, error) {
return yaml.Marshal(p)
@@ -88,7 +93,7 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
nb := high.NewNodeBuilder(p, p.low)
extNode := nb.Render()
if extNode.Content != nil {
if extNode != nil && extNode.Content != nil {
for u := range extNode.Content {
mapped = append(mapped, &pathItem{nil, extNode.Content[u].Value,
extNode.Content[u].Line, extNode.Content[u]})

View File

@@ -35,6 +35,11 @@ func (r *RequestBody) GoLow() *low.RequestBody {
return r.low
}
// GoLowUntyped will return the low-level RequestBody instance that was used to create the high-level one, with no type
func (r *RequestBody) GoLowUntyped() any {
return r.low
}
// Render will return a YAML representation of the RequestBody object as a byte slice.
func (r *RequestBody) Render() ([]byte, error) {
return yaml.Marshal(r)

View File

@@ -50,6 +50,11 @@ func (r *Response) GoLow() *low.Response {
return r.low
}
// GoLowUntyped will return the low-level Response instance that was used to create the high-level one, with no type
func (r *Response) GoLowUntyped() any {
return r.low
}
// Render will return a YAML representation of the Response object as a byte slice.
func (r *Response) Render() ([]byte, error) {
return yaml.Marshal(r)

View File

@@ -80,6 +80,11 @@ func (r *Responses) GoLow() *low.Responses {
return r.low
}
// GoLowUntyped will return the low-level Responses instance that was used to create the high-level one, with no type
func (r *Responses) GoLowUntyped() any {
return r.low
}
// Render will return a YAML representation of the Responses object as a byte slice.
func (r *Responses) Render() ([]byte, error) {
return yaml.Marshal(r)

View File

@@ -55,6 +55,11 @@ func (s *SecurityScheme) GoLow() *low.SecurityScheme {
return s.low
}
// GoLowUntyped will return the low-level SecurityScheme instance that was used to create the high-level one, with no type
func (s *SecurityScheme) GoLowUntyped() any {
return s.low
}
// Render will return a YAML representation of the SecurityScheme object as a byte slice.
func (s *SecurityScheme) Render() ([]byte, error) {
return yaml.Marshal(s)

View File

@@ -39,6 +39,11 @@ func (s *Server) GoLow() *low.Server {
return s.low
}
// GoLowUntyped will return the low-level Server instance that was used to create the high-level one, with no type
func (s *Server) GoLowUntyped() any {
return s.low
}
// Render will return a YAML representation of the Server object as a byte slice.
func (s *Server) Render() ([]byte, error) {
return yaml.Marshal(s)

View File

@@ -41,6 +41,11 @@ func (s *ServerVariable) GoLow() *low.ServerVariable {
return s.low
}
// GoLowUntyped will return the low-level ServerVariable instance that was used to create the high-level one, with no type
func (s *ServerVariable) GoLowUntyped() any {
return s.low
}
// Render will return a YAML representation of the ServerVariable object as a byte slice.
func (s *ServerVariable) Render() ([]byte, error) {
return yaml.Marshal(s)

View File

@@ -18,10 +18,12 @@ type Contact struct {
Name low.NodeReference[string]
URL low.NodeReference[string]
Email low.NodeReference[string]
*low.Reference
}
// Build is not implemented for Contact (there is nothing to build).
func (c *Contact) Build(root *yaml.Node, idx *index.SpecIndex) error {
c.Reference = new(low.Reference)
// not implemented.
return nil
}

View File

@@ -21,6 +21,7 @@ import (
type Discriminator struct {
PropertyName low.NodeReference[string]
Mapping map[low.KeyReference[string]]low.ValueReference[string]
low.Reference
}
// FindMappingValue will return a ValueReference containing the string mapping value

View File

@@ -23,6 +23,7 @@ type Example struct {
Value low.NodeReference[any]
ExternalValue low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension returns a ValueReference containing the extension value, if found.
@@ -59,6 +60,7 @@ func (ex *Example) Hash() [32]byte {
// Build extracts extensions and example value
func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error {
ex.Reference = new(low.Reference)
ex.Extensions = low.ExtractExtensions(root)
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)

View File

@@ -22,6 +22,7 @@ type ExternalDoc struct {
Description low.NodeReference[string]
URL low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension returns a ValueReference containing the extension value, if found.
@@ -31,6 +32,7 @@ func (ex *ExternalDoc) FindExtension(ext string) *low.ValueReference[any] {
// Build will extract extensions from the ExternalDoc instance.
func (ex *ExternalDoc) Build(root *yaml.Node, idx *index.SpecIndex) error {
ex.Reference = new(low.Reference)
ex.Extensions = low.ExtractExtensions(root)
return nil
}

View File

@@ -30,6 +30,7 @@ type Info struct {
License low.NodeReference[*License]
Version low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension attempts to locate an extension with the supplied key
@@ -44,6 +45,7 @@ func (i *Info) GetExtensions() map[low.KeyReference[string]]low.ValueReference[a
// Build will extract out the Contact and Info objects from the supplied root node.
func (i *Info) Build(root *yaml.Node, idx *index.SpecIndex) error {
i.Reference = new(low.Reference)
i.Extensions = low.ExtractExtensions(root)
// extract contact

View File

@@ -17,10 +17,12 @@ import (
type License struct {
Name low.NodeReference[string]
URL low.NodeReference[string]
*low.Reference
}
// Build is not implemented for License (there is nothing to build)
func (l *License) Build(root *yaml.Node, idx *index.SpecIndex) error {
l.Reference = new(low.Reference)
return nil
}

View File

@@ -125,6 +125,7 @@ type Schema struct {
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
ParentProxy *SchemaProxy
*low.Reference
}
// Hash will calculate a SHA256 hash from the values of the schema, This allows equality checking against
@@ -504,6 +505,7 @@ func (s *Schema) GetExtensions() map[low.KeyReference[string]]low.ValueReference
// - UnevaluatedItems
// - UnevaluatedProperties
func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
s.Reference = new(low.Reference)
if h, _, _ := utils.IsNodeRefValue(root); h {
ref, err := low.LocateRefNode(root, idx)
if ref != nil {
@@ -1233,7 +1235,8 @@ func ExtractSchema(root *yaml.Node, idx *index.SpecIndex) (*low.NodeReference[*S
if schNode != nil {
// check if schema has already been built.
schema := &SchemaProxy{kn: schLabel, vn: schNode, idx: idx, isReference: isRef, referenceLookup: refLocation}
return &low.NodeReference[*SchemaProxy]{Value: schema, KeyNode: schLabel, ValueNode: schNode}, nil
return &low.NodeReference[*SchemaProxy]{Value: schema, KeyNode: schLabel, ValueNode: schNode, ReferenceNode: isRef,
Reference: refLocation}, nil
}
return nil, nil
}

View File

@@ -104,6 +104,21 @@ func (sp *SchemaProxy) IsSchemaReference() bool {
return sp.isReference
}
// IsReference is an alias for IsSchemaReference() except it's compatible wih the IsReferenced interface type.
func (sp *SchemaProxy) IsReference() bool {
return sp.IsSchemaReference()
}
// GetReference is an alias for GetSchemaReference() except it's compatible wih the IsReferenced interface type.
func (sp *SchemaProxy) GetReference() string {
return sp.GetSchemaReference()
}
// SetReference will set the reference lookup for this SchemaProxy.
func (sp *SchemaProxy) SetReference(ref string) {
sp.referenceLookup = ref
}
// GetSchemaReference will return the lookup defined by the $ref that this schema points to. If the schema
// is inline, and not a reference, then this method returns an empty string. Only useful when combined with
// IsSchemaReference()

View File

@@ -23,10 +23,12 @@ import (
// - https://swagger.io/specification/#security-requirement-object
type SecurityRequirement struct {
Requirements low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]
*low.Reference
}
// Build will extract security requirements from the node (the structure is odd, to be honest)
func (s *SecurityRequirement) Build(root *yaml.Node, _ *index.SpecIndex) error {
s.Reference = new(low.Reference)
var labelNode *yaml.Node
valueMap := make(map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]])
var arr []low.ValueReference[string]

View File

@@ -24,6 +24,7 @@ type Tag struct {
Description low.NodeReference[string]
ExternalDocs low.NodeReference[*ExternalDoc]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension returns a ValueReference containing the extension value, if found.
@@ -33,6 +34,7 @@ func (t *Tag) FindExtension(ext string) *low.ValueReference[any] {
// Build will extract extensions and external docs for the Tag.
func (t *Tag) Build(root *yaml.Node, idx *index.SpecIndex) error {
t.Reference = new(low.Reference)
t.Extensions = low.ExtractExtensions(root)
// extract externalDocs

View File

@@ -25,10 +25,12 @@ type XML struct {
Attribute low.NodeReference[bool]
Wrapped low.NodeReference[bool]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// Build will extract extensions from the XML instance.
func (x *XML) Build(root *yaml.Node, _ *index.SpecIndex) error {
x.Reference = new(low.Reference)
x.Extensions = low.ExtractExtensions(root)
return nil
}

View File

@@ -146,6 +146,12 @@ func ExtractObjectRaw[T Buildable[N], N any](root *yaml.Node, idx *index.SpecInd
if err != nil {
return n, err, isReference, referenceValue
}
// if this is a reference, keep track of the reference in the value
if isReference {
SetReference(n, referenceValue)
}
// do we want to throw an error as well if circular error reporting is on?
if circError != nil && !idx.AllowCircularReferenceResolving() {
return n, circError, isReference, referenceValue
@@ -208,13 +214,19 @@ func ExtractObject[T Buildable[N], N any](label string, root *yaml.Node, idx *in
return NodeReference[T]{}, err
}
// if this is a reference, keep track of the reference in the value
if isReference {
SetReference(n, referenceValue)
}
res := NodeReference[T]{
Value: n,
KeyNode: ln,
ValueNode: vn,
IsReference: isReference,
ReferenceNode: isReference,
Reference: referenceValue,
}
// do we want to throw an error as well if circular error reporting is on?
if circError != nil && !idx.AllowCircularReferenceResolving() {
return res, circError
@@ -222,6 +234,15 @@ func ExtractObject[T Buildable[N], N any](label string, root *yaml.Node, idx *in
return res, nil
}
func SetReference(obj any, ref string) {
if obj == nil {
return
}
if r, ok := obj.(IsReferenced); ok {
r.SetReference(ref)
}
}
// ExtractArray will extract a slice of []ValueReference[T] from a root yaml.Node that is defined as a sequence.
// Used when the value being extracted is an array.
func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *index.SpecIndex) ([]ValueReference[T],
@@ -229,15 +250,11 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
) {
var ln, vn *yaml.Node
var circError error
var isReference bool
var referenceValue string
if rf, rl, rv := utils.IsNodeRefValue(root); rf {
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
ref, err := LocateRefNode(root, idx)
if ref != nil {
vn = ref
ln = rl
isReference = true
referenceValue = rv
if err != nil {
circError = err
}
@@ -248,12 +265,11 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
} else {
_, ln, vn = utils.FindKeyNodeFullTop(label, root.Content)
if vn != nil {
if h, _, rVal := utils.IsNodeRefValue(vn); h {
if h, _, _ := utils.IsNodeRefValue(vn); h {
ref, err := LocateRefNode(vn, idx)
if ref != nil {
vn = ref
isReference = true
referenceValue = rVal
//referenceValue = rVal
if err != nil {
circError = err
}
@@ -274,13 +290,13 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
}
for _, node := range vn.Content {
localReferenceValue := ""
localIsReference := false
//localIsReference := false
if rf, _, rv := utils.IsNodeRefValue(node); rf {
ref, err := LocateRefNode(node, idx)
if ref != nil {
node = ref
localIsReference = true
refg, err := LocateRefNode(node, idx)
if refg != nil {
node = refg
//localIsReference = true
localReferenceValue = rv
if err != nil {
circError = err
@@ -302,15 +318,14 @@ func ExtractArray[T Buildable[N], N any](label string, root *yaml.Node, idx *ind
return nil, ln, vn, berr
}
if localReferenceValue == "" {
localReferenceValue = referenceValue
localIsReference = isReference
if localReferenceValue != "" {
SetReference(n, localReferenceValue)
}
items = append(items, ValueReference[T]{
Value: n,
ValueNode: node,
IsReference: localIsReference,
ReferenceNode: localReferenceValue != "",
Reference: localReferenceValue,
})
}
@@ -395,13 +410,17 @@ func ExtractMapNoLookup[PT Buildable[N], N any](
if berr != nil {
return nil, berr
}
if isReference {
SetReference(n, referenceValue)
}
valueMap[KeyReference[string]{
Value: currentKey.Value,
KeyNode: currentKey,
}] = ValueReference[PT]{
Value: n,
ValueNode: node,
IsReference: isReference,
//IsReference: isReference,
Reference: referenceValue,
}
}
@@ -427,7 +446,7 @@ func ExtractMap[PT Buildable[N], N any](
root *yaml.Node,
idx *index.SpecIndex,
) (map[KeyReference[string]]ValueReference[PT], *yaml.Node, *yaml.Node, error) {
var isReference bool
//var isReference bool
var referenceValue string
var labelNode, valueNode *yaml.Node
var circError error
@@ -437,7 +456,7 @@ func ExtractMap[PT Buildable[N], N any](
if ref != nil {
valueNode = ref
labelNode = rl
isReference = true
//isReference = true
referenceValue = rv
if err != nil {
circError = err
@@ -449,12 +468,12 @@ func ExtractMap[PT Buildable[N], N any](
} else {
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
if valueNode != nil {
if h, _, rv := utils.IsNodeRefValue(valueNode); h {
if h, _, rvt := utils.IsNodeRefValue(valueNode); h {
ref, err := LocateRefNode(valueNode, idx)
if ref != nil {
valueNode = ref
isReference = true
referenceValue = rv
//isReference = true
referenceValue = rvt
if err != nil {
circError = err
}
@@ -474,7 +493,7 @@ func ExtractMap[PT Buildable[N], N any](
bChan := make(chan mappingResult[PT])
eChan := make(chan error)
buildMap := func(label *yaml.Node, value *yaml.Node, c chan mappingResult[PT], ec chan<- error) {
buildMap := func(label *yaml.Node, value *yaml.Node, c chan mappingResult[PT], ec chan<- error, ref string) {
var n PT = new(N)
_ = BuildModel(value, n)
err := n.Build(value, idx)
@@ -482,6 +501,13 @@ func ExtractMap[PT Buildable[N], N any](
ec <- err
return
}
//isRef := false
if ref != "" {
//isRef = true
SetReference(n, ref)
}
c <- mappingResult[PT]{
k: KeyReference[string]{
KeyNode: label,
@@ -490,23 +516,25 @@ func ExtractMap[PT Buildable[N], N any](
v: ValueReference[PT]{
Value: n,
ValueNode: value,
IsReference: isReference,
Reference: referenceValue,
//IsReference: isRef,
Reference: ref,
},
}
}
totalKeys := 0
for i, en := range valueNode.Content {
referenceValue = ""
if i%2 == 0 {
currentLabelNode = en
continue
}
// check our valueNode isn't a reference still.
if h, _, _ := utils.IsNodeRefValue(en); h {
if h, _, refVal := utils.IsNodeRefValue(en); h {
ref, err := LocateRefNode(en, idx)
if ref != nil {
en = ref
referenceValue = refVal
if err != nil {
circError = err
}
@@ -522,7 +550,7 @@ func ExtractMap[PT Buildable[N], N any](
continue // yo, don't pay any attention to extensions, not here anyway.
}
totalKeys++
go buildMap(currentLabelNode, en, bChan, eChan)
go buildMap(currentLabelNode, en, bChan, eChan, referenceValue)
}
completedKeys := 0

View File

@@ -11,6 +11,28 @@ const (
HASH = "%x"
)
type Reference struct {
Reference string `json:"-" yaml:"-"`
}
func (r *Reference) GetReference() string {
return r.Reference
}
func (r *Reference) IsReference() bool {
return r.Reference != ""
}
func (r *Reference) SetReference(ref string) {
r.Reference = ref
}
type IsReferenced interface {
IsReference() bool
GetReference() string
SetReference(string)
}
// Buildable is an interface for any struct that can be 'built out'. This means that a struct can accept
// a root node and a reference to the index that carries data about any references used.
//
@@ -29,6 +51,7 @@ type HasValueNode[T any] interface {
// HasValueNodeUntyped is implemented by NodeReference and ValueReference to return the yaml.Node backing the value.
type HasValueNodeUntyped interface {
GetValueNode() *yaml.Node
IsReferenced
}
// Hashable defines any struct that implements a Hash function that returns a 256SHA hash of the state of the
@@ -85,7 +108,7 @@ type NodeReference[T any] struct {
KeyNode *yaml.Node
// Is this value actually a reference in the original tree?
IsReference bool
ReferenceNode bool
// If HasReference is true, then Reference contains the original $ref value.
Reference string
@@ -113,7 +136,7 @@ type ValueReference[T any] struct {
ValueNode *yaml.Node
// Is this value actually a reference in the original tree?
IsReference bool
ReferenceNode bool
// If HasReference is true, then Reference contains the original $ref value.
Reference string
@@ -132,12 +155,24 @@ func (n NodeReference[T]) NodeLineNumber() int {
}
}
// IsReferenceNode will return true if the key node contains a $ref key.
func (n NodeReference[T]) IsReferenceNode() bool {
func (n NodeReference[T]) GetReference() string {
return n.Reference
}
func (n NodeReference[T]) SetReference(ref string) {
n.Reference = ref
}
// IsReference will return true if the key node contains a $ref key.
func (n NodeReference[T]) IsReference() bool {
if n.ReferenceNode {
return true
}
if n.KeyNode != nil {
for k := range n.KeyNode.Content {
if k%2 == 0 {
if n.KeyNode.Content[k].Value == "$ref" {
n.ReferenceNode = true
return true
}
}
@@ -164,6 +199,11 @@ func (n NodeReference[T]) GetValueNode() *yaml.Node {
return n.ValueNode
}
// GetKeyNode will return the yaml.Node containing the reference key node
func (n NodeReference[T]) GetKeyNode() *yaml.Node {
return n.KeyNode
}
// GetValue will return the raw value of the node
func (n NodeReference[T]) GetValue() T {
return n.Value
@@ -208,6 +248,22 @@ func (n ValueReference[T]) GetValueUntyped() any {
return n.Value
}
func (n ValueReference[T]) GetReference() string {
return n.Reference
}
func (n ValueReference[T]) SetReference(ref string) {
n.Reference = ref
}
// IsReference will return true if the key node contains a $ref
func (n ValueReference[T]) IsReference() bool {
if n.Reference != "" {
return true
}
return false
}
// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
func (n KeyReference[T]) IsEmpty() bool {
return n.KeyNode == nil

View File

@@ -40,7 +40,7 @@ func TestNodeReference_Mutate(t *testing.T) {
n := nr.Mutate("nice one!")
assert.NotNil(t, nr.GetValueNode())
assert.Empty(t, nr.GetValue())
assert.False(t, nr.IsReferenceNode())
assert.False(t, nr.IsReference())
assert.Equal(t, "nice one!", n.Value)
assert.Equal(t, "nice one!", nr.ValueNode.Value)
}
@@ -52,7 +52,7 @@ func TestNodeReference_RefNode(t *testing.T) {
Value: "$ref",
}},
}
assert.True(t, nr.IsReferenceNode())
assert.True(t, nr.IsReference())
}
func TestValueReference_Mutate(t *testing.T) {

View File

@@ -84,12 +84,12 @@ func (d *Definitions) Build(root *yaml.Node, idx *index.SpecIndex) error {
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*base.SchemaProxy], e chan error) {
obj, err, isRef, rv := low.ExtractObjectRaw[*base.SchemaProxy](value, idx)
obj, err, _, rv := low.ExtractObjectRaw[*base.SchemaProxy](value, idx)
if err != nil {
e <- err
}
r <- definitionResult[*base.SchemaProxy]{k: label, v: low.ValueReference[*base.SchemaProxy]{
Value: obj, ValueNode: value, IsReference: isRef, Reference: rv,
Value: obj, ValueNode: value, Reference: rv,
}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
@@ -144,12 +144,12 @@ func (pd *ParameterDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) err
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*Parameter], e chan error) {
obj, err, isRef, rv := low.ExtractObjectRaw[*Parameter](value, idx)
obj, err, _, rv := low.ExtractObjectRaw[*Parameter](value, idx)
if err != nil {
e <- err
}
r <- definitionResult[*Parameter]{k: label, v: low.ValueReference[*Parameter]{Value: obj,
ValueNode: value, IsReference: isRef, Reference: rv}}
ValueNode: value, Reference: rv}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
@@ -193,12 +193,12 @@ func (r *ResponsesDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) erro
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*Response], e chan error) {
obj, err, isRef, rv := low.ExtractObjectRaw[*Response](value, idx)
obj, err, _, rv := low.ExtractObjectRaw[*Response](value, idx)
if err != nil {
e <- err
}
r <- definitionResult[*Response]{k: label, v: low.ValueReference[*Response]{Value: obj,
ValueNode: value, IsReference: isRef, Reference: rv}}
ValueNode: value, Reference: rv}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
}
@@ -236,12 +236,12 @@ func (s *SecurityDefinitions) Build(root *yaml.Node, idx *index.SpecIndex) error
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*SecurityScheme], e chan error) {
obj, err, isRef, rv := low.ExtractObjectRaw[*SecurityScheme](value, idx)
obj, err, _, rv := low.ExtractObjectRaw[*SecurityScheme](value, idx)
if err != nil {
e <- err
}
r <- definitionResult[*SecurityScheme]{k: label, v: low.ValueReference[*SecurityScheme]{
Value: obj, ValueNode: value, IsReference: isRef, Reference: rv,
Value: obj, ValueNode: value, Reference: rv,
}}
}
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)

View File

@@ -23,6 +23,7 @@ import (
type Callback struct {
Expression low.ValueReference[map[low.KeyReference[string]]low.ValueReference[*PathItem]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all Callback extensions and satisfies the low.HasExtensions interface.
@@ -37,6 +38,7 @@ func (cb *Callback) FindExpression(exp string) *low.ValueReference[*PathItem] {
// Build will extract extensions, expressions and PathItem objects for Callback
func (cb *Callback) Build(root *yaml.Node, idx *index.SpecIndex) error {
cb.Reference = new(low.Reference)
cb.Extensions = low.ExtractExtensions(root)
// handle callback
@@ -51,7 +53,7 @@ func (cb *Callback) Build(root *yaml.Node, idx *index.SpecIndex) error {
if strings.HasPrefix(currentCB.Value, "x-") {
continue // ignore extension.
}
callback, eErr, isRef, rv := low.ExtractObjectRaw[*PathItem](callbackNode, idx)
callback, eErr, _, rv := low.ExtractObjectRaw[*PathItem](callbackNode, idx)
if eErr != nil {
return eErr
}
@@ -61,7 +63,6 @@ func (cb *Callback) Build(root *yaml.Node, idx *index.SpecIndex) error {
}] = low.ValueReference[*PathItem]{
Value: callback,
ValueNode: callbackNode,
IsReference: isRef,
Reference: rv,
}
}

View File

@@ -31,6 +31,7 @@ type Components struct {
Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]
Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all Components extensions and satisfies the low.HasExtensions interface.
@@ -126,6 +127,7 @@ func (co *Components) FindCallback(callback string) *low.ValueReference[*Callbac
}
func (co *Components) Build(root *yaml.Node, idx *index.SpecIndex) error {
co.Reference = new(low.Reference)
co.Extensions = low.ExtractExtensions(root)
// build out components asynchronously for speed. There could be some significant weight here.

View File

@@ -127,11 +127,13 @@ func extractSecurity(info *datamodel.SpecInfo, doc *Document, idx *index.SpecInd
if err != nil {
return err
}
if vn != nil && ln != nil {
doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
Value: sec,
KeyNode: ln,
ValueNode: vn,
}
}
return nil
}

View File

@@ -20,6 +20,7 @@ type Encoding struct {
Style low.NodeReference[string]
Explode low.NodeReference[bool]
AllowReserved low.NodeReference[bool]
*low.Reference
}
// FindHeader attempts to locate a Header with the supplied name
@@ -57,6 +58,7 @@ func (en *Encoding) Hash() [32]byte {
// Build will extract all Header objects from supplied node.
func (en *Encoding) Build(root *yaml.Node, idx *index.SpecIndex) error {
en.Reference = new(low.Reference)
headers, hL, hN, err := low.ExtractMap[*Header](HeadersLabel, root, idx)
if err != nil {
return err

View File

@@ -30,6 +30,7 @@ type Header struct {
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension will attempt to locate an extension with the supplied name
@@ -95,6 +96,7 @@ func (h *Header) Hash() [32]byte {
// Build will extract extensions, examples, schema and content/media types from node.
func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
h.Reference = new(low.Reference)
h.Extensions = low.ExtractExtensions(root)
// handle example if set.

View File

@@ -33,6 +33,7 @@ type Link struct {
Description low.NodeReference[string]
Server low.NodeReference[*Server]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface.
@@ -52,6 +53,7 @@ func (l *Link) FindExtension(ext string) *low.ValueReference[any] {
// Build will extract extensions and servers from the node.
func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error {
l.Reference = new(low.Reference)
l.Extensions = low.ExtractExtensions(root)
// extract server.
ser, sErr := low.ExtractObject[*Server](ServerLabel, root, idx)

View File

@@ -25,6 +25,7 @@ type MediaType struct {
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]
Encoding low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all MediaType extensions and satisfies the low.HasExtensions interface.
@@ -54,6 +55,7 @@ func (mt *MediaType) GetAllExamples() map[low.KeyReference[string]]low.ValueRefe
// Build will extract examples, extensions, schema and encoding from node.
func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error {
mt.Reference = new(low.Reference)
mt.Extensions = low.ExtractExtensions(root)
// handle example if set.

View File

@@ -21,6 +21,7 @@ type OAuthFlows struct {
ClientCredentials low.NodeReference[*OAuthFlow]
AuthorizationCode low.NodeReference[*OAuthFlow]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all OAuthFlows extensions and satisfies the low.HasExtensions interface.
@@ -35,6 +36,7 @@ func (o *OAuthFlows) FindExtension(ext string) *low.ValueReference[any] {
// Build will extract extensions and all OAuthFlow types from the supplied node.
func (o *OAuthFlows) Build(root *yaml.Node, idx *index.SpecIndex) error {
o.Reference = new(low.Reference)
o.Extensions = low.ExtractExtensions(root)
v, vErr := low.ExtractObject[*OAuthFlow](ImplicitLabel, root, idx)
@@ -92,6 +94,7 @@ type OAuthFlow struct {
RefreshUrl low.NodeReference[string]
Scopes low.NodeReference[map[low.KeyReference[string]]low.ValueReference[string]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all OAuthFlow extensions and satisfies the low.HasExtensions interface.
@@ -111,6 +114,7 @@ func (o *OAuthFlow) FindExtension(ext string) *low.ValueReference[any] {
// Build will extract extensions from the node.
func (o *OAuthFlow) Build(root *yaml.Node, idx *index.SpecIndex) error {
o.Reference = new(low.Reference)
o.Extensions = low.ExtractExtensions(root)
return nil
}

View File

@@ -33,6 +33,7 @@ type Operation struct {
Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]
Servers low.NodeReference[[]low.ValueReference[*Server]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindCallback will attempt to locate a Callback instance by the supplied name.
@@ -54,6 +55,7 @@ func (o *Operation) FindSecurityRequirement(name string) []low.ValueReference[st
// Build will extract external docs, parameters, request body, responses, callbacks, security and servers.
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
o.Reference = new(low.Reference)
o.Extensions = low.ExtractExtensions(root)
// extract externalDocs

View File

@@ -34,6 +34,7 @@ type Parameter struct {
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindContent will attempt to locate a MediaType instance using the specified name.
@@ -58,6 +59,7 @@ func (p *Parameter) GetExtensions() map[low.KeyReference[string]]low.ValueRefere
// Build will extract examples, extensions and content/media types.
func (p *Parameter) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Reference = new(low.Reference)
p.Extensions = low.ExtractExtensions(root)
// handle example if set.

View File

@@ -35,6 +35,7 @@ type PathItem struct {
Servers low.NodeReference[[]low.ValueReference[*Server]]
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// Hash will return a consistent SHA256 Hash of the PathItem object
@@ -107,6 +108,7 @@ func (p *PathItem) GetExtensions() map[low.KeyReference[string]]low.ValueReferen
// Build extracts extensions, parameters, servers and each http method defined.
// everything is extracted asynchronously for speed.
func (p *PathItem) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Reference = new(low.Reference)
p.Extensions = low.ExtractExtensions(root)
skip := false
var currentNode *yaml.Node

View File

@@ -23,6 +23,7 @@ import (
type Paths struct {
PathItems map[low.KeyReference[string]]low.ValueReference[*PathItem]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindPath will attempt to locate a PathItem using the provided path string.
@@ -57,6 +58,7 @@ func (p *Paths) GetExtensions() map[low.KeyReference[string]]low.ValueReference[
// Build will extract extensions and all PathItems. This happens asynchronously for speed.
func (p *Paths) Build(root *yaml.Node, idx *index.SpecIndex) error {
p.Reference = new(low.Reference)
p.Extensions = low.ExtractExtensions(root)
skip := false
var currentNode *yaml.Node

View File

@@ -20,6 +20,7 @@ type RequestBody struct {
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
Required low.NodeReference[bool]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// FindExtension attempts to locate an extension using the provided name.
@@ -39,6 +40,7 @@ func (rb *RequestBody) FindContent(cType string) *low.ValueReference[*MediaType]
// Build will extract extensions and MediaType objects from the node.
func (rb *RequestBody) Build(root *yaml.Node, idx *index.SpecIndex) error {
rb.Reference = new(low.Reference)
rb.Extensions = low.ExtractExtensions(root)
// handle content, if set.

View File

@@ -24,6 +24,7 @@ type Response struct {
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
Links low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Link]]
*low.Reference
}
// FindExtension will attempt to locate an extension using the supplied key
@@ -53,6 +54,7 @@ func (r *Response) FindLink(hType string) *low.ValueReference[*Link] {
// Build will extract headers, extensions, content and links from node.
func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error {
r.Reference = new(low.Reference)
r.Extensions = low.ExtractExtensions(root)
//extract headers

View File

@@ -36,6 +36,7 @@ type Responses struct {
Codes map[low.KeyReference[string]]low.ValueReference[*Response]
Default low.NodeReference[*Response]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all Responses extensions and satisfies the low.HasExtensions interface.
@@ -45,6 +46,7 @@ func (r *Responses) GetExtensions() map[low.KeyReference[string]]low.ValueRefere
// Build will extract default response and all Response objects for each code
func (r *Responses) Build(root *yaml.Node, idx *index.SpecIndex) error {
r.Reference = new(low.Reference)
r.Extensions = low.ExtractExtensions(root)
if utils.IsNodeMap(root) {
codes, err := low.ExtractMapNoLookup[*Response](root, idx)

View File

@@ -33,26 +33,9 @@ type SecurityScheme struct {
Flows low.NodeReference[*OAuthFlows]
OpenIdConnectUrl low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// SecurityRequirement is a low-level representation of an OpenAPI 3+ SecurityRequirement object.
//
// It lists the required security schemes to execute this operation. The name used for each property MUST correspond
// to a security scheme declared in the Security Schemes under the Components Object.
//
// Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a
// request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are
// required to convey security information.
//
// When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the
// Security Requirement Objects in the list needs to be satisfied to authorize the request.
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
//type SecurityRequirement struct {
//
// // FYI, I hate this data structure. Even without the low level wrapping, it sucks.
// ValueRequirements []low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]
//}
// FindExtension attempts to locate an extension using the supplied key.
func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, ss.Extensions)
@@ -65,6 +48,7 @@ func (ss *SecurityScheme) GetExtensions() map[low.KeyReference[string]]low.Value
// Build will extract OAuthFlows and extensions from the node.
func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
ss.Reference = new(low.Reference)
ss.Extensions = low.ExtractExtensions(root)
oa, oaErr := low.ExtractObject[*OAuthFlows](OAuthFlowsLabel, root, idx)

View File

@@ -20,6 +20,7 @@ type Server struct {
Description low.NodeReference[string]
Variables low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*ServerVariable]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
}
// GetExtensions returns all Paths extensions and satisfies the low.HasExtensions interface.
@@ -34,6 +35,7 @@ func (s *Server) FindVariable(serverVar string) *low.ValueReference[*ServerVaria
// Build will extract server variables from the supplied node.
func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error {
s.Reference = new(low.Reference)
s.Extensions = low.ExtractExtensions(root)
kn, vars := utils.FindKeyNode(VariablesLabel, root.Content)
if vars == nil {
@@ -50,6 +52,7 @@ func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error {
continue
}
variable := ServerVariable{}
variable.Reference = new(low.Reference)
_ = low.BuildModel(varNode, &variable)
variablesMap[low.KeyReference[string]{
Value: currentNode,

View File

@@ -19,6 +19,7 @@ type ServerVariable struct {
Enum []low.NodeReference[string]
Default low.NodeReference[string]
Description low.NodeReference[string]
*low.Reference
}
// Hash will return a consistent SHA256 Hash of the ServerVariable object