From 059078ed1b4c7491976090680f636f12eef19fb5 Mon Sep 17 00:00:00 2001 From: Tristan Cartledge Date: Wed, 14 Aug 2024 12:10:07 +0100 Subject: [PATCH] chore: update to use iterators on orderedmaps --- datamodel/high/base/discriminator.go | 19 ++-- datamodel/high/base/example.go | 19 ++-- datamodel/high/base/schema.go | 14 +-- datamodel/high/base/security_requirement.go | 18 ++-- datamodel/high/node_builder.go | 12 +-- datamodel/high/node_builder_test.go | 11 +- datamodel/high/shared.go | 13 +-- datamodel/high/v2/examples.go | 15 ++- datamodel/high/v2/path_item_test.go | 8 +- datamodel/high/v2/response.go | 15 ++- datamodel/high/v2/scopes.go | 15 ++- datamodel/high/v3/callback.go | 35 +++--- datamodel/high/v3/document.go | 15 ++- datamodel/high/v3/document_test.go | 9 +- datamodel/high/v3/encoding.go | 17 ++- datamodel/high/v3/header.go | 17 ++- datamodel/high/v3/link.go | 15 ++- datamodel/high/v3/oauth_flow.go | 15 ++- datamodel/high/v3/operation.go | 15 ++- datamodel/high/v3/path_item_test.go | 13 ++- datamodel/high/v3/paths.go | 20 ++-- datamodel/high/v3/response.go | 15 ++- datamodel/high/v3/responses.go | 24 ++--- datamodel/high/v3/server.go | 15 ++- datamodel/low/base/discriminator.go | 12 +-- datamodel/low/base/schema.go | 14 +-- datamodel/low/base/security_requirement.go | 20 ++-- datamodel/low/extraction_functions.go | 33 +++++- datamodel/low/extraction_functions_test.go | 50 ++++++--- datamodel/low/model_builder_test.go | 13 ++- datamodel/low/node_map.go | 13 +-- datamodel/low/v2/definitions.go | 4 +- datamodel/low/v2/examples.go | 4 +- datamodel/low/v2/paths.go | 4 +- datamodel/low/v2/response.go | 4 +- datamodel/low/v2/responses.go | 14 ++- datamodel/low/v2/scopes.go | 4 +- datamodel/low/v3/callback.go | 8 +- datamodel/low/v3/components.go | 8 +- datamodel/low/v3/create_document.go | 7 +- datamodel/low/v3/create_document_test.go | 9 +- datamodel/low/v3/document.go | 6 +- datamodel/low/v3/encoding.go | 8 +- datamodel/low/v3/header.go | 18 +++- datamodel/low/v3/link.go | 8 +- datamodel/low/v3/media_type.go | 16 +-- datamodel/low/v3/oauth_flows.go | 8 +- datamodel/low/v3/operation.go | 14 +-- datamodel/low/v3/parameter.go | 16 +-- datamodel/low/v3/paths.go | 8 +- datamodel/low/v3/request_body.go | 8 +- datamodel/low/v3/response.go | 25 ++--- datamodel/low/v3/responses.go | 17 ++- datamodel/low/v3/server.go | 4 +- datamodel/low/v3/server_test.go | 6 +- document_iteration_test.go | 56 +++++----- document_test.go | 16 ++- go.mod | 4 +- go.sum | 4 +- orderedmap/orderedmap.go | 97 +++++++++++++++++ orderedmap/orderedmap_test.go | 114 ++++++++++++++++++++ renderer/mock_generator.go | 6 +- renderer/schema_renderer.go | 8 +- what-changed/model/callback.go | 13 ++- what-changed/model/comparison_functions.go | 18 ++-- what-changed/model/examples.go | 13 ++- what-changed/model/extensions.go | 10 +- what-changed/model/link.go | 9 +- what-changed/model/oauth_flows.go | 25 ++--- what-changed/model/paths.go | 24 ++--- what-changed/model/schema.go | 19 ++-- what-changed/model/scopes.go | 25 +++-- what-changed/model/security_requirement.go | 12 +-- 73 files changed, 690 insertions(+), 550 deletions(-) diff --git a/datamodel/high/base/discriminator.go b/datamodel/high/base/discriminator.go index c8d1408b..4e11f3be 100644 --- a/datamodel/high/base/discriminator.go +++ b/datamodel/high/base/discriminator.go @@ -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 } diff --git a/datamodel/high/base/example.go b/datamodel/high/base/example.go index e1985a4f..e452bde3 100644 --- a/datamodel/high/base/example.go +++ b/datamodel/high/base/example.go @@ -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) } diff --git a/datamodel/high/base/schema.go b/datamodel/high/base/schema.go index 4a02ae7d..6b090b11 100644 --- a/datamodel/high/base/schema.go +++ b/datamodel/high/base/schema.go @@ -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 diff --git a/datamodel/high/base/security_requirement.go b/datamodel/high/base/security_requirement.go index 9e0881c9..5aea9e70 100644 --- a/datamodel/high/base/security_requirement.go +++ b/datamodel/high/base/security_requirement.go @@ -21,9 +21,9 @@ import ( // The name used for each property MUST correspond to a security scheme declared in the Security Definitions // - https://swagger.io/specification/v2/#securityDefinitionsObject type SecurityRequirement struct { - Requirements *orderedmap.Map[string, []string] `json:"-" yaml:"-"` - ContainsEmptyRequirement bool // if a requirement is empty (this means it's optional) - low *base.SecurityRequirement + Requirements *orderedmap.Map[string, []string] `json:"-" yaml:"-"` + ContainsEmptyRequirement bool // if a requirement is empty (this means it's optional) + low *base.SecurityRequirement } // NewSecurityRequirement creates a new high-level SecurityRequirement from a low-level one. @@ -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 diff --git a/datamodel/high/node_builder.go b/datamodel/high/node_builder.go index 25b938ee..e96f1b70 100644 --- a/datamodel/high/node_builder.go +++ b/datamodel/high/node_builder.go @@ -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) diff --git a/datamodel/high/node_builder_test.go b/datamodel/high/node_builder_test.go index 74f93e93..a370547a 100644 --- a/datamodel/high/node_builder_test.go +++ b/datamodel/high/node_builder_test.go @@ -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 { diff --git a/datamodel/high/shared.go b/datamodel/high/shared.go index 7c01aadd..865f90dc 100644 --- a/datamodel/high/shared.go +++ b/datamodel/high/shared.go @@ -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 } diff --git a/datamodel/high/v2/examples.go b/datamodel/high/v2/examples.go index 702f1931..0c3f8072 100644 --- a/datamodel/high/v2/examples.go +++ b/datamodel/high/v2/examples.go @@ -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 } diff --git a/datamodel/high/v2/path_item_test.go b/datamodel/high/v2/path_item_test.go index be79c360..eeece33e 100644 --- a/datamodel/high/v2/path_item_test.go +++ b/datamodel/high/v2/path_item_test.go @@ -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) diff --git a/datamodel/high/v2/response.go b/datamodel/high/v2/response.go index 595af99c..4092f753 100644 --- a/datamodel/high/v2/response.go +++ b/datamodel/high/v2/response.go @@ -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 } diff --git a/datamodel/high/v2/scopes.go b/datamodel/high/v2/scopes.go index a580d94f..52ec296c 100644 --- a/datamodel/high/v2/scopes.go +++ b/datamodel/high/v2/scopes.go @@ -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 } diff --git a/datamodel/high/v3/callback.go b/datamodel/high/v3/callback.go index 70b75468..c6e04803 100644 --- a/datamodel/high/v3/callback.go +++ b/datamodel/high/v3/callback.go @@ -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 } } diff --git a/datamodel/high/v3/document.go b/datamodel/high/v3/document.go index df6337f7..ed81c258 100644 --- a/datamodel/high/v3/document.go +++ b/datamodel/high/v3/document.go @@ -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 } diff --git a/datamodel/high/v3/document_test.go b/datamodel/high/v3/document_test.go index ea72ff40..106df8c3 100644 --- a/datamodel/high/v3/document_test.go +++ b/datamodel/high/v3/document_test.go @@ -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()) - } diff --git a/datamodel/high/v3/encoding.go b/datamodel/high/v3/encoding.go index f7c417b9..4fecec83 100644 --- a/datamodel/high/v3/encoding.go +++ b/datamodel/high/v3/encoding.go @@ -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) } diff --git a/datamodel/high/v3/header.go b/datamodel/high/v3/header.go index abe93817..d8bfa3c2 100644 --- a/datamodel/high/v3/header.go +++ b/datamodel/high/v3/header.go @@ -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. diff --git a/datamodel/high/v3/link.go b/datamodel/high/v3/link.go index 48f4a852..38fbffb2 100644 --- a/datamodel/high/v3/link.go +++ b/datamodel/high/v3/link.go @@ -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 } diff --git a/datamodel/high/v3/oauth_flow.go b/datamodel/high/v3/oauth_flow.go index 0563b06e..5f5d2758 100644 --- a/datamodel/high/v3/oauth_flow.go +++ b/datamodel/high/v3/oauth_flow.go @@ -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 } diff --git a/datamodel/high/v3/operation.go b/datamodel/high/v3/operation.go index 0bc76ce1..31b4a490 100644 --- a/datamodel/high/v3/operation.go +++ b/datamodel/high/v3/operation.go @@ -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 } diff --git a/datamodel/high/v3/path_item_test.go b/datamodel/high/v3/path_item_test.go index 06986b63..0572ec8c 100644 --- a/datamodel/high/v3/path_item_test.go +++ b/datamodel/high/v3/path_item_test.go @@ -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) diff --git a/datamodel/high/v3/paths.go b/datamodel/high/v3/paths.go index 460723e3..b5748c7c 100644 --- a/datamodel/high/v3/paths.go +++ b/datamodel/high/v3/paths.go @@ -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 } } diff --git a/datamodel/high/v3/response.go b/datamodel/high/v3/response.go index 49b7da3e..2adbcb37 100644 --- a/datamodel/high/v3/response.go +++ b/datamodel/high/v3/response.go @@ -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 } diff --git a/datamodel/high/v3/responses.go b/datamodel/high/v3/responses.go index 0953949f..9e128838 100644 --- a/datamodel/high/v3/responses.go +++ b/datamodel/high/v3/responses.go @@ -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 diff --git a/datamodel/high/v3/server.go b/datamodel/high/v3/server.go index 2fbf06d9..6adb3875 100644 --- a/datamodel/high/v3/server.go +++ b/datamodel/high/v3/server.go @@ -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 } diff --git a/datamodel/low/base/discriminator.go b/datamodel/low/base/discriminator.go index 082b2cee..3aac3228 100644 --- a/datamodel/low/base/discriminator.go +++ b/datamodel/low/base/discriminator.go @@ -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, "|"))) diff --git a/datamodel/low/base/schema.go b/datamodel/low/base/schema.go index e1fdba54..9007e4d7 100644 --- a/datamodel/low/base/schema.go +++ b/datamodel/low/base/schema.go @@ -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 diff --git a/datamodel/low/base/security_requirement.go b/datamodel/low/base/security_requirement.go index c87beb98..7a89a960 100644 --- a/datamodel/low/base/security_requirement.go +++ b/datamodel/low/base/security_requirement.go @@ -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, "|"))) } diff --git a/datamodel/low/extraction_functions.go b/datamodel/low/extraction_functions.go index fe908fe5..0a6b6eaa 100644 --- a/datamodel/low/extraction_functions.go +++ b/datamodel/low/extraction_functions.go @@ -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 +} diff --git a/datamodel/low/extraction_functions_test.go b/datamodel/low/extraction_functions_test.go index da59d6b8..646f5591 100644 --- a/datamodel/low/extraction_functions_test.go +++ b/datamodel/low/extraction_functions_test.go @@ -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]) +} diff --git a/datamodel/low/model_builder_test.go b/datamodel/low/model_builder_test.go index 54916470..b8dc8742 100644 --- a/datamodel/low/model_builder_test.go +++ b/datamodel/low/model_builder_test.go @@ -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 } diff --git a/datamodel/low/node_map.go b/datamodel/low/node_map.go index 4944ce96..f0d82209 100644 --- a/datamodel/low/node_map.go +++ b/datamodel/low/node_map.go @@ -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} diff --git a/datamodel/low/v2/definitions.go b/datamodel/low/v2/definitions.go index 2917a082..0ef973d5 100644 --- a/datamodel/low/v2/definitions.go +++ b/datamodel/low/v2/definitions.go @@ -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, "|"))) } diff --git a/datamodel/low/v2/examples.go b/datamodel/low/v2/examples.go index 308b28af..735142d4 100644 --- a/datamodel/low/v2/examples.go +++ b/datamodel/low/v2/examples.go @@ -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, "|"))) } diff --git a/datamodel/low/v2/paths.go b/datamodel/low/v2/paths.go index 614f0d8e..f218e36c 100644 --- a/datamodel/low/v2/paths.go +++ b/datamodel/low/v2/paths.go @@ -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, "|"))) diff --git a/datamodel/low/v2/response.go b/datamodel/low/v2/response.go index b2ac4c9d..6dd07465 100644 --- a/datamodel/low/v2/response.go +++ b/datamodel/low/v2/response.go @@ -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)...) diff --git a/datamodel/low/v2/responses.go b/datamodel/low/v2/responses.go index c2564dc1..b003dce8 100644 --- a/datamodel/low/v2/responses.go +++ b/datamodel/low/v2/responses.go @@ -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)) } diff --git a/datamodel/low/v2/scopes.go b/datamodel/low/v2/scopes.go index e9aaa3ce..acc56134 100644 --- a/datamodel/low/v2/scopes.go +++ b/datamodel/low/v2/scopes.go @@ -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, "|"))) diff --git a/datamodel/low/v3/callback.go b/datamodel/low/v3/callback.go index 6ccc8c54..fa233c96 100644 --- a/datamodel/low/v3/callback.go +++ b/datamodel/low/v3/callback.go @@ -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)...) diff --git a/datamodel/low/v3/components.go b/datamodel/low/v3/components.go index e20dfcbf..3d73a99c 100644 --- a/datamodel/low/v3/components.go +++ b/datamodel/low/v3/components.go @@ -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, diff --git a/datamodel/low/v3/create_document.go b/datamodel/low/v3/create_document.go index f9718730..ca7737b4 100644 --- a/datamodel/low/v3/create_document.go +++ b/datamodel/low/v3/create_document.go @@ -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 diff --git a/datamodel/low/v3/create_document_test.go b/datamodel/low/v3/create_document_test.go index 2616173e..d039bb9d 100644 --- a/datamodel/low/v3/create_document_test.go +++ b/datamodel/low/v3/create_document_test.go @@ -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 { diff --git a/datamodel/low/v3/document.go b/datamodel/low/v3/document.go index 56de3c22..3adf2d26 100644 --- a/datamodel/low/v3/document.go +++ b/datamodel/low/v3/document.go @@ -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 } } } diff --git a/datamodel/low/v3/encoding.go b/datamodel/low/v3/encoding.go index ad75874d..d8a915f1 100644 --- a/datamodel/low/v3/encoding.go +++ b/datamodel/low/v3/encoding.go @@ -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 diff --git a/datamodel/low/v3/header.go b/datamodel/low/v3/header.go index 34718ada..6bb7e8c8 100644 --- a/datamodel/low/v3/header.go +++ b/datamodel/low/v3/header.go @@ -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, diff --git a/datamodel/low/v3/link.go b/datamodel/low/v3/link.go index 1114a8f7..a42548fe 100644 --- a/datamodel/low/v3/link.go +++ b/datamodel/low/v3/link.go @@ -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, "|"))) diff --git a/datamodel/low/v3/media_type.go b/datamodel/low/v3/media_type.go index 51a79693..ae19ab5a 100644 --- a/datamodel/low/v3/media_type.go +++ b/datamodel/low/v3/media_type.go @@ -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, "|"))) diff --git a/datamodel/low/v3/oauth_flows.go b/datamodel/low/v3/oauth_flows.go index 537a7598..dcf035cd 100644 --- a/datamodel/low/v3/oauth_flows.go +++ b/datamodel/low/v3/oauth_flows.go @@ -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, "|"))) diff --git a/datamodel/low/v3/operation.go b/datamodel/low/v3/operation.go index 22eee70d..1308d8dd 100644 --- a/datamodel/low/v3/operation.go +++ b/datamodel/low/v3/operation.go @@ -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)...) diff --git a/datamodel/low/v3/parameter.go b/datamodel/low/v3/parameter.go index e11d3965..d1e8f430 100644 --- a/datamodel/low/v3/parameter.go +++ b/datamodel/low/v3/parameter.go @@ -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, "|"))) diff --git a/datamodel/low/v3/paths.go b/datamodel/low/v3/paths.go index cc463e8a..3a7cd677 100644 --- a/datamodel/low/v3/paths.go +++ b/datamodel/low/v3/paths.go @@ -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, "|"))) } diff --git a/datamodel/low/v3/request_body.go b/datamodel/low/v3/request_body.go index bb45d19e..680e50e5 100644 --- a/datamodel/low/v3/request_body.go +++ b/datamodel/low/v3/request_body.go @@ -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, "|"))) diff --git a/datamodel/low/v3/response.go b/datamodel/low/v3/response.go index 197b3419..80a8a1fd 100644 --- a/datamodel/low/v3/response.go +++ b/datamodel/low/v3/response.go @@ -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, "|"))) } diff --git a/datamodel/low/v3/responses.go b/datamodel/low/v3/responses.go index 4ce0fb0d..657d0210 100644 --- a/datamodel/low/v3/responses.go +++ b/datamodel/low/v3/responses.go @@ -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)) } diff --git a/datamodel/low/v3/server.go b/datamodel/low/v3/server.go index 458b3d06..09b5705d 100644 --- a/datamodel/low/v3/server.go +++ b/datamodel/low/v3/server.go @@ -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) diff --git a/datamodel/low/v3/server_test.go b/datamodel/low/v3/server_test.go index abfe2668..2e7bde9c 100644 --- a/datamodel/low/v3/server_test.go +++ b/datamodel/low/v3/server_test.go @@ -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()) } } diff --git a/document_iteration_test.go b/document_iteration_test.go index ccd0535c..40161de6 100644 --- a/document_iteration_test.go +++ b/document_iteration_test.go @@ -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 contentPair := orderedmap.First(codePair.Value().Content); contentPair != nil; contentPair = contentPair.Next() { - t.Log(contentPair.Key()) + for code, response := range op.Responses.Codes.FromOldest() { + t.Log(code) - 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() { diff --git a/document_test.go b/document_test.go index 2c116d58..17a3adb1 100644 --- a/document_test.go +++ b/document_test.go @@ -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) - } diff --git a/go.mod b/go.mod index d7a4a48b..4ef44507 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 3734334e..5610c44e 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/orderedmap/orderedmap.go b/orderedmap/orderedmap.go index 9cf90fc4..f2e1e9e3 100644 --- a/orderedmap/orderedmap.go +++ b/orderedmap/orderedmap.go @@ -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]{ diff --git a/orderedmap/orderedmap_test.go b/orderedmap/orderedmap_test.go index 139a23eb..e3a02c95 100644 --- a/orderedmap/orderedmap_test.go +++ b/orderedmap/orderedmap_test.go @@ -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: diff --git a/renderer/mock_generator.go b/renderer/mock_generator.go index 81c313f5..205e6193 100644 --- a/renderer/mock_generator.go +++ b/renderer/mock_generator.go @@ -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 } } diff --git a/renderer/schema_renderer.go b/renderer/schema_renderer.go index 3d4f0e92..84253a22 100644 --- a/renderer/schema_renderer.go +++ b/renderer/schema_renderer.go @@ -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) diff --git a/what-changed/model/callback.go b/what-changed/model/callback.go index bcc630c6..5c755fed 100644 --- a/what-changed/model/callback.go +++ b/what-changed/model/callback.go @@ -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) diff --git a/what-changed/model/comparison_functions.go b/what-changed/model/comparison_functions.go index a83ead2f..3b16464b 100644 --- a/what-changed/model/comparison_functions.go +++ b/what-changed/model/comparison_functions.go @@ -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) diff --git a/what-changed/model/examples.go b/what-changed/model/examples.go index cf284331..7c428522 100644 --- a/what-changed/model/examples.go +++ b/what-changed/model/examples.go @@ -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 diff --git a/what-changed/model/extensions.go b/what-changed/model/extensions.go index 2da201e3..34b78c0a 100644 --- a/what-changed/model/extensions.go +++ b/what-changed/model/extensions.go @@ -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 diff --git a/what-changed/model/link.go b/what-changed/model/link.go index cc870122..5a097658 100644 --- a/what-changed/model/link.go +++ b/what-changed/model/link.go @@ -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 { diff --git a/what-changed/model/oauth_flows.go b/what-changed/model/oauth_flows.go index bb71edf1..dc1b0d25 100644 --- a/what-changed/model/oauth_flows.go +++ b/what-changed/model/oauth_flows.go @@ -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) diff --git a/what-changed/model/paths.go b/what-changed/model/paths.go index 6095495e..cb26401d 100644 --- a/what-changed/model/paths.go +++ b/what-changed/model/paths.go @@ -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() - } + for k, v := range lPath.PathItems.FromOldest() { + lKeys[k.Value] = v } - if rPath != nil { - 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 *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) diff --git a/what-changed/model/schema.go b/what-changed/model/schema.go index ad7061c4..5e655263 100644 --- a/what-changed/model/schema.go +++ b/what-changed/model/schema.go @@ -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) diff --git a/what-changed/model/scopes.go b/what-changed/model/scopes.go index 1f9882fe..b4a08e0f 100644 --- a/what-changed/model/scopes.go +++ b/what-changed/model/scopes.go @@ -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) } } diff --git a/what-changed/model/security_requirement.go b/what-changed/model/security_requirement.go index 774fdc5d..2a19bb88 100644 --- a/what-changed/model/security_requirement.go +++ b/what-changed/model/security_requirement.go @@ -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++ }