chore: update to use iterators on orderedmaps

This commit is contained in:
Tristan Cartledge
2024-08-14 12:10:07 +01:00
committed by quobix
parent c3eb16d4e4
commit 161a41f73b
73 changed files with 690 additions and 550 deletions

View File

@@ -4,8 +4,9 @@
package base
import (
low2 "github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/low"
lowBase "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -22,24 +23,20 @@ import (
type Discriminator struct {
PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"`
Mapping *orderedmap.Map[string, string] `json:"mapping,omitempty" yaml:"mapping,omitempty"`
low *low.Discriminator
low *lowBase.Discriminator
}
// NewDiscriminator will create a new high-level Discriminator from a low-level one.
func NewDiscriminator(disc *low.Discriminator) *Discriminator {
func NewDiscriminator(disc *lowBase.Discriminator) *Discriminator {
d := new(Discriminator)
d.low = disc
d.PropertyName = disc.PropertyName.Value
mapping := orderedmap.New[string, string]()
for pair := orderedmap.First(disc.Mapping.Value); pair != nil; pair = pair.Next() {
mapping.Set(pair.Key().Value, pair.Value().Value)
}
d.Mapping = mapping
d.Mapping = low.FromReferenceMap(disc.Mapping.Value)
return d
}
// GoLow returns the low-level Discriminator used to build the high-level one.
func (d *Discriminator) GoLow() *low.Discriminator {
func (d *Discriminator) GoLow() *lowBase.Discriminator {
return d.low
}
@@ -55,6 +52,6 @@ func (d *Discriminator) Render() ([]byte, error) {
// MarshalYAML will create a ready to render YAML representation of the Discriminator object.
func (d *Discriminator) MarshalYAML() (interface{}, error) {
nb := low2.NewNodeBuilder(d, d.low)
nb := high.NewNodeBuilder(d, d.low)
return nb.Render(), nil
}

View File

@@ -5,9 +5,10 @@ package base
import (
"encoding/json"
"github.com/pb33f/libopenapi/datamodel/high"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
low "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/datamodel/low"
lowBase "github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -21,11 +22,11 @@ type Example struct {
Value *yaml.Node `json:"value,omitempty" yaml:"value,omitempty"`
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Example
low *lowBase.Example
}
// NewExample will create a new instance of an Example, using a low-level Example.
func NewExample(example *low.Example) *Example {
func NewExample(example *lowBase.Example) *Example {
e := new(Example)
e.low = example
e.Summary = example.Summary.Value
@@ -37,7 +38,7 @@ func NewExample(example *low.Example) *Example {
}
// GoLow will return the low-level Example used to build the high level one.
func (e *Example) GoLow() *low.Example {
func (e *Example) GoLow() *lowBase.Example {
return e.low
}
@@ -68,10 +69,6 @@ func (e *Example) MarshalJSON() ([]byte, error) {
// ExtractExamples will convert a low-level example map, into a high level one that is simple to navigate.
// no fidelity is lost, everything is still available via GoLow()
func ExtractExamples(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Example]]) *orderedmap.Map[string, *Example] {
extracted := orderedmap.New[string, *Example]()
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
extracted.Set(pair.Key().Value, NewExample(pair.Value().Value))
}
return extracted
func ExtractExamples(elements *orderedmap.Map[low.KeyReference[string], low.ValueReference[*lowBase.Example]]) *orderedmap.Map[string, *Example] {
return low.FromReferenceMapWithFunc(elements, NewExample)
}

View File

@@ -5,6 +5,7 @@ package base
import (
"encoding/json"
"github.com/pb33f/libopenapi/datamodel/high"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
@@ -376,17 +377,18 @@ func NewSchema(schema *base.Schema) *Schema {
}
props := orderedmap.New[string, *SchemaProxy]()
for pair := orderedmap.First(schema.Properties.Value); pair != nil; pair = pair.Next() {
buildProps(pair.Key(), pair.Value(), props, 0)
for name, schemaProxy := range schema.Properties.Value.FromOldest() {
buildProps(name, schemaProxy, props, 0)
}
dependents := orderedmap.New[string, *SchemaProxy]()
for pair := orderedmap.First(schema.DependentSchemas.Value); pair != nil; pair = pair.Next() {
buildProps(pair.Key(), pair.Value(), dependents, 1)
for name, schemaProxy := range schema.DependentSchemas.Value.FromOldest() {
buildProps(name, schemaProxy, dependents, 1)
}
patternProps := orderedmap.New[string, *SchemaProxy]()
for pair := orderedmap.First(schema.PatternProperties.Value); pair != nil; pair = pair.Next() {
buildProps(pair.Key(), pair.Value(), patternProps, 2)
for name, schemaProxy := range schema.PatternProperties.Value.FromOldest() {
buildProps(name, schemaProxy, patternProps, 2)
}
var allOf []*SchemaProxy

View File

@@ -32,12 +32,12 @@ func NewSecurityRequirement(req *base.SecurityRequirement) *SecurityRequirement
r.low = req
values := orderedmap.New[string, []string]()
// to keep things fast, avoiding copying anything - makes it a little hard to read.
for pair := orderedmap.First(req.Requirements.Value); pair != nil; pair = pair.Next() {
for name, val := range req.Requirements.Value.FromOldest() {
var vals []string
for valK := range pair.Value().Value {
vals = append(vals, pair.Value().Value[valK].Value)
for valK := range val.Value {
vals = append(vals, val.Value[valK].Value)
}
values.Set(pair.Key().Value, vals)
values.Set(name.Value, vals)
}
r.Requirements = values
r.ContainsEmptyRequirement = req.ContainsEmptyRequirement
@@ -74,8 +74,8 @@ func (s *SecurityRequirement) MarshalYAML() (interface{}, error) {
i := 0
for pair := orderedmap.First(s.Requirements); pair != nil; pair = pair.Next() {
keys[i] = &req{key: pair.Key(), val: pair.Value()}
for name, vals := range s.Requirements.FromOldest() {
keys[i] = &req{key: name, val: vals}
i++
}
i = 0

View File

@@ -78,18 +78,18 @@ func (n *NodeBuilder) add(key string, i int) {
j := 0
if lowExtensions != nil {
// If we have low extensions get the original lowest line number so we end up in the same place
for pair := orderedmap.First(lowExtensions); pair != nil; pair = pair.Next() {
if j == 0 || pair.Key().KeyNode.Line < j {
j = pair.Key().KeyNode.Line
for ext := range lowExtensions.KeysFromOldest() {
if j == 0 || ext.KeyNode.Line < j {
j = ext.KeyNode.Line
}
}
}
for pair := orderedmap.First(extensions); pair != nil; pair = pair.Next() {
nodeEntry := &nodes.NodeEntry{Tag: pair.Key(), Key: pair.Key(), Value: pair.Value(), Line: j}
for ext, node := range extensions.FromOldest() {
nodeEntry := &nodes.NodeEntry{Tag: ext, Key: ext, Value: node, Line: j}
if lowExtensions != nil {
lowItem := low.FindItemInOrderedMap(pair.Key(), lowExtensions)
lowItem := low.FindItemInOrderedMap(ext, lowExtensions)
nodeEntry.LowValue = lowItem
}
n.Nodes = append(n.Nodes, nodeEntry)

View File

@@ -94,16 +94,16 @@ func (te *test1) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.V
g := orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
i := 0
for pair := orderedmap.First(te.Extensions); pair != nil; pair = pair.Next() {
kn := utils.CreateStringNode(pair.Key())
for ext, node := range te.Extensions.FromOldest() {
kn := utils.CreateStringNode(ext)
kn.Line = 999999 + i // weighted to the bottom.
g.Set(low.KeyReference[string]{
Value: pair.Key(),
Value: ext,
KeyNode: kn,
}, low.ValueReference[*yaml.Node]{
ValueNode: pair.Value(),
Value: pair.Value(),
ValueNode: node,
Value: node,
})
i++
}
@@ -175,7 +175,6 @@ func (t test2) GetReference() string {
}
func (t test2) SetReference(ref string, _ *yaml.Node) {
}
func (t test2) GetReferenceNode() *yaml.Node {

View File

@@ -38,11 +38,7 @@ type GoesLowUntyped interface {
// ExtractExtensions is a convenience method for converting low-level extension definitions, to a high level *orderedmap.Map[string, *yaml.Node]
// definition that is easier to consume in applications.
func ExtractExtensions(extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]) *orderedmap.Map[string, *yaml.Node] {
extracted := orderedmap.New[string, *yaml.Node]()
for pair := orderedmap.First(extensions); pair != nil; pair = pair.Next() {
extracted.Set(pair.Key().Value, pair.Value().Value)
}
return extracted
return low.FromReferenceMap(extensions)
}
// UnpackExtensions is a convenience function that makes it easy and simple to unpack an objects extensions
@@ -64,15 +60,14 @@ func ExtractExtensions(extensions *orderedmap.Map[low.KeyReference[string], low.
func UnpackExtensions[T any, R low.HasExtensions[T]](low GoesLow[R]) (*orderedmap.Map[string, *T], error) {
m := orderedmap.New[string, *T]()
ext := low.GoLow().GetExtensions()
for pair := orderedmap.First(ext); pair != nil; pair = pair.Next() {
key := pair.Key().Value
for ext, value := range ext.FromOldest() {
g := new(T)
valueNode := pair.Value().ValueNode
valueNode := value.ValueNode
err := valueNode.Decode(g)
if err != nil {
return nil, err
}
m.Set(key, g)
m.Set(ext.Value, g)
}
return m, nil
}

View File

@@ -4,7 +4,8 @@
package v2
import (
low "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/datamodel/low"
lowv2 "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -14,24 +15,20 @@ import (
// - https://swagger.io/specification/v2/#exampleObject
type Example struct {
Values *orderedmap.Map[string, *yaml.Node]
low *low.Examples
low *lowv2.Examples
}
// NewExample creates a new high-level Example instance from a low-level one.
func NewExample(examples *low.Examples) *Example {
func NewExample(examples *lowv2.Examples) *Example {
e := new(Example)
e.low = examples
if orderedmap.Len(examples.Values) > 0 {
values := orderedmap.New[string, *yaml.Node]()
for pair := orderedmap.First(examples.Values); pair != nil; pair = pair.Next() {
values.Set(pair.Key().Value, pair.Value().Value)
}
e.Values = values
e.Values = low.FromReferenceMap(examples.Values)
}
return e
}
// GoLow returns the low-level Example used to create the high-level one.
func (e *Example) GoLow() *low.Examples {
func (e *Example) GoLow() *lowv2.Examples {
return e.low
}

View File

@@ -56,8 +56,8 @@ func TestPathItem_GetOperations_NoLow(t *testing.T) {
expectedOrderOfOps := []string{"get", "post", "delete"}
actualOrder := []string{}
for pair := orderedmap.First(ops); pair != nil; pair = pair.Next() {
actualOrder = append(actualOrder, pair.Key())
for op := range ops.KeysFromOldest() {
actualOrder = append(actualOrder, op)
}
assert.Equal(t, expectedOrderOfOps, actualOrder)
@@ -75,8 +75,8 @@ func TestPathItem_GetOperations_LowWithUnsetOperations(t *testing.T) {
expectedOrderOfOps := []string{"get", "post", "delete"}
actualOrder := []string{}
for pair := orderedmap.First(ops); pair != nil; pair = pair.Next() {
actualOrder = append(actualOrder, pair.Key())
for op := range ops.KeysFromOldest() {
actualOrder = append(actualOrder, op)
}
assert.Equal(t, expectedOrderOfOps, actualOrder)

View File

@@ -6,7 +6,8 @@ package v2
import (
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/high/base"
low "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/datamodel/low"
lowv2 "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -20,11 +21,11 @@ type Response struct {
Headers *orderedmap.Map[string, *Header]
Examples *Example
Extensions *orderedmap.Map[string, *yaml.Node]
low *low.Response
low *lowv2.Response
}
// NewResponse creates a new high-level instance of Response from a low level one.
func NewResponse(response *low.Response) *Response {
func NewResponse(response *lowv2.Response) *Response {
r := new(Response)
r.low = response
r.Extensions = high.ExtractExtensions(response.Extensions)
@@ -35,11 +36,7 @@ func NewResponse(response *low.Response) *Response {
r.Schema = base.NewSchemaProxy(&response.Schema)
}
if !response.Headers.IsEmpty() {
headers := orderedmap.New[string, *Header]()
for pair := orderedmap.First(response.Headers.Value); pair != nil; pair = pair.Next() {
headers.Set(pair.Key().Value, NewHeader(pair.Value().Value))
}
r.Headers = headers
r.Headers = low.FromReferenceMapWithFunc(response.Headers.Value, NewHeader)
}
if !response.Examples.IsEmpty() {
r.Examples = NewExample(response.Examples.Value)
@@ -48,6 +45,6 @@ func NewResponse(response *low.Response) *Response {
}
// GoLow will return the low-level Response instance used to create the high level one.
func (r *Response) GoLow() *low.Response {
func (r *Response) GoLow() *lowv2.Response {
return r.low
}

View File

@@ -4,7 +4,8 @@
package v2
import (
low "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/datamodel/low"
lowv2 "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/orderedmap"
)
@@ -14,22 +15,18 @@ import (
// - https://swagger.io/specification/v2/#scopesObject
type Scopes struct {
Values *orderedmap.Map[string, string]
low *low.Scopes
low *lowv2.Scopes
}
// NewScopes creates a new high-level instance of Scopes from a low-level one.
func NewScopes(scopes *low.Scopes) *Scopes {
func NewScopes(scopes *lowv2.Scopes) *Scopes {
s := new(Scopes)
s.low = scopes
scopeValues := orderedmap.New[string, string]()
for pair := orderedmap.First(scopes.Values); pair != nil; pair = pair.Next() {
scopeValues.Set(pair.Key().Value, pair.Value().Value)
}
s.Values = scopeValues
s.Values = low.FromReferenceMap(scopes.Values)
return s
}
// GoLow returns the low-level instance of Scopes used to create the high-level one.
func (s *Scopes) GoLow() *low.Scopes {
func (s *Scopes) GoLow() *lowv2.Scopes {
return s.low
}

View File

@@ -7,7 +7,8 @@ import (
"sort"
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
@@ -23,24 +24,20 @@ import (
type Callback struct {
Expression *orderedmap.Map[string, *PathItem] `json:"-" yaml:"-"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Callback
low *lowv3.Callback
}
// NewCallback creates a new high-level callback from a low-level one.
func NewCallback(lowCallback *low.Callback) *Callback {
func NewCallback(lowCallback *lowv3.Callback) *Callback {
n := new(Callback)
n.low = lowCallback
n.Expression = orderedmap.New[string, *PathItem]()
for pair := orderedmap.First(lowCallback.Expression); pair != nil; pair = pair.Next() {
n.Expression.Set(pair.Key().Value, NewPathItem(pair.Value().Value))
}
n.Expression = low.FromReferenceMapWithFunc(lowCallback.Expression, NewPathItem)
n.Extensions = high.ExtractExtensions(lowCallback.Extensions)
return n
}
// GoLow returns the low-level Callback instance used to create the high-level one.
func (c *Callback) GoLow() *low.Callback {
func (c *Callback) GoLow() *lowv3.Callback {
return c.low
}
@@ -73,9 +70,7 @@ func (c *Callback) MarshalYAML() (interface{}, error) {
}
var mapped []*pathItem
for pair := orderedmap.First(c.Expression); pair != nil; pair = pair.Next() {
k := pair.Key()
pi := pair.Value()
for k, pi := range c.Expression.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if c.low != nil {
@@ -84,9 +79,9 @@ func (c *Callback) MarshalYAML() (interface{}, error) {
ln = lpi.ValueNode.Line
}
for pair := orderedmap.First(c.low.Expression); pair != nil; pair = pair.Next() {
if pair.Key().Value == k {
style = pair.Key().KeyNode.Style
for lk := range c.low.Expression.KeysFromOldest() {
if lk.Value == k {
style = lk.KeyNode.Style
break
}
}
@@ -144,9 +139,7 @@ func (c *Callback) MarshalYAMLInline() (interface{}, error) {
}
var mapped []*pathItem
for pair := orderedmap.First(c.Expression); pair != nil; pair = pair.Next() {
k := pair.Key()
pi := pair.Value()
for k, pi := range c.Expression.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if c.low != nil {
@@ -155,9 +148,9 @@ func (c *Callback) MarshalYAMLInline() (interface{}, error) {
ln = lpi.ValueNode.Line
}
for pair := orderedmap.First(c.low.Expression); pair != nil; pair = pair.Next() {
if pair.Key().Value == k {
style = pair.Key().KeyNode.Style
for lk := range c.low.Expression.KeysFromOldest() {
if lk.Value == k {
style = lk.KeyNode.Style
break
}
}

View File

@@ -14,7 +14,8 @@ import (
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/high/base"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/json"
"github.com/pb33f/libopenapi/orderedmap"
@@ -94,11 +95,11 @@ type Document struct {
// Rolodex is the low-level rolodex used when creating this document.
// This in an internal structure and not part of the OpenAPI schema.
Rolodex *index.Rolodex `json:"-" yaml:"-"`
low *low.Document
low *lowv3.Document
}
// NewDocument will create a new high-level Document from a low-level one.
func NewDocument(document *low.Document) *Document {
func NewDocument(document *lowv3.Document) *Document {
d := new(Document)
d.low = document
d.Index = document.Index
@@ -134,11 +135,7 @@ func NewDocument(document *low.Document) *Document {
d.JsonSchemaDialect = document.JsonSchemaDialect.Value
}
if !document.Webhooks.IsEmpty() {
hooks := orderedmap.New[string, *PathItem]()
for pair := orderedmap.First(document.Webhooks.Value); pair != nil; pair = pair.Next() {
hooks.Set(pair.Key().Value, NewPathItem(pair.Value().Value))
}
d.Webhooks = hooks
d.Webhooks = low.FromReferenceMapWithFunc(document.Webhooks.Value, NewPathItem)
}
if !document.Security.IsEmpty() {
var security []*base.SecurityRequirement
@@ -151,7 +148,7 @@ func NewDocument(document *low.Document) *Document {
}
// GoLow returns the low-level Document that was used to create the high level one.
func (d *Document) GoLow() *low.Document {
func (d *Document) GoLow() *lowv3.Document {
return d.low
}

View File

@@ -215,10 +215,10 @@ func TestNewDocument_Components_Callbacks(t *testing.T) {
assert.Equal(t, "please", xBreakEverything)
for pair := orderedmap.First(h.Components.GoLow().Callbacks.Value); pair != nil; pair = pair.Next() {
if pair.Key().Value == "BurgerCallback" {
assert.Equal(t, 295, pair.Key().KeyNode.Line)
assert.Equal(t, 5, pair.Key().KeyNode.Column)
for k := range h.Components.GoLow().Callbacks.Value.KeysFromOldest() {
if k.Value == "BurgerCallback" {
assert.Equal(t, 295, k.KeyNode.Line)
assert.Equal(t, 5, k.KeyNode.Column)
}
}
}
@@ -900,5 +900,4 @@ func TestDocument_RenderJSONError(t *testing.T) {
assert.Nil(t, r)
assert.Error(t, e)
assert.Equal(t, "yaml: cannot decode !!float `-999.99` as a !!int", e.Error())
}

View File

@@ -5,8 +5,9 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/low"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -19,11 +20,11 @@ type Encoding struct {
Style string `json:"style,omitempty" yaml:"style,omitempty"`
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
low *low.Encoding
low *lowv3.Encoding
}
// NewEncoding creates a new instance of Encoding from a low-level one.
func NewEncoding(encoding *low.Encoding) *Encoding {
func NewEncoding(encoding *lowv3.Encoding) *Encoding {
e := new(Encoding)
e.low = encoding
e.ContentType = encoding.ContentType.Value
@@ -37,7 +38,7 @@ func NewEncoding(encoding *low.Encoding) *Encoding {
}
// GoLow returns the low-level Encoding instance used to create the high-level one.
func (e *Encoding) GoLow() *low.Encoding {
func (e *Encoding) GoLow() *lowv3.Encoding {
return e.low
}
@@ -58,10 +59,6 @@ func (e *Encoding) MarshalYAML() (interface{}, error) {
}
// ExtractEncoding converts hard to navigate low-level plumbing Encoding definitions, into a high-level simple map
func ExtractEncoding(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Encoding]]) *orderedmap.Map[string, *Encoding] {
extracted := orderedmap.New[string, *Encoding]()
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
extracted.Set(pair.Key().Value, NewEncoding(pair.Value().Value))
}
return extracted
func ExtractEncoding(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*lowv3.Encoding]]) *orderedmap.Map[string, *Encoding] {
return low.FromReferenceMapWithFunc(elements, NewEncoding)
}

View File

@@ -6,9 +6,10 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
highbase "github.com/pb33f/libopenapi/datamodel/high/base"
"github.com/pb33f/libopenapi/datamodel/low"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -28,11 +29,11 @@ type Header struct {
Examples *orderedmap.Map[string, *highbase.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Header
low *lowv3.Header
}
// NewHeader creates a new high-level Header instance from a low-level one.
func NewHeader(header *low.Header) *Header {
func NewHeader(header *lowv3.Header) *Header {
h := new(Header)
h.low = header
h.Description = header.Description.Value
@@ -57,7 +58,7 @@ func NewHeader(header *low.Header) *Header {
}
// GoLow returns the low-level Header instance used to create the high-level one.
func (h *Header) GoLow() *low.Header {
func (h *Header) GoLow() *lowv3.Header {
return h.low
}
@@ -67,12 +68,8 @@ func (h *Header) GoLowUntyped() any {
}
// ExtractHeaders will extract a hard to navigate low-level Header map, into simple high-level one.
func ExtractHeaders(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Header]]) *orderedmap.Map[string, *Header] {
extracted := orderedmap.New[string, *Header]()
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
extracted.Set(pair.Key().Value, NewHeader(pair.Value().Value))
}
return extracted
func ExtractHeaders(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*lowv3.Header]]) *orderedmap.Map[string, *Header] {
return low.FromReferenceMapWithFunc(elements, NewHeader)
}
// Render will return a YAML representation of the Header object as a byte slice.

View File

@@ -5,7 +5,8 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -30,20 +31,16 @@ type Link struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Link
low *lowv3.Link
}
// NewLink will create a new high-level Link instance from a low-level one.
func NewLink(link *low.Link) *Link {
func NewLink(link *lowv3.Link) *Link {
l := new(Link)
l.low = link
l.OperationRef = link.OperationRef.Value
l.OperationId = link.OperationId.Value
params := orderedmap.New[string, string]()
for pair := orderedmap.First(link.Parameters.Value); pair != nil; pair = pair.Next() {
params.Set(pair.Key().Value, pair.Value().Value)
}
l.Parameters = params
l.Parameters = low.FromReferenceMap(link.Parameters.Value)
l.RequestBody = link.RequestBody.Value
l.Description = link.Description.Value
if link.Server.Value != nil {
@@ -54,7 +51,7 @@ func NewLink(link *low.Link) *Link {
}
// GoLow will return the low-level Link instance used to create the high-level one.
func (l *Link) GoLow() *low.Link {
func (l *Link) GoLow() *lowv3.Link {
return l.low
}

View File

@@ -5,7 +5,8 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -18,27 +19,23 @@ type OAuthFlow struct {
RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
Scopes *orderedmap.Map[string, string] `json:"scopes,renderZero" yaml:"scopes,renderZero"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.OAuthFlow
low *lowv3.OAuthFlow
}
// NewOAuthFlow creates a new high-level OAuthFlow instance from a low-level one.
func NewOAuthFlow(flow *low.OAuthFlow) *OAuthFlow {
func NewOAuthFlow(flow *lowv3.OAuthFlow) *OAuthFlow {
o := new(OAuthFlow)
o.low = flow
o.TokenUrl = flow.TokenUrl.Value
o.AuthorizationUrl = flow.AuthorizationUrl.Value
o.RefreshUrl = flow.RefreshUrl.Value
scopes := orderedmap.New[string, string]()
for pair := orderedmap.First(flow.Scopes.Value); pair != nil; pair = pair.Next() {
scopes.Set(pair.Key().Value, pair.Value().Value)
}
o.Scopes = scopes
o.Scopes = low.FromReferenceMap(flow.Scopes.Value)
o.Extensions = high.ExtractExtensions(flow.Extensions)
return o
}
// GoLow returns the low-level OAuthFlow instance used to create the high-level one.
func (o *OAuthFlow) GoLow() *low.OAuthFlow {
func (o *OAuthFlow) GoLow() *lowv3.OAuthFlow {
return o.low
}

View File

@@ -6,7 +6,8 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
"github.com/pb33f/libopenapi/datamodel/high/base"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -30,11 +31,11 @@ type Operation struct {
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Operation
low *lowv3.Operation
}
// NewOperation will create a new Operation instance from a low-level one.
func NewOperation(operation *low.Operation) *Operation {
func NewOperation(operation *lowv3.Operation) *Operation {
o := new(Operation)
o.low = operation
var tags []string
@@ -84,17 +85,13 @@ func NewOperation(operation *low.Operation) *Operation {
o.Servers = servers
o.Extensions = high.ExtractExtensions(operation.Extensions)
if !operation.Callbacks.IsEmpty() {
cbs := orderedmap.New[string, *Callback]()
for pair := orderedmap.First(operation.Callbacks.Value); pair != nil; pair = pair.Next() {
cbs.Set(pair.Key().Value, NewCallback(pair.Value().Value))
}
o.Callbacks = cbs
o.Callbacks = low.FromReferenceMapWithFunc(operation.Callbacks.Value, NewCallback)
}
return o
}
// GoLow will return the low-level Operation instance that was used to create the high-level one.
func (o *Operation) GoLow() *low.Operation {
func (o *Operation) GoLow() *lowv3.Operation {
return o.low
}

View File

@@ -11,7 +11,6 @@ import (
"github.com/pb33f/libopenapi/datamodel/low"
lowV3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
@@ -74,8 +73,8 @@ trace:
expectedOrder := []string{"get", "put", "post", "patch", "delete", "head", "options", "trace"}
i := 0
for pair := orderedmap.First(r.GetOperations()); pair != nil; pair = pair.Next() {
assert.Equal(t, expectedOrder[i], pair.Value().Description)
for v := range r.GetOperations().ValuesFromOldest() {
assert.Equal(t, expectedOrder[i], v.Description)
i++
}
}
@@ -171,8 +170,8 @@ func TestPathItem_GetOperations_NoLow(t *testing.T) {
expectedOrderOfOps := []string{"get", "post", "delete"}
actualOrder := []string{}
for pair := orderedmap.First(ops); pair != nil; pair = pair.Next() {
actualOrder = append(actualOrder, pair.Key())
for k := range ops.KeysFromOldest() {
actualOrder = append(actualOrder, k)
}
assert.Equal(t, expectedOrderOfOps, actualOrder)
@@ -190,8 +189,8 @@ func TestPathItem_GetOperations_LowWithUnsetOperations(t *testing.T) {
expectedOrderOfOps := []string{"get", "post", "delete"}
actualOrder := []string{}
for pair := orderedmap.First(ops); pair != nil; pair = pair.Next() {
actualOrder = append(actualOrder, pair.Key())
for k := range ops.KeysFromOldest() {
actualOrder = append(actualOrder, k)
}
assert.Equal(t, expectedOrderOfOps, actualOrder)

View File

@@ -86,9 +86,7 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
}
var mapped []*pathItem
for pair := orderedmap.First(p.PathItems); pair != nil; pair = pair.Next() {
k := pair.Key()
pi := pair.Value()
for k, pi := range p.PathItems.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if p.low != nil {
@@ -97,9 +95,9 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
ln = lpi.ValueNode.Line
}
for pair := orderedmap.First(p.low.PathItems); pair != nil; pair = pair.Next() {
if pair.Key().Value == k {
style = pair.Key().KeyNode.Style
for lk := range p.low.PathItems.KeysFromOldest() {
if lk.Value == k {
style = lk.KeyNode.Style
break
}
}
@@ -157,9 +155,7 @@ func (p *Paths) MarshalYAMLInline() (interface{}, error) {
}
var mapped []*pathItem
for pair := orderedmap.First(p.PathItems); pair != nil; pair = pair.Next() {
k := pair.Key()
pi := pair.Value()
for k, pi := range p.PathItems.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if p.low != nil {
@@ -168,9 +164,9 @@ func (p *Paths) MarshalYAMLInline() (interface{}, error) {
ln = lpi.ValueNode.Line
}
for pair := orderedmap.First(p.low.PathItems); pair != nil; pair = pair.Next() {
if pair.Key().Value == k {
style = pair.Key().KeyNode.Style
for lk := range p.low.PathItems.KeysFromOldest() {
if lk.Value == k {
style = lk.KeyNode.Style
break
}
}

View File

@@ -5,7 +5,8 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -21,11 +22,11 @@ type Response struct {
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
Links *orderedmap.Map[string, *Link] `json:"links,omitempty" yaml:"links,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Response
low *lowv3.Response
}
// NewResponse creates a new high-level Response object that is backed by a low-level one.
func NewResponse(response *low.Response) *Response {
func NewResponse(response *lowv3.Response) *Response {
r := new(Response)
r.low = response
r.Description = response.Description.Value
@@ -37,17 +38,13 @@ func NewResponse(response *low.Response) *Response {
r.Content = ExtractContent(response.Content.Value)
}
if !response.Links.IsEmpty() {
responseLinks := orderedmap.New[string, *Link]()
for pair := orderedmap.First(response.Links.Value); pair != nil; pair = pair.Next() {
responseLinks.Set(pair.Key().Value, NewLink(pair.Value().Value))
}
r.Links = responseLinks
r.Links = low.FromReferenceMapWithFunc(response.Links.Value, NewLink)
}
return r
}
// GoLow returns the low-level Response object that was used to create the high-level one.
func (r *Response) GoLow() *low.Response {
func (r *Response) GoLow() *lowv3.Response {
return r.low
}

View File

@@ -101,18 +101,18 @@ func (r *Responses) MarshalYAML() (interface{}, error) {
}
var mapped []*responseItem
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
for code, resp := range r.Codes.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if r.low != nil {
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
if lPair.Key().Value == pair.Key() {
ln = lPair.Key().KeyNode.Line
style = lPair.Key().KeyNode.Style
for lk := range r.low.Codes.KeysFromOldest() {
if lk.Value == code {
ln = lk.KeyNode.Line
style = lk.KeyNode.Style
}
}
}
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil, style})
mapped = append(mapped, &responseItem{resp, code, ln, nil, style})
}
// extract extensions
@@ -166,18 +166,18 @@ func (r *Responses) MarshalYAMLInline() (interface{}, error) {
}
var mapped []*responseItem
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
for code, resp := range r.Codes.FromOldest() {
ln := 9999 // default to a high value to weight new content to the bottom.
var style yaml.Style
if r.low != nil {
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
if lPair.Key().Value == pair.Key() {
ln = lPair.Key().KeyNode.Line
style = lPair.Key().KeyNode.Style
for lk := range r.low.Codes.KeysFromOldest() {
if lk.Value == code {
ln = lk.KeyNode.Line
style = lk.KeyNode.Style
}
}
}
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil, style})
mapped = append(mapped, &responseItem{resp, code, ln, nil, style})
}
// extract extensions

View File

@@ -5,7 +5,8 @@ package v3
import (
"github.com/pb33f/libopenapi/datamodel/high"
low "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/datamodel/low"
lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -17,26 +18,22 @@ type Server struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Variables *orderedmap.Map[string, *ServerVariable] `json:"variables,omitempty" yaml:"variables,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Server
low *lowv3.Server
}
// NewServer will create a new high-level Server instance from a low-level one.
func NewServer(server *low.Server) *Server {
func NewServer(server *lowv3.Server) *Server {
s := new(Server)
s.low = server
s.Description = server.Description.Value
s.URL = server.URL.Value
vars := orderedmap.New[string, *ServerVariable]()
for pair := orderedmap.First(server.Variables.Value); pair != nil; pair = pair.Next() {
vars.Set(pair.Key().Value, NewServerVariable(pair.Value().Value))
}
s.Variables = vars
s.Variables = low.FromReferenceMapWithFunc(server.Variables.Value, NewServerVariable)
s.Extensions = high.ExtractExtensions(server.Extensions)
return s
}
// GoLow returns the low-level Server instance that was used to create the high-level one
func (s *Server) GoLow() *low.Server {
func (s *Server) GoLow() *lowv3.Server {
return s.low
}

View File

@@ -5,9 +5,10 @@ package base
import (
"crypto/sha256"
"gopkg.in/yaml.v3"
"strings"
"gopkg.in/yaml.v3"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/orderedmap"
)
@@ -42,9 +43,8 @@ func (d *Discriminator) GetKeyNode() *yaml.Node {
// FindMappingValue will return a ValueReference containing the string mapping value
func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] {
for pair := orderedmap.First(d.Mapping.Value); pair != nil; pair = pair.Next() {
if pair.Key().Value == key {
v := pair.Value()
for k, v := range d.Mapping.Value.FromOldest() {
if k.Value == key {
return &v
}
}
@@ -59,8 +59,8 @@ func (d *Discriminator) Hash() [32]byte {
f = append(f, d.PropertyName.Value)
}
for pair := orderedmap.First(orderedmap.SortAlpha(d.Mapping.Value)); pair != nil; pair = pair.Next() {
f = append(f, pair.Value().Value)
for v := range orderedmap.SortAlpha(d.Mapping.Value).ValuesFromOldest() {
f = append(f, v.Value)
}
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -262,9 +262,7 @@ func (s *Schema) Hash() [32]byte {
sort.Strings(keys)
d = append(d, keys...)
for pair := orderedmap.First(orderedmap.SortAlpha(s.Properties.Value)); pair != nil; pair = pair.Next() {
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
d = low.AppendMapHashes(d, s.Properties.Value)
if s.XML.Value != nil {
d = append(d, low.GenerateHashString(s.XML.Value))
}
@@ -364,13 +362,8 @@ func (s *Schema) Hash() [32]byte {
d = append(d, fmt.Sprint(s.Anchor.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(s.DependentSchemas.Value)); pair != nil; pair = pair.Next() {
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
for pair := orderedmap.First(orderedmap.SortAlpha(s.PatternProperties.Value)); pair != nil; pair = pair.Next() {
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
d = low.AppendMapHashes(d, orderedmap.SortAlpha(s.DependentSchemas.Value))
d = low.AppendMapHashes(d, orderedmap.SortAlpha(s.PatternProperties.Value))
if len(s.PrefixItems.Value) > 0 {
itemsKeys := make([]string, len(s.PrefixItems.Value))
@@ -1180,7 +1173,6 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
res: res,
idx: schemaIdx,
}
}
isRef := false

View File

@@ -36,7 +36,6 @@ type SecurityRequirement struct {
// Build will extract security requirements from the node (the structure is odd, to be honest)
func (s *SecurityRequirement) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.SpecIndex) error {
s.KeyNode = keyNode
root = utils.NodeAlias(root)
s.RootNode = root
@@ -96,9 +95,9 @@ func (s *SecurityRequirement) GetKeyNode() *yaml.Node {
// FindRequirement will attempt to locate a security requirement string from a supplied name.
func (s *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] {
for pair := orderedmap.First(s.Requirements.Value); pair != nil; pair = pair.Next() {
if pair.Key().Value == name {
return pair.Value().Value
for k, v := range s.Requirements.Value.FromOldest() {
if k.Value == name {
return v.Value
}
}
return nil
@@ -108,8 +107,9 @@ func (s *SecurityRequirement) FindRequirement(name string) []low.ValueReference[
func (s *SecurityRequirement) GetKeys() []string {
keys := make([]string, orderedmap.Len(s.Requirements.Value))
z := 0
for pair := orderedmap.First(s.Requirements.Value); pair != nil; pair = pair.Next() {
keys[z] = pair.Key().Value
for k := range s.Requirements.Value.KeysFromOldest() {
keys[z] = k.Value
z++
}
return keys
}
@@ -117,14 +117,14 @@ func (s *SecurityRequirement) GetKeys() []string {
// Hash will return a consistent SHA256 Hash of the SecurityRequirement object
func (s *SecurityRequirement) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(s.Requirements.Value)); pair != nil; pair = pair.Next() {
for k, v := range orderedmap.SortAlpha(s.Requirements.Value).FromOldest() {
var vals []string
for y := range pair.Value().Value {
vals = append(vals, pair.Value().Value[y].Value)
for y := range v.Value {
vals = append(vals, v.Value[y].Value)
}
sort.Strings(vals)
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, strings.Join(vals, "|")))
f = append(f, fmt.Sprintf("%s-%s", k.Value, strings.Join(vals, "|")))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -47,9 +47,9 @@ func FindItemInOrderedMapWithKey[T any](item string, collection *orderedmap.Map[
func HashExtensions(ext *orderedmap.Map[KeyReference[string], ValueReference[*yaml.Node]]) []string {
f := []string{}
for pair := orderedmap.First(orderedmap.SortAlpha(ext)); pair != nil; pair = pair.Next() {
b, _ := yaml.Marshal(pair.Value().GetValue())
f = append(f, fmt.Sprintf("%s-%x", pair.Key().Value, sha256.Sum256([]byte(b))))
for e, node := range orderedmap.SortAlpha(ext).FromOldest() {
b, _ := yaml.Marshal(node.GetValue())
f = append(f, fmt.Sprintf("%s-%x", e.Value, sha256.Sum256([]byte(b))))
}
return f
@@ -725,7 +725,6 @@ func ExtractMapExtensions[PT Buildable[N], N any](
startCtx := foundContext
translateFunc := func(input buildInput) (mappingResult[PT], error) {
en := input.value
sCtx := startCtx
@@ -876,6 +875,14 @@ func GenerateHashString(v any) string {
return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v))))
}
// AppendMapHashes will append all the hashes of a map to a slice of strings
func AppendMapHashes[v any](a []string, m *orderedmap.Map[KeyReference[string], ValueReference[v]]) []string {
for k, v := range orderedmap.SortAlpha(m).FromOldest() {
a = append(a, fmt.Sprintf("%s-%s", k.Value, GenerateHashString(v.Value)))
}
return a
}
func ValueToString(v any) string {
if n, ok := v.(*yaml.Node); ok {
b, _ := yaml.Marshal(n)
@@ -904,3 +911,21 @@ func LocateRefEnd(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, de
return ref, fIdx, err, nCtx
}
}
// FromReferenceMap will convert a *orderedmap.Map[KeyReference[K], ValueReference[V]] to a *orderedmap.Map[K, V]
func FromReferenceMap[K comparable, V any](refMap *orderedmap.Map[KeyReference[K], ValueReference[V]]) *orderedmap.Map[K, V] {
om := orderedmap.New[K, V]()
for k, v := range refMap.FromOldest() {
om.Set(k.Value, v.Value)
}
return om
}
// FromReferenceMapWithFunc will convert a *orderedmap.Map[KeyReference[K], ValueReference[V]] to a *orderedmap.Map[K, VOut] using a transform function
func FromReferenceMapWithFunc[K comparable, V any, VOut any](refMap *orderedmap.Map[KeyReference[K], ValueReference[V]], transform func(v V) VOut) *orderedmap.Map[K, VOut] {
om := orderedmap.New[K, VOut]()
for k, v := range refMap.FromOldest() {
om.Set(k.Value, transform(v.Value))
}
return om
}

View File

@@ -12,6 +12,7 @@ import (
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
"gopkg.in/yaml.v3"
@@ -21,7 +22,6 @@ import (
"github.com/pb33f/libopenapi/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sync"
)
func TestFindItemInOrderedMap(t *testing.T) {
@@ -932,12 +932,12 @@ one:
assert.NoError(t, err)
assert.Equal(t, 2, orderedmap.Len(things))
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
if pair.Key().Value == "x-hey" {
for k, v := range things.FromOldest() {
if k.Value == "x-hey" {
continue
}
assert.Equal(t, "one", pair.Key().Value)
assert.Len(t, pair.Value().ValueNode.Content, 2)
assert.Equal(t, "one", k.Value)
assert.Len(t, v.ValueNode.Content, 2)
}
}
@@ -985,8 +985,8 @@ one:
assert.NoError(t, err)
assert.Equal(t, 1, orderedmap.Len(things))
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
assert.Equal(t, "one", pair.Key().Value)
for k := range things.KeysFromOldest() {
assert.Equal(t, "one", k.Value)
}
}
@@ -1203,8 +1203,8 @@ one:
assert.NoError(t, err)
assert.Equal(t, 1, orderedmap.Len(things))
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
assert.Equal(t, 99, pair.Value().Value.AlmostWork.Value)
for v := range things.ValuesFromOldest() {
assert.Equal(t, 99, v.Value.AlmostWork.Value)
}
}
@@ -1231,8 +1231,8 @@ func TestExtractMapFlat_DoubleRef(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 1, orderedmap.Len(things))
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
assert.Equal(t, 99, pair.Value().Value.AlmostWork.Value)
for v := range things.ValuesFromOldest() {
assert.Equal(t, 99, v.Value.AlmostWork.Value)
}
}
@@ -1490,11 +1490,11 @@ x-tacos: [1,2,3]`
r := ExtractExtensions(idxNode.Content[0])
assert.Equal(t, 6, orderedmap.Len(r))
for pair := orderedmap.First(r); pair != nil; pair = pair.Next() {
for k, val := range r.FromOldest() {
var v any
_ = pair.Value().Value.Decode(&v)
_ = val.Value.Decode(&v)
switch pair.Key().Value {
switch k.Value {
case "x-bing":
assert.Equal(t, "ding", v)
case "x-bong":
@@ -1505,7 +1505,7 @@ x-tacos: [1,2,3]`
assert.Equal(t, 0.99, v)
case "x-fish":
var m map[string]any
err := pair.Value().Value.Decode(&m)
err := val.Value.Decode(&m)
require.NoError(t, err)
assert.Equal(t, "yeah", m["woo"])
case "x-tacos":
@@ -1868,7 +1868,6 @@ func TestLocateRefNode_NoExplode_NoSpecPath(t *testing.T) {
}
func TestLocateRefNode_DoARealLookup(t *testing.T) {
lookup := "/root.yaml#/components/schemas/Burger"
if runtime.GOOS == "windows" {
lookup = "C:\\root.yaml#/components/schemas/Burger"
@@ -2176,3 +2175,22 @@ func TestExtractExtensions_Nill(t *testing.T) {
err := ExtractExtensions(nil)
assert.Nil(t, err)
}
func TestFromReferenceMap(t *testing.T) {
refMap := orderedmap.New[KeyReference[string], ValueReference[string]]()
refMap.Set(KeyReference[string]{Value: "foo"}, ValueReference[string]{Value: "bar"})
refMap.Set(KeyReference[string]{Value: "baz"}, ValueReference[string]{Value: "qux"})
om := FromReferenceMap(refMap)
assert.Equal(t, "bar", om.GetOrZero("foo"))
assert.Equal(t, "qux", om.GetOrZero("baz"))
}
func TestAppendMapHashes(t *testing.T) {
m := orderedmap.New[KeyReference[string], ValueReference[string]]()
m.Set(KeyReference[string]{Value: "foo"}, ValueReference[string]{Value: "bar"})
m.Set(KeyReference[string]{Value: "baz"}, ValueReference[string]{Value: "qux"})
a := AppendMapHashes([]string{}, m)
assert.Equal(t, 2, len(a))
assert.Equal(t, "baz-21f58d27f827d295ffcd860c65045685e3baf1ad4506caa0140113b316647534", a[0])
assert.Equal(t, "foo-fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9", a[1])
}

View File

@@ -139,12 +139,12 @@ allTheThings:
assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value)
allTheThings := hd.AllTheThings.Value
for pair := orderedmap.First(allTheThings); pair != nil; pair = pair.Next() {
if pair.Key().Value == "beer" {
assert.Equal(t, "isGood", pair.Value().Value)
for k, v := range allTheThings.FromOldest() {
if k.Value == "beer" {
assert.Equal(t, "isGood", v.Value)
}
if pair.Key().Value == "cake" {
assert.Equal(t, "isNice", pair.Value().Value)
if k.Value == "cake" {
assert.Equal(t, "isNice", v.Value)
}
}
assert.NoError(t, cErr)
@@ -364,8 +364,7 @@ func TestHandleSlicesOfBools(t *testing.T) {
}
func TestSetField_Ignore(t *testing.T) {
type Complex struct {
}
type Complex struct{}
type internal struct {
Thing *Complex
}

View File

@@ -6,9 +6,10 @@ package low
import (
"context"
"sync"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
"sync"
)
// HasNodes is an interface that defines a method to get a map of nodes
@@ -23,7 +24,6 @@ type AddNodes interface {
// NodeMap represents a map of yaml nodes
type NodeMap struct {
// Nodes is a sync map of nodes for this object, and the key is the line number of the node
// a line can contain many nodes (in JSON), so the value is a slice of *yaml.Node
Nodes *sync.Map `yaml:"-" json:"-"`
@@ -115,13 +115,10 @@ func ExtractNodesRecursive(_ context.Context, root *yaml.Node) *sync.Map {
// ExtractExtensionNodes will extract all extension nodes from a map of extensions, recursively.
func ExtractExtensionNodes(_ context.Context,
extensionMap *orderedmap.Map[KeyReference[string],
ValueReference[*yaml.Node]], nodeMap *sync.Map) {
ValueReference[*yaml.Node]], nodeMap *sync.Map,
) {
// range over the extension map and extract all nodes
for extPairs := extensionMap.First(); extPairs != nil; extPairs = extPairs.Next() {
k := extPairs.Key()
v := extPairs.Value()
for k, v := range extensionMap.FromOldest() {
results := []*yaml.Node{k.KeyNode}
var newNodeMap sync.Map
nm := &NodeMap{Nodes: &newNodeMap}

View File

@@ -158,8 +158,8 @@ func (d *Definitions) Build(ctx context.Context, _, root *yaml.Node, idx *index.
// Hash will return a consistent SHA256 Hash of the Definitions object
func (d *Definitions) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(d.Schemas)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(d.FindSchema(pair.Key().Value).Value))
for k := range orderedmap.SortAlpha(d.Schemas).KeysFromOldest() {
f = append(f, low.GenerateHashString(d.FindSchema(k.Value).Value))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -57,8 +57,8 @@ func (e *Examples) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecInd
// Hash will return a consistent SHA256 Hash of the Examples object
func (e *Examples) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(e.Values)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(e.Values).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -157,8 +157,8 @@ func (p *Paths) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIn
// Hash will return a consistent SHA256 Hash of the PathItem object
func (p *Paths) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(p.PathItems)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(p.PathItems).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(p.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -88,8 +88,8 @@ func (r *Response) Hash() [32]byte {
f = append(f, low.GenerateHashString(r.Schema.Value))
}
if !r.Examples.IsEmpty() {
for pair := orderedmap.First(orderedmap.SortAlpha(r.Examples.Value.Values)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(r.Examples.Value.Values).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
}
f = append(f, low.HashExtensions(r.Extensions)...)

View File

@@ -57,12 +57,12 @@ func (r *Responses) Build(ctx context.Context, _, root *yaml.Node, idx *index.Sp
}
func (r *Responses) getDefault() *low.NodeReference[*Response] {
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
if strings.ToLower(pair.Key().Value) == DefaultLabel {
for code, resp := range r.Codes.FromOldest() {
if strings.ToLower(code.Value) == DefaultLabel {
return &low.NodeReference[*Response]{
ValueNode: pair.Value().ValueNode,
KeyNode: pair.Key().KeyNode,
Value: pair.Value().Value,
ValueNode: resp.ValueNode,
KeyNode: code.KeyNode,
Value: resp.Value,
}
}
}
@@ -94,9 +94,7 @@ func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Respons
// Hash will return a consistent SHA256 Hash of the Examples object
func (r *Responses) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(r.Codes)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
f = low.AppendMapHashes(f, orderedmap.SortAlpha(r.Codes))
if !r.Default.IsEmpty() {
f = append(f, low.GenerateHashString(r.Default.Value))
}

View File

@@ -67,8 +67,8 @@ func (s *Scopes) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecIndex
// Hash will return a consistent SHA256 Hash of the Scopes object
func (s *Scopes) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(s.Values)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, pair.Value().Value))
for k, v := range orderedmap.SortAlpha(s.Values).FromOldest() {
f = append(f, fmt.Sprintf("%s-%s", k.Value, v.Value))
}
f = append(f, low.HashExtensions(s.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -68,8 +68,8 @@ func (cb *Callback) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
return err
}
cb.Expression = expressions
for xp := expressions.First(); xp != nil; xp = xp.Next() {
cb.Nodes.Store(xp.Key().KeyNode.Line, xp.Key().KeyNode)
for k := range expressions.KeysFromOldest() {
cb.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
return nil
}
@@ -77,8 +77,8 @@ func (cb *Callback) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
// Hash will return a consistent SHA256 Hash of the Callback object
func (cb *Callback) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(cb.Expression)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(cb.Expression).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(cb.Extensions)...)

View File

@@ -86,8 +86,8 @@ func (co *Components) Hash() [32]byte {
}
func generateHashForObjectMap[T any](collection *orderedmap.Map[low.KeyReference[string], low.ValueReference[T]], hash *[]string) {
for pair := orderedmap.First(orderedmap.SortAlpha(collection)); pair != nil; pair = pair.Next() {
*hash = append(*hash, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(collection).ValuesFromOldest() {
*hash = append(*hash, low.GenerateHashString(v.Value))
}
}
@@ -347,10 +347,6 @@ func extractComponentValues[T low.Buildable[N], N any](ctx context.Context, labe
return emptyResult, err
}
//for rt := componentValues.First(); rt != nil; rt = rt.Next() {
//
//}
results := low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[T]]]{
KeyNode: nodeLabel,
ValueNode: nodeValue,

View File

@@ -5,6 +5,7 @@ import (
"errors"
"path/filepath"
"sync"
"time"
"github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/datamodel/low"
@@ -12,7 +13,6 @@ import (
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/pb33f/libopenapi/utils"
"time"
)
// CreateDocument will create a new Document instance from the provided SpecInfo.
@@ -178,7 +178,6 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
done = time.Duration(time.Since(now).Milliseconds())
if config.Logger != nil {
config.Logger.Debug("extractions complete", "time", done)
}
return &doc, errors.Join(errs...)
}
@@ -313,8 +312,8 @@ func extractWebhooks(ctx context.Context, info *datamodel.SpecInfo, doc *Documen
KeyNode: hooksL,
ValueNode: hooksN,
}
for xj := hooks.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range hooks.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
return nil

View File

@@ -311,10 +311,10 @@ func TestCreateDocument_Info(t *testing.T) {
func TestCreateDocument_WebHooks(t *testing.T) {
initTest()
assert.Equal(t, 1, orderedmap.Len(doc.Webhooks.Value))
for pair := orderedmap.First(doc.Webhooks.Value); pair != nil; pair = pair.Next() {
for v := range doc.Webhooks.Value.ValuesFromOldest() {
// a nice deep model should be available for us.
assert.Equal(t, "Information about a new burger",
pair.Value().Value.Post.Value.RequestBody.Value.Description.Value)
v.Value.Post.Value.RequestBody.Value.Description.Value)
}
}
@@ -366,10 +366,7 @@ func TestCreateDocument_Tags(t *testing.T) {
assert.NotEmpty(t, doc.Tags.Value[0].Value.ExternalDocs.Value.URL.Value)
assert.Equal(t, 7, orderedmap.Len(doc.Tags.Value[0].Value.Extensions))
for pair := orderedmap.First(doc.Tags.Value[0].Value.Extensions); pair != nil; pair = pair.Next() {
key := pair.Key()
extension := pair.Value()
for key, extension := range doc.Tags.Value[0].Value.Extensions.FromOldest() {
var val any
_ = extension.Value.Decode(&val)
switch key.Value {

View File

@@ -94,9 +94,9 @@ type Document struct {
func (d *Document) FindSecurityRequirement(name string) []low.ValueReference[string] {
for k := range d.Security.Value {
requirements := d.Security.Value[k].Value.Requirements
for pair := orderedmap.First(requirements.Value); pair != nil; pair = pair.Next() {
if pair.Key().Value == name {
return pair.Value().Value
for k, v := range requirements.Value.FromOldest() {
if k.Value == name {
return v.Value
}
}
}

View File

@@ -51,8 +51,8 @@ func (en *Encoding) Hash() [32]byte {
if en.ContentType.Value != "" {
f = append(f, en.ContentType.Value)
}
for pair := orderedmap.First(orderedmap.SortAlpha(en.Headers.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%x", pair.Key().Value, pair.Value().Value.Hash()))
for k, v := range orderedmap.SortAlpha(en.Headers.Value).FromOldest() {
f = append(f, fmt.Sprintf("%s-%x", k.Value, v.Value.Hash()))
}
if en.Style.Value != "" {
f = append(f, en.Style.Value)
@@ -81,8 +81,8 @@ func (en *Encoding) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
ValueNode: hN,
}
en.Nodes.Store(hL.Line, hL)
for xj := headers.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range headers.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
return nil

View File

@@ -88,11 +88,11 @@ func (h *Header) Hash() [32]byte {
if h.Example.Value != nil && !h.Example.Value.IsZero() {
f = append(f, low.GenerateHashString(h.Example.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(h.Examples.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%x", pair.Key().Value, pair.Value().Value.Hash()))
for k, v := range orderedmap.SortAlpha(h.Examples.Value).FromOldest() {
f = append(f, fmt.Sprintf("%s-%x", k.Value, v.Value.Hash()))
}
for pair := orderedmap.First(orderedmap.SortAlpha(h.Content.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%x", pair.Key().Value, pair.Value().Value.Hash()))
for k, v := range orderedmap.SortAlpha(h.Content.Value).FromOldest() {
f = append(f, fmt.Sprintf("%s-%x", k.Value, v.Value.Hash()))
}
f = append(f, low.HashExtensions(h.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))
@@ -168,15 +168,19 @@ func (h *Header) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index
func (h *Header) GetDescription() *low.NodeReference[string] {
return &h.Description
}
func (h *Header) GetRequired() *low.NodeReference[bool] {
return &h.Required
}
func (h *Header) GetDeprecated() *low.NodeReference[bool] {
return &h.Deprecated
}
func (h *Header) GetAllowEmptyValue() *low.NodeReference[bool] {
return &h.AllowEmptyValue
}
func (h *Header) GetSchema() *low.NodeReference[any] {
i := low.NodeReference[any]{
KeyNode: h.Schema.KeyNode,
@@ -185,18 +189,23 @@ func (h *Header) GetSchema() *low.NodeReference[any] {
}
return &i
}
func (h *Header) GetStyle() *low.NodeReference[string] {
return &h.Style
}
func (h *Header) GetAllowReserved() *low.NodeReference[bool] {
return &h.AllowReserved
}
func (h *Header) GetExplode() *low.NodeReference[bool] {
return &h.Explode
}
func (h *Header) GetExample() *low.NodeReference[*yaml.Node] {
return &h.Example
}
func (h *Header) GetExamples() *low.NodeReference[any] {
i := low.NodeReference[any]{
KeyNode: h.Examples.KeyNode,
@@ -205,6 +214,7 @@ func (h *Header) GetExamples() *low.NodeReference[any] {
}
return &i
}
func (h *Header) GetContent() *low.NodeReference[any] {
c := low.NodeReference[any]{
KeyNode: h.Content.KeyNode,

View File

@@ -79,8 +79,8 @@ func (l *Link) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.S
// extract parameter nodes.
if l.Parameters.Value != nil && l.Parameters.Value.Len() > 0 {
for fk := l.Parameters.Value.First(); fk != nil; fk = fk.Next() {
l.Nodes.Store(fk.Key().KeyNode.Line, fk.Key().KeyNode)
for k := range l.Parameters.Value.KeysFromOldest() {
l.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -111,8 +111,8 @@ func (l *Link) Hash() [32]byte {
if l.Server.Value != nil {
f = append(f, low.GenerateHashString(l.Server.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(l.Parameters.Value)); pair != nil; pair = pair.Next() {
f = append(f, pair.Value().Value)
for v := range orderedmap.SortAlpha(l.Parameters.Value).ValuesFromOldest() {
f = append(f, v.Value)
}
f = append(f, low.HashExtensions(l.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -107,8 +107,8 @@ func (mt *MediaType) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
}
if exps != nil && slices.Contains(root.Content, expsL) {
mt.Nodes.Store(expsL.Line, expsL)
for xj := exps.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range exps.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
mt.Examples = low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*base.Example]]]{
Value: exps,
@@ -130,8 +130,8 @@ func (mt *MediaType) Build(ctx context.Context, keyNode, root *yaml.Node, idx *i
ValueNode: encsN,
}
mt.Nodes.Store(encsL.Line, encsL)
for xj := encs.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range encs.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
return nil
@@ -146,11 +146,11 @@ func (mt *MediaType) Hash() [32]byte {
if mt.Example.Value != nil && !mt.Example.Value.IsZero() {
f = append(f, low.GenerateHashString(mt.Example.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(mt.Examples.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(mt.Examples.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(mt.Encoding.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(mt.Encoding.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(mt.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -146,8 +146,8 @@ func (o *OAuthFlow) Build(ctx context.Context, _, root *yaml.Node, idx *index.Sp
low.ExtractExtensionNodes(ctx, o.Extensions, o.Nodes)
if o.Scopes.Value != nil && o.Scopes.Value.Len() > 0 {
for fk := o.Scopes.Value.First(); fk != nil; fk = fk.Next() {
o.Nodes.Store(fk.Key().KeyNode.Line, fk.Key().KeyNode)
for k := range o.Scopes.Value.KeysFromOldest() {
o.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -167,8 +167,8 @@ func (o *OAuthFlow) Hash() [32]byte {
if !o.RefreshUrl.IsEmpty() {
f = append(f, o.RefreshUrl.Value)
}
for pair := orderedmap.First(orderedmap.SortAlpha(o.Scopes.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, sha256.Sum256([]byte(fmt.Sprint(pair.Value().Value)))))
for k, v := range orderedmap.SortAlpha(o.Scopes.Value).FromOldest() {
f = append(f, fmt.Sprintf("%s-%s", k.Value, sha256.Sum256([]byte(fmt.Sprint(v.Value)))))
}
f = append(f, low.HashExtensions(o.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -52,9 +52,9 @@ func (o *Operation) FindCallback(callback string) *low.ValueReference[*Callback]
func (o *Operation) FindSecurityRequirement(name string) []low.ValueReference[string] {
for k := range o.Security.Value {
requirements := o.Security.Value[k].Value.Requirements
for pair := orderedmap.First(requirements.Value); pair != nil; pair = pair.Next() {
if pair.Key().Value == name {
return pair.Value().Value
for k, v := range requirements.Value.FromOldest() {
if k.Value == name {
return v.Value
}
}
}
@@ -140,8 +140,8 @@ func (o *Operation) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
ValueNode: cbN,
}
o.Nodes.Store(cbL.Line, cbL)
for xj := callbacks.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range callbacks.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -242,8 +242,8 @@ func (o *Operation) Hash() [32]byte {
sort.Strings(keys)
f = append(f, keys...)
for pair := orderedmap.First(orderedmap.SortAlpha(o.Callbacks.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(o.Callbacks.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(o.Extensions)...)

View File

@@ -113,8 +113,8 @@ func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
ValueNode: expsN,
}
p.Nodes.Store(expsL.Line, expsL)
for xj := exps.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range exps.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -130,8 +130,8 @@ func (p *Parameter) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
}
if cL != nil {
p.Nodes.Store(cL.Line, cL)
for xj := con.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range con.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -164,11 +164,11 @@ func (p *Parameter) Hash() [32]byte {
if p.Example.Value != nil && !p.Example.Value.IsZero() {
f = append(f, low.GenerateHashString(p.Example.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(p.Examples.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(p.Examples.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(p.Content.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(p.Content.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(p.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -94,9 +94,9 @@ func (p *Paths) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.
p.PathItems = pathsMap
for pm := pathsMap.First(); pm != nil; pm = pm.Next() {
for k, v := range pathsMap.FromOldest() {
// add path as node to path item, not this path object.
pm.Value().Value.Nodes.Store(pm.Key().KeyNode.Line, pm.Key().KeyNode)
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
return nil
@@ -105,9 +105,7 @@ func (p *Paths) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.
// Hash will return a consistent SHA256 Hash of the PathItem object
func (p *Paths) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(p.PathItems)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
f = low.AppendMapHashes(f, p.PathItems)
f = append(f, low.HashExtensions(p.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -77,8 +77,8 @@ func (rb *RequestBody) Build(ctx context.Context, keyNode, root *yaml.Node, idx
ValueNode: cN,
}
rb.Nodes.Store(cL.Line, cL)
for xj := con.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range con.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
return nil
@@ -93,8 +93,8 @@ func (rb *RequestBody) Hash() [32]byte {
if !rb.Required.IsEmpty() {
f = append(f, fmt.Sprint(rb.Required.Value))
}
for pair := orderedmap.First(orderedmap.SortAlpha(rb.Content.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(rb.Content.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
f = append(f, low.HashExtensions(rb.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))

View File

@@ -6,7 +6,6 @@ package v3
import (
"context"
"crypto/sha256"
"fmt"
"strings"
"github.com/pb33f/libopenapi/datamodel/low"
@@ -91,8 +90,8 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
ValueNode: kN,
}
r.Nodes.Store(lN.Line, lN)
for xj := headers.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range headers.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -107,8 +106,8 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
ValueNode: cN,
}
r.Nodes.Store(clN.Line, clN)
for xj := con.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range con.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
@@ -124,8 +123,8 @@ func (r *Response) Build(ctx context.Context, keyNode, root *yaml.Node, idx *ind
ValueNode: linkValue,
}
r.Nodes.Store(linkLabel.Line, linkLabel)
for xj := links.First(); xj != nil; xj = xj.Next() {
xj.Value().Value.Nodes.Store(xj.Key().KeyNode.Line, xj.Key().KeyNode)
for k, v := range links.FromOldest() {
v.Value.Nodes.Store(k.KeyNode.Line, k.KeyNode)
}
}
return nil
@@ -137,15 +136,9 @@ func (r *Response) Hash() [32]byte {
if r.Description.Value != "" {
f = append(f, r.Description.Value)
}
for pair := orderedmap.First(orderedmap.SortAlpha(r.Headers.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
for pair := orderedmap.First(orderedmap.SortAlpha(r.Content.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
for pair := orderedmap.First(orderedmap.SortAlpha(r.Links.Value)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
f = low.AppendMapHashes(f, r.Headers.Value)
f = low.AppendMapHashes(f, r.Content.Value)
f = low.AppendMapHashes(f, r.Links.Value)
f = append(f, low.HashExtensions(r.Extensions)...)
return sha256.Sum256([]byte(strings.Join(f, "|")))
}

View File

@@ -76,8 +76,7 @@ func (r *Responses) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
}
if codes != nil {
r.Codes = codes
for codePairs := codes.First(); codePairs != nil; codePairs = codePairs.Next() {
code := codePairs.Key()
for code := range codes.KeysFromOldest() {
r.Nodes.Store(code.KeyNode.Line, code.KeyNode)
}
}
@@ -98,12 +97,12 @@ func (r *Responses) Build(ctx context.Context, keyNode, root *yaml.Node, idx *in
}
func (r *Responses) getDefault() *low.NodeReference[*Response] {
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
if strings.ToLower(pair.Key().Value) == DefaultLabel {
for code, resp := range r.Codes.FromOldest() {
if strings.ToLower(code.Value) == DefaultLabel {
return &low.NodeReference[*Response]{
ValueNode: pair.Value().ValueNode,
KeyNode: pair.Key().KeyNode,
Value: pair.Value().Value,
ValueNode: resp.ValueNode,
KeyNode: code.KeyNode,
Value: resp.Value,
}
}
}
@@ -133,9 +132,7 @@ func (r *Responses) FindResponseByCode(code string) *low.ValueReference[*Respons
// Hash will return a consistent SHA256 Hash of the Examples object
func (r *Responses) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(r.Codes)); pair != nil; pair = pair.Next() {
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
}
f = low.AppendMapHashes(f, r.Codes)
if !r.Default.IsEmpty() {
f = append(f, low.GenerateHashString(r.Default.Value))
}

View File

@@ -100,8 +100,8 @@ func (s *Server) Build(ctx context.Context, keyNode, root *yaml.Node, _ *index.S
// Hash will return a consistent SHA256 Hash of the Server object
func (s *Server) Hash() [32]byte {
var f []string
for pair := orderedmap.First(orderedmap.SortAlpha(s.Variables.Value)); pair != nil; pair = pair.Next() {
f = append(f, low.GenerateHashString(pair.Value().Value))
for v := range orderedmap.SortAlpha(s.Variables.Value).ValuesFromOldest() {
f = append(f, low.GenerateHashString(v.Value))
}
if !s.URL.IsEmpty() {
f = append(f, s.URL.Value)

View File

@@ -52,9 +52,9 @@ variables:
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
// check nodes on variables
for k := n.Variables.Value.First(); k != nil; k = k.Next() {
assert.NotNil(t, k.Value().Value.GetKeyNode())
assert.NotNil(t, k.Value().Value.GetRootNode())
for v := range n.Variables.Value.ValuesFromOldest() {
assert.NotNil(t, v.Value.GetKeyNode())
assert.NotNil(t, v.Value.GetRootNode())
}
}

View File

@@ -2,6 +2,7 @@ package libopenapi
import (
"os"
"slices"
"strings"
"testing"
@@ -10,7 +11,6 @@ import (
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
"github.com/pb33f/libopenapi/orderedmap"
"github.com/stretchr/testify/require"
"slices"
)
type loopFrame struct {
@@ -38,31 +38,27 @@ func Test_Speakeasy_Document_Iteration(t *testing.T) {
m, errs := doc.BuildV3Model()
require.Empty(t, errs)
for pair := orderedmap.First(m.Model.Paths.PathItems); pair != nil; pair = pair.Next() {
path := pair.Key()
for path, pathItem := range m.Model.Paths.PathItems.FromOldest() {
t.Log(path)
iterateOperations(t, pair.Value().GetOperations())
iterateOperations(t, pathItem.GetOperations())
}
for pair := orderedmap.First(m.Model.Webhooks); pair != nil; pair = pair.Next() {
t.Log(pair.Key())
for path, pathItem := range m.Model.Webhooks.FromOldest() {
t.Log(path)
iterateOperations(t, pair.Value().GetOperations())
iterateOperations(t, pathItem.GetOperations())
}
for pair := orderedmap.First(m.Model.Components.Schemas); pair != nil; pair = pair.Next() {
t.Log(pair.Key())
for name, schemaProxy := range m.Model.Components.Schemas.FromOldest() {
t.Log(name)
handleSchema(t, pair.Value(), context{})
handleSchema(t, schemaProxy, context{})
}
}
func iterateOperations(t *testing.T, ops *orderedmap.Map[string, *v3.Operation]) {
for pair := orderedmap.First(ops); pair != nil; pair = pair.Next() {
method := pair.Key()
op := pair.Value()
for method, op := range ops.FromOldest() {
t.Log(method)
for i, param := range op.Parameters {
@@ -76,10 +72,8 @@ func iterateOperations(t *testing.T, ops *orderedmap.Map[string, *v3.Operation])
if op.RequestBody != nil {
t.Log("request body")
for pair := orderedmap.First(op.RequestBody.Content); pair != nil; pair = pair.Next() {
t.Log(pair.Key())
mediaType := pair.Value()
for contentType, mediaType := range op.RequestBody.Content.FromOldest() {
t.Log(contentType)
if mediaType.Schema != nil {
handleSchema(t, mediaType.Schema, context{})
@@ -91,13 +85,11 @@ func iterateOperations(t *testing.T, ops *orderedmap.Map[string, *v3.Operation])
t.Log("responses")
}
for codePair := orderedmap.First(op.Responses.Codes); codePair != nil; codePair = codePair.Next() {
t.Log(codePair.Key())
for code, response := range op.Responses.Codes.FromOldest() {
t.Log(code)
for contentPair := orderedmap.First(codePair.Value().Content); contentPair != nil; contentPair = contentPair.Next() {
t.Log(contentPair.Key())
mediaType := contentPair.Value()
for contentType, mediaType := range response.Content.FromOldest() {
t.Log(contentType)
if mediaType.Schema != nil {
handleSchema(t, mediaType.Schema, context{})
@@ -109,13 +101,13 @@ func iterateOperations(t *testing.T, ops *orderedmap.Map[string, *v3.Operation])
t.Log("callbacks")
}
for callacksPair := orderedmap.First(op.Callbacks); callacksPair != nil; callacksPair = callacksPair.Next() {
t.Log(callacksPair.Key())
for callbackName, callback := range op.Callbacks.FromOldest() {
t.Log(callbackName)
for expressionPair := orderedmap.First(callacksPair.Value().Expression); expressionPair != nil; expressionPair = expressionPair.Next() {
t.Log(expressionPair.Key())
for name, pathItem := range callback.Expression.FromOldest() {
t.Log(name)
iterateOperations(t, expressionPair.Value().GetOperations())
iterateOperations(t, pathItem.GetOperations())
}
}
}
@@ -252,9 +244,9 @@ func handleArray(t *testing.T, sch *base.Schema, ctx context) {
}
func handleObject(t *testing.T, sch *base.Schema, ctx context) {
for pair := orderedmap.First(sch.Properties); pair != nil; pair = pair.Next() {
ctx.stack = append(ctx.stack, loopFrame{Type: "object", Restricted: slices.Contains(sch.Required, pair.Key())})
handleSchema(t, pair.Value(), ctx)
for name, schemaProxy := range sch.Properties.FromOldest() {
ctx.stack = append(ctx.stack, loopFrame{Type: "object", Restricted: slices.Contains(sch.Required, name)})
handleSchema(t, schemaProxy, ctx)
}
if sch.AdditionalProperties != nil && sch.AdditionalProperties.IsA() {

View File

@@ -1021,9 +1021,9 @@ func TestDocument_Render_PreserveOrder(t *testing.T) {
require.Equal(t, itemCount, orderedmap.Len(pathItems))
var i int
for pair := orderedmap.First(model.Model.Paths.PathItems); pair != nil; pair = pair.Next() {
for path := range model.Model.Paths.PathItems.KeysFromOldest() {
pathName := fmt.Sprintf("/foobar/%d", i)
assert.Equal(t, pathName, pair.Key())
assert.Equal(t, pathName, path)
i++
}
assert.Equal(t, itemCount, i)
@@ -1085,9 +1085,9 @@ func TestDocument_Render_PreserveOrder(t *testing.T) {
responses := pathItem.Get.Responses
var i int
for pair := orderedmap.First(responses.Codes); pair != nil; pair = pair.Next() {
for code := range responses.Codes.KeysFromOldest() {
expectedCode := strconv.Itoa(200 + i)
assert.Equal(t, expectedCode, pair.Key())
assert.Equal(t, expectedCode, code)
i++
}
assert.Equal(t, itemCount, i)
@@ -1180,9 +1180,8 @@ func TestDocument_Render_PreserveOrder(t *testing.T) {
mediaTypeResp := respCode.Content.GetOrZero(mediaType)
var i int
for pair := orderedmap.First(mediaTypeResp.Examples); pair != nil; pair = pair.Next() {
assert.Equal(t, fmt.Sprintf("FoobarExample%d", i), pair.Key())
example := pair.Value()
for exampleName, example := range mediaTypeResp.Examples.FromOldest() {
assert.Equal(t, fmt.Sprintf("FoobarExample%d", i), exampleName)
assert.Equal(t, fmt.Sprintf("Summary example %d", i), example.Summary)
i++
}
@@ -1356,7 +1355,6 @@ func TestDocument_TestNestedFiles(t *testing.T) {
}
func TestDocument_Issue264(t *testing.T) {
openAPISpec := `{"openapi":"3.0.0","info":{"title":"dummy","version":"1.0.0"},"paths":{"/dummy":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"value":{"type":"number","format":"decimal","multipleOf":0.01,"minimum":-999.99}}}}}},"responses":{"200":{"description":"OK"}}}}}}`
d, _ := NewDocument([]byte(openAPISpec))
@@ -1369,7 +1367,6 @@ func TestDocument_Issue264(t *testing.T) {
}
func TestDocument_Issue269(t *testing.T) {
spec := `openapi: "3.0.0"
info:
title: test
@@ -1390,5 +1387,4 @@ components:
}
_, errs := doc.BuildV3Model()
assert.Len(t, errs, 0)
}

4
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/pb33f/libopenapi
go 1.21
go 1.23
require (
github.com/lucasjones/reggen v0.0.0-20200904144131-37ba4fa293bb
@@ -19,3 +19,5 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)
replace github.com/wk8/go-ordered-map/v2 => github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283

4
go.sum
View File

@@ -60,6 +60,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283 h1:QPZc0Mne/K4/R0giVVay0YODjMwP/BMSpYnQm5kWBgE=
github.com/speakeasy-api/go-ordered-map/v2 v2.0.0-20240813202817-2f1629387283/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -67,8 +69,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=

View File

@@ -7,6 +7,7 @@ package orderedmap
import (
"context"
"fmt"
"iter"
"reflect"
"slices"
"strings"
@@ -74,6 +75,102 @@ func (o *Map[K, V]) First() Pair[K, V] {
}
}
// FromOldest returns an iterator that yields the oldest key-value pair in the map.
func (o *Map[K, V]) FromOldest() iter.Seq2[K, V] {
return func(yield func(K, V) bool) {
if o == nil {
return
}
for k, v := range o.OrderedMap.FromOldest() {
if !yield(k, v) {
return
}
}
}
}
// FromNewest returns an iterator that yields the newest key-value pair in the map.
func (o *Map[K, V]) FromNewest() iter.Seq2[K, V] {
o.OrderedMap.FromNewest()
return func(yield func(K, V) bool) {
if o == nil {
return
}
for k, v := range o.OrderedMap.FromNewest() {
if !yield(k, v) {
return
}
}
}
}
// FromNewest returns an iterator that yields the newest key-value pair in the map.
func (o *Map[K, V]) KeysFromOldest() iter.Seq[K] {
return func(yield func(K) bool) {
if o == nil {
return
}
for k := range o.OrderedMap.KeysFromOldest() {
if !yield(k) {
return
}
}
}
}
// KeysFromNewest returns an iterator that yields the newest key in the map.
func (o *Map[K, V]) KeysFromNewest() iter.Seq[K] {
return func(yield func(K) bool) {
if o == nil {
return
}
for k := range o.OrderedMap.KeysFromNewest() {
if !yield(k) {
return
}
}
}
}
// ValuesFromOldest returns an iterator that yields the oldest value in the map.
func (o *Map[K, V]) ValuesFromOldest() iter.Seq[V] {
return func(yield func(V) bool) {
if o == nil {
return
}
for v := range o.OrderedMap.ValuesFromOldest() {
if !yield(v) {
return
}
}
}
}
// ValuesFromNewest returns an iterator that yields the newest value in the map.
func (o *Map[K, V]) ValuesFromNewest() iter.Seq[V] {
return func(yield func(V) bool) {
if o == nil {
return
}
for v := range o.OrderedMap.ValuesFromNewest() {
if !yield(v) {
return
}
}
}
}
// From creates a new ordered map from an iterator.
func From[K comparable, V any](iter iter.Seq2[K, V]) *Map[K, V] {
return &Map[K, V]{
OrderedMap: wk8orderedmap.From(iter),
}
}
// NewPair instantiates a `Pair` object for use with `FromPairs()`.
func NewPair[K comparable, V any](key K, value V) Pair[K, V] {
return &wrapPair[K, V]{

View File

@@ -364,6 +364,120 @@ func TestFromPairs(t *testing.T) {
})
}
func TestIterators(t *testing.T) {
om := orderedmap.New[int, any]()
om.Set(1, "bar")
om.Set(2, 28)
om.Set(3, 100)
om.Set(4, "baz")
om.Set(5, "28")
om.Set(6, "100")
om.Set(7, "baz")
om.Set(8, "baz")
expectedKeys := []int{1, 2, 3, 4, 5, 6, 7, 8}
expectedKeysFromNewest := []int{8, 7, 6, 5, 4, 3, 2, 1}
expectedValues := []any{"bar", 28, 100, "baz", "28", "100", "baz", "baz"}
expectedValuesFromNewest := []any{"baz", "baz", "100", "28", "baz", 100, 28, "bar"}
var keys []int
var values []any
for k, v := range om.FromOldest() {
keys = append(keys, k)
values = append(values, v)
}
assert.Equal(t, expectedKeys, keys)
assert.Equal(t, expectedValues, values)
keys, values = []int{}, []any{}
for k, v := range om.FromNewest() {
keys = append(keys, k)
values = append(values, v)
}
assert.Equal(t, expectedKeysFromNewest, keys)
assert.Equal(t, expectedValuesFromNewest, values)
keys = []int{}
for k := range om.KeysFromOldest() {
keys = append(keys, k)
}
assert.Equal(t, expectedKeys, keys)
keys = []int{}
for k := range om.KeysFromNewest() {
keys = append(keys, k)
}
assert.Equal(t, expectedKeysFromNewest, keys)
values = []any{}
for v := range om.ValuesFromOldest() {
values = append(values, v)
}
assert.Equal(t, expectedValues, values)
values = []any{}
for v := range om.ValuesFromNewest() {
values = append(values, v)
}
assert.Equal(t, expectedValuesFromNewest, values)
}
func TestIteratorsFrom(t *testing.T) {
om := orderedmap.New[int, any]()
om.Set(1, "bar")
om.Set(2, 28)
om.Set(3, 100)
om.Set(4, "baz")
om.Set(5, "28")
om.Set(6, "100")
om.Set(7, "baz")
om.Set(8, "baz")
om2 := orderedmap.From(om.FromOldest())
expectedKeys := []int{1, 2, 3, 4, 5, 6, 7, 8}
expectedValues := []any{"bar", 28, 100, "baz", "28", "100", "baz", "baz"}
var keys []int
var values []any
for k, v := range om2.FromOldest() {
keys = append(keys, k)
values = append(values, v)
}
assert.Equal(t, expectedKeys, keys)
assert.Equal(t, expectedValues, values)
expectedKeysFromNewest := []int{8, 7, 6, 5, 4, 3, 2, 1}
expectedValuesFromNewest := []any{"baz", "baz", "100", "28", "baz", 100, 28, "bar"}
om2 = orderedmap.From(om.FromNewest())
keys = []int{}
values = []any{}
for k, v := range om2.FromOldest() {
keys = append(keys, k)
values = append(values, v)
}
assert.Equal(t, expectedKeysFromNewest, keys)
assert.Equal(t, expectedValuesFromNewest, values)
}
func requireClosed[K comparable, V any](t *testing.T, c <-chan orderedmap.Pair[K, V]) {
select {
case pair := <-c:

View File

@@ -128,16 +128,14 @@ func (mg *MockGenerator) GenerateMock(mock any, name string) ([]byte, error) {
examplesMap := examplesValue.(*orderedmap.Map[string, *highbase.Example])
// if the name is not empty, try and find the example by name
for pair := orderedmap.First(examplesMap); pair != nil; pair = pair.Next() {
k, exp := pair.Key(), pair.Value()
for k, exp := range examplesMap.FromOldest() {
if k == name {
return mg.renderMock(exp.Value), nil
}
}
// if the name is empty, just return the first example
for pair := orderedmap.First(examplesMap); pair != nil; pair = pair.Next() {
exp := pair.Value()
for exp := range examplesMap.ValuesFromOldest() {
return mg.renderMock(exp.Value), nil
}
}

View File

@@ -10,13 +10,13 @@ import (
"io"
"math/rand"
"os"
"slices"
"strings"
"time"
"github.com/lucasjones/reggen"
"github.com/pb33f/libopenapi/datamodel/high/base"
"github.com/pb33f/libopenapi/orderedmap"
"slices"
)
const (
@@ -305,9 +305,8 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
} else {
checkProps = properties
}
for pair := orderedmap.First(checkProps); pair != nil; pair = pair.Next() {
for propName, propValue := range checkProps.FromOldest() {
// render property
propName, propValue := pair.Key(), pair.Value()
propertySchema := propValue.Schema()
wr.DiveIntoSchema(propertySchema, propName, propertyMap, depth+1)
}
@@ -335,9 +334,8 @@ func (wr *SchemaRenderer) DiveIntoSchema(schema *base.Schema, key string, struct
dependentSchemas := schema.DependentSchemas
if dependentSchemas != nil {
dependentSchemasMap := make(map[string]any)
for pair := orderedmap.First(dependentSchemas); pair != nil; pair = pair.Next() {
for k, dependentSchema := range dependentSchemas.FromOldest() {
// only map if the property exists
k, dependentSchema := pair.Key(), pair.Value()
if propertyMap[k] != nil {
dependentSchemaCompiled := dependentSchema.Schema()
wr.DiveIntoSchema(dependentSchemaCompiled, k, dependentSchemasMap, depth+1)

View File

@@ -6,7 +6,6 @@ package model
import (
"github.com/pb33f/libopenapi/datamodel/low"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
)
// CallbackChanges represents all changes made between two Callback OpenAPI objects.
@@ -65,14 +64,14 @@ func CompareCallback(l, r *v3.Callback) *CallbackChanges {
lValues := make(map[string]low.ValueReference[*v3.PathItem])
rValues := make(map[string]low.ValueReference[*v3.PathItem])
for pair := orderedmap.First(l.Expression); pair != nil; pair = pair.Next() {
lHashes[pair.Key().Value] = low.GenerateHashString(pair.Value().Value)
lValues[pair.Key().Value] = pair.Value()
for k, v := range l.Expression.FromOldest() {
lHashes[k.Value] = low.GenerateHashString(v.Value)
lValues[k.Value] = v
}
for pair := orderedmap.First(r.Expression); pair != nil; pair = pair.Next() {
rHashes[pair.Key().Value] = low.GenerateHashString(pair.Value().Value)
rValues[pair.Key().Value] = pair.Value()
for k, v := range r.Expression.FromOldest() {
rHashes[k.Value] = low.GenerateHashString(v.Value)
rValues[k.Value] = v
}
expChanges := make(map[string]*PathItemChanges)

View File

@@ -75,9 +75,7 @@ func FlattenLowLevelOrderedMap[T any](
) map[string]*low.ValueReference[T] {
flat := make(map[string]*low.ValueReference[T])
for pair := orderedmap.First(lowMap); pair != nil; pair = pair.Next() {
k := pair.Key()
l := pair.Value()
for k, l := range lowMap.FromOldest() {
flat[k.Value] = &l
}
return flat
@@ -276,16 +274,14 @@ func CheckMapForChangesWithComp[T any, R any](expLeft, expRight *orderedmap.Map[
lValues := make(map[string]low.ValueReference[T])
rValues := make(map[string]low.ValueReference[T])
for pair := orderedmap.First(expLeft); pair != nil; pair = pair.Next() {
k := pair.Key()
lHashes[k.Value] = low.GenerateHashString(pair.Value().Value)
lValues[k.Value] = pair.Value()
for k, v := range expLeft.FromOldest() {
lHashes[k.Value] = low.GenerateHashString(v.Value)
lValues[k.Value] = v
}
for pair := orderedmap.First(expRight); pair != nil; pair = pair.Next() {
k := pair.Key()
rHashes[k.Value] = low.GenerateHashString(pair.Value().Value)
rValues[k.Value] = pair.Value()
for k, v := range expRight.FromOldest() {
rHashes[k.Value] = low.GenerateHashString(v.Value)
rValues[k.Value] = v
}
expChanges := make(map[string]R)

View File

@@ -6,7 +6,6 @@ package model
import (
"github.com/pb33f/libopenapi/datamodel/low"
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
"github.com/pb33f/libopenapi/orderedmap"
"gopkg.in/yaml.v3"
)
@@ -38,14 +37,14 @@ func CompareExamplesV2(l, r *v2.Examples) *ExamplesChanges {
lValues := make(map[string]low.ValueReference[*yaml.Node])
rValues := make(map[string]low.ValueReference[*yaml.Node])
for pair := orderedmap.First(l.Values); pair != nil; pair = pair.Next() {
lHashes[pair.Key().Value] = low.GenerateHashString(pair.Value().Value)
lValues[pair.Key().Value] = pair.Value()
for k, v := range l.Values.FromOldest() {
lHashes[k.Value] = low.GenerateHashString(v.Value)
lValues[k.Value] = v
}
for pair := orderedmap.First(r.Values); pair != nil; pair = pair.Next() {
rHashes[pair.Key().Value] = low.GenerateHashString(pair.Value().Value)
rValues[pair.Key().Value] = pair.Value()
for k, v := range r.Values.FromOldest() {
rHashes[k.Value] = low.GenerateHashString(v.Value)
rValues[k.Value] = v
}
var changes []*Change

View File

@@ -42,13 +42,11 @@ func CompareExtensions(l, r *orderedmap.Map[low.KeyReference[string], low.ValueR
seenLeft := make(map[string]*low.ValueReference[*yaml.Node])
seenRight := make(map[string]*low.ValueReference[*yaml.Node])
for pair := orderedmap.First(l); pair != nil; pair = pair.Next() {
h := pair.Value()
seenLeft[strings.ToLower(pair.Key().Value)] = &h
for k, h := range l.FromOldest() {
seenLeft[strings.ToLower(k.Value)] = &h
}
for pair := orderedmap.First(r); pair != nil; pair = pair.Next() {
h := pair.Value()
seenRight[strings.ToLower(pair.Key().Value)] = &h
for k, h := range r.FromOldest() {
seenRight[strings.ToLower(k.Value)] = &h
}
var changes []*Change

View File

@@ -6,7 +6,6 @@ package model
import (
"github.com/pb33f/libopenapi/datamodel/low"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
)
// LinkChanges represent changes made between two OpenAPI Link Objects.
@@ -128,11 +127,11 @@ func CompareLinks(l, r *v3.Link) *LinkChanges {
// parameters
lValues := make(map[string]low.ValueReference[string])
rValues := make(map[string]low.ValueReference[string])
for pair := orderedmap.First(l.Parameters.Value); pair != nil; pair = pair.Next() {
lValues[pair.Key().Value] = pair.Value()
for k, v := range l.Parameters.Value.FromOldest() {
lValues[k.Value] = v
}
for pair := orderedmap.First(r.Parameters.Value); pair != nil; pair = pair.Next() {
rValues[pair.Key().Value] = pair.Value()
for k, v := range r.Parameters.Value.FromOldest() {
rValues[k.Value] = v
}
for k := range lValues {
if _, ok := rValues[k]; !ok {

View File

@@ -6,7 +6,6 @@ package model
import (
"github.com/pb33f/libopenapi/datamodel/low"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
)
// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects.
@@ -229,26 +228,22 @@ func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges {
CheckProperties(props)
for pair := orderedmap.First(l.Scopes.Value); pair != nil; pair = pair.Next() {
if r != nil && r.FindScope(pair.Key().Value) == nil {
CreateChange(&changes, ObjectRemoved, v3.Scopes,
pair.Value().ValueNode, nil, true,
pair.Key().Value, nil)
for k, v := range l.Scopes.Value.FromOldest() {
if r != nil && r.FindScope(k.Value) == nil {
CreateChange(&changes, ObjectRemoved, v3.Scopes, v.ValueNode, nil, true, k.Value, nil)
continue
}
if r != nil && r.FindScope(pair.Key().Value) != nil {
if pair.Value().Value != r.FindScope(pair.Key().Value).Value {
if r != nil && r.FindScope(k.Value) != nil {
if v.Value != r.FindScope(k.Value).Value {
CreateChange(&changes, Modified, v3.Scopes,
pair.Value().ValueNode, r.FindScope(pair.Key().Value).ValueNode, true,
pair.Value().Value, r.FindScope(pair.Key().Value).Value)
v.ValueNode, r.FindScope(k.Value).ValueNode, true,
v.Value, r.FindScope(k.Value).Value)
}
}
}
for pair := orderedmap.First(r.Scopes.Value); pair != nil; pair = pair.Next() {
if l != nil && l.FindScope(pair.Key().Value) == nil {
CreateChange(&changes, ObjectAdded, v3.Scopes,
nil, pair.Value().ValueNode, false,
nil, pair.Key().Value)
for k, v := range r.Scopes.Value.FromOldest() {
if l != nil && l.FindScope(k.Value) == nil {
CreateChange(&changes, ObjectAdded, v3.Scopes, nil, v.ValueNode, false, nil, k.Value)
}
}
oa := new(OAuthFlowChanges)

View File

@@ -77,16 +77,16 @@ func ComparePaths(l, r any) *PathsChanges {
lKeys := make(map[string]low.ValueReference[*v2.PathItem])
rKeys := make(map[string]low.ValueReference[*v2.PathItem])
for pair := orderedmap.First(lPath.PathItems); pair != nil; pair = pair.Next() {
lKeys[pair.Key().Value] = pair.Value()
for k, v := range lPath.PathItems.FromOldest() {
lKeys[k.Value] = v
}
for pair := orderedmap.First(rPath.PathItems); pair != nil; pair = pair.Next() {
rKeys[pair.Key().Value] = pair.Value()
for k, v := range rPath.PathItems.FromOldest() {
rKeys[k.Value] = v
}
// run every comparison in a thread.
var mLock sync.Mutex
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
compare := func(path string, _ map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
if !low.AreEqual(l, r) {
mLock.Lock()
pathChanges[path] = ComparePathItems(l, r)
@@ -147,20 +147,16 @@ func ComparePaths(l, r any) *PathsChanges {
lKeys := make(map[string]low.ValueReference[*v3.PathItem])
rKeys := make(map[string]low.ValueReference[*v3.PathItem])
if lPath != nil {
for pair := orderedmap.First(lPath.PathItems); pair != nil; pair = pair.Next() {
lKeys[pair.Key().Value] = pair.Value()
}
}
if rPath != nil {
for pair := orderedmap.First(rPath.PathItems); pair != nil; pair = pair.Next() {
rKeys[pair.Key().Value] = pair.Value()
for k, v := range lPath.PathItems.FromOldest() {
lKeys[k.Value] = v
}
for k, v := range rPath.PathItems.FromOldest() {
rKeys[k.Value] = v
}
// run every comparison in a thread.
var mLock sync.Mutex
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
compare := func(path string, _ map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
if !low.AreEqual(l, r) {
mLock.Lock()
pathChanges[path] = ComparePathItems(l, r)

View File

@@ -5,11 +5,10 @@ package model
import (
"fmt"
"slices"
"sort"
"sync"
"slices"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
@@ -466,15 +465,15 @@ func checkMappedSchemaOfASchema(
rEntities := make(map[string]*base.SchemaProxy)
rKeyNodes := make(map[string]*yaml.Node)
for pair := orderedmap.First(lSchema); pair != nil; pair = pair.Next() {
lProps = append(lProps, pair.Key().Value)
lEntities[pair.Key().Value] = pair.Value().Value
lKeyNodes[pair.Key().Value] = pair.Key().KeyNode
for k, v := range lSchema.FromOldest() {
lProps = append(lProps, k.Value)
lEntities[k.Value] = v.Value
lKeyNodes[k.Value] = k.KeyNode
}
for pair := orderedmap.First(rSchema); pair != nil; pair = pair.Next() {
rProps = append(rProps, pair.Key().Value)
rEntities[pair.Key().Value] = pair.Value().Value
rKeyNodes[pair.Key().Value] = pair.Key().KeyNode
for k, v := range rSchema.FromOldest() {
rProps = append(rProps, k.Value)
rEntities[k.Value] = v.Value
rKeyNodes[k.Value] = k.KeyNode
}
sort.Strings(lProps)
sort.Strings(rProps)

View File

@@ -7,7 +7,6 @@ import (
"github.com/pb33f/libopenapi/datamodel/low"
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
"github.com/pb33f/libopenapi/orderedmap"
)
// ScopesChanges represents changes between two Swagger Scopes Objects
@@ -47,26 +46,26 @@ func CompareScopes(l, r *v2.Scopes) *ScopesChanges {
return nil
}
var changes []*Change
for pair := orderedmap.First(l.Values); pair != nil; pair = pair.Next() {
if r != nil && r.FindScope(pair.Key().Value) == nil {
for k, v := range l.Values.FromOldest() {
if r != nil && r.FindScope(k.Value) == nil {
CreateChange(&changes, ObjectRemoved, v3.Scopes,
pair.Value().ValueNode, nil, true,
pair.Key().Value, nil)
v.ValueNode, nil, true,
k.Value, nil)
continue
}
if r != nil && r.FindScope(pair.Key().Value) != nil {
if pair.Value().Value != r.FindScope(pair.Key().Value).Value {
if r != nil && r.FindScope(k.Value) != nil {
if v.Value != r.FindScope(k.Value).Value {
CreateChange(&changes, Modified, v3.Scopes,
pair.Value().ValueNode, r.FindScope(pair.Key().Value).ValueNode, true,
pair.Value().Value, r.FindScope(pair.Key().Value).Value)
v.ValueNode, r.FindScope(k.Value).ValueNode, true,
v.Value, r.FindScope(k.Value).Value)
}
}
}
for pair := orderedmap.First(r.Values); pair != nil; pair = pair.Next() {
if l != nil && l.FindScope(pair.Key().Value) == nil {
for k, v := range r.Values.FromOldest() {
if l != nil && l.FindScope(k.Value) == nil {
CreateChange(&changes, ObjectAdded, v3.Scopes,
nil, pair.Value().ValueNode, false,
nil, pair.Key().Value)
nil, v.ValueNode, false,
nil, k.Value)
}
}

View File

@@ -64,14 +64,14 @@ func checkSecurityRequirement(lSec, rSec *orderedmap.Map[low.KeyReference[string
lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
var n, z int
for pair := orderedmap.First(lSec); pair != nil; pair = pair.Next() {
lKeys[n] = pair.Key().Value
lValues[pair.Key().Value] = pair.Value()
for k, v := range lSec.FromOldest() {
lKeys[n] = k.Value
lValues[k.Value] = v
n++
}
for pair := orderedmap.First(rSec); pair != nil; pair = pair.Next() {
rKeys[z] = pair.Key().Value
rValues[pair.Key().Value] = pair.Value()
for k, v := range rSec.FromOldest() {
rKeys[z] = k.Value
rValues[k.Value] = v
z++
}