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 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) { func (c *Contact) Render() ([]byte, error) {
return yaml.Marshal(c) return yaml.Marshal(c)
} }

View File

@@ -41,6 +41,11 @@ func (d *Discriminator) GoLow() *low.Discriminator {
return d.low 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. // Render will return a YAML representation of the Discriminator object as a byte slice.
func (d *Discriminator) Render() ([]byte, error) { func (d *Discriminator) Render() ([]byte, error) {
return yaml.Marshal(d) return yaml.Marshal(d)

View File

@@ -38,6 +38,11 @@ func (e *Example) GoLow() *low.Example {
return e.low 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. // Render will return a YAML representation of the Example object as a byte slice.
func (e *Example) Render() ([]byte, error) { func (e *Example) Render() ([]byte, error) {
return yaml.Marshal(e) return yaml.Marshal(e)

View File

@@ -40,6 +40,11 @@ func (e *ExternalDoc) GoLow() *low.ExternalDoc {
return e.low 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 { func (e *ExternalDoc) GetExtensions() map[string]any {
return e.Extensions return e.Extensions
} }

View File

@@ -64,6 +64,11 @@ func (i *Info) GoLow() *low.Info {
return i.low 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. // Render will return a YAML representation of the Info object as a byte slice.
func (i *Info) Render() ([]byte, error) { func (i *Info) Render() ([]byte, error) {
return yaml.Marshal(i) return yaml.Marshal(i)

View File

@@ -36,6 +36,11 @@ func (l *License) GoLow() *low.License {
return l.low 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. // Render will return a YAML representation of the License object as a byte slice.
func (l *License) Render() ([]byte, error) { func (l *License) Render() ([]byte, error) {
return yaml.Marshal(l) return yaml.Marshal(l)

View File

@@ -444,6 +444,11 @@ func (s *Schema) GoLow() *base.Schema {
return s.low 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. // Render will return a YAML representation of the Schema object as a byte slice.
func (s *Schema) Render() ([]byte, error) { func (s *Schema) Render() ([]byte, error) {
return yaml.Marshal(s) return yaml.Marshal(s)

View File

@@ -86,25 +86,32 @@ func (sp *SchemaProxy) BuildSchema() (*Schema, error) {
// GetBuildError returns any error that was thrown when calling Schema() // GetBuildError returns any error that was thrown when calling Schema()
func (sp *SchemaProxy) GetBuildError() error { func (sp *SchemaProxy) GetBuildError() error {
return sp.buildError return sp.buildError
} }
func (sp *SchemaProxy) GoLow() *base.SchemaProxy { func (sp *SchemaProxy) GoLow() *base.SchemaProxy {
if sp.schema == nil { if sp.schema == nil {
return nil return nil
} }
return sp.schema.Value 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. // Render will return a YAML representation of the Schema object as a byte slice.
func (sp *SchemaProxy) Render() ([]byte, error) { func (sp *SchemaProxy) Render() ([]byte, error) {
return yaml.Marshal(sp) return yaml.Marshal(sp)
} }
// MarshalYAML will create a ready to render YAML representation of the ExternalDoc object. // MarshalYAML will create a ready to render YAML representation of the ExternalDoc object.
func (sp *SchemaProxy) MarshalYAML() (interface{}, error) { func (sp *SchemaProxy) MarshalYAML() (interface{}, error) {
if sp == nil { if sp == nil {
return nil, nil return nil, nil
} }
var s *Schema var s *Schema
var err error var err error

View File

@@ -43,6 +43,11 @@ func (s *SecurityRequirement) GoLow() *base.SecurityRequirement {
return s.low 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. // Render will return a YAML representation of the SecurityRequirement object as a byte slice.
func (s *SecurityRequirement) Render() ([]byte, error) { func (s *SecurityRequirement) Render() ([]byte, error) {
return yaml.Marshal(s) return yaml.Marshal(s)

View File

@@ -45,6 +45,11 @@ func (t *Tag) GoLow() *low.Tag {
return t.low 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. // Render will return a YAML representation of the Info object as a byte slice.
func (t *Tag) Render() ([]byte, error) { func (t *Tag) Render() ([]byte, error) {
return yaml.Marshal(t) return yaml.Marshal(t)
@@ -58,28 +63,3 @@ func (t *Tag) MarshalYAML() (interface{}, error) {
nb := high.NewNodeBuilder(t, t.low) nb := high.NewNodeBuilder(t, t.low)
return nb.Render(), nil 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 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. // Render will return a YAML representation of the XML object as a byte slice.
func (x *XML) Render() ([]byte, error) { func (x *XML) Render() ([]byte, error) {
return yaml.Marshal(x) return yaml.Marshal(x)

View File

@@ -150,6 +150,16 @@ func (n *NodeBuilder) add(key string) {
case reflect.Struct: case reflect.Struct:
y := value.Interface() y := value.Interface()
if nb, ok := y.(low.HasValueNodeUntyped); ok { 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 { if nb.GetValueNode() != nil {
nodeEntry.Line = nb.GetValueNode().Line nodeEntry.Line = nb.GetValueNode().Line
} else { } 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 // Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined
func (n *NodeBuilder) Render() *yaml.Node { func (n *NodeBuilder) Render() *yaml.Node {
// order nodes by line number, retain original order // 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 { sort.Slice(n.Nodes, func(i, j int) bool {
return n.Nodes[i].Line < n.Nodes[j].Line return n.Nodes[i].Line < n.Nodes[j].Line
}) })
m := CreateEmptyMapNode()
for i := range n.Nodes { for i := range n.Nodes {
node := n.Nodes[i] node := n.Nodes[i]
n.AddYAMLNode(m, node.Tag, node.Key, node.Value) 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), Tag: uu.(string),
Key: uu.(string), Key: uu.(string),
Line: 9999 + j, 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 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) err := rawNode.Encode(value)
if err != nil { if err != nil {
return parent return parent
@@ -399,6 +454,15 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, tag, key string, value any)
case reflect.Ptr: case reflect.Ptr:
if r, ok := value.(Renderable); ok { 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() rawRender, _ := r.MarshalYAML()
if rawRender != nil { if rawRender != nil {
valueNode = rawRender.(*yaml.Node) valueNode = rawRender.(*yaml.Node)
@@ -469,6 +533,14 @@ func CreateEmptyMapNode() *yaml.Node {
return n return n
} }
func CreateEmptySequenceNode() *yaml.Node {
n := &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
}
return n
}
func CreateStringNode(str string) *yaml.Node { func CreateStringNode(str string) *yaml.Node {
n := &yaml.Node{ n := &yaml.Node{
Kind: yaml.ScalarNode, Kind: yaml.ScalarNode,

View File

@@ -26,6 +26,15 @@ type GoesLow[T any] interface {
GoLow() T 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 // 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. // definition that is easier to consume in applications.
func ExtractExtensions(extensions map[low.KeyReference[string]]low.ValueReference[any]) map[string]any { 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 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. // Render will return a YAML representation of the Callback object as a byte slice.
func (c *Callback) Render() ([]byte, error) { func (c *Callback) Render() ([]byte, error) {
return yaml.Marshal(c) return yaml.Marshal(c)

View File

@@ -30,20 +30,20 @@ const (
// will have no effect on the API unless they are explicitly referenced from properties outside the components object. // 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 // - https://spec.openapis.org/oas/v3.1.0#components-object
type Components struct { type Components struct {
//Schemas map[string]*highbase.SchemaProxy `json:"schemas,omitempty" yaml:"schemas,omitempty"` Schemas map[string]*highbase.SchemaProxy `json:"schemas,omitempty" yaml:"schemas,omitempty"`
Schemas map[string]*highbase.SchemaProxy `json:"-" yaml:"-"` //Schemas map[string]*highbase.SchemaProxy `json:"-" yaml:"-"`
Responses map[string]*Response `json:"-" yaml:"-"` //Responses map[string]*Response `json:"-" yaml:"-"`
//Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"` Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Parameters map[string]*Parameter `json:"-" yaml:"-"` //Parameters map[string]*Parameter `json:"-" yaml:"-"`
//Parameters map[string]*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` 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:"examples,omitempty" yaml:"examples,omitempty"`
Examples map[string]*highbase.Example `json:"-" yaml:"-"` //Examples map[string]*highbase.Example `json:"-" yaml:"-"`
RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"` RequestBodies map[string]*RequestBody `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"` Headers map[string]*Header `json:"headers,omitempty" yaml:"headers,omitempty"`
SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"` SecuritySchemes map[string]*SecurityScheme `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
Links map[string]*Link `json:"links,omitempty" yaml:"links,omitempty"` Links map[string]*Link `json:"links,omitempty" yaml:"links,omitempty"`
Callbacks map[string]*Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"` Callbacks map[string]*Callback `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
Extensions map[string]any `json:"-" yaml:"-"` Extensions map[string]any `json:"-" yaml:"-"`
low *low.Components low *low.Components
} }

View File

@@ -8,6 +8,7 @@ import (
"io/ioutil" "io/ioutil"
"net/url" "net/url"
"os" "os"
"strings"
"testing" "testing"
"github.com/pb33f/libopenapi/datamodel" "github.com/pb33f/libopenapi/datamodel"
@@ -490,14 +491,149 @@ func TestDocument_MarshalYAML(t *testing.T) {
os.WriteFile("rendered.yaml", r, 0644) os.WriteFile("rendered.yaml", r, 0644)
// re-parse the document // 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) info, _ := datamodel.ExtractSpecInfo(r)
lDoc, e := lowv3.CreateDocumentFromConfig(info, datamodel.NewOpenDocumentConfiguration()) lDoc, e := lowv3.CreateDocumentFromConfig(info, datamodel.NewOpenDocumentConfiguration())
assert.Nil(t, e) assert.Nil(t, e)
highDoc := NewDocument(lDoc) highDoc := NewDocument(lDoc)
assert.Equal(t, "3.1.0", highDoc.Version) 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 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. // Render will return a YAML representation of the Encoding object as a byte slice.
func (e *Encoding) Render() ([]byte, error) { func (e *Encoding) Render() ([]byte, error) {
return yaml.Marshal(e) return yaml.Marshal(e)

View File

@@ -59,6 +59,11 @@ func (h *Header) GoLow() *low.Header {
return h.low 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. // 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 { func ExtractHeaders(elements map[lowmodel.KeyReference[string]]lowmodel.ValueReference[*low.Header]) map[string]*Header {
extracted := make(map[string]*Header) extracted := make(map[string]*Header)

View File

@@ -57,6 +57,11 @@ func (l *Link) GoLow() *low.Link {
return l.low 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. // Render will return a YAML representation of the Link object as a byte slice.
func (l *Link) Render() ([]byte, error) { func (l *Link) Render() ([]byte, error) {
return yaml.Marshal(l) return yaml.Marshal(l)

View File

@@ -44,6 +44,11 @@ func (m *MediaType) GoLow() *low.MediaType {
return m.low 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. // Render will return a YAML representation of the MediaType object as a byte slice.
func (m *MediaType) Render() ([]byte, error) { func (m *MediaType) Render() ([]byte, error) {
return yaml.Marshal(m) return yaml.Marshal(m)

View File

@@ -41,6 +41,11 @@ func (o *OAuthFlow) GoLow() *low.OAuthFlow {
return o.low 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. // Render will return a YAML representation of the OAuthFlow object as a byte slice.
func (o *OAuthFlow) Render() ([]byte, error) { func (o *OAuthFlow) Render() ([]byte, error) {
return yaml.Marshal(o) return yaml.Marshal(o)

View File

@@ -48,6 +48,11 @@ func (o *OAuthFlows) GoLow() *low.OAuthFlows {
return o.low 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. // Render will return a YAML representation of the OAuthFlows object as a byte slice.
func (o *OAuthFlows) Render() ([]byte, error) { func (o *OAuthFlows) Render() ([]byte, error) {
return yaml.Marshal(o) return yaml.Marshal(o)

View File

@@ -91,6 +91,11 @@ func (o *Operation) GoLow() *low.Operation {
return o.low 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. // Render will return a YAML representation of the Operation object as a byte slice.
func (o *Operation) Render() ([]byte, error) { func (o *Operation) Render() ([]byte, error) {
return yaml.Marshal(o) return yaml.Marshal(o)

View File

@@ -62,6 +62,11 @@ func (p *Parameter) GoLow() *low.Parameter {
return p.low 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. // Render will return a YAML representation of the Encoding object as a byte slice.
func (p *Parameter) Render() ([]byte, error) { func (p *Parameter) Render() ([]byte, error) {
return yaml.Marshal(p) return yaml.Marshal(p)

View File

@@ -124,6 +124,11 @@ func (p *PathItem) GoLow() *low.PathItem {
return p.low 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 { func (p *PathItem) GetOperations() map[string]*Operation {
o := make(map[string]*Operation) o := make(map[string]*Operation)
if p.Get != nil { if p.Get != nil {

View File

@@ -58,6 +58,11 @@ func (p *Paths) GoLow() *low.Paths {
return p.low 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. // Render will return a YAML representation of the Paths object as a byte slice.
func (p *Paths) Render() ([]byte, error) { func (p *Paths) Render() ([]byte, error) {
return yaml.Marshal(p) return yaml.Marshal(p)
@@ -88,7 +93,7 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
nb := high.NewNodeBuilder(p, p.low) nb := high.NewNodeBuilder(p, p.low)
extNode := nb.Render() extNode := nb.Render()
if extNode.Content != nil { if extNode != nil && extNode.Content != nil {
for u := range extNode.Content { for u := range extNode.Content {
mapped = append(mapped, &pathItem{nil, extNode.Content[u].Value, mapped = append(mapped, &pathItem{nil, extNode.Content[u].Value,
extNode.Content[u].Line, extNode.Content[u]}) extNode.Content[u].Line, extNode.Content[u]})

View File

@@ -35,6 +35,11 @@ func (r *RequestBody) GoLow() *low.RequestBody {
return r.low 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. // Render will return a YAML representation of the RequestBody object as a byte slice.
func (r *RequestBody) Render() ([]byte, error) { func (r *RequestBody) Render() ([]byte, error) {
return yaml.Marshal(r) return yaml.Marshal(r)

View File

@@ -50,6 +50,11 @@ func (r *Response) GoLow() *low.Response {
return r.low 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. // Render will return a YAML representation of the Response object as a byte slice.
func (r *Response) Render() ([]byte, error) { func (r *Response) Render() ([]byte, error) {
return yaml.Marshal(r) return yaml.Marshal(r)

View File

@@ -80,6 +80,11 @@ func (r *Responses) GoLow() *low.Responses {
return r.low 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. // Render will return a YAML representation of the Responses object as a byte slice.
func (r *Responses) Render() ([]byte, error) { func (r *Responses) Render() ([]byte, error) {
return yaml.Marshal(r) return yaml.Marshal(r)

View File

@@ -55,6 +55,11 @@ func (s *SecurityScheme) GoLow() *low.SecurityScheme {
return s.low 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. // Render will return a YAML representation of the SecurityScheme object as a byte slice.
func (s *SecurityScheme) Render() ([]byte, error) { func (s *SecurityScheme) Render() ([]byte, error) {
return yaml.Marshal(s) return yaml.Marshal(s)

View File

@@ -39,6 +39,11 @@ func (s *Server) GoLow() *low.Server {
return s.low 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. // Render will return a YAML representation of the Server object as a byte slice.
func (s *Server) Render() ([]byte, error) { func (s *Server) Render() ([]byte, error) {
return yaml.Marshal(s) return yaml.Marshal(s)

View File

@@ -41,6 +41,11 @@ func (s *ServerVariable) GoLow() *low.ServerVariable {
return s.low 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. // Render will return a YAML representation of the ServerVariable object as a byte slice.
func (s *ServerVariable) Render() ([]byte, error) { func (s *ServerVariable) Render() ([]byte, error) {
return yaml.Marshal(s) return yaml.Marshal(s)

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,6 +30,7 @@ type Info struct {
License low.NodeReference[*License] License low.NodeReference[*License]
Version low.NodeReference[string] Version low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
} }
// FindExtension attempts to locate an extension with the supplied key // 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. // 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 { func (i *Info) Build(root *yaml.Node, idx *index.SpecIndex) error {
i.Reference = new(low.Reference)
i.Extensions = low.ExtractExtensions(root) i.Extensions = low.ExtractExtensions(root)
// extract contact // extract contact

View File

@@ -17,10 +17,12 @@ import (
type License struct { type License struct {
Name low.NodeReference[string] Name low.NodeReference[string]
URL low.NodeReference[string] URL low.NodeReference[string]
*low.Reference
} }
// Build is not implemented for License (there is nothing to build) // Build is not implemented for License (there is nothing to build)
func (l *License) Build(root *yaml.Node, idx *index.SpecIndex) error { func (l *License) Build(root *yaml.Node, idx *index.SpecIndex) error {
l.Reference = new(low.Reference)
return nil 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. // Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
ParentProxy *SchemaProxy ParentProxy *SchemaProxy
*low.Reference
} }
// Hash will calculate a SHA256 hash from the values of the schema, This allows equality checking against // 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 // - UnevaluatedItems
// - UnevaluatedProperties // - UnevaluatedProperties
func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error { func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
s.Reference = new(low.Reference)
if h, _, _ := utils.IsNodeRefValue(root); h { if h, _, _ := utils.IsNodeRefValue(root); h {
ref, err := low.LocateRefNode(root, idx) ref, err := low.LocateRefNode(root, idx)
if ref != nil { if ref != nil {
@@ -1233,7 +1235,8 @@ func ExtractSchema(root *yaml.Node, idx *index.SpecIndex) (*low.NodeReference[*S
if schNode != nil { if schNode != nil {
// check if schema has already been built. // check if schema has already been built.
schema := &SchemaProxy{kn: schLabel, vn: schNode, idx: idx, isReference: isRef, referenceLookup: refLocation} 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 return nil, nil
} }

View File

@@ -104,6 +104,21 @@ func (sp *SchemaProxy) IsSchemaReference() bool {
return sp.isReference 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 // 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 // is inline, and not a reference, then this method returns an empty string. Only useful when combined with
// IsSchemaReference() // IsSchemaReference()

View File

@@ -23,10 +23,12 @@ import (
// - https://swagger.io/specification/#security-requirement-object // - https://swagger.io/specification/#security-requirement-object
type SecurityRequirement struct { type SecurityRequirement struct {
Requirements low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] 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) // 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 { func (s *SecurityRequirement) Build(root *yaml.Node, _ *index.SpecIndex) error {
s.Reference = new(low.Reference)
var labelNode *yaml.Node var labelNode *yaml.Node
valueMap := make(map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) valueMap := make(map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]])
var arr []low.ValueReference[string] var arr []low.ValueReference[string]

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,28 @@ const (
HASH = "%x" 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 // 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. // 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. // HasValueNodeUntyped is implemented by NodeReference and ValueReference to return the yaml.Node backing the value.
type HasValueNodeUntyped interface { type HasValueNodeUntyped interface {
GetValueNode() *yaml.Node GetValueNode() *yaml.Node
IsReferenced
} }
// Hashable defines any struct that implements a Hash function that returns a 256SHA hash of the state of the // 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 KeyNode *yaml.Node
// Is this value actually a reference in the original tree? // 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. // If HasReference is true, then Reference contains the original $ref value.
Reference string Reference string
@@ -113,7 +136,7 @@ type ValueReference[T any] struct {
ValueNode *yaml.Node ValueNode *yaml.Node
// Is this value actually a reference in the original tree? // 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. // If HasReference is true, then Reference contains the original $ref value.
Reference string 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]) GetReference() string {
func (n NodeReference[T]) IsReferenceNode() bool { 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 { if n.KeyNode != nil {
for k := range n.KeyNode.Content { for k := range n.KeyNode.Content {
if k%2 == 0 { if k%2 == 0 {
if n.KeyNode.Content[k].Value == "$ref" { if n.KeyNode.Content[k].Value == "$ref" {
n.ReferenceNode = true
return true return true
} }
} }
@@ -164,6 +199,11 @@ func (n NodeReference[T]) GetValueNode() *yaml.Node {
return n.ValueNode 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 // GetValue will return the raw value of the node
func (n NodeReference[T]) GetValue() T { func (n NodeReference[T]) GetValue() T {
return n.Value return n.Value
@@ -208,6 +248,22 @@ func (n ValueReference[T]) GetValueUntyped() any {
return n.Value 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) // IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
func (n KeyReference[T]) IsEmpty() bool { func (n KeyReference[T]) IsEmpty() bool {
return n.KeyNode == nil return n.KeyNode == nil

View File

@@ -40,7 +40,7 @@ func TestNodeReference_Mutate(t *testing.T) {
n := nr.Mutate("nice one!") n := nr.Mutate("nice one!")
assert.NotNil(t, nr.GetValueNode()) assert.NotNil(t, nr.GetValueNode())
assert.Empty(t, nr.GetValue()) 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!", n.Value)
assert.Equal(t, "nice one!", nr.ValueNode.Value) assert.Equal(t, "nice one!", nr.ValueNode.Value)
} }
@@ -52,7 +52,7 @@ func TestNodeReference_RefNode(t *testing.T) {
Value: "$ref", Value: "$ref",
}}, }},
} }
assert.True(t, nr.IsReferenceNode()) assert.True(t, nr.IsReference())
} }
func TestValueReference_Mutate(t *testing.T) { 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, var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*base.SchemaProxy], e chan error) { 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 { if err != nil {
e <- err e <- err
} }
r <- definitionResult[*base.SchemaProxy]{k: label, v: low.ValueReference[*base.SchemaProxy]{ 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) 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, var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*Parameter], e chan error) { 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 { if err != nil {
e <- err e <- err
} }
r <- definitionResult[*Parameter]{k: label, v: low.ValueReference[*Parameter]{Value: obj, 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) 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, var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*Response], e chan error) { 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 { if err != nil {
e <- err e <- err
} }
r <- definitionResult[*Response]{k: label, v: low.ValueReference[*Response]{Value: obj, 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) 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, var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
r chan definitionResult[*SecurityScheme], e chan error) { 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 { if err != nil {
e <- err e <- err
} }
r <- definitionResult[*SecurityScheme]{k: label, v: low.ValueReference[*SecurityScheme]{ 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) go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,6 +33,7 @@ type Link struct {
Description low.NodeReference[string] Description low.NodeReference[string]
Server low.NodeReference[*Server] Server low.NodeReference[*Server]
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
} }
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface. // 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. // Build will extract extensions and servers from the node.
func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error { func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error {
l.Reference = new(low.Reference)
l.Extensions = low.ExtractExtensions(root) l.Extensions = low.ExtractExtensions(root)
// extract server. // extract server.
ser, sErr := low.ExtractObject[*Server](ServerLabel, root, idx) 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]] Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]
Encoding low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]] Encoding low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Encoding]]
Extensions map[low.KeyReference[string]]low.ValueReference[any] Extensions map[low.KeyReference[string]]low.ValueReference[any]
*low.Reference
} }
// GetExtensions returns all MediaType extensions and satisfies the low.HasExtensions interface. // 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. // Build will extract examples, extensions, schema and encoding from node.
func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error { func (mt *MediaType) Build(root *yaml.Node, idx *index.SpecIndex) error {
mt.Reference = new(low.Reference)
mt.Extensions = low.ExtractExtensions(root) mt.Extensions = low.ExtractExtensions(root)
// handle example if set. // handle example if set.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,26 +33,9 @@ type SecurityScheme struct {
Flows low.NodeReference[*OAuthFlows] Flows low.NodeReference[*OAuthFlows]
OpenIdConnectUrl low.NodeReference[string] OpenIdConnectUrl low.NodeReference[string]
Extensions map[low.KeyReference[string]]low.ValueReference[any] 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. // FindExtension attempts to locate an extension using the supplied key.
func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] { func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, ss.Extensions) 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. // Build will extract OAuthFlows and extensions from the node.
func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error { func (ss *SecurityScheme) Build(root *yaml.Node, idx *index.SpecIndex) error {
ss.Reference = new(low.Reference)
ss.Extensions = low.ExtractExtensions(root) ss.Extensions = low.ExtractExtensions(root)
oa, oaErr := low.ExtractObject[*OAuthFlows](OAuthFlowsLabel, root, idx) oa, oaErr := low.ExtractObject[*OAuthFlows](OAuthFlowsLabel, root, idx)

View File

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

View File

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