mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
fix: continued moving everything to orderedmaps plus cleaned up most the tests
This commit is contained in:
@@ -20,8 +20,8 @@ import (
|
|||||||
//
|
//
|
||||||
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
|
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
|
||||||
type Discriminator struct {
|
type Discriminator struct {
|
||||||
PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"`
|
PropertyName string `json:"propertyName,omitempty" yaml:"propertyName,omitempty"`
|
||||||
Mapping orderedmap.Map[string, string] `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
Mapping *orderedmap.Map[string, string] `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
||||||
low *low.Discriminator
|
low *low.Discriminator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func TestDynamicValue_MarshalYAMLInline(t *testing.T) {
|
|||||||
|
|
||||||
// convert node into yaml
|
// convert node into yaml
|
||||||
bits, _ := yaml.Marshal(rend)
|
bits, _ := yaml.Marshal(rend)
|
||||||
assert.Equal(t, "properties:\n rice:\n $ref: '#/components/schemas/rice'", strings.TrimSpace(string(bits)))
|
assert.Equal(t, "properties:\n rice:\n type: array\n items:\n type: string", strings.TrimSpace(string(bits)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDynamicValue_MarshalYAMLInline_Error(t *testing.T) {
|
func TestDynamicValue_MarshalYAMLInline_Error(t *testing.T) {
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ import (
|
|||||||
//
|
//
|
||||||
// v3 - https://spec.openapis.org/oas/v3.1.0#example-object
|
// v3 - https://spec.openapis.org/oas/v3.1.0#example-object
|
||||||
type Example struct {
|
type Example struct {
|
||||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Value any `json:"value,omitempty" yaml:"value,omitempty"`
|
Value *yaml.Node `json:"value,omitempty" yaml:"value,omitempty"`
|
||||||
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
|
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Example
|
low *low.Example
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ func (e *Example) MarshalYAML() (interface{}, error) {
|
|||||||
|
|
||||||
// ExtractExamples will convert a low-level example map, into a high level one that is simple to navigate.
|
// 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()
|
// 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] {
|
func ExtractExamples(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Example]]) *orderedmap.Map[string, *Example] {
|
||||||
extracted := orderedmap.New[string, *Example]()
|
extracted := orderedmap.New[string, *Example]()
|
||||||
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
||||||
extracted.Set(pair.Key().Value, NewExample(pair.Value().Value))
|
extracted.Set(pair.Key().Value, NewExample(pair.Value().Value))
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewExample(t *testing.T) {
|
func TestNewExample(t *testing.T) {
|
||||||
|
|
||||||
var cNode yaml.Node
|
var cNode yaml.Node
|
||||||
|
|
||||||
yml := `summary: an example
|
yml := `summary: an example
|
||||||
@@ -37,18 +36,23 @@ x-hack: code`
|
|||||||
// build high
|
// build high
|
||||||
highExample := NewExample(&lowExample)
|
highExample := NewExample(&lowExample)
|
||||||
|
|
||||||
|
var xHack string
|
||||||
|
_ = highExample.Extensions.GetOrZero("x-hack").Decode(&xHack)
|
||||||
|
|
||||||
|
var example string
|
||||||
|
_ = highExample.Value.Decode(&example)
|
||||||
|
|
||||||
assert.Equal(t, "an example", highExample.Summary)
|
assert.Equal(t, "an example", highExample.Summary)
|
||||||
assert.Equal(t, "something more", highExample.Description)
|
assert.Equal(t, "something more", highExample.Description)
|
||||||
assert.Equal(t, "https://pb33f.io", highExample.ExternalValue)
|
assert.Equal(t, "https://pb33f.io", highExample.ExternalValue)
|
||||||
assert.Equal(t, "code", highExample.Extensions["x-hack"])
|
assert.Equal(t, "code", xHack)
|
||||||
assert.Equal(t, "a thing", highExample.Value)
|
assert.Equal(t, "a thing", example)
|
||||||
assert.Equal(t, 4, highExample.GoLow().ExternalValue.ValueNode.Line)
|
assert.Equal(t, 4, highExample.GoLow().ExternalValue.ValueNode.Line)
|
||||||
assert.NotNil(t, highExample.GoLowUntyped())
|
assert.NotNil(t, highExample.GoLowUntyped())
|
||||||
|
|
||||||
// render the example as YAML
|
// render the example as YAML
|
||||||
rendered, _ := highExample.Render()
|
rendered, _ := highExample.Render()
|
||||||
assert.Equal(t, strings.TrimSpace(string(rendered)), yml)
|
assert.Equal(t, yml, strings.TrimSpace(string(rendered)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractExamples(t *testing.T) {
|
func TestExtractExamples(t *testing.T) {
|
||||||
@@ -71,11 +75,9 @@ func TestExtractExamples(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, "herbs", ExtractExamples(examplesMap).GetOrZero("green").Summary)
|
assert.Equal(t, "herbs", ExtractExamples(examplesMap).GetOrZero("green").Summary)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleNewExample() {
|
func ExampleNewExample() {
|
||||||
|
|
||||||
// create some example yaml (or can be JSON, it does not matter)
|
// create some example yaml (or can be JSON, it does not matter)
|
||||||
yml := `summary: something interesting
|
yml := `summary: something interesting
|
||||||
description: something more interesting with detail
|
description: something more interesting with detail
|
||||||
@@ -98,5 +100,4 @@ x-hack: code`
|
|||||||
|
|
||||||
fmt.Print(highExample.ExternalValue)
|
fmt.Print(highExample.ExternalValue)
|
||||||
// Output: https://pb33f.io
|
// Output: https://pb33f.io
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package base
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,9 +17,9 @@ import (
|
|||||||
// v2 - https://swagger.io/specification/v2/#externalDocumentationObject
|
// v2 - https://swagger.io/specification/v2/#externalDocumentationObject
|
||||||
// v3 - https://spec.openapis.org/oas/v3.1.0#external-documentation-object
|
// v3 - https://spec.openapis.org/oas/v3.1.0#external-documentation-object
|
||||||
type ExternalDoc struct {
|
type ExternalDoc struct {
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.ExternalDoc
|
low *low.ExternalDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ func (e *ExternalDoc) GoLowUntyped() any {
|
|||||||
return e.low
|
return e.low
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExternalDoc) GetExtensions() map[string]any {
|
func (e *ExternalDoc) GetExtensions() *orderedmap.Map[string, *yaml.Node] {
|
||||||
return e.Extensions
|
return e.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
|
||||||
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewExternalDoc(t *testing.T) {
|
func TestNewExternalDoc(t *testing.T) {
|
||||||
|
|
||||||
var cNode yaml.Node
|
var cNode yaml.Node
|
||||||
|
|
||||||
yml := `description: hack code
|
yml := `description: hack code
|
||||||
@@ -31,22 +31,23 @@ x-hack: code`
|
|||||||
|
|
||||||
highExt := NewExternalDoc(&lowExt)
|
highExt := NewExternalDoc(&lowExt)
|
||||||
|
|
||||||
|
var xHack string
|
||||||
|
_ = highExt.Extensions.GetOrZero("x-hack").Decode(&xHack)
|
||||||
|
|
||||||
assert.Equal(t, "hack code", highExt.Description)
|
assert.Equal(t, "hack code", highExt.Description)
|
||||||
assert.Equal(t, "https://pb33f.io", highExt.URL)
|
assert.Equal(t, "https://pb33f.io", highExt.URL)
|
||||||
assert.Equal(t, "code", highExt.Extensions["x-hack"])
|
assert.Equal(t, "code", xHack)
|
||||||
|
|
||||||
wentLow := highExt.GoLow()
|
wentLow := highExt.GoLow()
|
||||||
assert.Equal(t, 2, wentLow.URL.ValueNode.Line)
|
assert.Equal(t, 2, wentLow.URL.ValueNode.Line)
|
||||||
assert.Len(t, highExt.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(highExt.GetExtensions()))
|
||||||
|
|
||||||
// render the high-level object as YAML
|
// render the high-level object as YAML
|
||||||
rendered, _ := highExt.Render()
|
rendered, _ := highExt.Render()
|
||||||
assert.Equal(t, strings.TrimSpace(string(rendered)), yml)
|
assert.Equal(t, strings.TrimSpace(string(rendered)), yml)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleNewExternalDoc() {
|
func TestExampleNewExternalDoc(t *testing.T) {
|
||||||
|
|
||||||
// create a new external documentation spec reference
|
// create a new external documentation spec reference
|
||||||
// this can be YAML or JSON.
|
// this can be YAML or JSON.
|
||||||
yml := `description: hack code docs
|
yml := `description: hack code docs
|
||||||
@@ -67,7 +68,8 @@ x-hack: code`
|
|||||||
// create new high-level ExternalDoc
|
// create new high-level ExternalDoc
|
||||||
highExt := NewExternalDoc(&lowExt)
|
highExt := NewExternalDoc(&lowExt)
|
||||||
|
|
||||||
// print out a extension
|
var xHack string
|
||||||
fmt.Print(highExt.Extensions["x-hack"])
|
_ = highExt.Extensions.GetOrZero("x-hack").Decode(&xHack)
|
||||||
// Output: code
|
|
||||||
|
assert.Equal(t, "code", xHack)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package base
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,14 +18,14 @@ import (
|
|||||||
// v2 - https://swagger.io/specification/v2/#infoObject
|
// v2 - https://swagger.io/specification/v2/#infoObject
|
||||||
// v3 - https://spec.openapis.org/oas/v3.1.0#info-object
|
// v3 - https://spec.openapis.org/oas/v3.1.0#info-object
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
|
TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
|
||||||
Contact *Contact `json:"contact,omitempty" yaml:"contact,omitempty"`
|
Contact *Contact `json:"contact,omitempty" yaml:"contact,omitempty"`
|
||||||
License *License `json:"license,omitempty" yaml:"license,omitempty"`
|
License *License `json:"license,omitempty" yaml:"license,omitempty"`
|
||||||
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Info
|
low *low.Info
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ func NewInfo(info *low.Info) *Info {
|
|||||||
if !info.Version.IsEmpty() {
|
if !info.Version.IsEmpty() {
|
||||||
i.Version = info.Version.Value
|
i.Version = info.Version.Value
|
||||||
}
|
}
|
||||||
if len(info.Extensions) > 0 {
|
if orderedmap.Len(info.Extensions) > 0 {
|
||||||
i.Extensions = high.ExtractExtensions(info.Extensions)
|
i.Extensions = high.ExtractExtensions(info.Extensions)
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
|
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -37,6 +39,9 @@ x-cli-name: chicken cli`
|
|||||||
|
|
||||||
highInfo := NewInfo(&lowInfo)
|
highInfo := NewInfo(&lowInfo)
|
||||||
|
|
||||||
|
var xCliName string
|
||||||
|
_ = highInfo.Extensions.GetOrZero("x-cli-name").Decode(&xCliName)
|
||||||
|
|
||||||
assert.Equal(t, "chicken", highInfo.Title)
|
assert.Equal(t, "chicken", highInfo.Title)
|
||||||
assert.Equal(t, "a chicken nugget", highInfo.Summary)
|
assert.Equal(t, "a chicken nugget", highInfo.Summary)
|
||||||
assert.Equal(t, "nugget", highInfo.Description)
|
assert.Equal(t, "nugget", highInfo.Description)
|
||||||
@@ -45,7 +50,7 @@ x-cli-name: chicken cli`
|
|||||||
assert.Equal(t, "pb33f", highInfo.License.Name)
|
assert.Equal(t, "pb33f", highInfo.License.Name)
|
||||||
assert.Equal(t, "https://pb33f.io", highInfo.License.URL)
|
assert.Equal(t, "https://pb33f.io", highInfo.License.URL)
|
||||||
assert.Equal(t, "99.99", highInfo.Version)
|
assert.Equal(t, "99.99", highInfo.Version)
|
||||||
assert.Equal(t, "chicken cli", highInfo.Extensions["x-cli-name"])
|
assert.Equal(t, "chicken cli", xCliName)
|
||||||
|
|
||||||
wentLow := highInfo.GoLow()
|
wentLow := highInfo.GoLow()
|
||||||
assert.Equal(t, 10, wentLow.Version.ValueNode.Line)
|
assert.Equal(t, 10, wentLow.Version.ValueNode.Line)
|
||||||
@@ -109,13 +114,12 @@ url: https://opensource.org/licenses/MIT`
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInfo_Render(t *testing.T) {
|
func TestInfo_Render(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
ext := make(map[string]any)
|
ext.Set("x-pizza", utils.CreateStringNode("pepperoni"))
|
||||||
ext["x-pizza"] = "pepperoni"
|
ext.Set("x-cake", utils.CreateYamlNode(&License{
|
||||||
ext["x-cake"] = &License{
|
|
||||||
Name: "someone",
|
Name: "someone",
|
||||||
URL: "nowhere",
|
URL: "nowhere",
|
||||||
}
|
}))
|
||||||
highI := &Info{
|
highI := &Info{
|
||||||
Title: "hey",
|
Title: "hey",
|
||||||
Description: "there you",
|
Description: "there you",
|
||||||
@@ -146,6 +150,9 @@ func TestInfo_Render(t *testing.T) {
|
|||||||
// build high
|
// build high
|
||||||
highInfo := NewInfo(&lowInfo)
|
highInfo := NewInfo(&lowInfo)
|
||||||
|
|
||||||
|
var xPizza string
|
||||||
|
_ = highInfo.Extensions.GetOrZero("x-pizza").Decode(&xPizza)
|
||||||
|
|
||||||
assert.Equal(t, "hey", highInfo.Title)
|
assert.Equal(t, "hey", highInfo.Title)
|
||||||
assert.Equal(t, "there you", highInfo.Description)
|
assert.Equal(t, "there you", highInfo.Description)
|
||||||
assert.Equal(t, "have you got any money", highInfo.TermsOfService)
|
assert.Equal(t, "have you got any money", highInfo.TermsOfService)
|
||||||
@@ -154,12 +161,11 @@ func TestInfo_Render(t *testing.T) {
|
|||||||
assert.Equal(t, "MIT", highInfo.License.Name)
|
assert.Equal(t, "MIT", highInfo.License.Name)
|
||||||
assert.Equal(t, "https://opensource.org/licenses/MIT", highInfo.License.URL)
|
assert.Equal(t, "https://opensource.org/licenses/MIT", highInfo.License.URL)
|
||||||
assert.Equal(t, "1.2.3", highInfo.Version)
|
assert.Equal(t, "1.2.3", highInfo.Version)
|
||||||
assert.Equal(t, "pepperoni", highInfo.Extensions["x-pizza"])
|
assert.Equal(t, "pepperoni", xPizza)
|
||||||
assert.NotNil(t, highInfo.GoLowUntyped())
|
assert.NotNil(t, highInfo.GoLowUntyped())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInfo_RenderOrder(t *testing.T) {
|
func TestInfo_RenderOrder(t *testing.T) {
|
||||||
|
|
||||||
yml := `title: hey
|
yml := `title: hey
|
||||||
description: there you
|
description: there you
|
||||||
termsOfService: have you got any money
|
termsOfService: have you got any money
|
||||||
@@ -187,6 +193,9 @@ x-cake:
|
|||||||
// build high
|
// build high
|
||||||
highInfo := NewInfo(&lowInfo)
|
highInfo := NewInfo(&lowInfo)
|
||||||
|
|
||||||
|
var xPizza string
|
||||||
|
_ = highInfo.Extensions.GetOrZero("x-pizza").Decode(&xPizza)
|
||||||
|
|
||||||
assert.Equal(t, "hey", highInfo.Title)
|
assert.Equal(t, "hey", highInfo.Title)
|
||||||
assert.Equal(t, "there you", highInfo.Description)
|
assert.Equal(t, "there you", highInfo.Description)
|
||||||
assert.Equal(t, "have you got any money", highInfo.TermsOfService)
|
assert.Equal(t, "have you got any money", highInfo.TermsOfService)
|
||||||
@@ -195,7 +204,7 @@ x-cake:
|
|||||||
assert.Equal(t, "MIT", highInfo.License.Name)
|
assert.Equal(t, "MIT", highInfo.License.Name)
|
||||||
assert.Equal(t, "https://opensource.org/licenses/MIT", highInfo.License.URL)
|
assert.Equal(t, "https://opensource.org/licenses/MIT", highInfo.License.URL)
|
||||||
assert.Equal(t, "1.2.3", highInfo.Version)
|
assert.Equal(t, "1.2.3", highInfo.Version)
|
||||||
assert.Equal(t, "pepperoni", highInfo.Extensions["x-pizza"])
|
assert.Equal(t, "pepperoni", xPizza)
|
||||||
|
|
||||||
// marshal high back to yaml, should be the same as the original, in same order.
|
// marshal high back to yaml, should be the same as the original, in same order.
|
||||||
bytes, _ := highInfo.Render()
|
bytes, _ := highInfo.Render()
|
||||||
|
|||||||
@@ -45,22 +45,22 @@ type Schema struct {
|
|||||||
Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"`
|
Discriminator *Discriminator `json:"discriminator,omitempty" yaml:"discriminator,omitempty"`
|
||||||
|
|
||||||
// in 3.1 examples can be an array (which is recommended)
|
// in 3.1 examples can be an array (which is recommended)
|
||||||
Examples []any `json:"examples,omitempty" yaml:"examples,omitempty"`
|
Examples []*yaml.Node `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
|
|
||||||
// in 3.1 prefixItems provides tuple validation support.
|
// in 3.1 prefixItems provides tuple validation support.
|
||||||
PrefixItems []*SchemaProxy `json:"prefixItems,omitempty" yaml:"prefixItems,omitempty"`
|
PrefixItems []*SchemaProxy `json:"prefixItems,omitempty" yaml:"prefixItems,omitempty"`
|
||||||
|
|
||||||
// 3.1 Specific properties
|
// 3.1 Specific properties
|
||||||
Contains *SchemaProxy `json:"contains,omitempty" yaml:"contains,omitempty"`
|
Contains *SchemaProxy `json:"contains,omitempty" yaml:"contains,omitempty"`
|
||||||
MinContains *int64 `json:"minContains,omitempty" yaml:"minContains,omitempty"`
|
MinContains *int64 `json:"minContains,omitempty" yaml:"minContains,omitempty"`
|
||||||
MaxContains *int64 `json:"maxContains,omitempty" yaml:"maxContains,omitempty"`
|
MaxContains *int64 `json:"maxContains,omitempty" yaml:"maxContains,omitempty"`
|
||||||
If *SchemaProxy `json:"if,omitempty" yaml:"if,omitempty"`
|
If *SchemaProxy `json:"if,omitempty" yaml:"if,omitempty"`
|
||||||
Else *SchemaProxy `json:"else,omitempty" yaml:"else,omitempty"`
|
Else *SchemaProxy `json:"else,omitempty" yaml:"else,omitempty"`
|
||||||
Then *SchemaProxy `json:"then,omitempty" yaml:"then,omitempty"`
|
Then *SchemaProxy `json:"then,omitempty" yaml:"then,omitempty"`
|
||||||
DependentSchemas orderedmap.Map[string, *SchemaProxy] `json:"dependentSchemas,omitempty" yaml:"dependentSchemas,omitempty"`
|
DependentSchemas *orderedmap.Map[string, *SchemaProxy] `json:"dependentSchemas,omitempty" yaml:"dependentSchemas,omitempty"`
|
||||||
PatternProperties orderedmap.Map[string, *SchemaProxy] `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"`
|
PatternProperties *orderedmap.Map[string, *SchemaProxy] `json:"patternProperties,omitempty" yaml:"patternProperties,omitempty"`
|
||||||
PropertyNames *SchemaProxy `json:"propertyNames,omitempty" yaml:"propertyNames,omitempty"`
|
PropertyNames *SchemaProxy `json:"propertyNames,omitempty" yaml:"propertyNames,omitempty"`
|
||||||
UnevaluatedItems *SchemaProxy `json:"unevaluatedItems,omitempty" yaml:"unevaluatedItems,omitempty"`
|
UnevaluatedItems *SchemaProxy `json:"unevaluatedItems,omitempty" yaml:"unevaluatedItems,omitempty"`
|
||||||
|
|
||||||
// in 3.1 UnevaluatedProperties can be a Schema or a boolean
|
// in 3.1 UnevaluatedProperties can be a Schema or a boolean
|
||||||
// https://github.com/pb33f/libopenapi/issues/118
|
// https://github.com/pb33f/libopenapi/issues/118
|
||||||
@@ -73,35 +73,35 @@ type Schema struct {
|
|||||||
Anchor string `json:"$anchor,omitempty" yaml:"$anchor,omitempty"`
|
Anchor string `json:"$anchor,omitempty" yaml:"$anchor,omitempty"`
|
||||||
|
|
||||||
// Compatible with all versions
|
// Compatible with all versions
|
||||||
Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"`
|
Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"`
|
||||||
Properties orderedmap.Map[string, *SchemaProxy] `json:"properties,omitempty" yaml:"properties,omitempty"`
|
Properties *orderedmap.Map[string, *SchemaProxy] `json:"properties,omitempty" yaml:"properties,omitempty"`
|
||||||
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
Title string `json:"title,omitempty" yaml:"title,omitempty"`
|
||||||
MultipleOf *float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
|
MultipleOf *float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
|
||||||
Maximum *float64 `json:"maximum,renderZero,omitempty" yaml:"maximum,renderZero,omitempty"`
|
Maximum *float64 `json:"maximum,renderZero,omitempty" yaml:"maximum,renderZero,omitempty"`
|
||||||
Minimum *float64 `json:"minimum,renderZero,omitempty," yaml:"minimum,renderZero,omitempty"`
|
Minimum *float64 `json:"minimum,renderZero,omitempty," yaml:"minimum,renderZero,omitempty"`
|
||||||
MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
|
MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
|
||||||
MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
|
MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
|
||||||
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
|
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
|
||||||
Format string `json:"format,omitempty" yaml:"format,omitempty"`
|
Format string `json:"format,omitempty" yaml:"format,omitempty"`
|
||||||
MaxItems *int64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
|
MaxItems *int64 `json:"maxItems,omitempty" yaml:"maxItems,omitempty"`
|
||||||
MinItems *int64 `json:"minItems,omitempty" yaml:"minItems,omitempty"`
|
MinItems *int64 `json:"minItems,omitempty" yaml:"minItems,omitempty"`
|
||||||
UniqueItems *bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
|
UniqueItems *bool `json:"uniqueItems,omitempty" yaml:"uniqueItems,omitempty"`
|
||||||
MaxProperties *int64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
MaxProperties *int64 `json:"maxProperties,omitempty" yaml:"maxProperties,omitempty"`
|
||||||
MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
MinProperties *int64 `json:"minProperties,omitempty" yaml:"minProperties,omitempty"`
|
||||||
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
|
||||||
Enum []any `json:"enum,omitempty" yaml:"enum,omitempty"`
|
Enum []*yaml.Node `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||||
AdditionalProperties *DynamicValue[*SchemaProxy, bool] `json:"additionalProperties,renderZero,omitempty" yaml:"additionalProperties,renderZero,omitempty"`
|
AdditionalProperties *DynamicValue[*SchemaProxy, bool] `json:"additionalProperties,renderZero,omitempty" yaml:"additionalProperties,renderZero,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Default any `json:"default,omitempty" yaml:"default,renderZero,omitempty"`
|
Default *yaml.Node `json:"default,omitempty" yaml:"default,renderZero,omitempty"`
|
||||||
Const any `json:"const,omitempty" yaml:"const,renderZero,omitempty"`
|
Const *yaml.Node `json:"const,omitempty" yaml:"const,renderZero,omitempty"`
|
||||||
Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
Nullable *bool `json:"nullable,omitempty" yaml:"nullable,omitempty"`
|
||||||
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
ReadOnly *bool `json:"readOnly,renderZero,omitempty" yaml:"readOnly,renderZero,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
||||||
WriteOnly bool `json:"writeOnly,omitempty" yaml:"writeOnly,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
WriteOnly *bool `json:"writeOnly,renderZero,omitempty" yaml:"writeOnly,renderZero,omitempty"` // https://github.com/pb33f/libopenapi/issues/30
|
||||||
XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"`
|
XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"`
|
||||||
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
Example *yaml.Node `json:"example,omitempty" yaml:"example,omitempty"`
|
||||||
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *base.Schema
|
low *base.Schema
|
||||||
|
|
||||||
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
||||||
@@ -266,17 +266,17 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
s.Nullable = &schema.Nullable.Value
|
s.Nullable = &schema.Nullable.Value
|
||||||
}
|
}
|
||||||
if !schema.ReadOnly.IsEmpty() {
|
if !schema.ReadOnly.IsEmpty() {
|
||||||
s.ReadOnly = schema.ReadOnly.Value
|
s.ReadOnly = &schema.ReadOnly.Value
|
||||||
}
|
}
|
||||||
if !schema.WriteOnly.IsEmpty() {
|
if !schema.WriteOnly.IsEmpty() {
|
||||||
s.WriteOnly = schema.WriteOnly.Value
|
s.WriteOnly = &schema.WriteOnly.Value
|
||||||
}
|
}
|
||||||
if !schema.Deprecated.IsEmpty() {
|
if !schema.Deprecated.IsEmpty() {
|
||||||
s.Deprecated = &schema.Deprecated.Value
|
s.Deprecated = &schema.Deprecated.Value
|
||||||
}
|
}
|
||||||
s.Example = schema.Example.Value
|
s.Example = schema.Example.Value
|
||||||
if len(schema.Examples.Value) > 0 {
|
if len(schema.Examples.Value) > 0 {
|
||||||
examples := make([]any, len(schema.Examples.Value))
|
examples := make([]*yaml.Node, len(schema.Examples.Value))
|
||||||
for i := 0; i < len(schema.Examples.Value); i++ {
|
for i := 0; i < len(schema.Examples.Value); i++ {
|
||||||
examples[i] = schema.Examples.Value[i].Value
|
examples[i] = schema.Examples.Value[i].Value
|
||||||
}
|
}
|
||||||
@@ -298,11 +298,11 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
}
|
}
|
||||||
s.Required = req
|
s.Required = req
|
||||||
|
|
||||||
var enum []any
|
|
||||||
if !schema.Anchor.IsEmpty() {
|
if !schema.Anchor.IsEmpty() {
|
||||||
s.Anchor = schema.Anchor.Value
|
s.Anchor = schema.Anchor.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var enum []*yaml.Node
|
||||||
for i := range schema.Enum.Value {
|
for i := range schema.Enum.Value {
|
||||||
enum = append(enum, schema.Enum.Value[i].Value)
|
enum = append(enum, schema.Enum.Value[i].Value)
|
||||||
}
|
}
|
||||||
@@ -322,11 +322,13 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
|
|
||||||
// for every item, build schema async
|
// for every item, build schema async
|
||||||
buildSchema := func(sch lowmodel.ValueReference[*base.SchemaProxy], idx int, bChan chan buildResult) {
|
buildSchema := func(sch lowmodel.ValueReference[*base.SchemaProxy], idx int, bChan chan buildResult) {
|
||||||
p := NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{
|
n := &lowmodel.NodeReference[*base.SchemaProxy]{
|
||||||
ValueNode: sch.ValueNode,
|
ValueNode: sch.GetValueNode(),
|
||||||
Value: sch.Value,
|
Value: sch.Value,
|
||||||
Reference: sch.GetReference(),
|
}
|
||||||
})
|
n.SetReference(sch.GetReference(), sch.GetValueNode())
|
||||||
|
|
||||||
|
p := NewSchemaProxy(n)
|
||||||
|
|
||||||
bChan <- buildResult{idx: idx, s: p}
|
bChan <- buildResult{idx: idx, s: p}
|
||||||
}
|
}
|
||||||
@@ -353,7 +355,7 @@ func NewSchema(schema *base.Schema) *Schema {
|
|||||||
|
|
||||||
// props async
|
// props async
|
||||||
buildProps := func(k lowmodel.KeyReference[string], v lowmodel.ValueReference[*base.SchemaProxy],
|
buildProps := func(k lowmodel.KeyReference[string], v lowmodel.ValueReference[*base.SchemaProxy],
|
||||||
props orderedmap.Map[string, *SchemaProxy], sw int,
|
props *orderedmap.Map[string, *SchemaProxy], sw int,
|
||||||
) {
|
) {
|
||||||
props.Set(k.Value, NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{
|
props.Set(k.Value, NewSchemaProxy(&lowmodel.NodeReference[*base.SchemaProxy]{
|
||||||
Value: v.Value,
|
Value: v.Value,
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SchemaProxy exists as a stub that will create a Schema once (and only once) the Schema() method is called. An
|
// SchemaProxy exists as a stub that will create a Schema once (and only once) the Schema() method is called. An
|
||||||
@@ -98,11 +99,15 @@ func (sp *SchemaProxy) Schema() *Schema {
|
|||||||
|
|
||||||
// IsReference returns true if the SchemaProxy is a reference to another Schema.
|
// IsReference returns true if the SchemaProxy is a reference to another Schema.
|
||||||
func (sp *SchemaProxy) IsReference() bool {
|
func (sp *SchemaProxy) IsReference() bool {
|
||||||
|
if sp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if sp.refStr != "" {
|
if sp.refStr != "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if sp.schema != nil {
|
if sp.schema != nil {
|
||||||
return sp.schema.Value.IsSchemaReference()
|
return sp.schema.Value.IsReference()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -112,7 +117,14 @@ func (sp *SchemaProxy) GetReference() string {
|
|||||||
if sp.refStr != "" {
|
if sp.refStr != "" {
|
||||||
return sp.refStr
|
return sp.refStr
|
||||||
}
|
}
|
||||||
return sp.schema.Value.GetSchemaReference()
|
return sp.schema.GetValue().GetReference()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sp *SchemaProxy) GetReferenceNode() *yaml.Node {
|
||||||
|
if sp.refStr != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return sp.schema.GetValue().GetReferenceNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReferenceOrigin returns a pointer to the index.NodeOrigin of the $ref if this SchemaProxy is a reference to another Schema.
|
// GetReferenceOrigin returns a pointer to the index.NodeOrigin of the $ref if this SchemaProxy is a reference to another Schema.
|
||||||
@@ -171,12 +183,13 @@ func (sp *SchemaProxy) MarshalYAML() (interface{}, error) {
|
|||||||
nb := high.NewNodeBuilder(s, s.low)
|
nb := high.NewNodeBuilder(s, s.low)
|
||||||
return nb.Render(), nil
|
return nb.Render(), nil
|
||||||
} else {
|
} else {
|
||||||
|
refNode := sp.GetReferenceNode()
|
||||||
|
if refNode != nil {
|
||||||
|
return refNode, nil
|
||||||
|
}
|
||||||
|
|
||||||
// do not build out a reference, just marshal the reference.
|
// do not build out a reference, just marshal the reference.
|
||||||
mp := utils.CreateEmptyMapNode()
|
return utils.CreateRefNode(sp.GetReference()), nil
|
||||||
mp.Content = append(mp.Content,
|
|
||||||
utils.CreateStringNode("$ref"),
|
|
||||||
utils.CreateStringNode(sp.GetReference()))
|
|
||||||
return mp, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -306,8 +306,8 @@ $anchor: anchor`
|
|||||||
assert.Equal(t, "string", compiled.PropertyNames.Schema().Type[0])
|
assert.Equal(t, "string", compiled.PropertyNames.Schema().Type[0])
|
||||||
assert.Equal(t, "boolean", compiled.UnevaluatedItems.Schema().Type[0])
|
assert.Equal(t, "boolean", compiled.UnevaluatedItems.Schema().Type[0])
|
||||||
assert.Equal(t, "integer", compiled.UnevaluatedProperties.A.Schema().Type[0])
|
assert.Equal(t, "integer", compiled.UnevaluatedProperties.A.Schema().Type[0])
|
||||||
assert.True(t, compiled.ReadOnly)
|
assert.True(t, *compiled.ReadOnly)
|
||||||
assert.True(t, compiled.WriteOnly)
|
assert.True(t, *compiled.WriteOnly)
|
||||||
assert.True(t, *compiled.Deprecated)
|
assert.True(t, *compiled.Deprecated)
|
||||||
assert.True(t, *compiled.Nullable)
|
assert.True(t, *compiled.Nullable)
|
||||||
assert.Equal(t, "anchor", compiled.Anchor)
|
assert.Equal(t, "anchor", compiled.Anchor)
|
||||||
@@ -548,7 +548,7 @@ func TestSchemaProxy_GoLow(t *testing.T) {
|
|||||||
|
|
||||||
sp := NewSchemaProxy(&lowRef)
|
sp := NewSchemaProxy(&lowRef)
|
||||||
assert.Equal(t, lowProxy, sp.GoLow())
|
assert.Equal(t, lowProxy, sp.GoLow())
|
||||||
assert.Equal(t, ref, sp.GoLow().GetSchemaReference())
|
assert.Equal(t, ref, sp.GoLow().GetReference())
|
||||||
assert.Equal(t, ref, sp.GoLow().GetReference())
|
assert.Equal(t, ref, sp.GoLow().GetReference())
|
||||||
|
|
||||||
spNil := NewSchemaProxy(nil)
|
spNil := NewSchemaProxy(nil)
|
||||||
@@ -703,7 +703,14 @@ examples:
|
|||||||
`
|
`
|
||||||
highSchema := getHighSchema(t, yml)
|
highSchema := getHighSchema(t, yml)
|
||||||
|
|
||||||
assert.Equal(t, []any{int64(5), int64(10)}, highSchema.Examples)
|
examples := []any{}
|
||||||
|
for _, ex := range highSchema.Examples {
|
||||||
|
var v int64
|
||||||
|
assert.NoError(t, ex.Decode(&v))
|
||||||
|
examples = append(examples, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, []any{int64(5), int64(10)}, examples)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleNewSchema() {
|
func ExampleNewSchema() {
|
||||||
@@ -1123,7 +1130,7 @@ components:
|
|||||||
|
|
||||||
// now render it out, it should be identical.
|
// now render it out, it should be identical.
|
||||||
schemaBytes, _ := compiled.RenderInline()
|
schemaBytes, _ := compiled.RenderInline()
|
||||||
assert.Len(t, schemaBytes, 585)
|
assert.Equal(t, "properties:\n bigBank:\n type: object\n properties:\n failure_balance_transaction:\n allOf:\n - type: object\n properties:\n name:\n type: string\n price:\n type: number\n anyOf:\n - description: A balance transaction\n anyOf:\n - maxLength: 5000\n type: string\n - description: A balance transaction\n", string(schemaBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnevaluatedPropertiesBoolean_True(t *testing.T) {
|
func TestUnevaluatedPropertiesBoolean_True(t *testing.T) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
// The name used for each property MUST correspond to a security scheme declared in the Security Definitions
|
// The name used for each property MUST correspond to a security scheme declared in the Security Definitions
|
||||||
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
||||||
type SecurityRequirement struct {
|
type SecurityRequirement struct {
|
||||||
Requirements orderedmap.Map[string, []string] `json:"-" yaml:"-"`
|
Requirements *orderedmap.Map[string, []string] `json:"-" yaml:"-"`
|
||||||
low *base.SecurityRequirement
|
low *base.SecurityRequirement
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,6 @@ func (s *SecurityRequirement) Render() ([]byte, error) {
|
|||||||
|
|
||||||
// MarshalYAML will create a ready to render YAML representation of the SecurityRequirement object.
|
// MarshalYAML will create a ready to render YAML representation of the SecurityRequirement object.
|
||||||
func (s *SecurityRequirement) MarshalYAML() (interface{}, error) {
|
func (s *SecurityRequirement) MarshalYAML() (interface{}, error) {
|
||||||
|
|
||||||
type req struct {
|
type req struct {
|
||||||
line int
|
line int
|
||||||
key string
|
key string
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package base
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ type Tag struct {
|
|||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Tag
|
low *low.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTag(t *testing.T) {
|
func TestNewTag(t *testing.T) {
|
||||||
|
|
||||||
var cNode yaml.Node
|
var cNode yaml.Node
|
||||||
|
|
||||||
yml := `name: chicken
|
yml := `name: chicken
|
||||||
@@ -33,10 +32,13 @@ x-hack: code`
|
|||||||
|
|
||||||
highTag := NewTag(&lowTag)
|
highTag := NewTag(&lowTag)
|
||||||
|
|
||||||
|
var xHack string
|
||||||
|
_ = highTag.Extensions.GetOrZero("x-hack").Decode(&xHack)
|
||||||
|
|
||||||
assert.Equal(t, "chicken", highTag.Name)
|
assert.Equal(t, "chicken", highTag.Name)
|
||||||
assert.Equal(t, "nuggets", highTag.Description)
|
assert.Equal(t, "nuggets", highTag.Description)
|
||||||
assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL)
|
assert.Equal(t, "https://pb33f.io", highTag.ExternalDocs.URL)
|
||||||
assert.Equal(t, "code", highTag.Extensions["x-hack"])
|
assert.Equal(t, "code", xHack)
|
||||||
|
|
||||||
wentLow := highTag.GoLow()
|
wentLow := highTag.GoLow()
|
||||||
assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line)
|
assert.Equal(t, 5, wentLow.FindExtension("x-hack").ValueNode.Line)
|
||||||
@@ -45,11 +47,9 @@ x-hack: code`
|
|||||||
// render the tag as YAML
|
// render the tag as YAML
|
||||||
highTagBytes, _ := highTag.Render()
|
highTagBytes, _ := highTag.Render()
|
||||||
assert.Equal(t, strings.TrimSpace(string(highTagBytes)), yml)
|
assert.Equal(t, strings.TrimSpace(string(highTagBytes)), yml)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTag_RenderInline(t *testing.T) {
|
func TestTag_RenderInline(t *testing.T) {
|
||||||
|
|
||||||
tag := &Tag{
|
tag := &Tag{
|
||||||
Name: "cake",
|
Name: "cake",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package base
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ type XML struct {
|
|||||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||||
Attribute bool `json:"attribute,omitempty" yaml:"attribute,omitempty"`
|
Attribute bool `json:"attribute,omitempty" yaml:"attribute,omitempty"`
|
||||||
Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"`
|
Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"`
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.XML
|
low *low.XML
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,27 +11,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/high/nodes"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeEntry represents a single node used by NodeBuilder.
|
|
||||||
type NodeEntry struct {
|
|
||||||
Tag string
|
|
||||||
Key string
|
|
||||||
Value any
|
|
||||||
StringValue string
|
|
||||||
Line int
|
|
||||||
Style yaml.Style
|
|
||||||
RenderZero bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeBuilder is a structure used by libopenapi high-level objects, to render themselves back to YAML.
|
// NodeBuilder is a structure used by libopenapi high-level objects, to render themselves back to YAML.
|
||||||
// this allows high-level objects to be 'mutable' because all changes will be rendered out.
|
// this allows high-level objects to be 'mutable' because all changes will be rendered out.
|
||||||
type NodeBuilder struct {
|
type NodeBuilder struct {
|
||||||
Version float32
|
Version float32
|
||||||
Nodes []*NodeEntry
|
Nodes []*nodes.NodeEntry
|
||||||
High any
|
High any
|
||||||
Low any
|
Low any
|
||||||
Resolve bool // If set to true, all references will be rendered inline
|
Resolve bool // If set to true, all references will be rendered inline
|
||||||
@@ -62,7 +53,6 @@ func NewNodeBuilder(high any, low any) *NodeBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeBuilder) add(key string, i int) {
|
func (n *NodeBuilder) add(key string, i int) {
|
||||||
|
|
||||||
// only operate on exported fields.
|
// only operate on exported fields.
|
||||||
if unicode.IsLower(rune(key[0])) {
|
if unicode.IsLower(rune(key[0])) {
|
||||||
return
|
return
|
||||||
@@ -71,38 +61,38 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
// if the key is 'Extensions' then we need to extract the keys from the map
|
// if the key is 'Extensions' then we need to extract the keys from the map
|
||||||
// and add them to the node builder.
|
// and add them to the node builder.
|
||||||
if key == "Extensions" {
|
if key == "Extensions" {
|
||||||
extensions := reflect.ValueOf(n.High).Elem().FieldByName(key)
|
ev := reflect.ValueOf(n.High).Elem().FieldByName(key).Interface()
|
||||||
for b, e := range extensions.MapKeys() {
|
var extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
v := extensions.MapIndex(e)
|
if ev != nil {
|
||||||
|
extensions = ev.(*orderedmap.Map[string, *yaml.Node])
|
||||||
|
}
|
||||||
|
|
||||||
extKey := e.String()
|
var lowExtensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
extValue := v.Interface()
|
if n.Low != nil && !reflect.ValueOf(n.Low).IsZero() {
|
||||||
nodeEntry := &NodeEntry{Tag: extKey, Key: extKey, Value: extValue, Line: 9999 + b}
|
if j, ok := n.Low.(low.HasExtensionsUntyped); ok {
|
||||||
|
lowExtensions = j.GetExtensions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if n.Low != nil && !reflect.ValueOf(n.Low).IsZero() {
|
j := 0
|
||||||
fieldValue := reflect.ValueOf(n.Low).Elem().FieldByName("Extensions")
|
if lowExtensions != nil {
|
||||||
f := fieldValue.Interface()
|
// If we have low extensions get the original lowest line number so we end up in the same place
|
||||||
value := reflect.ValueOf(f)
|
for pair := orderedmap.First(lowExtensions); pair != nil; pair = pair.Next() {
|
||||||
switch value.Kind() {
|
if j == 0 || pair.Key().KeyNode.Line < j {
|
||||||
case reflect.Map:
|
j = pair.Key().KeyNode.Line
|
||||||
if j, ok := n.Low.(low.HasExtensionsUntyped); ok {
|
|
||||||
originalExtensions := j.GetExtensions()
|
|
||||||
u := 0
|
|
||||||
for k := range originalExtensions {
|
|
||||||
if k.Value == extKey {
|
|
||||||
if originalExtensions[k].ValueNode.Line != 0 {
|
|
||||||
nodeEntry.Style = originalExtensions[k].ValueNode.Style
|
|
||||||
nodeEntry.Line = originalExtensions[k].ValueNode.Line + u
|
|
||||||
} else {
|
|
||||||
nodeEntry.Line = 999999 + b + u
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for pair := orderedmap.First(extensions); pair != nil; pair = pair.Next() {
|
||||||
|
nodeEntry := &nodes.NodeEntry{Tag: pair.Key(), Key: pair.Key(), Value: pair.Value(), Line: j}
|
||||||
|
|
||||||
|
if lowExtensions != nil {
|
||||||
|
lowItem := low.FindItemInOrderedMap(pair.Key(), lowExtensions)
|
||||||
|
nodeEntry.LowValue = lowItem
|
||||||
|
}
|
||||||
n.Nodes = append(n.Nodes, nodeEntry)
|
n.Nodes = append(n.Nodes, nodeEntry)
|
||||||
|
j++
|
||||||
}
|
}
|
||||||
// done, extensions are handled separately.
|
// done, extensions are handled separately.
|
||||||
return
|
return
|
||||||
@@ -119,11 +109,11 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
|
|
||||||
var renderZeroFlag, omitemptyFlag bool
|
var renderZeroFlag, omitemptyFlag bool
|
||||||
tagParts := strings.Split(tag, ",")
|
tagParts := strings.Split(tag, ",")
|
||||||
for i = 1; i < len(tagParts); i++ {
|
for _, part := range tagParts {
|
||||||
if tagParts[i] == renderZero {
|
if part == renderZero {
|
||||||
renderZeroFlag = true
|
renderZeroFlag = true
|
||||||
}
|
}
|
||||||
if tagParts[i] == "omitempty" {
|
if part == "omitempty" {
|
||||||
omitemptyFlag = true
|
omitemptyFlag = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +123,9 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
f := fieldValue.Interface()
|
f := fieldValue.Interface()
|
||||||
value := reflect.ValueOf(f)
|
value := reflect.ValueOf(f)
|
||||||
var isZero bool
|
var isZero bool
|
||||||
if zeroer, ok := f.(yaml.IsZeroer); ok && zeroer.IsZero() {
|
if (value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr) && value.IsNil() {
|
||||||
|
isZero = true
|
||||||
|
} else if zeroer, ok := f.(yaml.IsZeroer); ok && zeroer.IsZero() {
|
||||||
isZero = true
|
isZero = true
|
||||||
} else if f == nil || value.IsZero() {
|
} else if f == nil || value.IsZero() {
|
||||||
isZero = true
|
isZero = true
|
||||||
@@ -146,7 +138,7 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create a new node entry
|
// create a new node entry
|
||||||
nodeEntry := &NodeEntry{Tag: tagName, Key: key}
|
nodeEntry := &nodes.NodeEntry{Tag: tagName, Key: key}
|
||||||
nodeEntry.RenderZero = renderZeroFlag
|
nodeEntry.RenderZero = renderZeroFlag
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Float64, reflect.Float32:
|
case reflect.Float64, reflect.Float32:
|
||||||
@@ -192,39 +184,24 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
fLow := lowFieldValue.Interface()
|
fLow := lowFieldValue.Interface()
|
||||||
value = reflect.ValueOf(fLow)
|
value = reflect.ValueOf(fLow)
|
||||||
|
|
||||||
type lineStyle struct {
|
nodeEntry.LowValue = fLow
|
||||||
line int
|
|
||||||
style yaml.Style
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
l := value.Len()
|
l := value.Len()
|
||||||
lines := make([]lineStyle, l)
|
lines := make([]int, l)
|
||||||
for g := 0; g < l; g++ {
|
for g := 0; g < l; g++ {
|
||||||
qw := value.Index(g).Interface()
|
qw := value.Index(g).Interface()
|
||||||
if we, wok := qw.(low.HasKeyNode); wok {
|
if we, wok := qw.(low.HasKeyNode); wok {
|
||||||
lines[g] = lineStyle{we.GetKeyNode().Line, we.GetKeyNode().Style}
|
lines[g] = we.GetKeyNode().Line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Slice(lines, func(i, j int) bool {
|
sort.Slice(lines, func(i, j int) bool {
|
||||||
return lines[i].line < lines[j].line
|
return lines[i] < lines[j]
|
||||||
})
|
})
|
||||||
nodeEntry.Line = lines[0].line // pick the lowest line number so this key is sorted in order.
|
nodeEntry.Line = lines[0]
|
||||||
nodeEntry.Style = lines[0].style
|
|
||||||
break
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
l := value.Len()
|
panic("only ordered maps are supported")
|
||||||
line := make([]int, l)
|
|
||||||
for q, ky := range value.MapKeys() {
|
|
||||||
if we, wok := ky.Interface().(low.HasKeyNode); wok {
|
|
||||||
line[q] = we.GetKeyNode().Line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Ints(line)
|
|
||||||
nodeEntry.Line = line[0]
|
|
||||||
|
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
y := value.Interface()
|
y := value.Interface()
|
||||||
nodeEntry.Line = 9999 + i
|
nodeEntry.Line = 9999 + i
|
||||||
@@ -232,13 +209,11 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
if nb.IsReference() {
|
if nb.IsReference() {
|
||||||
if jk, kj := y.(low.HasKeyNode); kj {
|
if jk, kj := y.(low.HasKeyNode); kj {
|
||||||
nodeEntry.Line = jk.GetKeyNode().Line
|
nodeEntry.Line = jk.GetKeyNode().Line
|
||||||
nodeEntry.Style = jk.GetKeyNode().Style
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nb.GetValueNode() != nil {
|
if nb.GetValueNode() != nil {
|
||||||
nodeEntry.Line = nb.GetValueNode().Line
|
nodeEntry.Line = nb.GetValueNode().Line
|
||||||
nodeEntry.Style = nb.GetValueNode().Style
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -252,12 +227,13 @@ func (n *NodeBuilder) add(key string, i int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeBuilder) renderReference() []*yaml.Node {
|
func (n *NodeBuilder) renderReference(fg low.IsReferenced) *yaml.Node {
|
||||||
fg := n.Low.(low.IsReferenced)
|
origNode := fg.GetReferenceNode()
|
||||||
nodes := make([]*yaml.Node, 2)
|
if origNode == nil {
|
||||||
nodes[0] = utils.CreateStringNode("$ref")
|
return utils.CreateRefNode(fg.GetReference())
|
||||||
nodes[1] = utils.CreateStringNode(fg.GetReference())
|
}
|
||||||
return nodes
|
|
||||||
|
return origNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined
|
// Render will render the NodeBuilder back to a YAML node, iterating over every NodeEntry defined
|
||||||
@@ -272,8 +248,7 @@ func (n *NodeBuilder) Render() *yaml.Node {
|
|||||||
g := reflect.ValueOf(fg)
|
g := reflect.ValueOf(fg)
|
||||||
if !g.IsNil() {
|
if !g.IsNil() {
|
||||||
if fg.IsReference() && !n.Resolve {
|
if fg.IsReference() && !n.Resolve {
|
||||||
m.Content = append(m.Content, n.renderReference()...)
|
return n.renderReference(n.Low.(low.IsReferenced))
|
||||||
return m
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,7 +270,7 @@ func (n *NodeBuilder) Render() *yaml.Node {
|
|||||||
// AddYAMLNode will add a new *yaml.Node to the parent node, using the tag, key and value provided.
|
// AddYAMLNode will add a new *yaml.Node to the parent node, using the tag, key and value provided.
|
||||||
// If the value is nil, then the node will not be added. This method is recursive, so it will dig down
|
// If the value is nil, then the node will not be added. This method is recursive, so it will dig down
|
||||||
// into any non-scalar types.
|
// into any non-scalar types.
|
||||||
func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Node {
|
func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *nodes.NodeEntry) *yaml.Node {
|
||||||
if entry.Value == nil {
|
if entry.Value == nil {
|
||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
@@ -305,11 +280,11 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
var l *yaml.Node
|
var l *yaml.Node
|
||||||
if entry.Tag != "" {
|
if entry.Tag != "" {
|
||||||
l = utils.CreateStringNode(entry.Tag)
|
l = utils.CreateStringNode(entry.Tag)
|
||||||
|
l.Style = entry.KeyStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
value := entry.Value
|
value := entry.Value
|
||||||
line := entry.Line
|
line := entry.Line
|
||||||
key := entry.Key
|
|
||||||
|
|
||||||
var valueNode *yaml.Node
|
var valueNode *yaml.Node
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
@@ -318,9 +293,15 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
val := value.(string)
|
val := value.(string)
|
||||||
valueNode = utils.CreateStringNode(val)
|
valueNode = utils.CreateStringNode(val)
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
valueNode.Style = entry.Style
|
|
||||||
break
|
|
||||||
|
|
||||||
|
if entry.LowValue != nil {
|
||||||
|
if vnut, ok := entry.LowValue.(low.HasValueNodeUntyped); ok {
|
||||||
|
vn := vnut.GetValueNode()
|
||||||
|
if vn != nil {
|
||||||
|
valueNode.Style = vn.Style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
val := value.(bool)
|
val := value.(bool)
|
||||||
if !val {
|
if !val {
|
||||||
@@ -329,26 +310,18 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
valueNode = utils.CreateBoolNode("true")
|
valueNode = utils.CreateBoolNode("true")
|
||||||
}
|
}
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
break
|
|
||||||
|
|
||||||
case reflect.Int:
|
case reflect.Int:
|
||||||
val := strconv.Itoa(value.(int))
|
val := strconv.Itoa(value.(int))
|
||||||
valueNode = utils.CreateIntNode(val)
|
valueNode = utils.CreateIntNode(val)
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
break
|
|
||||||
|
|
||||||
case reflect.Int64:
|
case reflect.Int64:
|
||||||
val := strconv.FormatInt(value.(int64), 10)
|
val := strconv.FormatInt(value.(int64), 10)
|
||||||
valueNode = utils.CreateIntNode(val)
|
valueNode = utils.CreateIntNode(val)
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
break
|
|
||||||
|
|
||||||
case reflect.Float32:
|
case reflect.Float32:
|
||||||
val := strconv.FormatFloat(float64(value.(float32)), 'f', 2, 64)
|
val := strconv.FormatFloat(float64(value.(float32)), 'f', 2, 64)
|
||||||
valueNode = utils.CreateFloatNode(val)
|
valueNode = utils.CreateFloatNode(val)
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
break
|
|
||||||
|
|
||||||
case reflect.Float64:
|
case reflect.Float64:
|
||||||
precision := -1
|
precision := -1
|
||||||
if entry.StringValue != "" && strings.Contains(entry.StringValue, ".") {
|
if entry.StringValue != "" && strings.Contains(entry.StringValue, ".") {
|
||||||
@@ -357,87 +330,8 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
val := strconv.FormatFloat(value.(float64), 'f', precision, 64)
|
val := strconv.FormatFloat(value.(float64), 'f', precision, 64)
|
||||||
valueNode = utils.CreateFloatNode(val)
|
valueNode = utils.CreateFloatNode(val)
|
||||||
valueNode.Line = line
|
valueNode.Line = line
|
||||||
break
|
|
||||||
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
|
panic("only ordered maps are supported")
|
||||||
// the keys will be rendered randomly, if we don't find out the original line
|
|
||||||
// number of the tag.
|
|
||||||
|
|
||||||
var orderedCollection []*NodeEntry
|
|
||||||
m := reflect.ValueOf(value)
|
|
||||||
for g, k := range m.MapKeys() {
|
|
||||||
var x string
|
|
||||||
// extract key
|
|
||||||
yu := k.Interface()
|
|
||||||
if o, ok := yu.(low.HasKeyNode); ok {
|
|
||||||
x = o.GetKeyNode().Value
|
|
||||||
} else {
|
|
||||||
x = k.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// go low and pull out the line number.
|
|
||||||
lowProps := reflect.ValueOf(n.Low)
|
|
||||||
if n.Low != nil && !lowProps.IsZero() && !lowProps.IsNil() {
|
|
||||||
gu := lowProps.Elem()
|
|
||||||
gi := gu.FieldByName(key)
|
|
||||||
jl := reflect.ValueOf(gi)
|
|
||||||
if !jl.IsZero() && gi.Interface() != nil {
|
|
||||||
gh := gi.Interface()
|
|
||||||
// extract low level key line number
|
|
||||||
if pr, ok := gh.(low.HasValueUnTyped); ok {
|
|
||||||
fg := reflect.ValueOf(pr.GetValueUntyped())
|
|
||||||
found := false
|
|
||||||
found, orderedCollection = n.extractLowMapKeys(fg, x, found, orderedCollection, m, k)
|
|
||||||
if found != true {
|
|
||||||
// this is something new, add it.
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: 9999 + g,
|
|
||||||
Value: m.MapIndex(k).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this is a map, but it may be wrapped still.
|
|
||||||
bj := reflect.ValueOf(gh)
|
|
||||||
orderedCollection = n.extractLowMapKeysWrapped(bj, x, orderedCollection, g)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this is a map, without any low level details available (probably an extension map).
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: 9999 + g,
|
|
||||||
Value: m.MapIndex(k).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this is a map, without any low level details available (probably an extension map).
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: 9999 + g,
|
|
||||||
Value: m.MapIndex(k).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort the slice by line number to ensure everything is rendered in order.
|
|
||||||
sort.Slice(orderedCollection, func(i, j int) bool {
|
|
||||||
return orderedCollection[i].Line < orderedCollection[j].Line
|
|
||||||
})
|
|
||||||
|
|
||||||
// create an empty map.
|
|
||||||
p := utils.CreateEmptyMapNode()
|
|
||||||
|
|
||||||
// build out each map node in original order.
|
|
||||||
for _, cv := range orderedCollection {
|
|
||||||
n.AddYAMLNode(p, cv)
|
|
||||||
}
|
|
||||||
if len(p.Content) > 0 {
|
|
||||||
valueNode = p
|
|
||||||
}
|
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
|
|
||||||
@@ -456,8 +350,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
if ut != nil && r.GetReference() != "" &&
|
if ut != nil && r.GetReference() != "" &&
|
||||||
ut.(low.IsReferenced).IsReference() {
|
ut.(low.IsReferenced).IsReference() {
|
||||||
if !n.Resolve {
|
if !n.Resolve {
|
||||||
refNode := utils.CreateRefNode(glu.GoLowUntyped().(low.IsReferenced).GetReference())
|
sl.Content = append(sl.Content, n.renderReference(glu.GoLowUntyped().(low.IsReferenced)))
|
||||||
sl.Content = append(sl.Content, refNode)
|
|
||||||
skip = true
|
skip = true
|
||||||
} else {
|
} else {
|
||||||
skip = false
|
skip = false
|
||||||
@@ -472,13 +365,13 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
if er, ko := sqi.(Renderable); ko {
|
if er, ko := sqi.(Renderable); ko {
|
||||||
var rend interface{}
|
var rend interface{}
|
||||||
if !n.Resolve {
|
if !n.Resolve {
|
||||||
rend, _ = er.(Renderable).MarshalYAML()
|
rend, _ = er.MarshalYAML()
|
||||||
} else {
|
} else {
|
||||||
// try and render inline, if we can, otherwise treat as normal.
|
// try and render inline, if we can, otherwise treat as normal.
|
||||||
if _, ko := er.(RenderableInline); ko {
|
if _, ko := er.(RenderableInline); ko {
|
||||||
rend, _ = er.(RenderableInline).MarshalYAMLInline()
|
rend, _ = er.(RenderableInline).MarshalYAMLInline()
|
||||||
} else {
|
} else {
|
||||||
rend, _ = er.(Renderable).MarshalYAML()
|
rend, _ = er.MarshalYAML()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check if this is a pointer or not.
|
// check if this is a pointer or not.
|
||||||
@@ -505,6 +398,17 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return parent
|
return parent
|
||||||
} else {
|
} else {
|
||||||
|
if entry.LowValue != nil {
|
||||||
|
if vnut, ok := entry.LowValue.(low.HasValueNodeUntyped); ok {
|
||||||
|
vn := vnut.GetValueNode()
|
||||||
|
if vn.Kind == yaml.SequenceNode {
|
||||||
|
for i := range vn.Content {
|
||||||
|
rawNode.Content[i].Style = vn.Content[i].Style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
valueNode = &rawNode
|
valueNode = &rawNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,18 +428,29 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
return parent
|
return parent
|
||||||
|
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if r, ok := value.(Renderable); ok {
|
if m, ok := value.(orderedmap.MapToYamlNoder); ok {
|
||||||
|
l := entry.LowValue
|
||||||
|
|
||||||
|
if l == nil {
|
||||||
|
if gl, ok := value.(GoesLowUntyped); ok && gl.GoLowUntyped() != nil {
|
||||||
|
l = gl.GoLowUntyped()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p := m.ToYamlNode(n, l)
|
||||||
|
if len(p.Content) > 0 {
|
||||||
|
valueNode = p
|
||||||
|
}
|
||||||
|
} else if r, ok := value.(Renderable); ok {
|
||||||
if gl, lg := value.(GoesLowUntyped); lg {
|
if gl, lg := value.(GoesLowUntyped); lg {
|
||||||
if gl.GoLowUntyped() != nil {
|
lut := gl.GoLowUntyped()
|
||||||
ut := reflect.ValueOf(gl.GoLowUntyped())
|
if lut != nil {
|
||||||
|
lr := lut.(low.IsReferenced)
|
||||||
|
ut := reflect.ValueOf(lr)
|
||||||
if !ut.IsNil() {
|
if !ut.IsNil() {
|
||||||
if gl.GoLowUntyped().(low.IsReferenced).IsReference() {
|
if lut.(low.IsReferenced).IsReference() {
|
||||||
if !n.Resolve {
|
if !n.Resolve {
|
||||||
// TODO: use renderReference here.
|
valueNode = n.renderReference(lut.(low.IsReferenced))
|
||||||
rvn := utils.CreateEmptyMapNode()
|
|
||||||
rvn.Content = append(rvn.Content, utils.CreateStringNode("$ref"))
|
|
||||||
rvn.Content = append(rvn.Content, utils.CreateStringNode(gl.GoLowUntyped().(low.IsReferenced).GetReference()))
|
|
||||||
valueNode = rvn
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,64 +536,6 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *NodeEntry) *yaml.Nod
|
|||||||
return parent
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeBuilder) extractLowMapKeysWrapped(iu reflect.Value, x string, orderedCollection []*NodeEntry, g int) []*NodeEntry {
|
|
||||||
for _, ky := range iu.MapKeys() {
|
|
||||||
ty := ky.Interface()
|
|
||||||
if ere, eok := ty.(low.HasKeyNode); eok {
|
|
||||||
er := ere.GetKeyNode().Value
|
|
||||||
if er == x {
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: ky.Interface().(low.HasKeyNode).GetKeyNode().Line,
|
|
||||||
Value: iu.MapIndex(ky).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: 9999 + g,
|
|
||||||
Value: iu.MapIndex(ky).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return orderedCollection
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NodeBuilder) extractLowMapKeys(fg reflect.Value, x string, found bool, orderedCollection []*NodeEntry, m reflect.Value, k reflect.Value) (bool, []*NodeEntry) {
|
|
||||||
if fg.IsValid() && !fg.IsZero() {
|
|
||||||
for j, ky := range fg.MapKeys() {
|
|
||||||
hu := ky.Interface()
|
|
||||||
if we, wok := hu.(low.HasKeyNode); wok {
|
|
||||||
er := we.GetKeyNode().Value
|
|
||||||
if er == x {
|
|
||||||
found = true
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: x,
|
|
||||||
Key: x,
|
|
||||||
Line: we.GetKeyNode().Line,
|
|
||||||
Value: m.MapIndex(k).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uu := ky.Interface()
|
|
||||||
if uu == x {
|
|
||||||
// this is a map, without any low level details available
|
|
||||||
found = true
|
|
||||||
orderedCollection = append(orderedCollection, &NodeEntry{
|
|
||||||
Tag: uu.(string),
|
|
||||||
Key: uu.(string),
|
|
||||||
Line: 9999 + j,
|
|
||||||
Value: m.MapIndex(k).Interface(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found, orderedCollection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renderable is an interface that can be implemented by types that provide a custom MarshalYAML method.
|
// Renderable is an interface that can be implemented by types that provide a custom MarshalYAML method.
|
||||||
type Renderable interface {
|
type Renderable interface {
|
||||||
MarshalYAML() (interface{}, error)
|
MarshalYAML() (interface{}, error)
|
||||||
|
|||||||
@@ -4,169 +4,147 @@
|
|||||||
package high
|
package high
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/high/nodes"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type key struct {
|
type valueReferenceStruct struct {
|
||||||
Name string `yaml:"name,omitempty"`
|
ref bool
|
||||||
ref bool
|
refStr string
|
||||||
refStr string
|
Value string `yaml:"value,omitempty"`
|
||||||
ln int
|
|
||||||
nilval bool
|
|
||||||
v any
|
|
||||||
kn *yaml.Node
|
|
||||||
low.IsReferenced `yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) GetKeyNode() *yaml.Node {
|
func (r valueReferenceStruct) IsReference() bool {
|
||||||
if k.kn != nil {
|
return r.ref
|
||||||
return k.kn
|
|
||||||
}
|
|
||||||
kn := utils.CreateStringNode("meddy")
|
|
||||||
kn.Line = k.ln
|
|
||||||
return kn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) GetValueUntyped() any {
|
func (r valueReferenceStruct) GetReference() string {
|
||||||
return k.v
|
return r.refStr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) GetValueNode() *yaml.Node {
|
func (r *valueReferenceStruct) SetReference(ref string, _ *yaml.Node) {
|
||||||
return k.GetValueNodeUntyped()
|
r.refStr = ref
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) GetValueNodeUntyped() *yaml.Node {
|
func (r *valueReferenceStruct) GetReferenceNode() *yaml.Node {
|
||||||
if k.nilval {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
kn := utils.CreateStringNode("maddy")
|
|
||||||
kn.Line = k.ln
|
|
||||||
return kn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) IsReference() bool {
|
func (r valueReferenceStruct) MarshalYAML() (interface{}, error) {
|
||||||
return k.ref
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k key) GetReference() string {
|
|
||||||
return k.refStr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k key) SetReference(ref string) {
|
|
||||||
k.refStr = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k key) GoLowUntyped() any {
|
|
||||||
return &k
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k key) MarshalYAML() (interface{}, error) {
|
|
||||||
return utils.CreateStringNode("pizza"), nil
|
return utils.CreateStringNode("pizza"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k key) MarshalYAMLInline() (interface{}, error) {
|
func (r valueReferenceStruct) MarshalYAMLInline() (interface{}, error) {
|
||||||
return utils.CreateStringNode("pizza-inline!"), nil
|
return utils.CreateStringNode("pizza-inline!"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r valueReferenceStruct) GoLowUntyped() any {
|
||||||
|
return &r
|
||||||
|
}
|
||||||
|
|
||||||
type plug struct {
|
type plug struct {
|
||||||
Name []string `yaml:"name,omitempty"`
|
Name []string `yaml:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type test1 struct {
|
type test1 struct {
|
||||||
Thrig map[string]*plug `yaml:"thrig,omitempty"`
|
Thrig *orderedmap.Map[string, *plug] `yaml:"thrig,omitempty"`
|
||||||
Thing string `yaml:"thing,omitempty"`
|
Thing string `yaml:"thing,omitempty"`
|
||||||
Thong int `yaml:"thong,omitempty"`
|
Thong int `yaml:"thong,omitempty"`
|
||||||
Thrum int64 `yaml:"thrum,omitempty"`
|
Thrum int64 `yaml:"thrum,omitempty"`
|
||||||
Thang float32 `yaml:"thang,omitempty"`
|
Thang float32 `yaml:"thang,omitempty"`
|
||||||
Thung float64 `yaml:"thung,omitempty"`
|
Thung float64 `yaml:"thung,omitempty"`
|
||||||
Thyme bool `yaml:"thyme,omitempty"`
|
Thyme bool `yaml:"thyme,omitempty"`
|
||||||
Thurm any `yaml:"thurm,omitempty"`
|
Thurm any `yaml:"thurm,omitempty"`
|
||||||
Thugg *bool `yaml:"thugg,renderZero"`
|
Thugg *bool `yaml:"thugg,renderZero"`
|
||||||
Thurr *int64 `yaml:"thurr,omitempty"`
|
Thurr *int64 `yaml:"thurr,omitempty"`
|
||||||
Thral *float64 `yaml:"thral,omitempty"`
|
Thral *float64 `yaml:"thral,omitempty"`
|
||||||
Throo *float64 `yaml:"throo,renderZero,omitempty"`
|
Throo *float64 `yaml:"throo,renderZero,omitempty"`
|
||||||
Tharg []string `yaml:"tharg,omitempty"`
|
Tharg []string `yaml:"tharg,omitempty"`
|
||||||
Type []string `yaml:"type,omitempty"`
|
Type []string `yaml:"type,omitempty"`
|
||||||
Throg []*key `yaml:"throg,omitempty"`
|
Throg []*valueReferenceStruct `yaml:"throg,omitempty"`
|
||||||
Thrat []interface{} `yaml:"thrat,omitempty"`
|
Thrat []interface{} `yaml:"thrat,omitempty"`
|
||||||
Thrag []map[string][]string `yaml:"thrag,omitempty"`
|
Thrag []*orderedmap.Map[string, []string] `yaml:"thrag,omitempty"`
|
||||||
Thrug map[string]string `yaml:"thrug,omitempty"`
|
Thrug *orderedmap.Map[string, string] `yaml:"thrug,omitempty"`
|
||||||
Thoom []map[string]string `yaml:"thoom,omitempty"`
|
Thoom []*orderedmap.Map[string, string] `yaml:"thoom,omitempty"`
|
||||||
Thomp map[key]string `yaml:"thomp,omitempty"`
|
Thomp *orderedmap.Map[low.KeyReference[string], string] `yaml:"thomp,omitempty"`
|
||||||
Thump key `yaml:"thump,omitempty"`
|
Thump valueReferenceStruct `yaml:"thump,omitempty"`
|
||||||
Thane key `yaml:"thane,omitempty"`
|
Thane valueReferenceStruct `yaml:"thane,omitempty"`
|
||||||
Thunk key `yaml:"thunk,omitempty"`
|
Thunk valueReferenceStruct `yaml:"thunk,omitempty"`
|
||||||
Thrim *key `yaml:"thrim,omitempty"`
|
Thrim *valueReferenceStruct `yaml:"thrim,omitempty"`
|
||||||
Thril map[string]*key `yaml:"thril,omitempty"`
|
Thril *orderedmap.Map[string, *valueReferenceStruct] `yaml:"thril,omitempty"`
|
||||||
Extensions map[string]any `yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `yaml:"-"`
|
||||||
ignoreMe string `yaml:"-"`
|
ignoreMe string `yaml:"-"`
|
||||||
IgnoreMe string `yaml:"-"`
|
IgnoreMe string `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (te *test1) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (te *test1) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
|
g := orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
|
||||||
|
|
||||||
g := make(map[low.KeyReference[string]]low.ValueReference[any])
|
i := 0
|
||||||
|
for pair := orderedmap.First(te.Extensions); pair != nil; pair = pair.Next() {
|
||||||
for i := range te.Extensions {
|
kn := utils.CreateStringNode(pair.Key())
|
||||||
|
kn.Line = 999999 + i // weighted to the bottom.
|
||||||
f := reflect.TypeOf(te.Extensions[i])
|
|
||||||
switch f.Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
vn := utils.CreateStringNode(te.Extensions[i].(string))
|
|
||||||
vn.Line = 999999 // weighted to the bottom.
|
|
||||||
g[low.KeyReference[string]{
|
|
||||||
Value: i,
|
|
||||||
KeyNode: vn,
|
|
||||||
}] = low.ValueReference[any]{
|
|
||||||
ValueNode: vn,
|
|
||||||
Value: te.Extensions[i].(string),
|
|
||||||
}
|
|
||||||
case reflect.Map:
|
|
||||||
kn := utils.CreateStringNode(i)
|
|
||||||
var vn yaml.Node
|
|
||||||
_ = vn.Decode(te.Extensions[i])
|
|
||||||
|
|
||||||
kn.Line = 999999 // weighted to the bottom.
|
|
||||||
g[low.KeyReference[string]{
|
|
||||||
Value: i,
|
|
||||||
KeyNode: kn,
|
|
||||||
}] = low.ValueReference[any]{
|
|
||||||
ValueNode: &vn,
|
|
||||||
Value: te.Extensions[i],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
g.Set(low.KeyReference[string]{
|
||||||
|
Value: pair.Key(),
|
||||||
|
KeyNode: kn,
|
||||||
|
}, low.ValueReference[*yaml.Node]{
|
||||||
|
ValueNode: pair.Value(),
|
||||||
|
Value: pair.Value(),
|
||||||
|
})
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (te *test1) MarshalYAML() (interface{}, error) {
|
func (te *test1) MarshalYAML() (interface{}, error) {
|
||||||
|
panic("MarshalYAML")
|
||||||
nb := NewNodeBuilder(te, te)
|
nb := NewNodeBuilder(te, te)
|
||||||
return nb.Render(), nil
|
return nb.Render(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (te *test1) GetKeyNode() *yaml.Node {
|
func (te *test1) GetKeyNode() *yaml.Node {
|
||||||
|
panic("GetKeyNode")
|
||||||
kn := utils.CreateStringNode("meddy")
|
kn := utils.CreateStringNode("meddy")
|
||||||
kn.Line = 20
|
kn.Line = 20
|
||||||
return kn
|
return kn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (te *test1) GoesLowUntyped() any {
|
func (te *test1) GoesLowUntyped() any {
|
||||||
|
panic("GoesLowUntyped")
|
||||||
return te
|
return te
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder(t *testing.T) {
|
func TestNewNodeBuilder(t *testing.T) {
|
||||||
|
|
||||||
b := true
|
b := true
|
||||||
c := int64(12345)
|
c := int64(12345)
|
||||||
d := 1234.1234
|
d := 1234.1234
|
||||||
|
|
||||||
|
thoom1 := orderedmap.New[string, string]()
|
||||||
|
thoom1.Set("maddy", "champion")
|
||||||
|
|
||||||
|
thoom2 := orderedmap.New[string, string]()
|
||||||
|
thoom2.Set("ember", "naughty")
|
||||||
|
|
||||||
|
thomp := orderedmap.New[low.KeyReference[string], string]()
|
||||||
|
thomp.Set(low.KeyReference[string]{
|
||||||
|
Value: "meddy",
|
||||||
|
KeyNode: utils.CreateStringNode("meddy"),
|
||||||
|
}, "princess")
|
||||||
|
|
||||||
|
thrug := orderedmap.New[string, string]()
|
||||||
|
thrug.Set("chicken", "nuggets")
|
||||||
|
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-pizza", utils.CreateStringNode("time"))
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
ignoreMe: "I should never be seen!",
|
ignoreMe: "I should never be seen!",
|
||||||
Thing: "ding",
|
Thing: "ding",
|
||||||
@@ -181,30 +159,18 @@ func TestNewNodeBuilder(t *testing.T) {
|
|||||||
Thral: &d,
|
Thral: &d,
|
||||||
Tharg: []string{"chicken", "nuggets"},
|
Tharg: []string{"chicken", "nuggets"},
|
||||||
Type: []string{"chicken"},
|
Type: []string{"chicken"},
|
||||||
Thoom: []map[string]string{
|
Thoom: []*orderedmap.Map[string, string]{
|
||||||
{
|
thoom1,
|
||||||
"maddy": "champion",
|
thoom2,
|
||||||
},
|
|
||||||
{
|
|
||||||
"ember": "naughty",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Thomp: map[key]string{
|
Thomp: thomp,
|
||||||
{ln: 1}: "princess",
|
Thane: valueReferenceStruct{ // this is going to be ignored, needs to be a ValueReference
|
||||||
},
|
Value: "ripples",
|
||||||
Thane: key{ // this is going to be ignored, needs to be a ValueReference
|
|
||||||
ln: 2,
|
|
||||||
ref: true,
|
|
||||||
refStr: "ripples",
|
|
||||||
},
|
|
||||||
Thrug: map[string]string{
|
|
||||||
"chicken": "nuggets",
|
|
||||||
},
|
|
||||||
Thump: key{Name: "I will be ignored", ln: 3},
|
|
||||||
Thunk: key{ln: 4, nilval: true},
|
|
||||||
Extensions: map[string]any{
|
|
||||||
"x-pizza": "time",
|
|
||||||
},
|
},
|
||||||
|
Thrug: thrug,
|
||||||
|
Thump: valueReferenceStruct{Value: "I will be ignored"},
|
||||||
|
Thunk: valueReferenceStruct{},
|
||||||
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, nil)
|
nb := NewNodeBuilder(&t1, nil)
|
||||||
@@ -235,11 +201,9 @@ thomp:
|
|||||||
x-pizza: time`
|
x-pizza: time`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_Type(t *testing.T) {
|
func TestNewNodeBuilder_Type(t *testing.T) {
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Type: []string{"chicken", "soup"},
|
Type: []string{"chicken", "soup"},
|
||||||
}
|
}
|
||||||
@@ -257,15 +221,12 @@ func TestNewNodeBuilder_Type(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_IsReferenced(t *testing.T) {
|
func TestNewNodeBuilder_IsReferenced(t *testing.T) {
|
||||||
|
t1 := &low.ValueReference[string]{
|
||||||
t1 := key{
|
Value: "cotton",
|
||||||
Name: "cotton",
|
|
||||||
ref: true,
|
|
||||||
refStr: "#/my/heart",
|
|
||||||
ln: 2,
|
|
||||||
}
|
}
|
||||||
|
t1.SetReference("#/my/heart", nil)
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
node := nb.Render()
|
node := nb.Render()
|
||||||
|
|
||||||
data, _ := yaml.Marshal(node)
|
data, _ := yaml.Marshal(node)
|
||||||
@@ -276,14 +237,14 @@ func TestNewNodeBuilder_IsReferenced(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_Extensions(t *testing.T) {
|
func TestNewNodeBuilder_Extensions(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-pizza", utils.CreateStringNode("time"))
|
||||||
|
ext.Set("x-money", utils.CreateStringNode("time"))
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thing: "ding",
|
Thing: "ding",
|
||||||
Extensions: map[string]any{
|
Extensions: ext,
|
||||||
"x-pizza": "time",
|
Thong: 1,
|
||||||
"x-money": "time",
|
|
||||||
},
|
|
||||||
Thong: 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
@@ -294,14 +255,14 @@ func TestNewNodeBuilder_Extensions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_LowValueNode(t *testing.T) {
|
func TestNewNodeBuilder_LowValueNode(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-pizza", utils.CreateStringNode("time"))
|
||||||
|
ext.Set("x-money", utils.CreateStringNode("time"))
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thing: "ding",
|
Thing: "ding",
|
||||||
Extensions: map[string]any{
|
Extensions: ext,
|
||||||
"x-pizza": "time",
|
Thong: 1,
|
||||||
"x-money": "time",
|
|
||||||
},
|
|
||||||
Thong: 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
@@ -313,12 +274,11 @@ func TestNewNodeBuilder_LowValueNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_NoValue(t *testing.T) {
|
func TestNewNodeBuilder_NoValue(t *testing.T) {
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thing: "",
|
Thing: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeEnty := NodeEntry{}
|
nodeEnty := nodes.NodeEntry{}
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
node := nb.AddYAMLNode(nil, &nodeEnty)
|
node := nb.AddYAMLNode(nil, &nodeEnty)
|
||||||
assert.Nil(t, node)
|
assert.Nil(t, node)
|
||||||
@@ -326,7 +286,7 @@ func TestNewNodeBuilder_NoValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewNodeBuilder_EmptyString(t *testing.T) {
|
func TestNewNodeBuilder_EmptyString(t *testing.T) {
|
||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nodeEnty := NodeEntry{}
|
nodeEnty := nodes.NodeEntry{}
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
node := nb.AddYAMLNode(nil, &nodeEnty)
|
node := nb.AddYAMLNode(nil, &nodeEnty)
|
||||||
assert.Nil(t, node)
|
assert.Nil(t, node)
|
||||||
@@ -334,7 +294,7 @@ func TestNewNodeBuilder_EmptyString(t *testing.T) {
|
|||||||
|
|
||||||
func TestNewNodeBuilder_EmptyStringRenderZero(t *testing.T) {
|
func TestNewNodeBuilder_EmptyStringRenderZero(t *testing.T) {
|
||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nodeEnty := NodeEntry{RenderZero: true, Value: ""}
|
nodeEnty := nodes.NodeEntry{RenderZero: true, Value: ""}
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
m := utils.CreateEmptyMapNode()
|
m := utils.CreateEmptyMapNode()
|
||||||
node := nb.AddYAMLNode(m, &nodeEnty)
|
node := nb.AddYAMLNode(m, &nodeEnty)
|
||||||
@@ -344,7 +304,7 @@ func TestNewNodeBuilder_EmptyStringRenderZero(t *testing.T) {
|
|||||||
func TestNewNodeBuilder_Bool(t *testing.T) {
|
func TestNewNodeBuilder_Bool(t *testing.T) {
|
||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
nodeEnty := NodeEntry{}
|
nodeEnty := nodes.NodeEntry{}
|
||||||
node := nb.AddYAMLNode(nil, &nodeEnty)
|
node := nb.AddYAMLNode(nil, &nodeEnty)
|
||||||
assert.Nil(t, node)
|
assert.Nil(t, node)
|
||||||
}
|
}
|
||||||
@@ -364,7 +324,7 @@ func TestNewNodeBuilder_Int(t *testing.T) {
|
|||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
p := utils.CreateEmptyMapNode()
|
p := utils.CreateEmptyMapNode()
|
||||||
nodeEnty := NodeEntry{Tag: "p", Value: 12, Key: "p"}
|
nodeEnty := nodes.NodeEntry{Tag: "p", Value: 12, Key: "p"}
|
||||||
node := nb.AddYAMLNode(p, &nodeEnty)
|
node := nb.AddYAMLNode(p, &nodeEnty)
|
||||||
assert.NotNil(t, node)
|
assert.NotNil(t, node)
|
||||||
assert.Len(t, node.Content, 2)
|
assert.Len(t, node.Content, 2)
|
||||||
@@ -375,7 +335,7 @@ func TestNewNodeBuilder_Int64(t *testing.T) {
|
|||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
p := utils.CreateEmptyMapNode()
|
p := utils.CreateEmptyMapNode()
|
||||||
nodeEnty := NodeEntry{Tag: "p", Value: int64(234556), Key: "p"}
|
nodeEnty := nodes.NodeEntry{Tag: "p", Value: int64(234556), Key: "p"}
|
||||||
node := nb.AddYAMLNode(p, &nodeEnty)
|
node := nb.AddYAMLNode(p, &nodeEnty)
|
||||||
assert.NotNil(t, node)
|
assert.NotNil(t, node)
|
||||||
assert.Len(t, node.Content, 2)
|
assert.Len(t, node.Content, 2)
|
||||||
@@ -386,7 +346,7 @@ func TestNewNodeBuilder_Float32(t *testing.T) {
|
|||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
p := utils.CreateEmptyMapNode()
|
p := utils.CreateEmptyMapNode()
|
||||||
nodeEnty := NodeEntry{Tag: "p", Value: float32(1234.23), Key: "p"}
|
nodeEnty := nodes.NodeEntry{Tag: "p", Value: float32(1234.23), Key: "p"}
|
||||||
node := nb.AddYAMLNode(p, &nodeEnty)
|
node := nb.AddYAMLNode(p, &nodeEnty)
|
||||||
assert.NotNil(t, node)
|
assert.NotNil(t, node)
|
||||||
assert.Len(t, node.Content, 2)
|
assert.Len(t, node.Content, 2)
|
||||||
@@ -397,7 +357,7 @@ func TestNewNodeBuilder_Float64(t *testing.T) {
|
|||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
p := utils.CreateEmptyMapNode()
|
p := utils.CreateEmptyMapNode()
|
||||||
nodeEnty := NodeEntry{Tag: "p", Value: 1234.232323, Key: "p", StringValue: "1234.232323"}
|
nodeEnty := nodes.NodeEntry{Tag: "p", Value: 1234.232323, Key: "p", StringValue: "1234.232323"}
|
||||||
node := nb.AddYAMLNode(p, &nodeEnty)
|
node := nb.AddYAMLNode(p, &nodeEnty)
|
||||||
assert.NotNil(t, node)
|
assert.NotNil(t, node)
|
||||||
assert.Len(t, node.Content, 2)
|
assert.Len(t, node.Content, 2)
|
||||||
@@ -410,30 +370,33 @@ func TestNewNodeBuilder_EmptyNode(t *testing.T) {
|
|||||||
nb.Nodes = nil
|
nb.Nodes = nil
|
||||||
m := nb.Render()
|
m := nb.Render()
|
||||||
assert.Len(t, m.Content, 0)
|
assert.Len(t, m.Content, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValue(t *testing.T) {
|
func TestNewNodeBuilder_MapKeyHasValue(t *testing.T) {
|
||||||
|
thrug := orderedmap.New[string, string]()
|
||||||
|
thrug.Set("dump", "trump")
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thrug: map[string]string{
|
Thrug: thrug,
|
||||||
"dump": "trump",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type test1low struct {
|
type test1low struct {
|
||||||
Thrug key `yaml:"thrug"`
|
Thrug *orderedmap.Map[*low.KeyReference[string], *low.ValueReference[string]] `yaml:"thrug"`
|
||||||
Thugg *bool `yaml:"thugg"`
|
Thugg *bool `yaml:"thugg"`
|
||||||
Throo *float32 `yaml:"throo"`
|
Throo *float32 `yaml:"throo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thrugLow := orderedmap.New[*low.KeyReference[string], *low.ValueReference[string]]()
|
||||||
|
thrugLow.Set(&low.KeyReference[string]{
|
||||||
|
Value: "dump",
|
||||||
|
KeyNode: utils.CreateStringNode("dump"),
|
||||||
|
}, &low.ValueReference[string]{
|
||||||
|
Value: "trump",
|
||||||
|
ValueNode: utils.CreateStringNode("trump"),
|
||||||
|
})
|
||||||
|
|
||||||
t2 := test1low{
|
t2 := test1low{
|
||||||
Thrug: key{
|
Thrug: thrugLow,
|
||||||
v: map[string]string{
|
|
||||||
"dump": "trump",
|
|
||||||
},
|
|
||||||
ln: 2,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t2)
|
nb := NewNodeBuilder(&t1, &t2)
|
||||||
@@ -448,31 +411,30 @@ func TestNewNodeBuilder_MapKeyHasValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValueThatHasValue(t *testing.T) {
|
func TestNewNodeBuilder_MapKeyHasValueThatHasValue(t *testing.T) {
|
||||||
|
thomp := orderedmap.New[low.KeyReference[string], string]()
|
||||||
|
thomp.Set(low.KeyReference[string]{Value: "meddy", KeyNode: utils.CreateStringNode("meddy")}, "princess")
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thomp: map[key]string{
|
Thomp: thomp,
|
||||||
{v: "who"}: "princess",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type test1low struct {
|
type test1low struct {
|
||||||
Thomp key `yaml:"thomp"`
|
Thomp low.ValueReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]] `yaml:"thomp"`
|
||||||
Thugg *bool `yaml:"thugg"`
|
Thugg *bool `yaml:"thugg"`
|
||||||
Throo *float32 `yaml:"throo"`
|
Throo *float32 `yaml:"throo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valueMap := orderedmap.New[low.KeyReference[string], low.ValueReference[string]]()
|
||||||
|
valueMap.Set(low.KeyReference[string]{
|
||||||
|
Value: "ice",
|
||||||
|
KeyNode: utils.CreateStringNode("ice"),
|
||||||
|
}, low.ValueReference[string]{
|
||||||
|
Value: "princess",
|
||||||
|
})
|
||||||
|
|
||||||
t2 := test1low{
|
t2 := test1low{
|
||||||
Thomp: key{
|
Thomp: low.ValueReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]{
|
||||||
v: map[key]string{
|
Value: valueMap,
|
||||||
{
|
|
||||||
v: key{
|
|
||||||
v: "ice",
|
|
||||||
kn: utils.CreateStringNode("limes"),
|
|
||||||
},
|
|
||||||
kn: utils.CreateStringNode("chimes"),
|
|
||||||
ln: 6}: "princess",
|
|
||||||
},
|
|
||||||
ln: 2,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,23 +450,27 @@ func TestNewNodeBuilder_MapKeyHasValueThatHasValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMatch(t *testing.T) {
|
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMatch(t *testing.T) {
|
||||||
|
thomp := orderedmap.New[low.KeyReference[string], string]()
|
||||||
|
thomp.Set(low.KeyReference[string]{Value: "meddy", KeyNode: utils.CreateStringNode("meddy")}, "princess")
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thomp: map[key]string{
|
Thomp: thomp,
|
||||||
{v: "who"}: "princess",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type test1low struct {
|
type test1low struct {
|
||||||
Thomp low.NodeReference[map[key]string] `yaml:"thomp"`
|
Thomp low.NodeReference[*orderedmap.Map[low.KeyReference[string], string]] `yaml:"thomp"`
|
||||||
Thugg *bool `yaml:"thugg"`
|
Thugg *bool `yaml:"thugg"`
|
||||||
Throo *float32 `yaml:"throo"`
|
Throo *float32 `yaml:"throo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
g := low.NodeReference[map[key]string]{
|
valMap := orderedmap.New[low.KeyReference[string], string]()
|
||||||
Value: map[key]string{
|
valMap.Set(low.KeyReference[string]{
|
||||||
{v: "my", kn: utils.CreateStringNode("limes")}: "princess",
|
Value: "meddy",
|
||||||
},
|
KeyNode: utils.CreateStringNode("meddy"),
|
||||||
|
}, "princess")
|
||||||
|
|
||||||
|
g := low.NodeReference[*orderedmap.Map[low.KeyReference[string], string]]{
|
||||||
|
Value: valMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
t2 := test1low{
|
t2 := test1low{
|
||||||
@@ -522,94 +488,27 @@ func TestNewNodeBuilder_MapKeyHasValueThatHasValueMatch(t *testing.T) {
|
|||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMatchKeyNode(t *testing.T) {
|
|
||||||
|
|
||||||
t1 := test1{
|
|
||||||
Thomp: map[key]string{
|
|
||||||
{v: "who"}: "princess",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type test1low struct {
|
|
||||||
Thomp low.NodeReference[map[key]string] `yaml:"thomp"`
|
|
||||||
Thugg *bool `yaml:"thugg"`
|
|
||||||
Throo *float32 `yaml:"throo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
g := low.NodeReference[map[key]string]{
|
|
||||||
Value: map[key]string{
|
|
||||||
{v: "my", kn: utils.CreateStringNode("limes")}: "princess",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
t2 := test1low{
|
|
||||||
Thomp: g,
|
|
||||||
}
|
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t2)
|
|
||||||
node := nb.Render()
|
|
||||||
|
|
||||||
data, _ := yaml.Marshal(node)
|
|
||||||
|
|
||||||
desired := `thomp:
|
|
||||||
meddy: princess`
|
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMatch_NoWrap(t *testing.T) {
|
|
||||||
|
|
||||||
t1 := test1{
|
|
||||||
Thomp: map[key]string{
|
|
||||||
{v: "who"}: "princess",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type test1low struct {
|
|
||||||
Thomp map[key]string `yaml:"thomp"`
|
|
||||||
Thugg *bool `yaml:"thugg"`
|
|
||||||
Throo *float32 `yaml:"throo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
t2 := test1low{
|
|
||||||
Thomp: map[key]string{
|
|
||||||
{v: "my", kn: utils.CreateStringNode("meddy")}: "princess",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t2)
|
|
||||||
node := nb.Render()
|
|
||||||
|
|
||||||
data, _ := yaml.Marshal(node)
|
|
||||||
|
|
||||||
desired := `thomp:
|
|
||||||
meddy: princess`
|
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewNodeBuilder_MissingLabel(t *testing.T) {
|
func TestNewNodeBuilder_MissingLabel(t *testing.T) {
|
||||||
|
|
||||||
t1 := new(test1)
|
t1 := new(test1)
|
||||||
nb := NewNodeBuilder(t1, t1)
|
nb := NewNodeBuilder(t1, t1)
|
||||||
p := utils.CreateEmptyMapNode()
|
p := utils.CreateEmptyMapNode()
|
||||||
nodeEnty := NodeEntry{Value: 1234.232323, Key: "p"}
|
nodeEnty := nodes.NodeEntry{Value: 1234.232323, Key: "p"}
|
||||||
node := nb.AddYAMLNode(p, &nodeEnty)
|
node := nb.AddYAMLNode(p, &nodeEnty)
|
||||||
assert.NotNil(t, node)
|
assert.NotNil(t, node)
|
||||||
assert.Len(t, node.Content, 0)
|
assert.Len(t, node.Content, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_ExtensionMap(t *testing.T) {
|
func TestNewNodeBuilder_ExtensionMap(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
pizza := orderedmap.New[string, string]()
|
||||||
|
pizza.Set("dump", "trump")
|
||||||
|
ext.Set("x-pizza", utils.CreateYamlNode(pizza))
|
||||||
|
ext.Set("x-money", utils.CreateStringNode("time"))
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thing: "ding",
|
Thing: "ding",
|
||||||
Extensions: map[string]any{
|
Extensions: ext,
|
||||||
"x-pizza": map[string]string{
|
Thong: 1,
|
||||||
"dump": "trump",
|
|
||||||
},
|
|
||||||
"x-money": "time",
|
|
||||||
},
|
|
||||||
Thong: 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
@@ -621,20 +520,21 @@ func TestNewNodeBuilder_ExtensionMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMismatch(t *testing.T) {
|
func TestNewNodeBuilder_MapKeyHasValueThatHasValueMismatch(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
pizza := orderedmap.New[string, string]()
|
||||||
|
pizza.Set("dump", "trump")
|
||||||
|
ext.Set("x-pizza", utils.CreateYamlNode(pizza))
|
||||||
|
cake := orderedmap.New[string, string]()
|
||||||
|
cake.Set("maga", "nomore")
|
||||||
|
ext.Set("x-cake", utils.CreateYamlNode(cake))
|
||||||
|
|
||||||
|
thril := orderedmap.New[string, *valueReferenceStruct]()
|
||||||
|
thril.Set("princess", &valueReferenceStruct{Value: "who"})
|
||||||
|
thril.Set("heavy", &valueReferenceStruct{Value: "who"})
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Extensions: map[string]any{
|
Extensions: ext,
|
||||||
"x-pizza": map[string]string{
|
Thril: thril,
|
||||||
"dump": "trump",
|
|
||||||
},
|
|
||||||
"x-cake": map[string]string{
|
|
||||||
"maga": "nomore",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Thril: map[string]*key{
|
|
||||||
"princess": {v: "who", Name: "beef", ln: 2},
|
|
||||||
"heavy": {v: "who", Name: "industries", ln: 3},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, nil)
|
nb := NewNodeBuilder(&t1, nil)
|
||||||
@@ -642,13 +542,18 @@ func TestNewNodeBuilder_MapKeyHasValueThatHasValueMismatch(t *testing.T) {
|
|||||||
|
|
||||||
data, _ := yaml.Marshal(node)
|
data, _ := yaml.Marshal(node)
|
||||||
|
|
||||||
assert.Len(t, data, 94)
|
assert.Equal(t, `thril:
|
||||||
|
princess: pizza
|
||||||
|
heavy: pizza
|
||||||
|
x-pizza:
|
||||||
|
dump: trump
|
||||||
|
x-cake:
|
||||||
|
maga: nomore`, strings.TrimSpace(string(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_SliceRef(t *testing.T) {
|
func TestNewNodeBuilder_SliceRef(t *testing.T) {
|
||||||
|
c := valueReferenceStruct{ref: true, refStr: "#/red/robin/yummmmm", Value: "milky"}
|
||||||
c := key{ref: true, refStr: "#/red/robin/yummmmm", Name: "milky"}
|
ty := []*valueReferenceStruct{&c}
|
||||||
ty := []*key{&c}
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Throg: ty,
|
Throg: ty,
|
||||||
}
|
}
|
||||||
@@ -665,9 +570,8 @@ func TestNewNodeBuilder_SliceRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_SliceRef_Inline(t *testing.T) {
|
func TestNewNodeBuilder_SliceRef_Inline(t *testing.T) {
|
||||||
|
c := valueReferenceStruct{Value: "milky"}
|
||||||
c := key{ref: true, refStr: "#/red/robin/yummmmm", Name: "milky"}
|
ty := []*valueReferenceStruct{&c}
|
||||||
ty := []*key{&c}
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Throg: ty,
|
Throg: ty,
|
||||||
}
|
}
|
||||||
@@ -684,22 +588,19 @@ func TestNewNodeBuilder_SliceRef_Inline(t *testing.T) {
|
|||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
type testRender struct {
|
type testRender struct{}
|
||||||
}
|
|
||||||
|
|
||||||
func (t testRender) MarshalYAML() (interface{}, error) {
|
func (t testRender) MarshalYAML() (interface{}, error) {
|
||||||
return utils.CreateStringNode("testy!"), nil
|
return utils.CreateStringNode("testy!"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type testRenderRawNode struct {
|
type testRenderRawNode struct{}
|
||||||
}
|
|
||||||
|
|
||||||
func (t testRenderRawNode) MarshalYAML() (interface{}, error) {
|
func (t testRenderRawNode) MarshalYAML() (interface{}, error) {
|
||||||
return yaml.Node{Kind: yaml.ScalarNode, Value: "zesty!"}, nil
|
return yaml.Node{Kind: yaml.ScalarNode, Value: "zesty!"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_SliceRef_Inline_NotCompatible(t *testing.T) {
|
func TestNewNodeBuilder_SliceRef_Inline_NotCompatible(t *testing.T) {
|
||||||
|
|
||||||
ty := []interface{}{testRender{}}
|
ty := []interface{}{testRender{}}
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thrat: ty,
|
Thrat: ty,
|
||||||
@@ -718,7 +619,6 @@ func TestNewNodeBuilder_SliceRef_Inline_NotCompatible(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_SliceRef_Inline_NotCompatible_NotPointer(t *testing.T) {
|
func TestNewNodeBuilder_SliceRef_Inline_NotCompatible_NotPointer(t *testing.T) {
|
||||||
|
|
||||||
ty := []interface{}{testRenderRawNode{}}
|
ty := []interface{}{testRenderRawNode{}}
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thrat: ty,
|
Thrat: ty,
|
||||||
@@ -737,7 +637,6 @@ func TestNewNodeBuilder_SliceRef_Inline_NotCompatible_NotPointer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_PointerRef_Inline_NotCompatible_RawNode(t *testing.T) {
|
func TestNewNodeBuilder_PointerRef_Inline_NotCompatible_RawNode(t *testing.T) {
|
||||||
|
|
||||||
ty := testRenderRawNode{}
|
ty := testRenderRawNode{}
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: &ty,
|
Thurm: &ty,
|
||||||
@@ -755,8 +654,7 @@ func TestNewNodeBuilder_PointerRef_Inline_NotCompatible_RawNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_PointerRef_Inline_NotCompatible(t *testing.T) {
|
func TestNewNodeBuilder_PointerRef_Inline_NotCompatible(t *testing.T) {
|
||||||
|
ty := valueReferenceStruct{}
|
||||||
ty := key{}
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: &ty,
|
Thurm: &ty,
|
||||||
}
|
}
|
||||||
@@ -773,9 +671,8 @@ func TestNewNodeBuilder_PointerRef_Inline_NotCompatible(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_SliceNoRef(t *testing.T) {
|
func TestNewNodeBuilder_SliceNoRef(t *testing.T) {
|
||||||
|
c := valueReferenceStruct{Value: "milky"}
|
||||||
c := key{ref: false, Name: "milky"}
|
ty := []*valueReferenceStruct{&c}
|
||||||
ty := []*key{&c}
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Throg: ty,
|
Throg: ty,
|
||||||
}
|
}
|
||||||
@@ -792,7 +689,6 @@ func TestNewNodeBuilder_SliceNoRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestStructAny(t *testing.T) {
|
func TestNewNodeBuilder_TestStructAny(t *testing.T) {
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: low.ValueReference[any]{
|
Thurm: low.ValueReference[any]{
|
||||||
ValueNode: utils.CreateStringNode("beer"),
|
ValueNode: utils.CreateStringNode("beer"),
|
||||||
@@ -808,8 +704,8 @@ func TestNewNodeBuilder_TestStructAny(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
assert.Equal(t, desired, strings.TrimSpace(string(data)))
|
||||||
}
|
}
|
||||||
func TestNewNodeBuilder_TestStructString(t *testing.T) {
|
|
||||||
|
|
||||||
|
func TestNewNodeBuilder_TestStructString(t *testing.T) {
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: low.ValueReference[string]{
|
Thurm: low.ValueReference[string]{
|
||||||
ValueNode: utils.CreateStringNode("beer"),
|
ValueNode: utils.CreateStringNode("beer"),
|
||||||
@@ -827,12 +723,11 @@ func TestNewNodeBuilder_TestStructString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestStructPointer(t *testing.T) {
|
func TestNewNodeBuilder_TestStructPointer(t *testing.T) {
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thrim: &key{
|
Thrim: &valueReferenceStruct{
|
||||||
ref: true,
|
ref: true,
|
||||||
refStr: "#/cash/money",
|
refStr: "#/cash/money",
|
||||||
Name: "pizza",
|
Value: "pizza",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,17 +743,17 @@ func TestNewNodeBuilder_TestStructPointer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestStructRef(t *testing.T) {
|
func TestNewNodeBuilder_TestStructRef(t *testing.T) {
|
||||||
|
|
||||||
fkn := utils.CreateStringNode("pizzaBurgers")
|
fkn := utils.CreateStringNode("pizzaBurgers")
|
||||||
fkn.Line = 22
|
fkn.Line = 22
|
||||||
|
|
||||||
|
thurm := low.NodeReference[string]{
|
||||||
|
KeyNode: fkn,
|
||||||
|
ValueNode: fkn,
|
||||||
|
}
|
||||||
|
thurm.SetReference("#/cash/money", nil)
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: low.NodeReference[string]{
|
Thurm: thurm,
|
||||||
Reference: "#/cash/money",
|
|
||||||
ReferenceNode: true,
|
|
||||||
KeyNode: fkn,
|
|
||||||
ValueNode: fkn,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
@@ -872,7 +767,6 @@ func TestNewNodeBuilder_TestStructRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestStructDefaultEncode(t *testing.T) {
|
func TestNewNodeBuilder_TestStructDefaultEncode(t *testing.T) {
|
||||||
|
|
||||||
f := 1
|
f := 1
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thurm: &f,
|
Thurm: &f,
|
||||||
@@ -889,9 +783,10 @@ func TestNewNodeBuilder_TestStructDefaultEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestSliceMapSliceStruct(t *testing.T) {
|
func TestNewNodeBuilder_TestSliceMapSliceStruct(t *testing.T) {
|
||||||
|
pizza := orderedmap.New[string, []string]()
|
||||||
a := []map[string][]string{
|
pizza.Set("pizza", []string{"beer", "wine"})
|
||||||
{"pizza": {"beer", "wine"}},
|
a := []*orderedmap.Map[string, []string]{
|
||||||
|
pizza,
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
@@ -912,7 +807,6 @@ func TestNewNodeBuilder_TestSliceMapSliceStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestRenderZero(t *testing.T) {
|
func TestNewNodeBuilder_TestRenderZero(t *testing.T) {
|
||||||
|
|
||||||
f := false
|
f := false
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thugg: &f,
|
Thugg: &f,
|
||||||
@@ -929,7 +823,6 @@ func TestNewNodeBuilder_TestRenderZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestRenderZero_Float(t *testing.T) {
|
func TestNewNodeBuilder_TestRenderZero_Float(t *testing.T) {
|
||||||
|
|
||||||
f := 0.0
|
f := 0.0
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Throo: &f,
|
Throo: &f,
|
||||||
@@ -946,7 +839,6 @@ func TestNewNodeBuilder_TestRenderZero_Float(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestRenderZero_Float_NotZero(t *testing.T) {
|
func TestNewNodeBuilder_TestRenderZero_Float_NotZero(t *testing.T) {
|
||||||
|
|
||||||
f := 0.12
|
f := 0.12
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Throo: &f,
|
Throo: &f,
|
||||||
@@ -963,11 +855,11 @@ func TestNewNodeBuilder_TestRenderZero_Float_NotZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_TestRenderServerVariableSimulation(t *testing.T) {
|
func TestNewNodeBuilder_TestRenderServerVariableSimulation(t *testing.T) {
|
||||||
|
thrig := orderedmap.New[string, *plug]()
|
||||||
|
thrig.Set("pork", &plug{Name: []string{"gammon", "bacon"}})
|
||||||
|
|
||||||
t1 := test1{
|
t1 := test1{
|
||||||
Thrig: map[string]*plug{
|
Thrig: thrig,
|
||||||
"pork": {Name: []string{"gammon", "bacon"}},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := NewNodeBuilder(&t1, &t1)
|
nb := NewNodeBuilder(&t1, &t1)
|
||||||
@@ -985,22 +877,21 @@ func TestNewNodeBuilder_TestRenderServerVariableSimulation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewNodeBuilder_ShouldHaveNotDoneTestsLikeThisOhWell(t *testing.T) {
|
func TestNewNodeBuilder_ShouldHaveNotDoneTestsLikeThisOhWell(t *testing.T) {
|
||||||
|
m := orderedmap.New[low.KeyReference[string], low.ValueReference[*valueReferenceStruct]]()
|
||||||
|
|
||||||
m := make(map[low.KeyReference[string]]low.ValueReference[*key])
|
m.Set(low.KeyReference[string]{
|
||||||
|
|
||||||
m[low.KeyReference[string]{
|
|
||||||
KeyNode: utils.CreateStringNode("pizza"),
|
KeyNode: utils.CreateStringNode("pizza"),
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}] = low.ValueReference[*key]{
|
}, low.ValueReference[*valueReferenceStruct]{
|
||||||
ValueNode: utils.CreateStringNode("beer"),
|
ValueNode: utils.CreateStringNode("beer"),
|
||||||
Value: &key{},
|
Value: &valueReferenceStruct{},
|
||||||
}
|
})
|
||||||
|
|
||||||
d := make(map[string]*key)
|
d := orderedmap.New[string, *valueReferenceStruct]()
|
||||||
d["pizza"] = &key{}
|
d.Set("pizza", &valueReferenceStruct{})
|
||||||
|
|
||||||
type t1low struct {
|
type t1low struct {
|
||||||
Thril low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*key]]
|
Thril low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*valueReferenceStruct]]]
|
||||||
Thugg *bool `yaml:"thugg"`
|
Thugg *bool `yaml:"thugg"`
|
||||||
Throo *float32 `yaml:"throo"`
|
Throo *float32 `yaml:"throo"`
|
||||||
}
|
}
|
||||||
@@ -1010,7 +901,7 @@ func TestNewNodeBuilder_ShouldHaveNotDoneTestsLikeThisOhWell(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t2 := t1low{
|
t2 := t1low{
|
||||||
Thril: low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*key]]{
|
Thril: low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*valueReferenceStruct]]]{
|
||||||
Value: m,
|
Value: m,
|
||||||
ValueNode: utils.CreateStringNode("beer"),
|
ValueNode: utils.CreateStringNode("beer"),
|
||||||
},
|
},
|
||||||
|
|||||||
16
datamodel/high/nodes/nodeentry.go
Normal file
16
datamodel/high/nodes/nodeentry.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package nodes
|
||||||
|
|
||||||
|
import "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
// NodeEntry represents a single node used by NodeBuilder.
|
||||||
|
type NodeEntry struct {
|
||||||
|
Tag string
|
||||||
|
Key string
|
||||||
|
Value any
|
||||||
|
StringValue string
|
||||||
|
Line int
|
||||||
|
KeyStyle yaml.Style
|
||||||
|
// ValueStyle yaml.Style
|
||||||
|
RenderZero bool
|
||||||
|
LowValue any
|
||||||
|
}
|
||||||
@@ -15,12 +15,13 @@ package high
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GoesLow is used to represent any high-level model. All high level models meet this interface and can be used to
|
// GoesLow is used to represent any high-level model. All high level models meet this interface and can be used to
|
||||||
// extract low-level models from any high-level model.
|
// extract low-level models from any high-level model.
|
||||||
type GoesLow[T any] interface {
|
type GoesLow[T any] interface {
|
||||||
|
|
||||||
// GoLow returns the low-level object that was used to create the high-level object. This allows consumers
|
// GoLow returns the low-level object that was used to create the high-level object. This allows consumers
|
||||||
// to dive-down into the plumbing API at any point in the model.
|
// to dive-down into the plumbing API at any point in the model.
|
||||||
GoLow() T
|
GoLow() T
|
||||||
@@ -29,18 +30,17 @@ type GoesLow[T any] interface {
|
|||||||
// GoesLowUntyped is used to represent any high-level model. All high level models meet this interface and can be used to
|
// GoesLowUntyped is used to represent any high-level model. All high level models meet this interface and can be used to
|
||||||
// extract low-level models from any high-level model.
|
// extract low-level models from any high-level model.
|
||||||
type GoesLowUntyped interface {
|
type GoesLowUntyped interface {
|
||||||
|
|
||||||
// GoLowUntyped returns the low-level object that was used to create the high-level object. This allows consumers
|
// GoLowUntyped returns the low-level object that was used to create the high-level object. This allows consumers
|
||||||
// to dive-down into the plumbing API at any point in the model.
|
// to dive-down into the plumbing API at any point in the model.
|
||||||
GoLowUntyped() any
|
GoLowUntyped() any
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractExtensions is a convenience method for converting low-level extension definitions, to a high level map[string]any
|
// ExtractExtensions is a convenience method for converting low-level extension definitions, to a high level *orderedmap.Map[string, *yaml.Node]
|
||||||
// definition that is easier to consume in applications.
|
// definition that is easier to consume in applications.
|
||||||
func ExtractExtensions(extensions map[low.KeyReference[string]]low.ValueReference[any]) map[string]any {
|
func ExtractExtensions(extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]) *orderedmap.Map[string, *yaml.Node] {
|
||||||
extracted := make(map[string]any)
|
extracted := orderedmap.New[string, *yaml.Node]()
|
||||||
for k, v := range extensions {
|
for pair := orderedmap.First(extensions); pair != nil; pair = pair.Next() {
|
||||||
extracted[k.Value] = v.Value
|
extracted.Set(pair.Key().Value, pair.Value().Value)
|
||||||
}
|
}
|
||||||
return extracted
|
return extracted
|
||||||
}
|
}
|
||||||
@@ -61,18 +61,18 @@ func ExtractExtensions(extensions map[low.KeyReference[string]]low.ValueReferenc
|
|||||||
//
|
//
|
||||||
// schema := schemaProxy.Schema() // any high-level object that has
|
// schema := schemaProxy.Schema() // any high-level object that has
|
||||||
// extensions, err := UnpackExtensions[MyComplexType, low.Schema](schema)
|
// extensions, err := UnpackExtensions[MyComplexType, low.Schema](schema)
|
||||||
func UnpackExtensions[T any, R low.HasExtensions[T]](low GoesLow[R]) (map[string]*T, error) {
|
func UnpackExtensions[T any, R low.HasExtensions[T]](low GoesLow[R]) (*orderedmap.Map[string, *T], error) {
|
||||||
m := make(map[string]*T)
|
m := orderedmap.New[string, *T]()
|
||||||
ext := low.GoLow().GetExtensions()
|
ext := low.GoLow().GetExtensions()
|
||||||
for i := range ext {
|
for pair := orderedmap.First(ext); pair != nil; pair = pair.Next() {
|
||||||
key := i.Value
|
key := pair.Key().Value
|
||||||
g := new(T)
|
g := new(T)
|
||||||
valueNode := ext[i].ValueNode
|
valueNode := pair.Value().ValueNode
|
||||||
err := valueNode.Decode(g)
|
err := valueNode.Decode(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
m[key] = g
|
m.Set(key, g)
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,21 +4,30 @@
|
|||||||
package high
|
package high
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractExtensions(t *testing.T) {
|
func TestExtractExtensions(t *testing.T) {
|
||||||
n := make(map[low.KeyReference[string]]low.ValueReference[any])
|
n := orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
|
||||||
n[low.KeyReference[string]{
|
n.Set(low.KeyReference[string]{
|
||||||
Value: "pb33f",
|
Value: "pb33f",
|
||||||
}] = low.ValueReference[any]{
|
}, low.ValueReference[*yaml.Node]{
|
||||||
Value: "new cowboy in town",
|
Value: utils.CreateStringNode("new cowboy in town"),
|
||||||
}
|
})
|
||||||
ext := ExtractExtensions(n)
|
ext := ExtractExtensions(n)
|
||||||
assert.Equal(t, "new cowboy in town", ext["pb33f"])
|
|
||||||
|
var pb33f string
|
||||||
|
err := ext.GetOrZero("pb33f").Decode(&pb33f)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "new cowboy in town", pb33f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type textExtension struct {
|
type textExtension struct {
|
||||||
@@ -35,15 +44,14 @@ func (p *parent) GoLow() *child {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type child struct {
|
type child struct {
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *child) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (c *child) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return c.Extensions
|
return c.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackExtensions(t *testing.T) {
|
func TestUnpackExtensions(t *testing.T) {
|
||||||
|
|
||||||
var resultA, resultB yaml.Node
|
var resultA, resultB yaml.Node
|
||||||
|
|
||||||
ymlA := `
|
ymlA := `
|
||||||
@@ -59,18 +67,18 @@ power: 2`
|
|||||||
err = yaml.Unmarshal([]byte(ymlB), &resultB)
|
err = yaml.Unmarshal([]byte(ymlB), &resultB)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
n := make(map[low.KeyReference[string]]low.ValueReference[any])
|
n := orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
|
||||||
n[low.KeyReference[string]{
|
n.Set(low.KeyReference[string]{
|
||||||
Value: "x-rancher-a",
|
Value: "x-rancher-a",
|
||||||
}] = low.ValueReference[any]{
|
}, low.ValueReference[*yaml.Node]{
|
||||||
ValueNode: resultA.Content[0],
|
ValueNode: resultA.Content[0],
|
||||||
}
|
})
|
||||||
|
|
||||||
n[low.KeyReference[string]{
|
n.Set(low.KeyReference[string]{
|
||||||
Value: "x-rancher-b",
|
Value: "x-rancher-b",
|
||||||
}] = low.ValueReference[any]{
|
}, low.ValueReference[*yaml.Node]{
|
||||||
ValueNode: resultB.Content[0],
|
ValueNode: resultB.Content[0],
|
||||||
}
|
})
|
||||||
|
|
||||||
c := new(child)
|
c := new(child)
|
||||||
c.Extensions = n
|
c.Extensions = n
|
||||||
@@ -81,14 +89,13 @@ power: 2`
|
|||||||
res, err := UnpackExtensions[textExtension, *child](p)
|
res, err := UnpackExtensions[textExtension, *child](p)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, res)
|
assert.NotEmpty(t, res)
|
||||||
assert.Equal(t, "buckaroo", res["x-rancher-a"].Cowboy)
|
assert.Equal(t, "buckaroo", res.GetOrZero("x-rancher-a").Cowboy)
|
||||||
assert.Equal(t, 100, res["x-rancher-a"].Power)
|
assert.Equal(t, 100, res.GetOrZero("x-rancher-a").Power)
|
||||||
assert.Equal(t, "frogman", res["x-rancher-b"].Cowboy)
|
assert.Equal(t, "frogman", res.GetOrZero("x-rancher-b").Cowboy)
|
||||||
assert.Equal(t, 2, res["x-rancher-b"].Power)
|
assert.Equal(t, 2, res.GetOrZero("x-rancher-b").Power)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackExtensions_Fail(t *testing.T) {
|
func TestUnpackExtensions_Fail(t *testing.T) {
|
||||||
|
|
||||||
var resultA, resultB yaml.Node
|
var resultA, resultB yaml.Node
|
||||||
|
|
||||||
ymlA := `
|
ymlA := `
|
||||||
@@ -105,18 +112,18 @@ power: hello`
|
|||||||
err = yaml.Unmarshal([]byte(ymlB), &resultB)
|
err = yaml.Unmarshal([]byte(ymlB), &resultB)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
n := make(map[low.KeyReference[string]]low.ValueReference[any])
|
n := orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
|
||||||
n[low.KeyReference[string]{
|
n.Set(low.KeyReference[string]{
|
||||||
Value: "x-rancher-a",
|
Value: "x-rancher-a",
|
||||||
}] = low.ValueReference[any]{
|
}, low.ValueReference[*yaml.Node]{
|
||||||
ValueNode: resultA.Content[0],
|
ValueNode: resultA.Content[0],
|
||||||
}
|
})
|
||||||
|
|
||||||
n[low.KeyReference[string]{
|
n.Set(low.KeyReference[string]{
|
||||||
Value: "x-rancher-b",
|
Value: "x-rancher-b",
|
||||||
}] = low.ValueReference[any]{
|
}, low.ValueReference[*yaml.Node]{
|
||||||
ValueNode: resultB.Content[0],
|
ValueNode: resultB.Content[0],
|
||||||
}
|
})
|
||||||
|
|
||||||
c := new(child)
|
c := new(child)
|
||||||
c.Extensions = n
|
c.Extensions = n
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
highbase "github.com/pb33f/libopenapi/datamodel/high/base"
|
highbase "github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
lowbase "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
@@ -17,7 +18,7 @@ import (
|
|||||||
// arrays or models.
|
// arrays or models.
|
||||||
// - https://swagger.io/specification/v2/#definitionsObject
|
// - https://swagger.io/specification/v2/#definitionsObject
|
||||||
type Definitions struct {
|
type Definitions struct {
|
||||||
Definitions orderedmap.Map[string, *highbase.SchemaProxy]
|
Definitions *orderedmap.Map[string, *highbase.SchemaProxy]
|
||||||
low *low.Definitions
|
low *low.Definitions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ func NewDefinitions(definitions *low.Definitions) *Definitions {
|
|||||||
defs := orderedmap.New[string, *highbase.SchemaProxy]()
|
defs := orderedmap.New[string, *highbase.SchemaProxy]()
|
||||||
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*lowbase.SchemaProxy]]) (asyncResult[*highbase.SchemaProxy], error) {
|
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*lowbase.SchemaProxy]]) (asyncResult[*highbase.SchemaProxy], error) {
|
||||||
return asyncResult[*highbase.SchemaProxy]{
|
return asyncResult[*highbase.SchemaProxy]{
|
||||||
key: pair.Key().Value,
|
key: pair.Key().Value,
|
||||||
result: highbase.NewSchemaProxy(&lowmodel.NodeReference[*lowbase.SchemaProxy]{
|
result: highbase.NewSchemaProxy(&lowmodel.NodeReference[*lowbase.SchemaProxy]{
|
||||||
Value: pair.Value().Value,
|
Value: pair.Value().Value,
|
||||||
}),
|
}),
|
||||||
@@ -38,7 +39,7 @@ func NewDefinitions(definitions *low.Definitions) *Definitions {
|
|||||||
defs.Set(value.key, value.result)
|
defs.Set(value.key, value.result)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = orderedmap.TranslateMapParallel(definitions.Schemas, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(definitions.Schemas, translateFunc, resultFunc)
|
||||||
rd.Definitions = defs
|
rd.Definitions = defs
|
||||||
return rd
|
return rd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ package v2
|
|||||||
import (
|
import (
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Example represents a high-level Swagger / OpenAPI 2 Example object, backed by a low level one.
|
// Example represents a high-level Swagger / OpenAPI 2 Example object, backed by a low level one.
|
||||||
// Allows sharing examples for operation responses
|
// Allows sharing examples for operation responses
|
||||||
// - https://swagger.io/specification/v2/#exampleObject
|
// - https://swagger.io/specification/v2/#exampleObject
|
||||||
type Example struct {
|
type Example struct {
|
||||||
Values orderedmap.Map[string, any]
|
Values *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Examples
|
low *low.Examples
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ func NewExample(examples *low.Examples) *Example {
|
|||||||
e := new(Example)
|
e := new(Example)
|
||||||
e.low = examples
|
e.low = examples
|
||||||
if orderedmap.Len(examples.Values) > 0 {
|
if orderedmap.Len(examples.Values) > 0 {
|
||||||
values := orderedmap.New[string, any]()
|
values := orderedmap.New[string, *yaml.Node]()
|
||||||
for pair := orderedmap.First(examples.Values); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(examples.Values); pair != nil; pair = pair.Next() {
|
||||||
values.Set(pair.Key().Value, pair.Value().Value)
|
values.Set(pair.Key().Value, pair.Value().Value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Header Represents a high-level Swagger / OpenAPI 2 Header object, backed by a low-level one.
|
// Header Represents a high-level Swagger / OpenAPI 2 Header object, backed by a low-level one.
|
||||||
@@ -30,7 +32,7 @@ type Header struct {
|
|||||||
UniqueItems bool
|
UniqueItems bool
|
||||||
Enum []any
|
Enum []any
|
||||||
MultipleOf int
|
MultipleOf int
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Header
|
low *low.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Items is a high-level representation of a Swagger / OpenAPI 2 Items object, backed by a low level one.
|
// Items is a high-level representation of a Swagger / OpenAPI 2 Items object, backed by a low level one.
|
||||||
@@ -16,7 +17,7 @@ type Items struct {
|
|||||||
Format string
|
Format string
|
||||||
CollectionFormat string
|
CollectionFormat string
|
||||||
Items *Items
|
Items *Items
|
||||||
Default any
|
Default *yaml.Node
|
||||||
Maximum int
|
Maximum int
|
||||||
ExclusiveMaximum bool
|
ExclusiveMaximum bool
|
||||||
Minimum int
|
Minimum int
|
||||||
@@ -27,7 +28,7 @@ type Items struct {
|
|||||||
MaxItems int
|
MaxItems int
|
||||||
MinItems int
|
MinItems int
|
||||||
UniqueItems bool
|
UniqueItems bool
|
||||||
Enum []any
|
Enum []*yaml.Node
|
||||||
MultipleOf int
|
MultipleOf int
|
||||||
low *low.Items
|
low *low.Items
|
||||||
}
|
}
|
||||||
@@ -82,7 +83,7 @@ func NewItems(items *low.Items) *Items {
|
|||||||
i.UniqueItems = items.UniqueItems.Value
|
i.UniqueItems = items.UniqueItems.Value
|
||||||
}
|
}
|
||||||
if !items.Enum.IsEmpty() {
|
if !items.Enum.IsEmpty() {
|
||||||
var enums []any
|
var enums []*yaml.Node
|
||||||
for e := range items.Enum.Value {
|
for e := range items.Enum.Value {
|
||||||
enums = append(enums, items.Enum.Value[e].Value)
|
enums = append(enums, items.Enum.Value[e].Value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Operation represents a high-level Swagger / OpenAPI 2 Operation object, backed by a low-level one.
|
// Operation represents a high-level Swagger / OpenAPI 2 Operation object, backed by a low-level one.
|
||||||
@@ -25,7 +27,7 @@ type Operation struct {
|
|||||||
Schemes []string
|
Schemes []string
|
||||||
Deprecated bool
|
Deprecated bool
|
||||||
Security []*base.SecurityRequirement
|
Security []*base.SecurityRequirement
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Operation
|
low *low.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parameter represents a high-level Swagger / OpenAPI 2 Parameter object, backed by a low-level one.
|
// Parameter represents a high-level Swagger / OpenAPI 2 Parameter object, backed by a low-level one.
|
||||||
@@ -61,7 +63,7 @@ type Parameter struct {
|
|||||||
Schema *base.SchemaProxy
|
Schema *base.SchemaProxy
|
||||||
Items *Items
|
Items *Items
|
||||||
CollectionFormat string
|
CollectionFormat string
|
||||||
Default any
|
Default *yaml.Node
|
||||||
Maximum *int
|
Maximum *int
|
||||||
ExclusiveMaximum *bool
|
ExclusiveMaximum *bool
|
||||||
Minimum *int
|
Minimum *int
|
||||||
@@ -72,9 +74,9 @@ type Parameter struct {
|
|||||||
MaxItems *int
|
MaxItems *int
|
||||||
MinItems *int
|
MinItems *int
|
||||||
UniqueItems *bool
|
UniqueItems *bool
|
||||||
Enum []any
|
Enum []*yaml.Node
|
||||||
MultipleOf *int
|
MultipleOf *int
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Parameter
|
low *low.Parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +149,7 @@ func NewParameter(parameter *low.Parameter) *Parameter {
|
|||||||
p.UniqueItems = ¶meter.UniqueItems.Value
|
p.UniqueItems = ¶meter.UniqueItems.Value
|
||||||
}
|
}
|
||||||
if !parameter.Enum.IsEmpty() {
|
if !parameter.Enum.IsEmpty() {
|
||||||
var enums []any
|
var enums []*yaml.Node
|
||||||
for e := range parameter.Enum.Value {
|
for e := range parameter.Enum.Value {
|
||||||
enums = append(enums, parameter.Enum.Value[e].Value)
|
enums = append(enums, parameter.Enum.Value[e].Value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
@@ -16,7 +17,7 @@ import (
|
|||||||
// referenced to the ones defined here. It does not define global operation parameters
|
// referenced to the ones defined here. It does not define global operation parameters
|
||||||
// - https://swagger.io/specification/v2/#parametersDefinitionsObject
|
// - https://swagger.io/specification/v2/#parametersDefinitionsObject
|
||||||
type ParameterDefinitions struct {
|
type ParameterDefinitions struct {
|
||||||
Definitions orderedmap.Map[string, *Parameter]
|
Definitions *orderedmap.Map[string, *Parameter]
|
||||||
low *low.ParameterDefinitions
|
low *low.ParameterDefinitions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ func NewParametersDefinitions(parametersDefinitions *low.ParameterDefinitions) *
|
|||||||
params.Set(value.key, value.result)
|
params.Set(value.key, value.result)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = orderedmap.TranslateMapParallel(parametersDefinitions.Definitions, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(parametersDefinitions.Definitions, translateFunc, resultFunc)
|
||||||
pd.Definitions = params
|
pd.Definitions = params
|
||||||
return pd
|
return pd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,15 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PathItem represents a high-level Swagger / OpenAPI 2 PathItem object backed by a low-level one.
|
// PathItem represents a high-level Swagger / OpenAPI 2 PathItem object backed by a low-level one.
|
||||||
@@ -26,12 +31,12 @@ type PathItem struct {
|
|||||||
Head *Operation
|
Head *Operation
|
||||||
Patch *Operation
|
Patch *Operation
|
||||||
Parameters []*Parameter
|
Parameters []*Parameter
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.PathItem
|
low *lowV2.PathItem
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPathItem will create a new high-level PathItem from a low-level one. All paths are built out asynchronously.
|
// NewPathItem will create a new high-level PathItem from a low-level one. All paths are built out asynchronously.
|
||||||
func NewPathItem(pathItem *low.PathItem) *PathItem {
|
func NewPathItem(pathItem *lowV2.PathItem) *PathItem {
|
||||||
p := new(PathItem)
|
p := new(PathItem)
|
||||||
p.low = pathItem
|
p.low = pathItem
|
||||||
p.Extensions = high.ExtractExtensions(pathItem.Extensions)
|
p.Extensions = high.ExtractExtensions(pathItem.Extensions)
|
||||||
@@ -42,7 +47,7 @@ func NewPathItem(pathItem *low.PathItem) *PathItem {
|
|||||||
}
|
}
|
||||||
p.Parameters = params
|
p.Parameters = params
|
||||||
}
|
}
|
||||||
var buildOperation = func(method string, op *low.Operation) *Operation {
|
buildOperation := func(method string, op *lowV2.Operation) *Operation {
|
||||||
return NewOperation(op)
|
return NewOperation(op)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,49 +55,49 @@ func NewPathItem(pathItem *low.PathItem) *PathItem {
|
|||||||
if !pathItem.Get.IsEmpty() {
|
if !pathItem.Get.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Get = buildOperation(low.GetLabel, pathItem.Get.Value)
|
p.Get = buildOperation(lowV2.GetLabel, pathItem.Get.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Put.IsEmpty() {
|
if !pathItem.Put.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Put = buildOperation(low.PutLabel, pathItem.Put.Value)
|
p.Put = buildOperation(lowV2.PutLabel, pathItem.Put.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Post.IsEmpty() {
|
if !pathItem.Post.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Post = buildOperation(low.PostLabel, pathItem.Post.Value)
|
p.Post = buildOperation(lowV2.PostLabel, pathItem.Post.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Patch.IsEmpty() {
|
if !pathItem.Patch.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Patch = buildOperation(low.PatchLabel, pathItem.Patch.Value)
|
p.Patch = buildOperation(lowV2.PatchLabel, pathItem.Patch.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Delete.IsEmpty() {
|
if !pathItem.Delete.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Delete = buildOperation(low.DeleteLabel, pathItem.Delete.Value)
|
p.Delete = buildOperation(lowV2.DeleteLabel, pathItem.Delete.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Head.IsEmpty() {
|
if !pathItem.Head.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Head = buildOperation(low.HeadLabel, pathItem.Head.Value)
|
p.Head = buildOperation(lowV2.HeadLabel, pathItem.Head.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if !pathItem.Options.IsEmpty() {
|
if !pathItem.Options.IsEmpty() {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
p.Options = buildOperation(low.OptionsLabel, pathItem.Options.Value)
|
p.Options = buildOperation(lowV2.OptionsLabel, pathItem.Options.Value)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@@ -101,32 +106,65 @@ func NewPathItem(pathItem *low.PathItem) *PathItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GoLow returns the low-level PathItem used to create the high-level one.
|
// GoLow returns the low-level PathItem used to create the high-level one.
|
||||||
func (p *PathItem) GoLow() *low.PathItem {
|
func (p *PathItem) GoLow() *lowV2.PathItem {
|
||||||
return p.low
|
return p.low
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathItem) GetOperations() map[string]*Operation {
|
func (p *PathItem) GetOperations() *orderedmap.Map[string, *Operation] {
|
||||||
o := make(map[string]*Operation)
|
o := orderedmap.New[string, *Operation]()
|
||||||
|
|
||||||
|
// TODO: this is a bit of a hack, but it works for now. We might just want to actually pull the data out of the document as a map and split it into the individual operations
|
||||||
|
|
||||||
|
type op struct {
|
||||||
|
name string
|
||||||
|
op *Operation
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
getLine := func(field string, idx int) int {
|
||||||
|
if p.GoLow() == nil {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
l, ok := reflect.ValueOf(p.GoLow()).Elem().FieldByName(field).Interface().(low.NodeReference[*lowV2.Operation])
|
||||||
|
if !ok || l.GetKeyNode() == nil {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.GetKeyNode().Line
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := []op{}
|
||||||
|
|
||||||
if p.Get != nil {
|
if p.Get != nil {
|
||||||
o[low.GetLabel] = p.Get
|
ops = append(ops, op{name: lowV2.GetLabel, op: p.Get, line: getLine("Get", -7)})
|
||||||
}
|
}
|
||||||
if p.Put != nil {
|
if p.Put != nil {
|
||||||
o[low.PutLabel] = p.Put
|
ops = append(ops, op{name: lowV2.PutLabel, op: p.Put, line: getLine("Put", -6)})
|
||||||
}
|
}
|
||||||
if p.Post != nil {
|
if p.Post != nil {
|
||||||
o[low.PostLabel] = p.Post
|
ops = append(ops, op{name: lowV2.PostLabel, op: p.Post, line: getLine("Post", -5)})
|
||||||
}
|
}
|
||||||
if p.Delete != nil {
|
if p.Delete != nil {
|
||||||
o[low.DeleteLabel] = p.Delete
|
ops = append(ops, op{name: lowV2.DeleteLabel, op: p.Delete, line: getLine("Delete", -4)})
|
||||||
}
|
}
|
||||||
if p.Options != nil {
|
if p.Options != nil {
|
||||||
o[low.OptionsLabel] = p.Options
|
ops = append(ops, op{name: lowV2.OptionsLabel, op: p.Options, line: getLine("Options", -3)})
|
||||||
}
|
}
|
||||||
if p.Head != nil {
|
if p.Head != nil {
|
||||||
o[low.HeadLabel] = p.Head
|
ops = append(ops, op{name: lowV2.HeadLabel, op: p.Head, line: getLine("Head", -2)})
|
||||||
}
|
}
|
||||||
if p.Patch != nil {
|
if p.Patch != nil {
|
||||||
o[low.PatchLabel] = p.Patch
|
ops = append(ops, op{name: lowV2.PatchLabel, op: p.Patch, line: getLine("Patch", -1)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slices.SortStableFunc(ops, func(a op, b op) int {
|
||||||
|
return a.line - b.line
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, op := range ops {
|
||||||
|
o.Set(op.name, op.op)
|
||||||
|
}
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,17 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPathItem_GetOperations(t *testing.T) {
|
func TestPathItem_GetOperations(t *testing.T) {
|
||||||
|
|
||||||
yml := `get:
|
yml := `get:
|
||||||
description: get
|
description: get
|
||||||
put:
|
put:
|
||||||
@@ -41,5 +42,5 @@ options:
|
|||||||
|
|
||||||
r := NewPathItem(&n)
|
r := NewPathItem(&n)
|
||||||
|
|
||||||
assert.Len(t, r.GetOperations(), 7)
|
assert.Equal(t, 7, orderedmap.Len(r.GetOperations()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
v2low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Paths represents a high-level Swagger / OpenAPI Paths object, backed by a low-level one.
|
// Paths represents a high-level Swagger / OpenAPI Paths object, backed by a low-level one.
|
||||||
type Paths struct {
|
type Paths struct {
|
||||||
PathItems orderedmap.Map[string, *PathItem]
|
PathItems *orderedmap.Map[string, *PathItem]
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *v2low.Paths
|
low *v2low.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Response is a representation of a high-level Swagger / OpenAPI 2 Response object, backed by a low-level one.
|
// Response is a representation of a high-level Swagger / OpenAPI 2 Response object, backed by a low-level one.
|
||||||
@@ -16,9 +17,9 @@ import (
|
|||||||
type Response struct {
|
type Response struct {
|
||||||
Description string
|
Description string
|
||||||
Schema *base.SchemaProxy
|
Schema *base.SchemaProxy
|
||||||
Headers orderedmap.Map[string, *Header]
|
Headers *orderedmap.Map[string, *Header]
|
||||||
Examples *Example
|
Examples *Example
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Response
|
low *low.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,19 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Responses is a high-level representation of a Swagger / OpenAPI 2 Responses object, backed by a low level one.
|
// Responses is a high-level representation of a Swagger / OpenAPI 2 Responses object, backed by a low level one.
|
||||||
type Responses struct {
|
type Responses struct {
|
||||||
Codes orderedmap.Map[string, *Response]
|
Codes *orderedmap.Map[string, *Response]
|
||||||
Default *Response
|
Default *Response
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Responses
|
low *low.Responses
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ func NewResponses(responses *low.Responses) *Responses {
|
|||||||
resp := orderedmap.New[string, *Response]()
|
resp := orderedmap.New[string, *Response]()
|
||||||
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Response]]) (asyncResult[*Response], error) {
|
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Response]]) (asyncResult[*Response], error) {
|
||||||
return asyncResult[*Response]{
|
return asyncResult[*Response]{
|
||||||
key: pair.Key().Value,
|
key: pair.Key().Value,
|
||||||
result: NewResponse(pair.Value().Value),
|
result: NewResponse(pair.Value().Value),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,7 @@ func NewResponses(responses *low.Responses) *Responses {
|
|||||||
resp.Set(value.key, value.result)
|
resp.Set(value.key, value.result)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = orderedmap.TranslateMapParallel(responses.Codes, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(responses.Codes, translateFunc, resultFunc)
|
||||||
r.Codes = resp
|
r.Codes = resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
@@ -16,7 +17,7 @@ import (
|
|||||||
// referenced to the ones defined here. It does not define global operation responses
|
// referenced to the ones defined here. It does not define global operation responses
|
||||||
// - https://swagger.io/specification/v2/#responsesDefinitionsObject
|
// - https://swagger.io/specification/v2/#responsesDefinitionsObject
|
||||||
type ResponsesDefinitions struct {
|
type ResponsesDefinitions struct {
|
||||||
Definitions orderedmap.Map[string, *Response]
|
Definitions *orderedmap.Map[string, *Response]
|
||||||
low *low.ResponsesDefinitions
|
low *low.ResponsesDefinitions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ func NewResponsesDefinitions(responsesDefinitions *low.ResponsesDefinitions) *Re
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = orderedmap.TranslateMapParallel(responsesDefinitions.Definitions, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(responsesDefinitions.Definitions, translateFunc, resultFunc)
|
||||||
rd.Definitions = responses
|
rd.Definitions = responses
|
||||||
return rd
|
return rd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
// Scopes lists the available scopes for an OAuth2 security scheme.
|
// Scopes lists the available scopes for an OAuth2 security scheme.
|
||||||
// - https://swagger.io/specification/v2/#scopesObject
|
// - https://swagger.io/specification/v2/#scopesObject
|
||||||
type Scopes struct {
|
type Scopes struct {
|
||||||
Values orderedmap.Map[string, string]
|
Values *orderedmap.Map[string, string]
|
||||||
low *low.Scopes
|
low *low.Scopes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
@@ -16,7 +17,7 @@ import (
|
|||||||
// schemes on the operations and only serves to provide the relevant details for each scheme
|
// schemes on the operations and only serves to provide the relevant details for each scheme
|
||||||
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
||||||
type SecurityDefinitions struct {
|
type SecurityDefinitions struct {
|
||||||
Definitions orderedmap.Map[string, *SecurityScheme]
|
Definitions *orderedmap.Map[string, *SecurityScheme]
|
||||||
low *low.SecurityDefinitions
|
low *low.SecurityDefinitions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,12 +36,8 @@ func NewSecurityDefinitions(definitions *low.SecurityDefinitions) *SecurityDefin
|
|||||||
schemes.Set(value.key, value.result)
|
schemes.Set(value.key, value.result)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = orderedmap.TranslateMapParallel(definitions.Definitions, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(definitions.Definitions, translateFunc, resultFunc)
|
||||||
|
|
||||||
// schemes := make(map[string]*SecurityScheme)
|
|
||||||
// for k := range definitions.Definitions {
|
|
||||||
// schemes[k.Value] = NewSecurityScheme(definitions.Definitions[k].Value)
|
|
||||||
// }
|
|
||||||
sd.Definitions = schemes
|
sd.Definitions = schemes
|
||||||
return sd
|
return sd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecurityScheme is a high-level representation of a Swagger / OpenAPI 2 SecurityScheme object
|
// SecurityScheme is a high-level representation of a Swagger / OpenAPI 2 SecurityScheme object
|
||||||
@@ -24,7 +26,7 @@ type SecurityScheme struct {
|
|||||||
AuthorizationUrl string
|
AuthorizationUrl string
|
||||||
TokenUrl string
|
TokenUrl string
|
||||||
Scopes *Scopes
|
Scopes *Scopes
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.SecurityScheme
|
low *low.SecurityScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,12 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Swagger represents a high-level Swagger / OpenAPI 2 document. An instance of Swagger is the root of the specification.
|
// Swagger represents a high-level Swagger / OpenAPI 2 document. An instance of Swagger is the root of the specification.
|
||||||
type Swagger struct {
|
type Swagger struct {
|
||||||
|
|
||||||
// Swagger is the version of Swagger / OpenAPI being used, extracted from the 'swagger: 2.x' definition.
|
// Swagger is the version of Swagger / OpenAPI being used, extracted from the 'swagger: 2.x' definition.
|
||||||
Swagger string
|
Swagger string
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ type Swagger struct {
|
|||||||
ExternalDocs *base.ExternalDoc
|
ExternalDocs *base.ExternalDoc
|
||||||
|
|
||||||
// Extensions contains all custom extensions defined for the top-level document.
|
// Extensions contains all custom extensions defined for the top-level document.
|
||||||
Extensions map[string]any
|
Extensions *orderedmap.Map[string, *yaml.Node]
|
||||||
low *low.Swagger
|
low *low.Swagger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel"
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var doc *v2.Swagger
|
var doc *v2.Swagger
|
||||||
@@ -42,8 +41,12 @@ func BenchmarkNewDocument(b *testing.B) {
|
|||||||
func TestNewSwaggerDocument_Base(t *testing.T) {
|
func TestNewSwaggerDocument_Base(t *testing.T) {
|
||||||
initTest()
|
initTest()
|
||||||
highDoc := NewSwaggerDocument(doc)
|
highDoc := NewSwaggerDocument(doc)
|
||||||
|
|
||||||
|
var xPet bool
|
||||||
|
_ = highDoc.Extensions.GetOrZero("x-pet").Decode(&xPet)
|
||||||
|
|
||||||
assert.Equal(t, "2.0", highDoc.Swagger)
|
assert.Equal(t, "2.0", highDoc.Swagger)
|
||||||
assert.True(t, highDoc.Extensions["x-pet"].(bool))
|
assert.True(t, xPet)
|
||||||
assert.Equal(t, "petstore.swagger.io", highDoc.Host)
|
assert.Equal(t, "petstore.swagger.io", highDoc.Host)
|
||||||
assert.Equal(t, "/v2", highDoc.BasePath)
|
assert.Equal(t, "/v2", highDoc.BasePath)
|
||||||
assert.Len(t, highDoc.Schemes, 2)
|
assert.Len(t, highDoc.Schemes, 2)
|
||||||
@@ -56,7 +59,6 @@ func TestNewSwaggerDocument_Base(t *testing.T) {
|
|||||||
wentLow := highDoc.GoLow()
|
wentLow := highDoc.GoLow()
|
||||||
assert.Equal(t, 16, wentLow.Host.ValueNode.Line)
|
assert.Equal(t, 16, wentLow.Host.ValueNode.Line)
|
||||||
assert.Equal(t, 7, wentLow.Host.ValueNode.Column)
|
assert.Equal(t, 7, wentLow.Host.ValueNode.Column)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSwaggerDocument_Info(t *testing.T) {
|
func TestNewSwaggerDocument_Info(t *testing.T) {
|
||||||
@@ -82,11 +84,15 @@ func TestNewSwaggerDocument_Parameters(t *testing.T) {
|
|||||||
initTest()
|
initTest()
|
||||||
highDoc := NewSwaggerDocument(doc)
|
highDoc := NewSwaggerDocument(doc)
|
||||||
params := highDoc.Parameters
|
params := highDoc.Parameters
|
||||||
|
|
||||||
|
var xChicken string
|
||||||
|
_ = params.Definitions.GetOrZero("simpleParam").Extensions.GetOrZero("x-chicken").Decode(&xChicken)
|
||||||
|
|
||||||
assert.Equal(t, 1, orderedmap.Len(params.Definitions))
|
assert.Equal(t, 1, orderedmap.Len(params.Definitions))
|
||||||
assert.Equal(t, "query", params.Definitions.GetOrZero("simpleParam").In)
|
assert.Equal(t, "query", params.Definitions.GetOrZero("simpleParam").In)
|
||||||
assert.Equal(t, "simple", params.Definitions.GetOrZero("simpleParam").Name)
|
assert.Equal(t, "simple", params.Definitions.GetOrZero("simpleParam").Name)
|
||||||
assert.Equal(t, "string", params.Definitions.GetOrZero("simpleParam").Type)
|
assert.Equal(t, "string", params.Definitions.GetOrZero("simpleParam").Type)
|
||||||
assert.Equal(t, "nuggets", params.Definitions.GetOrZero("simpleParam").Extensions["x-chicken"])
|
assert.Equal(t, "nuggets", xChicken)
|
||||||
|
|
||||||
wentLow := params.GoLow()
|
wentLow := params.GoLow()
|
||||||
assert.Equal(t, 20, wentLow.FindParameter("simpleParam").ValueNode.Line)
|
assert.Equal(t, 20, wentLow.FindParameter("simpleParam").ValueNode.Line)
|
||||||
@@ -95,7 +101,6 @@ func TestNewSwaggerDocument_Parameters(t *testing.T) {
|
|||||||
wentLower := params.Definitions.GetOrZero("simpleParam").GoLow()
|
wentLower := params.Definitions.GetOrZero("simpleParam").GoLow()
|
||||||
assert.Equal(t, 21, wentLower.Name.ValueNode.Line)
|
assert.Equal(t, 21, wentLower.Name.ValueNode.Line)
|
||||||
assert.Equal(t, 11, wentLower.Name.ValueNode.Column)
|
assert.Equal(t, 11, wentLower.Name.ValueNode.Column)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSwaggerDocument_Security(t *testing.T) {
|
func TestNewSwaggerDocument_Security(t *testing.T) {
|
||||||
@@ -107,7 +112,6 @@ func TestNewSwaggerDocument_Security(t *testing.T) {
|
|||||||
wentLow := highDoc.Security[0].GoLow()
|
wentLow := highDoc.Security[0].GoLow()
|
||||||
assert.Equal(t, 25, wentLow.Requirements.ValueNode.Line)
|
assert.Equal(t, 25, wentLow.Requirements.ValueNode.Line)
|
||||||
assert.Equal(t, 5, wentLow.Requirements.ValueNode.Column)
|
assert.Equal(t, 5, wentLow.Requirements.ValueNode.Column)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSwaggerDocument_Definitions_Security(t *testing.T) {
|
func TestNewSwaggerDocument_Definitions_Security(t *testing.T) {
|
||||||
@@ -140,22 +144,32 @@ func TestNewSwaggerDocument_Definitions_Responses(t *testing.T) {
|
|||||||
assert.Equal(t, 2, orderedmap.Len(highDoc.Responses.Definitions))
|
assert.Equal(t, 2, orderedmap.Len(highDoc.Responses.Definitions))
|
||||||
|
|
||||||
defs := highDoc.Responses.Definitions
|
defs := highDoc.Responses.Definitions
|
||||||
assert.Equal(t, "morning", defs.GetOrZero("200").Extensions["x-coffee"])
|
|
||||||
|
var xCoffee string
|
||||||
|
_ = defs.GetOrZero("200").Extensions.GetOrZero("x-coffee").Decode(&xCoffee)
|
||||||
|
|
||||||
|
assert.Equal(t, "morning", xCoffee)
|
||||||
assert.Equal(t, "OK", defs.GetOrZero("200").Description)
|
assert.Equal(t, "OK", defs.GetOrZero("200").Description)
|
||||||
assert.Equal(t, "a generic API response object",
|
assert.Equal(t, "a generic API response object",
|
||||||
defs.GetOrZero("200").Schema.Schema().Description)
|
defs.GetOrZero("200").Schema.Schema().Description)
|
||||||
assert.Equal(t, 3, orderedmap.Len(defs.GetOrZero("200").Examples.Values))
|
assert.Equal(t, 3, orderedmap.Len(defs.GetOrZero("200").Examples.Values))
|
||||||
|
|
||||||
exp := defs.GetOrZero("200").Examples.Values.GetOrZero("application/json")
|
var appJson map[string]interface{}
|
||||||
assert.Len(t, exp.(map[string]interface{}), 2)
|
_ = defs.GetOrZero("200").Examples.Values.GetOrZero("application/json").Decode(&appJson)
|
||||||
assert.Equal(t, "two", exp.(map[string]interface{})["one"])
|
|
||||||
|
|
||||||
exp = defs.GetOrZero("200").Examples.Values.GetOrZero("text/xml")
|
assert.Len(t, appJson, 2)
|
||||||
assert.Len(t, exp.([]interface{}), 3)
|
assert.Equal(t, "two", appJson["one"])
|
||||||
assert.Equal(t, "two", exp.([]interface{})[1])
|
|
||||||
|
|
||||||
exp = defs.GetOrZero("200").Examples.Values.GetOrZero("text/plain")
|
var textXml []interface{}
|
||||||
assert.Equal(t, "something else.", exp)
|
_ = defs.GetOrZero("200").Examples.Values.GetOrZero("text/xml").Decode(&textXml)
|
||||||
|
|
||||||
|
assert.Len(t, textXml, 3)
|
||||||
|
assert.Equal(t, "two", textXml[1])
|
||||||
|
|
||||||
|
var textPlain string
|
||||||
|
_ = defs.GetOrZero("200").Examples.Values.GetOrZero("text/plain").Decode(&textPlain)
|
||||||
|
|
||||||
|
assert.Equal(t, "something else.", textPlain)
|
||||||
|
|
||||||
expWentLow := defs.GetOrZero("200").Examples.GoLow()
|
expWentLow := defs.GetOrZero("200").Examples.GoLow()
|
||||||
assert.Equal(t, 702, expWentLow.FindExample("application/json").ValueNode.Line)
|
assert.Equal(t, 702, expWentLow.FindExample("application/json").ValueNode.Line)
|
||||||
@@ -168,10 +182,13 @@ func TestNewSwaggerDocument_Definitions_Responses(t *testing.T) {
|
|||||||
assert.Len(t, y.Enum, 2)
|
assert.Len(t, y.Enum, 2)
|
||||||
x := y.Items
|
x := y.Items
|
||||||
|
|
||||||
|
var def string
|
||||||
|
_ = x.Default.Decode(&def)
|
||||||
|
|
||||||
assert.Equal(t, "something", x.Format)
|
assert.Equal(t, "something", x.Format)
|
||||||
assert.Equal(t, "array", x.Type)
|
assert.Equal(t, "array", x.Type)
|
||||||
assert.Equal(t, "csv", x.CollectionFormat)
|
assert.Equal(t, "csv", x.CollectionFormat)
|
||||||
assert.Equal(t, "cake", x.Default)
|
assert.Equal(t, "cake", def)
|
||||||
assert.Equal(t, 10, x.Maximum)
|
assert.Equal(t, 10, x.Maximum)
|
||||||
assert.Equal(t, 1, x.Minimum)
|
assert.Equal(t, 1, x.Minimum)
|
||||||
assert.True(t, x.ExclusiveMaximum)
|
assert.True(t, x.ExclusiveMaximum)
|
||||||
@@ -198,7 +215,6 @@ func TestNewSwaggerDocument_Definitions(t *testing.T) {
|
|||||||
|
|
||||||
wentLow := highDoc.Definitions.GoLow()
|
wentLow := highDoc.Definitions.GoLow()
|
||||||
assert.Equal(t, 848, wentLow.FindSchema("User").ValueNode.Line)
|
assert.Equal(t, 848, wentLow.FindSchema("User").ValueNode.Line)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSwaggerDocument_Paths(t *testing.T) {
|
func TestNewSwaggerDocument_Paths(t *testing.T) {
|
||||||
@@ -207,7 +223,14 @@ func TestNewSwaggerDocument_Paths(t *testing.T) {
|
|||||||
assert.Equal(t, 15, orderedmap.Len(highDoc.Paths.PathItems))
|
assert.Equal(t, 15, orderedmap.Len(highDoc.Paths.PathItems))
|
||||||
|
|
||||||
upload := highDoc.Paths.PathItems.GetOrZero("/pet/{petId}/uploadImage")
|
upload := highDoc.Paths.PathItems.GetOrZero("/pet/{petId}/uploadImage")
|
||||||
assert.Equal(t, "man", upload.Extensions["x-potato"])
|
|
||||||
|
var xPotato string
|
||||||
|
_ = upload.Extensions.GetOrZero("x-potato").Decode(&xPotato)
|
||||||
|
|
||||||
|
var paramEnum0 string
|
||||||
|
_ = upload.Post.Parameters[0].Enum[0].Decode(¶mEnum0)
|
||||||
|
|
||||||
|
assert.Equal(t, "man", xPotato)
|
||||||
assert.Nil(t, upload.Get)
|
assert.Nil(t, upload.Get)
|
||||||
assert.Nil(t, upload.Put)
|
assert.Nil(t, upload.Put)
|
||||||
assert.Nil(t, upload.Patch)
|
assert.Nil(t, upload.Patch)
|
||||||
@@ -238,8 +261,11 @@ func TestNewSwaggerDocument_Paths(t *testing.T) {
|
|||||||
assert.Equal(t, 20, *upload.Post.Parameters[0].MaxItems)
|
assert.Equal(t, 20, *upload.Post.Parameters[0].MaxItems)
|
||||||
assert.True(t, *upload.Post.Parameters[0].UniqueItems)
|
assert.True(t, *upload.Post.Parameters[0].UniqueItems)
|
||||||
assert.Len(t, upload.Post.Parameters[0].Enum, 2)
|
assert.Len(t, upload.Post.Parameters[0].Enum, 2)
|
||||||
assert.Equal(t, "hello", upload.Post.Parameters[0].Enum[0])
|
assert.Equal(t, "hello", paramEnum0)
|
||||||
def := upload.Post.Parameters[0].Default.(map[string]interface{})
|
|
||||||
|
var def map[string]any
|
||||||
|
_ = upload.Post.Parameters[0].Default.Decode(&def)
|
||||||
|
|
||||||
assert.Equal(t, "here", def["something"])
|
assert.Equal(t, "here", def["something"])
|
||||||
|
|
||||||
assert.Equal(t, "https://pb33f.io", upload.Post.ExternalDocs.URL)
|
assert.Equal(t, "https://pb33f.io", upload.Post.ExternalDocs.URL)
|
||||||
@@ -257,11 +283,9 @@ func TestNewSwaggerDocument_Paths(t *testing.T) {
|
|||||||
|
|
||||||
wentLowest := upload.Post.GoLow()
|
wentLowest := upload.Post.GoLow()
|
||||||
assert.Equal(t, 55, wentLowest.Tags.KeyNode.Line)
|
assert.Equal(t, 55, wentLowest.Tags.KeyNode.Line)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewSwaggerDocument_Responses(t *testing.T) {
|
func TestNewSwaggerDocument_Responses(t *testing.T) {
|
||||||
|
|
||||||
initTest()
|
initTest()
|
||||||
highDoc := NewSwaggerDocument(doc)
|
highDoc := NewSwaggerDocument(doc)
|
||||||
upload := highDoc.Paths.PathItems.GetOrZero("/pet/{petId}/uploadImage").Post
|
upload := highDoc.Paths.PathItems.GetOrZero("/pet/{petId}/uploadImage").Post
|
||||||
@@ -278,5 +302,4 @@ func TestNewSwaggerDocument_Responses(t *testing.T) {
|
|||||||
wentLower := OK.GoLow()
|
wentLower := OK.GoLow()
|
||||||
assert.Equal(t, 107, wentLower.Schema.KeyNode.Line)
|
assert.Equal(t, 107, wentLower.Schema.KeyNode.Line)
|
||||||
assert.Equal(t, 11, wentLower.Schema.KeyNode.Column)
|
assert.Equal(t, 11, wentLower.Schema.KeyNode.Column)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import (
|
|||||||
// that identifies a URL to use for the callback operation.
|
// that identifies a URL to use for the callback operation.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#callback-object
|
// - https://spec.openapis.org/oas/v3.1.0#callback-object
|
||||||
type Callback struct {
|
type Callback struct {
|
||||||
Expression orderedmap.Map[string, *PathItem] `json:"-" yaml:"-"`
|
Expression *orderedmap.Map[string, *PathItem] `json:"-" yaml:"-"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Callback
|
low *low.Callback
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,13 +31,11 @@ func NewCallback(lowCallback *low.Callback) *Callback {
|
|||||||
n := new(Callback)
|
n := new(Callback)
|
||||||
n.low = lowCallback
|
n.low = lowCallback
|
||||||
n.Expression = orderedmap.New[string, *PathItem]()
|
n.Expression = orderedmap.New[string, *PathItem]()
|
||||||
for pair := orderedmap.First(lowCallback.Expression.Value); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(lowCallback.Expression); pair != nil; pair = pair.Next() {
|
||||||
n.Expression.Set(pair.Key().Value, NewPathItem(pair.Value().Value))
|
n.Expression.Set(pair.Key().Value, NewPathItem(pair.Value().Value))
|
||||||
}
|
}
|
||||||
n.Extensions = make(map[string]any)
|
|
||||||
for k, v := range lowCallback.Extensions {
|
n.Extensions = high.ExtractExtensions(lowCallback.Extensions)
|
||||||
n.Extensions[k.Value] = v.Value
|
|
||||||
}
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,36 +49,50 @@ func (c *Callback) GoLowUntyped() any {
|
|||||||
return c.low
|
return c.low
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render will return a YAML representation of the Callback object as a byte slice.
|
// Render will return a YAML representation of the Paths object as a byte slice.
|
||||||
func (c *Callback) Render() ([]byte, error) {
|
func (c *Callback) Render() ([]byte, error) {
|
||||||
return yaml.Marshal(c)
|
return yaml.Marshal(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalYAML will create a ready to render YAML representation of the Callback object.
|
func (c *Callback) RenderInline() ([]byte, error) {
|
||||||
|
d, _ := c.MarshalYAMLInline()
|
||||||
|
return yaml.Marshal(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML will create a ready to render YAML representation of the Paths object.
|
||||||
func (c *Callback) MarshalYAML() (interface{}, error) {
|
func (c *Callback) MarshalYAML() (interface{}, error) {
|
||||||
// map keys correctly.
|
// map keys correctly.
|
||||||
m := utils.CreateEmptyMapNode()
|
m := utils.CreateEmptyMapNode()
|
||||||
type cbItem struct {
|
type pathItem struct {
|
||||||
cb *PathItem
|
pi *PathItem
|
||||||
exp string
|
path string
|
||||||
line int
|
line int
|
||||||
ext *yaml.Node
|
style yaml.Style
|
||||||
|
rendered *yaml.Node
|
||||||
}
|
}
|
||||||
var mapped []*cbItem
|
var mapped []*pathItem
|
||||||
|
|
||||||
for pair := orderedmap.First(c.Expression); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(c.Expression); pair != nil; pair = pair.Next() {
|
||||||
ln := 999 // default to a high value to weight new content to the bottom.
|
k := pair.Key()
|
||||||
|
pi := pair.Value()
|
||||||
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
if c.low != nil {
|
if c.low != nil {
|
||||||
for lPair := orderedmap.First(c.low.Expression.Value); lPair != nil; lPair = lPair.Next() {
|
lpi := c.low.FindExpression(k)
|
||||||
if lPair.Key().Value == pair.Key() {
|
if lpi != nil {
|
||||||
ln = lPair.Key().KeyNode.Line
|
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
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &cbItem{pair.Value(), pair.Key(), ln, nil})
|
mapped = append(mapped, &pathItem{pi, k, ln, style, nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract extensions
|
|
||||||
nb := high.NewNodeBuilder(c, c.low)
|
nb := high.NewNodeBuilder(c, c.low)
|
||||||
extNode := nb.Render()
|
extNode := nb.Render()
|
||||||
if extNode != nil && extNode.Content != nil {
|
if extNode != nil && extNode.Content != nil {
|
||||||
@@ -90,23 +102,101 @@ func (c *Callback) MarshalYAML() (interface{}, error) {
|
|||||||
label = extNode.Content[u].Value
|
label = extNode.Content[u].Value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &cbItem{nil, label,
|
mapped = append(mapped, &pathItem{
|
||||||
extNode.Content[u].Line, extNode.Content[u]})
|
nil, label,
|
||||||
|
extNode.Content[u].Line, 0, extNode.Content[u],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(mapped, func(i, j int) bool {
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
return mapped[i].line < mapped[j].line
|
return mapped[i].line < mapped[j].line
|
||||||
})
|
})
|
||||||
for j := range mapped {
|
for _, mp := range mapped {
|
||||||
if mapped[j].cb != nil {
|
if mp.pi != nil {
|
||||||
rendered, _ := mapped[j].cb.MarshalYAML()
|
rendered, _ := mp.pi.MarshalYAML()
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].exp))
|
|
||||||
|
kn := utils.CreateStringNode(mp.path)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
m.Content = append(m.Content, rendered.(*yaml.Node))
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
}
|
}
|
||||||
if mapped[j].ext != nil {
|
if mp.rendered != nil {
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].exp))
|
m.Content = append(m.Content, utils.CreateStringNode(mp.path))
|
||||||
m.Content = append(m.Content, mapped[j].ext)
|
m.Content = append(m.Content, mp.rendered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Callback) MarshalYAMLInline() (interface{}, error) {
|
||||||
|
// map keys correctly.
|
||||||
|
m := utils.CreateEmptyMapNode()
|
||||||
|
type pathItem struct {
|
||||||
|
pi *PathItem
|
||||||
|
path string
|
||||||
|
line int
|
||||||
|
style yaml.Style
|
||||||
|
rendered *yaml.Node
|
||||||
|
}
|
||||||
|
var mapped []*pathItem
|
||||||
|
|
||||||
|
for pair := orderedmap.First(c.Expression); pair != nil; pair = pair.Next() {
|
||||||
|
k := pair.Key()
|
||||||
|
pi := pair.Value()
|
||||||
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
|
if c.low != nil {
|
||||||
|
lpi := c.low.FindExpression(k)
|
||||||
|
if lpi != nil {
|
||||||
|
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
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapped = append(mapped, &pathItem{pi, k, ln, style, nil})
|
||||||
|
}
|
||||||
|
|
||||||
|
nb := high.NewNodeBuilder(c, c.low)
|
||||||
|
nb.Resolve = true
|
||||||
|
extNode := nb.Render()
|
||||||
|
if extNode != nil && extNode.Content != nil {
|
||||||
|
var label string
|
||||||
|
for u := range extNode.Content {
|
||||||
|
if u%2 == 0 {
|
||||||
|
label = extNode.Content[u].Value
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mapped = append(mapped, &pathItem{
|
||||||
|
nil, label,
|
||||||
|
extNode.Content[u].Line, 0, extNode.Content[u],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
|
return mapped[i].line < mapped[j].line
|
||||||
|
})
|
||||||
|
for _, mp := range mapped {
|
||||||
|
if mp.pi != nil {
|
||||||
|
rendered, _ := mp.pi.MarshalYAMLInline()
|
||||||
|
|
||||||
|
kn := utils.CreateStringNode(mp.path)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
|
}
|
||||||
|
if mp.rendered != nil {
|
||||||
|
m.Content = append(m.Content, utils.CreateStringNode(mp.path))
|
||||||
|
m.Content = append(m.Content, mp.rendered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ import (
|
|||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCallback_MarshalYAML(t *testing.T) {
|
func TestCallback_MarshalYAML(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
cb := &Callback{
|
cb := &Callback{
|
||||||
Expression: orderedmap.ToOrderedMap(map[string]*PathItem{
|
Expression: orderedmap.ToOrderedMap(map[string]*PathItem{
|
||||||
@@ -31,9 +34,7 @@ func TestCallback_MarshalYAML(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Extensions: map[string]any{
|
Extensions: ext,
|
||||||
"x-burgers": "why not?",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := cb.Render()
|
rend, _ := cb.Render()
|
||||||
@@ -43,7 +44,10 @@ func TestCallback_MarshalYAML(t *testing.T) {
|
|||||||
|
|
||||||
// mutate
|
// mutate
|
||||||
cb.Expression.GetOrZero("https://pb33f.io").Get.OperationId = "blim-blam"
|
cb.Expression.GetOrZero("https://pb33f.io").Get.OperationId = "blim-blam"
|
||||||
cb.Extensions = map[string]interface{}{"x-burgers": "yes please!"}
|
|
||||||
|
ext = orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("yes please!"))
|
||||||
|
cb.Extensions = ext
|
||||||
|
|
||||||
rend, _ = cb.Render()
|
rend, _ = cb.Render()
|
||||||
// there is no way to determine order in brand new maps, so we have to check length.
|
// there is no way to determine order in brand new maps, so we have to check length.
|
||||||
@@ -72,7 +76,10 @@ func TestCallback_MarshalYAML(t *testing.T) {
|
|||||||
|
|
||||||
r := NewCallback(&n)
|
r := NewCallback(&n)
|
||||||
|
|
||||||
assert.Equal(t, "please", r.Extensions["x-break-everything"])
|
var xBreakEverything string
|
||||||
|
_ = r.Extensions.GetOrZero("x-break-everything").Decode(&xBreakEverything)
|
||||||
|
|
||||||
|
assert.Equal(t, "please", xBreakEverything)
|
||||||
|
|
||||||
rend, _ = r.Render()
|
rend, _ = r.Render()
|
||||||
assert.Equal(t, k, strings.TrimSpace(string(rend)))
|
assert.Equal(t, k, strings.TrimSpace(string(rend)))
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ import (
|
|||||||
// will have no effect on the API unless they are explicitly referenced from properties outside the components object.
|
// will have no effect on the API unless they are explicitly referenced from properties outside the components object.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#components-object
|
// - https://spec.openapis.org/oas/v3.1.0#components-object
|
||||||
type Components struct {
|
type Components struct {
|
||||||
Schemas orderedmap.Map[string, *highbase.SchemaProxy] `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
Schemas *orderedmap.Map[string, *highbase.SchemaProxy] `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
Responses orderedmap.Map[string, *Response] `json:"responses,omitempty" yaml:"responses,omitempty"`
|
Responses *orderedmap.Map[string, *Response] `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||||
Parameters orderedmap.Map[string, *Parameter] `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
Parameters *orderedmap.Map[string, *Parameter] `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
Examples orderedmap.Map[string, *highbase.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
Examples *orderedmap.Map[string, *highbase.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
RequestBodies orderedmap.Map[string, *RequestBody] `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
RequestBodies *orderedmap.Map[string, *RequestBody] `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
||||||
Headers orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
Headers *orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||||
SecuritySchemes orderedmap.Map[string, *SecurityScheme] `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
SecuritySchemes *orderedmap.Map[string, *SecurityScheme] `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
||||||
Links orderedmap.Map[string, *Link] `json:"links,omitempty" yaml:"links,omitempty"`
|
Links *orderedmap.Map[string, *Link] `json:"links,omitempty" yaml:"links,omitempty"`
|
||||||
Callbacks orderedmap.Map[string, *Callback] `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
Callbacks *orderedmap.Map[string, *Callback] `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Components
|
low *low.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ type Components struct {
|
|||||||
func NewComponents(comp *low.Components) *Components {
|
func NewComponents(comp *low.Components) *Components {
|
||||||
c := new(Components)
|
c := new(Components)
|
||||||
c.low = comp
|
c.low = comp
|
||||||
if len(comp.Extensions) > 0 {
|
if orderedmap.Len(comp.Extensions) > 0 {
|
||||||
c.Extensions = high.ExtractExtensions(comp.Extensions)
|
c.Extensions = high.ExtractExtensions(comp.Extensions)
|
||||||
}
|
}
|
||||||
cbMap := orderedmap.New[string, *Callback]()
|
cbMap := orderedmap.New[string, *Callback]()
|
||||||
@@ -109,12 +109,12 @@ func NewComponents(comp *low.Components) *Components {
|
|||||||
|
|
||||||
// contains a component build result.
|
// contains a component build result.
|
||||||
type componentResult[T any] struct {
|
type componentResult[T any] struct {
|
||||||
res T
|
res T
|
||||||
key string
|
key string
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildComponent builds component structs from low level structs.
|
// buildComponent builds component structs from low level structs.
|
||||||
func buildComponent[IN any, OUT any](inMap orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[IN]], outMap orderedmap.Map[string, OUT], translateItem func(IN) OUT) {
|
func buildComponent[IN any, OUT any](inMap *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[IN]], outMap *orderedmap.Map[string, OUT], translateItem func(IN) OUT) {
|
||||||
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[IN]]) (componentResult[OUT], error) {
|
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[IN]]) (componentResult[OUT], error) {
|
||||||
return componentResult[OUT]{key: pair.Key().Value, res: translateItem(pair.Value().Value)}, nil
|
return componentResult[OUT]{key: pair.Key().Value, res: translateItem(pair.Value().Value)}, nil
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ func buildComponent[IN any, OUT any](inMap orderedmap.Map[lowmodel.KeyReference[
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildSchema builds a schema from low level structs.
|
// buildSchema builds a schema from low level structs.
|
||||||
func buildSchema(inMap orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*base.SchemaProxy]], outMap orderedmap.Map[string, *highbase.SchemaProxy]) {
|
func buildSchema(inMap *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*base.SchemaProxy]], outMap *orderedmap.Map[string, *highbase.SchemaProxy]) {
|
||||||
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*base.SchemaProxy]]) (componentResult[*highbase.SchemaProxy], error) {
|
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*base.SchemaProxy]]) (componentResult[*highbase.SchemaProxy], error) {
|
||||||
value := pair.Value()
|
value := pair.Value()
|
||||||
var sch *highbase.SchemaProxy
|
var sch *highbase.SchemaProxy
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
|
|
||||||
// Document represents a high-level OpenAPI 3 document (both 3.0 & 3.1). A Document is the root of the specification.
|
// Document represents a high-level OpenAPI 3 document (both 3.0 & 3.1). A Document is the root of the specification.
|
||||||
type Document struct {
|
type Document struct {
|
||||||
|
|
||||||
// Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition.
|
// Version is the version of OpenAPI being used, extracted from the 'openapi: x.x.x' definition.
|
||||||
// This is not a standard property of the OpenAPI model, it's a convenience mechanism only.
|
// This is not a standard property of the OpenAPI model, it's a convenience mechanism only.
|
||||||
Version string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
|
Version string `json:"openapi,omitempty" yaml:"openapi,omitempty"`
|
||||||
@@ -54,7 +53,7 @@ type Document struct {
|
|||||||
// an empty security requirement ({}) can be included in the array.
|
// an empty security requirement ({}) can be included in the array.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
|
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
|
||||||
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
|
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
|
||||||
//Security []*base.SecurityRequirement `json:"-" yaml:"-"`
|
// Security []*base.SecurityRequirement `json:"-" yaml:"-"`
|
||||||
|
|
||||||
// Tags is a slice of base.Tag instances defined by the specification
|
// Tags is a slice of base.Tag instances defined by the specification
|
||||||
// A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on
|
// A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on
|
||||||
@@ -69,7 +68,7 @@ type Document struct {
|
|||||||
ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
|
|
||||||
// Extensions contains all custom extensions defined for the top-level document.
|
// Extensions contains all custom extensions defined for the top-level document.
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
|
|
||||||
// JsonSchemaDialect is a 3.1+ property that sets the dialect to use for validating *base.Schema definitions
|
// JsonSchemaDialect is a 3.1+ property that sets the dialect to use for validating *base.Schema definitions
|
||||||
// The default value for the $schema keyword within Schema Objects contained within this OAS document.
|
// The default value for the $schema keyword within Schema Objects contained within this OAS document.
|
||||||
@@ -83,7 +82,7 @@ type Document struct {
|
|||||||
// for example by an out-of-band registration. The key name is a unique string to refer to each webhook,
|
// for example by an out-of-band registration. The key name is a unique string to refer to each webhook,
|
||||||
// while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider
|
// while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider
|
||||||
// and the expected responses. An example is available.
|
// and the expected responses. An example is available.
|
||||||
Webhooks orderedmap.Map[string, *PathItem] `json:"webhooks,omitempty" yaml:"webhooks,omitempty"`
|
Webhooks *orderedmap.Map[string, *PathItem] `json:"webhooks,omitempty" yaml:"webhooks,omitempty"`
|
||||||
|
|
||||||
// Index is a reference to the *index.SpecIndex that was created for the document and used
|
// Index is a reference to the *index.SpecIndex that was created for the document and used
|
||||||
// as a guide when building out the Document. Ideal if further processing is required on the model and
|
// as a guide when building out the Document. Ideal if further processing is required on the model and
|
||||||
@@ -122,7 +121,7 @@ func NewDocument(document *low.Document) *Document {
|
|||||||
if !document.ExternalDocs.IsEmpty() {
|
if !document.ExternalDocs.IsEmpty() {
|
||||||
d.ExternalDocs = base.NewExternalDoc(document.ExternalDocs.Value)
|
d.ExternalDocs = base.NewExternalDoc(document.ExternalDocs.Value)
|
||||||
}
|
}
|
||||||
if len(document.Extensions) > 0 {
|
if orderedmap.Len(document.Extensions) > 0 {
|
||||||
d.Extensions = high.ExtractExtensions(document.Extensions)
|
d.Extensions = high.ExtractExtensions(document.Extensions)
|
||||||
}
|
}
|
||||||
if !document.Components.IsEmpty() {
|
if !document.Components.IsEmpty() {
|
||||||
|
|||||||
@@ -51,7 +51,11 @@ func BenchmarkNewDocument(b *testing.B) {
|
|||||||
func TestNewDocument_Extensions(t *testing.T) {
|
func TestNewDocument_Extensions(t *testing.T) {
|
||||||
initTest()
|
initTest()
|
||||||
h := NewDocument(lowDoc)
|
h := NewDocument(lowDoc)
|
||||||
assert.Equal(t, "darkside", h.Extensions["x-something-something"])
|
|
||||||
|
var xSomethingSomething string
|
||||||
|
_ = h.Extensions.GetOrZero("x-something-something").Decode(&xSomethingSomething)
|
||||||
|
|
||||||
|
assert.Equal(t, "darkside", xSomethingSomething)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDocument_ExternalDocs(t *testing.T) {
|
func TestNewDocument_ExternalDocs(t *testing.T) {
|
||||||
@@ -133,15 +137,28 @@ func TestNewDocument_Servers(t *testing.T) {
|
|||||||
func TestNewDocument_Tags(t *testing.T) {
|
func TestNewDocument_Tags(t *testing.T) {
|
||||||
initTest()
|
initTest()
|
||||||
h := NewDocument(lowDoc)
|
h := NewDocument(lowDoc)
|
||||||
|
|
||||||
|
var xInternalTing string
|
||||||
|
_ = h.Tags[0].Extensions.GetOrZero("x-internal-ting").Decode(&xInternalTing)
|
||||||
|
|
||||||
|
var xInternalTong int64
|
||||||
|
_ = h.Tags[0].Extensions.GetOrZero("x-internal-tong").Decode(&xInternalTong)
|
||||||
|
|
||||||
|
var xInternalTang float64
|
||||||
|
_ = h.Tags[0].Extensions.GetOrZero("x-internal-tang").Decode(&xInternalTang)
|
||||||
|
|
||||||
assert.Len(t, h.Tags, 2)
|
assert.Len(t, h.Tags, 2)
|
||||||
assert.Equal(t, "Burgers", h.Tags[0].Name)
|
assert.Equal(t, "Burgers", h.Tags[0].Name)
|
||||||
assert.Equal(t, "All kinds of yummy burgers.", h.Tags[0].Description)
|
assert.Equal(t, "All kinds of yummy burgers.", h.Tags[0].Description)
|
||||||
assert.Equal(t, "Find out more", h.Tags[0].ExternalDocs.Description)
|
assert.Equal(t, "Find out more", h.Tags[0].ExternalDocs.Description)
|
||||||
assert.Equal(t, "https://pb33f.io", h.Tags[0].ExternalDocs.URL)
|
assert.Equal(t, "https://pb33f.io", h.Tags[0].ExternalDocs.URL)
|
||||||
assert.Equal(t, "somethingSpecial", h.Tags[0].Extensions["x-internal-ting"])
|
assert.Equal(t, "somethingSpecial", xInternalTing)
|
||||||
assert.Equal(t, int64(1), h.Tags[0].Extensions["x-internal-tong"])
|
assert.Equal(t, int64(1), xInternalTong)
|
||||||
assert.Equal(t, 1.2, h.Tags[0].Extensions["x-internal-tang"])
|
assert.Equal(t, 1.2, xInternalTang)
|
||||||
assert.True(t, h.Tags[0].Extensions["x-internal-tung"].(bool))
|
|
||||||
|
var tung bool
|
||||||
|
_ = h.Tags[0].Extensions.GetOrZero("x-internal-tung").Decode(&tung)
|
||||||
|
assert.True(t, tung)
|
||||||
|
|
||||||
wentLow := h.Tags[1].GoLow()
|
wentLow := h.Tags[1].GoLow()
|
||||||
assert.Equal(t, 39, wentLow.Description.KeyNode.Line)
|
assert.Equal(t, 39, wentLow.Description.KeyNode.Line)
|
||||||
@@ -191,7 +208,10 @@ func TestNewDocument_Components_Callbacks(t *testing.T) {
|
|||||||
h.Components.Callbacks.GetOrZero("BurgerCallback").GoLow().FindExpression("{$request.query.queryUrl}").ValueNode.Column,
|
h.Components.Callbacks.GetOrZero("BurgerCallback").GoLow().FindExpression("{$request.query.queryUrl}").ValueNode.Column,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, "please", h.Components.Callbacks.GetOrZero("BurgerCallback").Extensions["x-break-everything"])
|
var xBreakEverything string
|
||||||
|
_ = h.Components.Callbacks.GetOrZero("BurgerCallback").Extensions.GetOrZero("x-break-everything").Decode(&xBreakEverything)
|
||||||
|
|
||||||
|
assert.Equal(t, "please", xBreakEverything)
|
||||||
|
|
||||||
for pair := orderedmap.First(h.Components.GoLow().Callbacks.Value); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(h.Components.GoLow().Callbacks.Value); pair != nil; pair = pair.Next() {
|
||||||
if pair.Key().Value == "BurgerCallback" {
|
if pair.Key().Value == "BurgerCallback" {
|
||||||
@@ -209,7 +229,9 @@ func TestNewDocument_Components_Schemas(t *testing.T) {
|
|||||||
goLow := h.Components.GoLow()
|
goLow := h.Components.GoLow()
|
||||||
|
|
||||||
a := h.Components.Schemas.GetOrZero("Error")
|
a := h.Components.Schemas.GetOrZero("Error")
|
||||||
abcd := a.Schema().Properties.GetOrZero("message").Schema().Example
|
|
||||||
|
var abcd string
|
||||||
|
_ = a.Schema().Properties.GetOrZero("message").Schema().Example.Decode(&abcd)
|
||||||
assert.Equal(t, "No such burger as 'Big-Whopper'", abcd)
|
assert.Equal(t, "No such burger as 'Big-Whopper'", abcd)
|
||||||
assert.Equal(t, 433, goLow.Schemas.KeyNode.Line)
|
assert.Equal(t, 433, goLow.Schemas.KeyNode.Line)
|
||||||
assert.Equal(t, 3, goLow.Schemas.KeyNode.Column)
|
assert.Equal(t, 3, goLow.Schemas.KeyNode.Column)
|
||||||
@@ -218,13 +240,21 @@ func TestNewDocument_Components_Schemas(t *testing.T) {
|
|||||||
b := h.Components.Schemas.GetOrZero("Burger")
|
b := h.Components.Schemas.GetOrZero("Burger")
|
||||||
assert.Len(t, b.Schema().Required, 2)
|
assert.Len(t, b.Schema().Required, 2)
|
||||||
assert.Equal(t, "golden slices of happy fun joy", b.Schema().Properties.GetOrZero("fries").Schema().Description)
|
assert.Equal(t, "golden slices of happy fun joy", b.Schema().Properties.GetOrZero("fries").Schema().Description)
|
||||||
assert.Equal(t, int64(2), b.Schema().Properties.GetOrZero("numPatties").Schema().Example)
|
|
||||||
|
var numPattiesExample int64
|
||||||
|
_ = b.Schema().Properties.GetOrZero("numPatties").Schema().Example.Decode(&numPattiesExample)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(2), numPattiesExample)
|
||||||
assert.Equal(t, 448, goLow.FindSchema("Burger").Value.Schema().Properties.KeyNode.Line)
|
assert.Equal(t, 448, goLow.FindSchema("Burger").Value.Schema().Properties.KeyNode.Line)
|
||||||
assert.Equal(t, 7, goLow.FindSchema("Burger").Value.Schema().Properties.KeyNode.Column)
|
assert.Equal(t, 7, goLow.FindSchema("Burger").Value.Schema().Properties.KeyNode.Column)
|
||||||
assert.Equal(t, 450, b.Schema().GoLow().FindProperty("name").ValueNode.Line)
|
assert.Equal(t, 450, b.Schema().GoLow().FindProperty("name").ValueNode.Line)
|
||||||
|
|
||||||
f := h.Components.Schemas.GetOrZero("Fries")
|
f := h.Components.Schemas.GetOrZero("Fries")
|
||||||
assert.Equal(t, "salt", f.Schema().Properties.GetOrZero("seasoning").Schema().Items.A.Schema().Example)
|
|
||||||
|
var seasoningExample string
|
||||||
|
_ = f.Schema().Properties.GetOrZero("seasoning").Schema().Items.A.Schema().Example.Decode(&seasoningExample)
|
||||||
|
|
||||||
|
assert.Equal(t, "salt", seasoningExample)
|
||||||
assert.Len(t, f.Schema().Properties.GetOrZero("favoriteDrink").Schema().Properties.GetOrZero("drinkType").Schema().Enum, 1)
|
assert.Len(t, f.Schema().Properties.GetOrZero("favoriteDrink").Schema().Properties.GetOrZero("drinkType").Schema().Enum, 1)
|
||||||
|
|
||||||
d := h.Components.Schemas.GetOrZero("Drink")
|
d := h.Components.Schemas.GetOrZero("Drink")
|
||||||
@@ -240,7 +270,11 @@ func TestNewDocument_Components_Schemas(t *testing.T) {
|
|||||||
assert.Equal(t, 523, pl.Schema().XML.GoLow().Name.ValueNode.Line)
|
assert.Equal(t, 523, pl.Schema().XML.GoLow().Name.ValueNode.Line)
|
||||||
|
|
||||||
ext := h.Components.Extensions
|
ext := h.Components.Extensions
|
||||||
assert.Equal(t, "loud", ext["x-screaming-baby"])
|
|
||||||
|
var xScreamingBaby string
|
||||||
|
_ = ext.GetOrZero("x-screaming-baby").Decode(&xScreamingBaby)
|
||||||
|
|
||||||
|
assert.Equal(t, "loud", xScreamingBaby)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDocument_Components_Headers(t *testing.T) {
|
func TestNewDocument_Components_Headers(t *testing.T) {
|
||||||
@@ -319,8 +353,12 @@ func TestNewDocument_Components_Parameters(t *testing.T) {
|
|||||||
assert.Equal(t, "burgerHeader", bh.Name)
|
assert.Equal(t, "burgerHeader", bh.Name)
|
||||||
assert.Equal(t, 392, bh.GoLow().Name.KeyNode.Line)
|
assert.Equal(t, 392, bh.GoLow().Name.KeyNode.Line)
|
||||||
assert.Equal(t, 2, orderedmap.Len(bh.Schema.Schema().Properties))
|
assert.Equal(t, 2, orderedmap.Len(bh.Schema.Schema().Properties))
|
||||||
assert.Equal(t, "big-mac", bh.Example)
|
|
||||||
assert.True(t, bh.Required)
|
var example string
|
||||||
|
_ = bh.Example.Decode(&example)
|
||||||
|
|
||||||
|
assert.Equal(t, "big-mac", example)
|
||||||
|
assert.True(t, *bh.Required)
|
||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
"this is a header",
|
"this is a header",
|
||||||
@@ -341,8 +379,12 @@ func TestNewDocument_Paths(t *testing.T) {
|
|||||||
func testBurgerShop(t *testing.T, h *Document, checkLines bool) {
|
func testBurgerShop(t *testing.T, h *Document, checkLines bool) {
|
||||||
burgersOp := h.Paths.PathItems.GetOrZero("/burgers")
|
burgersOp := h.Paths.PathItems.GetOrZero("/burgers")
|
||||||
|
|
||||||
assert.Len(t, burgersOp.GetOperations(), 1)
|
assert.Equal(t, 1, burgersOp.GetOperations().Len())
|
||||||
assert.Equal(t, "meaty", burgersOp.Extensions["x-burger-meta"])
|
|
||||||
|
var xBurgerMeta string
|
||||||
|
_ = burgersOp.Extensions.GetOrZero("x-burger-meta").Decode(&xBurgerMeta)
|
||||||
|
|
||||||
|
assert.Equal(t, "meaty", xBurgerMeta)
|
||||||
assert.Nil(t, burgersOp.Get)
|
assert.Nil(t, burgersOp.Get)
|
||||||
assert.Nil(t, burgersOp.Put)
|
assert.Nil(t, burgersOp.Put)
|
||||||
assert.Nil(t, burgersOp.Patch)
|
assert.Nil(t, burgersOp.Patch)
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import (
|
|||||||
// Encoding represents an OpenAPI 3+ Encoding object
|
// Encoding represents an OpenAPI 3+ Encoding object
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#encoding-object
|
// - https://spec.openapis.org/oas/v3.1.0#encoding-object
|
||||||
type Encoding struct {
|
type Encoding struct {
|
||||||
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
|
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
|
||||||
Headers orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
Headers *orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||||
low *low.Encoding
|
low *low.Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,9 @@ func NewEncoding(encoding *low.Encoding) *Encoding {
|
|||||||
e.low = encoding
|
e.low = encoding
|
||||||
e.ContentType = encoding.ContentType.Value
|
e.ContentType = encoding.ContentType.Value
|
||||||
e.Style = encoding.Style.Value
|
e.Style = encoding.Style.Value
|
||||||
e.Explode = &encoding.Explode.Value
|
if !encoding.Explode.IsEmpty() {
|
||||||
|
e.Explode = &encoding.Explode.Value
|
||||||
|
}
|
||||||
e.AllowReserved = encoding.AllowReserved.Value
|
e.AllowReserved = encoding.AllowReserved.Value
|
||||||
e.Headers = ExtractHeaders(encoding.Headers.Value)
|
e.Headers = ExtractHeaders(encoding.Headers.Value)
|
||||||
return e
|
return e
|
||||||
@@ -56,7 +58,7 @@ func (e *Encoding) MarshalYAML() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExtractEncoding converts hard to navigate low-level plumbing Encoding definitions, into a high-level simple map
|
// 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] {
|
func ExtractEncoding(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Encoding]]) *orderedmap.Map[string, *Encoding] {
|
||||||
extracted := orderedmap.New[string, *Encoding]()
|
extracted := orderedmap.New[string, *Encoding]()
|
||||||
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
||||||
extracted.Set(pair.Key().Value, NewEncoding(pair.Value().Value))
|
extracted.Set(pair.Key().Value, NewEncoding(pair.Value().Value))
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ import (
|
|||||||
// Header represents a high-level OpenAPI 3+ Header object that is backed by a low-level one.
|
// Header represents a high-level OpenAPI 3+ Header object that is backed by a low-level one.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#header-object
|
// - https://spec.openapis.org/oas/v3.1.0#header-object
|
||||||
type Header struct {
|
type Header struct {
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||||
Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
Explode bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||||
Schema *highbase.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
Schema *highbase.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
Example *yaml.Node `json:"example,omitempty" yaml:"example,omitempty"`
|
||||||
Examples orderedmap.Map[string, *highbase.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
Examples *orderedmap.Map[string, *highbase.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
Content orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Header
|
low *low.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ func NewHeader(header *low.Header) *Header {
|
|||||||
h.Content = ExtractContent(header.Content.Value)
|
h.Content = ExtractContent(header.Content.Value)
|
||||||
h.Example = header.Example.Value
|
h.Example = header.Example.Value
|
||||||
h.Examples = highbase.ExtractExamples(header.Examples.Value)
|
h.Examples = highbase.ExtractExamples(header.Examples.Value)
|
||||||
|
h.Extensions = high.ExtractExtensions(header.Extensions)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ func (h *Header) GoLowUntyped() any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExtractHeaders will extract a hard to navigate low-level Header map, into simple high-level one.
|
// ExtractHeaders will extract a hard to navigate low-level Header map, into simple high-level one.
|
||||||
func ExtractHeaders(elements orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Header]]) orderedmap.Map[string, *Header] {
|
func ExtractHeaders(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.Header]]) *orderedmap.Map[string, *Header] {
|
||||||
extracted := orderedmap.New[string, *Header]()
|
extracted := orderedmap.New[string, *Header]()
|
||||||
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(elements); pair != nil; pair = pair.Next() {
|
||||||
extracted.Set(pair.Key().Value, NewHeader(pair.Value().Value))
|
extracted.Set(pair.Key().Value, NewHeader(pair.Value().Value))
|
||||||
|
|||||||
@@ -9,10 +9,14 @@ import (
|
|||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHeader_MarshalYAML(t *testing.T) {
|
func TestHeader_MarshalYAML(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
header := &Header{
|
header := &Header{
|
||||||
Description: "A header",
|
Description: "A header",
|
||||||
@@ -22,11 +26,11 @@ func TestHeader_MarshalYAML(t *testing.T) {
|
|||||||
Style: "simple",
|
Style: "simple",
|
||||||
Explode: true,
|
Explode: true,
|
||||||
AllowReserved: true,
|
AllowReserved: true,
|
||||||
Example: "example",
|
Example: utils.CreateStringNode("example"),
|
||||||
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
||||||
"example": {Value: "example"},
|
"example": {Value: utils.CreateStringNode("example")},
|
||||||
}),
|
}),
|
||||||
Extensions: map[string]interface{}{"x-burgers": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := header.Render()
|
rend, _ := header.Render()
|
||||||
@@ -45,5 +49,4 @@ examples:
|
|||||||
x-burgers: why not?`
|
x-burgers: why not?`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ import (
|
|||||||
// in an operation and using them as parameters while invoking the linked operation.
|
// in an operation and using them as parameters while invoking the linked operation.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#link-object
|
// - https://spec.openapis.org/oas/v3.1.0#link-object
|
||||||
type Link struct {
|
type Link struct {
|
||||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||||
OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||||
Parameters orderedmap.Map[string, string] `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
Parameters *orderedmap.Map[string, string] `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
RequestBody string `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
RequestBody string `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Link
|
low *low.Link
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
|
||||||
@@ -17,11 +18,11 @@ import (
|
|||||||
// Each Media Type Object provides schema and examples for the media type identified by its key.
|
// Each Media Type Object provides schema and examples for the media type identified by its key.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#media-type-object
|
// - https://spec.openapis.org/oas/v3.1.0#media-type-object
|
||||||
type MediaType struct {
|
type MediaType struct {
|
||||||
Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||||
Examples orderedmap.Map[string, *base.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
Examples *orderedmap.Map[string, *base.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
Encoding orderedmap.Map[string, *Encoding] `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
Encoding *orderedmap.Map[string, *Encoding] `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.MediaType
|
low *low.MediaType
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ func (m *MediaType) MarshalYAMLInline() (interface{}, error) {
|
|||||||
|
|
||||||
// ExtractContent takes in a complex and hard to navigate low-level content map, and converts it in to a much simpler
|
// ExtractContent takes in a complex and hard to navigate low-level content map, and converts it in to a much simpler
|
||||||
// and easier to navigate high-level one.
|
// and easier to navigate high-level one.
|
||||||
func ExtractContent(elements orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.MediaType]]) orderedmap.Map[string, *MediaType] {
|
func ExtractContent(elements *orderedmap.Map[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.MediaType]]) *orderedmap.Map[string, *MediaType] {
|
||||||
extracted := orderedmap.New[string, *MediaType]()
|
extracted := orderedmap.New[string, *MediaType]()
|
||||||
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.MediaType]]) (asyncResult[*MediaType], error) {
|
translateFunc := func(pair orderedmap.Pair[lowmodel.KeyReference[string], lowmodel.ValueReference[*low.MediaType]]) (asyncResult[*MediaType], error) {
|
||||||
return asyncResult[*MediaType]{
|
return asyncResult[*MediaType]{
|
||||||
@@ -85,6 +86,6 @@ func ExtractContent(elements orderedmap.Map[lowmodel.KeyReference[string], lowmo
|
|||||||
extracted.Set(value.key, value.result)
|
extracted.Set(value.key, value.result)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_ = orderedmap.TranslateMapParallel(elements, translateFunc, resultFunc)
|
_ = datamodel.TranslateMapParallel(elements, translateFunc, resultFunc)
|
||||||
return extracted
|
return extracted
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ func TestMediaType_MarshalYAMLInline(t *testing.T) {
|
|||||||
yml, _ := mt.Render()
|
yml, _ := mt.Render()
|
||||||
|
|
||||||
// the rendered output should be a ref to the media type.
|
// the rendered output should be a ref to the media type.
|
||||||
op := `schema:
|
op := `schema: {"$ref": "#/components/schemas/Pet"}`
|
||||||
$ref: '#/components/schemas/Pet'`
|
|
||||||
|
|
||||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||||
|
|
||||||
@@ -45,30 +44,30 @@ func TestMediaType_MarshalYAMLInline(t *testing.T) {
|
|||||||
|
|
||||||
op = `schema:
|
op = `schema:
|
||||||
required:
|
required:
|
||||||
- name
|
- "name"
|
||||||
- photoUrls
|
- "photoUrls"
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
id:
|
"id":
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
example: 10
|
example: 10
|
||||||
name:
|
"name":
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "doggie"
|
example: "doggie"
|
||||||
category:
|
"category":
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
id:
|
"id":
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
example: 1
|
example: 1
|
||||||
name:
|
"name":
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "Dogs"
|
example: "Dogs"
|
||||||
xml:
|
xml:
|
||||||
name: "category"
|
name: "category"
|
||||||
photoUrls:
|
"photoUrls":
|
||||||
type: "array"
|
type: "array"
|
||||||
xml:
|
xml:
|
||||||
wrapped: true
|
wrapped: true
|
||||||
@@ -76,27 +75,27 @@ func TestMediaType_MarshalYAMLInline(t *testing.T) {
|
|||||||
type: "string"
|
type: "string"
|
||||||
xml:
|
xml:
|
||||||
name: "photoUrl"
|
name: "photoUrl"
|
||||||
tags:
|
"tags":
|
||||||
type: "array"
|
type: "array"
|
||||||
xml:
|
xml:
|
||||||
wrapped: true
|
wrapped: true
|
||||||
items:
|
items:
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
id:
|
"id":
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
name:
|
"name":
|
||||||
type: "string"
|
type: "string"
|
||||||
xml:
|
xml:
|
||||||
name: "tag"
|
name: "tag"
|
||||||
status:
|
"status":
|
||||||
type: "string"
|
type: "string"
|
||||||
description: "pet status in the store"
|
description: "pet status in the store"
|
||||||
enum:
|
enum:
|
||||||
- available
|
- "available"
|
||||||
- pending
|
- "pending"
|
||||||
- sold
|
- "sold"
|
||||||
xml:
|
xml:
|
||||||
name: "pet"
|
name: "pet"
|
||||||
example: testing a nice mutation`
|
example: testing a nice mutation`
|
||||||
@@ -104,7 +103,6 @@ example: testing a nice mutation`
|
|||||||
yml, _ = mt.RenderInline()
|
yml, _ = mt.RenderInline()
|
||||||
|
|
||||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaType_MarshalYAML(t *testing.T) {
|
func TestMediaType_MarshalYAML(t *testing.T) {
|
||||||
@@ -125,22 +123,19 @@ func TestMediaType_MarshalYAML(t *testing.T) {
|
|||||||
yml, _ := mt.Render()
|
yml, _ := mt.Render()
|
||||||
|
|
||||||
// the rendered output should be a ref to the media type.
|
// the rendered output should be a ref to the media type.
|
||||||
op := `schema:
|
op := `schema: {"$ref": "#/components/schemas/Pet"}`
|
||||||
$ref: '#/components/schemas/Pet'`
|
|
||||||
|
|
||||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||||
|
|
||||||
// modify the media type to have an example
|
// modify the media type to have an example
|
||||||
mt.Example = "testing a nice mutation"
|
mt.Example = "testing a nice mutation"
|
||||||
|
|
||||||
op = `schema:
|
op = `schema: {"$ref": "#/components/schemas/Pet"}
|
||||||
$ref: '#/components/schemas/Pet'
|
|
||||||
example: testing a nice mutation`
|
example: testing a nice mutation`
|
||||||
|
|
||||||
yml, _ = mt.Render()
|
yml, _ = mt.Render()
|
||||||
|
|
||||||
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
assert.Equal(t, op, strings.TrimSpace(string(yml)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMediaType_Examples(t *testing.T) {
|
func TestMediaType_Examples(t *testing.T) {
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import (
|
|||||||
// OAuthFlow represents a high-level OpenAPI 3+ OAuthFlow object that is backed by a low-level one.
|
// OAuthFlow represents a high-level OpenAPI 3+ OAuthFlow object that is backed by a low-level one.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#oauth-flow-object
|
// - https://spec.openapis.org/oas/v3.1.0#oauth-flow-object
|
||||||
type OAuthFlow struct {
|
type OAuthFlow struct {
|
||||||
AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
AuthorizationUrl string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||||
TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
TokenUrl string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||||
RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
RefreshUrl string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||||
Scopes orderedmap.Map[string, string] `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
Scopes *orderedmap.Map[string, string] `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.OAuthFlow
|
low *low.OAuthFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func NewOAuthFlow(flow *low.OAuthFlow) *OAuthFlow {
|
|||||||
o.AuthorizationUrl = flow.AuthorizationUrl.Value
|
o.AuthorizationUrl = flow.AuthorizationUrl.Value
|
||||||
o.RefreshUrl = flow.RefreshUrl.Value
|
o.RefreshUrl = flow.RefreshUrl.Value
|
||||||
scopes := orderedmap.New[string, string]()
|
scopes := orderedmap.New[string, string]()
|
||||||
for pair := flow.Scopes.Value.First(); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(flow.Scopes.Value); pair != nil; pair = pair.Next() {
|
||||||
scopes.Set(pair.Key().Value, pair.Value().Value)
|
scopes.Set(pair.Key().Value, pair.Value().Value)
|
||||||
}
|
}
|
||||||
o.Scopes = scopes
|
o.Scopes = scopes
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOAuthFlow_MarshalYAML(t *testing.T) {
|
func TestOAuthFlow_MarshalYAML(t *testing.T) {
|
||||||
@@ -37,7 +39,9 @@ scopes:
|
|||||||
|
|
||||||
// mutate
|
// mutate
|
||||||
oflow.Scopes = nil
|
oflow.Scopes = nil
|
||||||
oflow.Extensions = map[string]interface{}{"x-burgers": "why not?"}
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("why not?"))
|
||||||
|
oflow.Extensions = ext
|
||||||
|
|
||||||
desired = `authorizationUrl: https://pb33f.io
|
desired = `authorizationUrl: https://pb33f.io
|
||||||
tokenUrl: https://pb33f.io/token
|
tokenUrl: https://pb33f.io/token
|
||||||
|
|||||||
@@ -6,17 +6,18 @@ package v3
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OAuthFlows represents a high-level OpenAPI 3+ OAuthFlows object that is backed by a low-level one.
|
// OAuthFlows represents a high-level OpenAPI 3+ OAuthFlows object that is backed by a low-level one.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#oauth-flows-object
|
// - https://spec.openapis.org/oas/v3.1.0#oauth-flows-object
|
||||||
type OAuthFlows struct {
|
type OAuthFlows struct {
|
||||||
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||||
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
||||||
ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
ClientCredentials *OAuthFlow `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||||
AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"`
|
AuthorizationCode *OAuthFlow `json:"authorizationCode,omitempty" yaml:"authorizationCode,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.OAuthFlows
|
low *low.OAuthFlows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,19 +17,19 @@ import (
|
|||||||
// happens here. The entire being for existence of this library and the specification, is this Operation.
|
// happens here. The entire being for existence of this library and the specification, is this Operation.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#operation-object
|
// - https://spec.openapis.org/oas/v3.1.0#operation-object
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *base.ExternalDoc `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||||
Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
RequestBody *RequestBody `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
RequestBody *RequestBody `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||||
Responses *Responses `json:"responses,omitempty" yaml:"responses,omitempty"`
|
Responses *Responses `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||||
Callbacks orderedmap.Map[string, *Callback] `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
Callbacks *orderedmap.Map[string, *Callback] `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||||
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
Deprecated *bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||||
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
|
Security []*base.SecurityRequirement `json:"security,omitempty" yaml:"security,omitempty"`
|
||||||
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
|
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Operation
|
low *low.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,9 @@ func NewOperation(operation *low.Operation) *Operation {
|
|||||||
}
|
}
|
||||||
o.Tags = tags
|
o.Tags = tags
|
||||||
o.Summary = operation.Summary.Value
|
o.Summary = operation.Summary.Value
|
||||||
o.Deprecated = &operation.Deprecated.Value
|
if !operation.Deprecated.IsEmpty() {
|
||||||
|
o.Deprecated = &operation.Deprecated.Value
|
||||||
|
}
|
||||||
o.Description = operation.Description.Value
|
o.Description = operation.Description.Value
|
||||||
if !operation.ExternalDocs.IsEmpty() {
|
if !operation.ExternalDocs.IsEmpty() {
|
||||||
o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value)
|
o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value)
|
||||||
|
|||||||
@@ -50,13 +50,13 @@ callbacks:
|
|||||||
|
|
||||||
assert.Equal(t, "https://pb33f.io", r.ExternalDocs.URL)
|
assert.Equal(t, "https://pb33f.io", r.ExternalDocs.URL)
|
||||||
assert.Equal(t, 1, r.GoLow().ExternalDocs.KeyNode.Line)
|
assert.Equal(t, 1, r.GoLow().ExternalDocs.KeyNode.Line)
|
||||||
assert.Contains(t, r.Callbacks, "testCallback")
|
|
||||||
assert.Contains(t, r.Callbacks.GetOrZero("testCallback").Expression, "{$request.body#/callbackUrl}")
|
assert.NotNil(t, r.Callbacks.GetOrZero("testCallback"))
|
||||||
|
assert.NotNil(t, r.Callbacks.GetOrZero("testCallback").Expression.GetOrZero("{$request.body#/callbackUrl}"))
|
||||||
assert.Equal(t, 3, r.GoLow().Callbacks.KeyNode.Line)
|
assert.Equal(t, 3, r.GoLow().Callbacks.KeyNode.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_MarshalYAML(t *testing.T) {
|
func TestOperation_MarshalYAML(t *testing.T) {
|
||||||
|
|
||||||
op := &Operation{
|
op := &Operation{
|
||||||
Tags: []string{"test"},
|
Tags: []string{"test"},
|
||||||
Summary: "nice",
|
Summary: "nice",
|
||||||
@@ -90,11 +90,9 @@ requestBody:
|
|||||||
description: dice`
|
description: dice`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_MarshalYAMLInline(t *testing.T) {
|
func TestOperation_MarshalYAMLInline(t *testing.T) {
|
||||||
|
|
||||||
op := &Operation{
|
op := &Operation{
|
||||||
Tags: []string{"test"},
|
Tags: []string{"test"},
|
||||||
Summary: "nice",
|
Summary: "nice",
|
||||||
@@ -128,7 +126,6 @@ requestBody:
|
|||||||
description: dice`
|
description: dice`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_EmptySecurity(t *testing.T) {
|
func TestOperation_EmptySecurity(t *testing.T) {
|
||||||
@@ -147,7 +144,6 @@ security: []`
|
|||||||
|
|
||||||
assert.NotNil(t, r.Security)
|
assert.NotNil(t, r.Security)
|
||||||
assert.Len(t, r.Security, 0)
|
assert.Len(t, r.Security, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_NoSecurity(t *testing.T) {
|
func TestOperation_NoSecurity(t *testing.T) {
|
||||||
@@ -164,5 +160,4 @@ func TestOperation_NoSecurity(t *testing.T) {
|
|||||||
r := NewOperation(&n)
|
r := NewOperation(&n)
|
||||||
|
|
||||||
assert.Nil(t, r.Security)
|
assert.Nil(t, r.Security)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,20 +16,20 @@ import (
|
|||||||
// A unique parameter is defined by a combination of a name and location.
|
// A unique parameter is defined by a combination of a name and location.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#parameter-object
|
// - https://spec.openapis.org/oas/v3.1.0#parameter-object
|
||||||
type Parameter struct {
|
type Parameter struct {
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
Required *bool `json:"required,renderZero,omitempty" yaml:"required,renderZero,omitempty"`
|
||||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
Explode *bool `json:"explode,renderZero,omitempty" yaml:"explode,renderZero,omitempty"`
|
||||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||||
Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
Schema *base.SchemaProxy `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
Example *yaml.Node `json:"example,omitempty" yaml:"example,omitempty"`
|
||||||
Examples orderedmap.Map[string, *base.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
Examples *orderedmap.Map[string, *base.Example] `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
Content orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Parameter
|
low *low.Parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,9 @@ func NewParameter(param *low.Parameter) *Parameter {
|
|||||||
if !param.Schema.IsEmpty() {
|
if !param.Schema.IsEmpty() {
|
||||||
p.Schema = base.NewSchemaProxy(¶m.Schema)
|
p.Schema = base.NewSchemaProxy(¶m.Schema)
|
||||||
}
|
}
|
||||||
p.Required = param.Required.Value
|
if !param.Required.IsEmpty() {
|
||||||
|
p.Required = ¶m.Required.Value
|
||||||
|
}
|
||||||
p.Example = param.Example.Value
|
p.Example = param.Example.Value
|
||||||
p.Examples = base.ExtractExamples(param.Examples.Value)
|
p.Examples = base.ExtractExamples(param.Examples.Value)
|
||||||
p.Content = ExtractContent(param.Content.Value)
|
p.Content = ExtractContent(param.Content.Value)
|
||||||
|
|||||||
@@ -9,10 +9,14 @@ import (
|
|||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high/base"
|
"github.com/pb33f/libopenapi/datamodel/high/base"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParameter_MarshalYAML(t *testing.T) {
|
func TestParameter_MarshalYAML(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
explode := true
|
explode := true
|
||||||
param := Parameter{
|
param := Parameter{
|
||||||
@@ -23,11 +27,11 @@ func TestParameter_MarshalYAML(t *testing.T) {
|
|||||||
Style: "simple",
|
Style: "simple",
|
||||||
Explode: &explode,
|
Explode: &explode,
|
||||||
AllowReserved: true,
|
AllowReserved: true,
|
||||||
Example: "example",
|
Example: utils.CreateStringNode("example"),
|
||||||
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
||||||
"example": {Value: "example"},
|
"example": {Value: utils.CreateStringNode("example")},
|
||||||
}),
|
}),
|
||||||
Extensions: map[string]interface{}{"x-burgers": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := param.Render()
|
rend, _ := param.Render()
|
||||||
@@ -49,6 +53,8 @@ x-burgers: why not?`
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_MarshalYAMLInline(t *testing.T) {
|
func TestParameter_MarshalYAMLInline(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-burgers", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
explode := true
|
explode := true
|
||||||
param := Parameter{
|
param := Parameter{
|
||||||
@@ -59,11 +65,11 @@ func TestParameter_MarshalYAMLInline(t *testing.T) {
|
|||||||
Style: "simple",
|
Style: "simple",
|
||||||
Explode: &explode,
|
Explode: &explode,
|
||||||
AllowReserved: true,
|
AllowReserved: true,
|
||||||
Example: "example",
|
Example: utils.CreateStringNode("example"),
|
||||||
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
Examples: orderedmap.ToOrderedMap(map[string]*base.Example{
|
||||||
"example": {Value: "example"},
|
"example": {Value: utils.CreateStringNode("example")},
|
||||||
}),
|
}),
|
||||||
Extensions: map[string]interface{}{"x-burgers": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := param.RenderInline()
|
rend, _ := param.RenderInline()
|
||||||
@@ -85,7 +91,6 @@ x-burgers: why not?`
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_IsExploded(t *testing.T) {
|
func TestParameter_IsExploded(t *testing.T) {
|
||||||
|
|
||||||
explode := true
|
explode := true
|
||||||
param := Parameter{
|
param := Parameter{
|
||||||
Explode: &explode,
|
Explode: &explode,
|
||||||
@@ -106,7 +111,6 @@ func TestParameter_IsExploded(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_IsDefaultFormEncoding(t *testing.T) {
|
func TestParameter_IsDefaultFormEncoding(t *testing.T) {
|
||||||
|
|
||||||
param := Parameter{}
|
param := Parameter{}
|
||||||
assert.True(t, param.IsDefaultFormEncoding())
|
assert.True(t, param.IsDefaultFormEncoding())
|
||||||
|
|
||||||
@@ -133,7 +137,6 @@ func TestParameter_IsDefaultFormEncoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_IsDefaultHeaderEncoding(t *testing.T) {
|
func TestParameter_IsDefaultHeaderEncoding(t *testing.T) {
|
||||||
|
|
||||||
param := Parameter{}
|
param := Parameter{}
|
||||||
assert.True(t, param.IsDefaultHeaderEncoding())
|
assert.True(t, param.IsDefaultHeaderEncoding())
|
||||||
|
|
||||||
@@ -163,8 +166,6 @@ func TestParameter_IsDefaultHeaderEncoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_IsDefaultPathEncoding(t *testing.T) {
|
func TestParameter_IsDefaultPathEncoding(t *testing.T) {
|
||||||
|
|
||||||
param := Parameter{}
|
param := Parameter{}
|
||||||
assert.True(t, param.IsDefaultPathEncoding())
|
assert.True(t, param.IsDefaultPathEncoding())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,13 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"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"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,24 +32,24 @@ const (
|
|||||||
// are available.
|
// are available.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#path-item-object
|
// - https://spec.openapis.org/oas/v3.1.0#path-item-object
|
||||||
type PathItem struct {
|
type PathItem struct {
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||||
Get *Operation `json:"get,omitempty" yaml:"get,omitempty"`
|
Get *Operation `json:"get,omitempty" yaml:"get,omitempty"`
|
||||||
Put *Operation `json:"put,omitempty" yaml:"put,omitempty"`
|
Put *Operation `json:"put,omitempty" yaml:"put,omitempty"`
|
||||||
Post *Operation `json:"post,omitempty" yaml:"post,omitempty"`
|
Post *Operation `json:"post,omitempty" yaml:"post,omitempty"`
|
||||||
Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"`
|
Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"`
|
||||||
Options *Operation `json:"options,omitempty" yaml:"options,omitempty"`
|
Options *Operation `json:"options,omitempty" yaml:"options,omitempty"`
|
||||||
Head *Operation `json:"head,omitempty" yaml:"head,omitempty"`
|
Head *Operation `json:"head,omitempty" yaml:"head,omitempty"`
|
||||||
Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"`
|
Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
Trace *Operation `json:"trace,omitempty" yaml:"trace,omitempty"`
|
Trace *Operation `json:"trace,omitempty" yaml:"trace,omitempty"`
|
||||||
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
|
Servers []*Server `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||||
Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
Parameters []*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.PathItem
|
low *lowV3.PathItem
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPathItem creates a new high-level PathItem instance from a low-level one.
|
// NewPathItem creates a new high-level PathItem instance from a low-level one.
|
||||||
func NewPathItem(pathItem *low.PathItem) *PathItem {
|
func NewPathItem(pathItem *lowV3.PathItem) *PathItem {
|
||||||
pi := new(PathItem)
|
pi := new(PathItem)
|
||||||
pi.low = pathItem
|
pi.low = pathItem
|
||||||
pi.Description = pathItem.Description.Value
|
pi.Description = pathItem.Description.Value
|
||||||
@@ -62,7 +67,7 @@ func NewPathItem(pathItem *low.PathItem) *PathItem {
|
|||||||
op *Operation
|
op *Operation
|
||||||
}
|
}
|
||||||
opChan := make(chan opResult)
|
opChan := make(chan opResult)
|
||||||
var buildOperation = func(method int, op *low.Operation, c chan opResult) {
|
buildOperation := func(method int, op *lowV3.Operation, c chan opResult) {
|
||||||
if op == nil {
|
if op == nil {
|
||||||
c <- opResult{method: method, op: nil}
|
c <- opResult{method: method, op: nil}
|
||||||
return
|
return
|
||||||
@@ -120,7 +125,7 @@ func NewPathItem(pathItem *low.PathItem) *PathItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GoLow returns the low level instance of PathItem, used to build the high-level one.
|
// GoLow returns the low level instance of PathItem, used to build the high-level one.
|
||||||
func (p *PathItem) GoLow() *low.PathItem {
|
func (p *PathItem) GoLow() *lowV3.PathItem {
|
||||||
return p.low
|
return p.low
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,32 +134,65 @@ func (p *PathItem) GoLowUntyped() any {
|
|||||||
return p.low
|
return p.low
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PathItem) GetOperations() map[string]*Operation {
|
func (p *PathItem) GetOperations() *orderedmap.Map[string, *Operation] {
|
||||||
o := make(map[string]*Operation)
|
o := orderedmap.New[string, *Operation]()
|
||||||
|
|
||||||
|
// TODO: this is a bit of a hack, but it works for now. We might just want to actually pull the data out of the document as a map and split it into the individual operations
|
||||||
|
|
||||||
|
type op struct {
|
||||||
|
name string
|
||||||
|
op *Operation
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
getLine := func(field string, idx int) int {
|
||||||
|
if p.GoLow() == nil {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
l, ok := reflect.ValueOf(p.GoLow()).Elem().FieldByName(field).Interface().(low.NodeReference[*lowV3.Operation])
|
||||||
|
if !ok || l.GetKeyNode() == nil {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.GetKeyNode().Line
|
||||||
|
}
|
||||||
|
|
||||||
|
ops := []op{}
|
||||||
|
|
||||||
if p.Get != nil {
|
if p.Get != nil {
|
||||||
o[low.GetLabel] = p.Get
|
ops = append(ops, op{name: lowV3.GetLabel, op: p.Get, line: getLine("Get", -8)})
|
||||||
}
|
}
|
||||||
if p.Put != nil {
|
if p.Put != nil {
|
||||||
o[low.PutLabel] = p.Put
|
ops = append(ops, op{name: lowV3.PutLabel, op: p.Put, line: getLine("Put", -7)})
|
||||||
}
|
}
|
||||||
if p.Post != nil {
|
if p.Post != nil {
|
||||||
o[low.PostLabel] = p.Post
|
ops = append(ops, op{name: lowV3.PostLabel, op: p.Post, line: getLine("Post", -6)})
|
||||||
}
|
}
|
||||||
if p.Delete != nil {
|
if p.Delete != nil {
|
||||||
o[low.DeleteLabel] = p.Delete
|
ops = append(ops, op{name: lowV3.DeleteLabel, op: p.Delete, line: getLine("Delete", -5)})
|
||||||
}
|
}
|
||||||
if p.Options != nil {
|
if p.Options != nil {
|
||||||
o[low.OptionsLabel] = p.Options
|
ops = append(ops, op{name: lowV3.OptionsLabel, op: p.Options, line: getLine("Options", -4)})
|
||||||
}
|
}
|
||||||
if p.Head != nil {
|
if p.Head != nil {
|
||||||
o[low.HeadLabel] = p.Head
|
ops = append(ops, op{name: lowV3.HeadLabel, op: p.Head, line: getLine("Head", -3)})
|
||||||
}
|
}
|
||||||
if p.Patch != nil {
|
if p.Patch != nil {
|
||||||
o[low.PatchLabel] = p.Patch
|
ops = append(ops, op{name: lowV3.PatchLabel, op: p.Patch, line: getLine("Patch", -2)})
|
||||||
}
|
}
|
||||||
if p.Trace != nil {
|
if p.Trace != nil {
|
||||||
o[low.TraceLabel] = p.Trace
|
ops = append(ops, op{name: lowV3.TraceLabel, op: p.Trace, line: getLine("Trace", -1)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slices.SortStableFunc(ops, func(a op, b op) int {
|
||||||
|
return a.line - b.line
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, op := range ops {
|
||||||
|
o.Set(op.name, op.op)
|
||||||
|
}
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,19 @@ trace:
|
|||||||
|
|
||||||
r := NewPathItem(&n)
|
r := NewPathItem(&n)
|
||||||
|
|
||||||
assert.Len(t, r.GetOperations(), 8)
|
assert.Equal(t, 8, r.GetOperations().Len())
|
||||||
|
|
||||||
|
// test that the operations are in the correct order
|
||||||
|
expectedOrder := []string{"get", "put", "post", "patch", "delete", "head", "options", "trace"}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for pair := r.GetOperations().First(); pair != nil; pair = pair.Next() {
|
||||||
|
assert.Equal(t, expectedOrder[i], pair.Value().Description)
|
||||||
|
i++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathItem_MarshalYAML(t *testing.T) {
|
func TestPathItem_MarshalYAML(t *testing.T) {
|
||||||
|
|
||||||
pi := &PathItem{
|
pi := &PathItem{
|
||||||
Description: "a path item",
|
Description: "a path item",
|
||||||
Summary: "It's a test, don't worry about it, Jim",
|
Summary: "It's a test, don't worry about it, Jim",
|
||||||
@@ -112,7 +120,6 @@ parameters:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPathItem_MarshalYAMLInline(t *testing.T) {
|
func TestPathItem_MarshalYAMLInline(t *testing.T) {
|
||||||
|
|
||||||
pi := &PathItem{
|
pi := &PathItem{
|
||||||
Description: "a path item",
|
Description: "a path item",
|
||||||
Summary: "It's a test, don't worry about it, Jim",
|
Summary: "It's a test, don't worry about it, Jim",
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
// constraints.
|
// constraints.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#paths-object
|
// - https://spec.openapis.org/oas/v3.1.0#paths-object
|
||||||
type Paths struct {
|
type Paths struct {
|
||||||
PathItems orderedmap.Map[string, *PathItem] `json:"-" yaml:"-"`
|
PathItems *orderedmap.Map[string, *PathItem] `json:"-" yaml:"-"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *v3low.Paths
|
low *v3low.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +81,7 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
|
|||||||
pi *PathItem
|
pi *PathItem
|
||||||
path string
|
path string
|
||||||
line int
|
line int
|
||||||
|
style yaml.Style
|
||||||
rendered *yaml.Node
|
rendered *yaml.Node
|
||||||
}
|
}
|
||||||
var mapped []*pathItem
|
var mapped []*pathItem
|
||||||
@@ -89,13 +90,21 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
|
|||||||
k := pair.Key()
|
k := pair.Key()
|
||||||
pi := pair.Value()
|
pi := pair.Value()
|
||||||
ln := 9999 // default to a high value to weight new content to the bottom.
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
if p.low != nil {
|
if p.low != nil {
|
||||||
lpi := p.low.FindPath(k)
|
lpi := p.low.FindPath(k)
|
||||||
if lpi != nil {
|
if lpi != nil {
|
||||||
ln = lpi.ValueNode.Line
|
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
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &pathItem{pi, k, ln, nil})
|
mapped = append(mapped, &pathItem{pi, k, ln, style, nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := high.NewNodeBuilder(p, p.low)
|
nb := high.NewNodeBuilder(p, p.low)
|
||||||
@@ -107,23 +116,29 @@ func (p *Paths) MarshalYAML() (interface{}, error) {
|
|||||||
label = extNode.Content[u].Value
|
label = extNode.Content[u].Value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &pathItem{nil, label,
|
mapped = append(mapped, &pathItem{
|
||||||
extNode.Content[u].Line, extNode.Content[u]})
|
nil, label,
|
||||||
|
extNode.Content[u].Line, 0, extNode.Content[u],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(mapped, func(i, j int) bool {
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
return mapped[i].line < mapped[j].line
|
return mapped[i].line < mapped[j].line
|
||||||
})
|
})
|
||||||
for j := range mapped {
|
for _, mp := range mapped {
|
||||||
if mapped[j].pi != nil {
|
if mp.pi != nil {
|
||||||
rendered, _ := mapped[j].pi.MarshalYAML()
|
rendered, _ := mp.pi.MarshalYAML()
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path))
|
|
||||||
|
kn := utils.CreateStringNode(mp.path)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
m.Content = append(m.Content, rendered.(*yaml.Node))
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
}
|
}
|
||||||
if mapped[j].rendered != nil {
|
if mp.rendered != nil {
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path))
|
m.Content = append(m.Content, utils.CreateStringNode(mp.path))
|
||||||
m.Content = append(m.Content, mapped[j].rendered)
|
m.Content = append(m.Content, mp.rendered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +152,7 @@ func (p *Paths) MarshalYAMLInline() (interface{}, error) {
|
|||||||
pi *PathItem
|
pi *PathItem
|
||||||
path string
|
path string
|
||||||
line int
|
line int
|
||||||
|
style yaml.Style
|
||||||
rendered *yaml.Node
|
rendered *yaml.Node
|
||||||
}
|
}
|
||||||
var mapped []*pathItem
|
var mapped []*pathItem
|
||||||
@@ -145,13 +161,21 @@ func (p *Paths) MarshalYAMLInline() (interface{}, error) {
|
|||||||
k := pair.Key()
|
k := pair.Key()
|
||||||
pi := pair.Value()
|
pi := pair.Value()
|
||||||
ln := 9999 // default to a high value to weight new content to the bottom.
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
if p.low != nil {
|
if p.low != nil {
|
||||||
lpi := p.low.FindPath(k)
|
lpi := p.low.FindPath(k)
|
||||||
if lpi != nil {
|
if lpi != nil {
|
||||||
ln = lpi.ValueNode.Line
|
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
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &pathItem{pi, k, ln, nil})
|
mapped = append(mapped, &pathItem{pi, k, ln, style, nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
nb := high.NewNodeBuilder(p, p.low)
|
nb := high.NewNodeBuilder(p, p.low)
|
||||||
@@ -164,23 +188,29 @@ func (p *Paths) MarshalYAMLInline() (interface{}, error) {
|
|||||||
label = extNode.Content[u].Value
|
label = extNode.Content[u].Value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &pathItem{nil, label,
|
mapped = append(mapped, &pathItem{
|
||||||
extNode.Content[u].Line, extNode.Content[u]})
|
nil, label,
|
||||||
|
extNode.Content[u].Line, 0, extNode.Content[u],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(mapped, func(i, j int) bool {
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
return mapped[i].line < mapped[j].line
|
return mapped[i].line < mapped[j].line
|
||||||
})
|
})
|
||||||
for j := range mapped {
|
for _, mp := range mapped {
|
||||||
if mapped[j].pi != nil {
|
if mp.pi != nil {
|
||||||
rendered, _ := mapped[j].pi.MarshalYAMLInline()
|
rendered, _ := mp.pi.MarshalYAMLInline()
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path))
|
|
||||||
|
kn := utils.CreateStringNode(mp.path)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
m.Content = append(m.Content, rendered.(*yaml.Node))
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
}
|
}
|
||||||
if mapped[j].rendered != nil {
|
if mp.rendered != nil {
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].path))
|
m.Content = append(m.Content, utils.CreateStringNode(mp.path))
|
||||||
m.Content = append(m.Content, mapped[j].rendered)
|
m.Content = append(m.Content, mp.rendered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
// RequestBody represents a high-level OpenAPI 3+ RequestBody object, backed by a low-level one.
|
// RequestBody represents a high-level OpenAPI 3+ RequestBody object, backed by a low-level one.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#request-body-object
|
// - https://spec.openapis.org/oas/v3.1.0#request-body-object
|
||||||
type RequestBody struct {
|
type RequestBody struct {
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Content orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
Required *bool `json:"required,omitempty" yaml:"required,renderZero,omitempty"`
|
Required *bool `json:"required,omitempty" yaml:"required,renderZero,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.RequestBody
|
low *low.RequestBody
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func NewRequestBody(rb *low.RequestBody) *RequestBody {
|
|||||||
r := new(RequestBody)
|
r := new(RequestBody)
|
||||||
r.low = rb
|
r.low = rb
|
||||||
r.Description = rb.Description.Value
|
r.Description = rb.Description.Value
|
||||||
if rb.Required.ValueNode != nil {
|
if !rb.Required.IsEmpty() {
|
||||||
r.Required = &rb.Required.Value
|
r.Required = &rb.Required.Value
|
||||||
}
|
}
|
||||||
r.Extensions = high.ExtractExtensions(rb.Extensions)
|
r.Extensions = high.ExtractExtensions(rb.Extensions)
|
||||||
|
|||||||
@@ -7,16 +7,21 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRequestBody_MarshalYAML(t *testing.T) {
|
func TestRequestBody_MarshalYAML(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-high-gravity", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
rb := true
|
rb := true
|
||||||
req := &RequestBody{
|
req := &RequestBody{
|
||||||
Description: "beer",
|
Description: "beer",
|
||||||
Required: &rb,
|
Required: &rb,
|
||||||
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := req.Render()
|
rend, _ := req.Render()
|
||||||
@@ -26,16 +31,17 @@ required: true
|
|||||||
x-high-gravity: why not?`
|
x-high-gravity: why not?`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRequestBody_MarshalYAMLInline(t *testing.T) {
|
func TestRequestBody_MarshalYAMLInline(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-high-gravity", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
rb := true
|
rb := true
|
||||||
req := &RequestBody{
|
req := &RequestBody{
|
||||||
Description: "beer",
|
Description: "beer",
|
||||||
Required: &rb,
|
Required: &rb,
|
||||||
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := req.RenderInline()
|
rend, _ := req.RenderInline()
|
||||||
@@ -45,15 +51,17 @@ required: true
|
|||||||
x-high-gravity: why not?`
|
x-high-gravity: why not?`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRequestBody_MarshalNoRequired(t *testing.T) {
|
func TestRequestBody_MarshalNoRequired(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-high-gravity", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
rb := false
|
rb := false
|
||||||
req := &RequestBody{
|
req := &RequestBody{
|
||||||
Description: "beer",
|
Description: "beer",
|
||||||
Required: &rb,
|
Required: &rb,
|
||||||
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := req.Render()
|
rend, _ := req.Render()
|
||||||
@@ -63,14 +71,15 @@ required: false
|
|||||||
x-high-gravity: why not?`
|
x-high-gravity: why not?`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRequestBody_MarshalRequiredNil(t *testing.T) {
|
func TestRequestBody_MarshalRequiredNil(t *testing.T) {
|
||||||
|
ext := orderedmap.New[string, *yaml.Node]()
|
||||||
|
ext.Set("x-high-gravity", utils.CreateStringNode("why not?"))
|
||||||
|
|
||||||
req := &RequestBody{
|
req := &RequestBody{
|
||||||
Description: "beer",
|
Description: "beer",
|
||||||
Extensions: map[string]interface{}{"x-high-gravity": "why not?"},
|
Extensions: ext,
|
||||||
}
|
}
|
||||||
|
|
||||||
rend, _ := req.Render()
|
rend, _ := req.Render()
|
||||||
@@ -79,5 +88,4 @@ func TestRequestBody_MarshalRequiredNil(t *testing.T) {
|
|||||||
x-high-gravity: why not?`
|
x-high-gravity: why not?`
|
||||||
|
|
||||||
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
assert.Equal(t, desired, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import (
|
|||||||
// operations based on the response.
|
// operations based on the response.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#response-object
|
// - https://spec.openapis.org/oas/v3.1.0#response-object
|
||||||
type Response struct {
|
type Response struct {
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Headers orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
Headers *orderedmap.Map[string, *Header] `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||||
Content orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
Content *orderedmap.Map[string, *MediaType] `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
Links orderedmap.Map[string, *Link] `json:"links,omitempty" yaml:"links,omitempty"`
|
Links *orderedmap.Map[string, *Link] `json:"links,omitempty" yaml:"links,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Response
|
low *low.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import (
|
|||||||
// with hard coded line and column numbers in them, changing the spec above the bottom will
|
// with hard coded line and column numbers in them, changing the spec above the bottom will
|
||||||
// create pointless test changes. So here is a standalone test. you know... for science.
|
// create pointless test changes. So here is a standalone test. you know... for science.
|
||||||
func TestNewResponse(t *testing.T) {
|
func TestNewResponse(t *testing.T) {
|
||||||
|
|
||||||
yml := `description: this is a response
|
yml := `description: this is a response
|
||||||
headers:
|
headers:
|
||||||
someHeader:
|
someHeader:
|
||||||
@@ -46,14 +45,16 @@ links:
|
|||||||
|
|
||||||
assert.Equal(t, 1, orderedmap.Len(r.Headers))
|
assert.Equal(t, 1, orderedmap.Len(r.Headers))
|
||||||
assert.Equal(t, 1, orderedmap.Len(r.Content))
|
assert.Equal(t, 1, orderedmap.Len(r.Content))
|
||||||
assert.Equal(t, "pizza!", r.Extensions["x-pizza-man"])
|
|
||||||
|
var xPizzaMan string
|
||||||
|
_ = r.Extensions.GetOrZero("x-pizza-man").Decode(&xPizzaMan)
|
||||||
|
|
||||||
|
assert.Equal(t, "pizza!", xPizzaMan)
|
||||||
assert.Equal(t, 1, orderedmap.Len(r.Links))
|
assert.Equal(t, 1, orderedmap.Len(r.Links))
|
||||||
assert.Equal(t, 1, r.GoLow().Description.KeyNode.Line)
|
assert.Equal(t, 1, r.GoLow().Description.KeyNode.Line)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResponse_MarshalYAML(t *testing.T) {
|
func TestResponse_MarshalYAML(t *testing.T) {
|
||||||
|
|
||||||
yml := `description: this is a response
|
yml := `description: this is a response
|
||||||
headers:
|
headers:
|
||||||
someHeader:
|
someHeader:
|
||||||
@@ -77,11 +78,9 @@ links:
|
|||||||
|
|
||||||
rend, _ := r.Render()
|
rend, _ := r.Render()
|
||||||
assert.Equal(t, yml, strings.TrimSpace(string(rend)))
|
assert.Equal(t, yml, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResponse_MarshalYAMLInline(t *testing.T) {
|
func TestResponse_MarshalYAMLInline(t *testing.T) {
|
||||||
|
|
||||||
yml := `description: this is a response
|
yml := `description: this is a response
|
||||||
headers:
|
headers:
|
||||||
someHeader:
|
someHeader:
|
||||||
@@ -105,5 +104,4 @@ links:
|
|||||||
|
|
||||||
rend, _ := r.RenderInline()
|
rend, _ := r.RenderInline()
|
||||||
assert.Equal(t, yml, strings.TrimSpace(string(rend)))
|
assert.Equal(t, yml, strings.TrimSpace(string(rend)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ import (
|
|||||||
// be the response for a successful operation call.
|
// be the response for a successful operation call.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#responses-object
|
// - https://spec.openapis.org/oas/v3.1.0#responses-object
|
||||||
type Responses struct {
|
type Responses struct {
|
||||||
Codes orderedmap.Map[string, *Response] `json:"-" yaml:"-"`
|
Codes *orderedmap.Map[string, *Response] `json:"-" yaml:"-"`
|
||||||
Default *Response `json:"default,omitempty" yaml:"default,omitempty"`
|
Default *Response `json:"default,omitempty" yaml:"default,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Responses
|
low *low.Responses
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,23 +93,26 @@ func (r *Responses) MarshalYAML() (interface{}, error) {
|
|||||||
// map keys correctly.
|
// map keys correctly.
|
||||||
m := utils.CreateEmptyMapNode()
|
m := utils.CreateEmptyMapNode()
|
||||||
type responseItem struct {
|
type responseItem struct {
|
||||||
resp *Response
|
resp *Response
|
||||||
code string
|
code string
|
||||||
line int
|
line int
|
||||||
ext *yaml.Node
|
ext *yaml.Node
|
||||||
|
style yaml.Style
|
||||||
}
|
}
|
||||||
var mapped []*responseItem
|
var mapped []*responseItem
|
||||||
|
|
||||||
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
|
||||||
ln := 9999 // default to a high value to weight new content to the bottom.
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
if r.low != nil {
|
if r.low != nil {
|
||||||
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
|
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
|
||||||
if lPair.Key().Value == pair.Key() {
|
if lPair.Key().Value == pair.Key() {
|
||||||
ln = lPair.Key().KeyNode.Line
|
ln = lPair.Key().KeyNode.Line
|
||||||
|
style = lPair.Key().KeyNode.Style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil})
|
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil, style})
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract extensions
|
// extract extensions
|
||||||
@@ -124,7 +127,7 @@ func (r *Responses) MarshalYAML() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
mapped = append(mapped, &responseItem{
|
mapped = append(mapped, &responseItem{
|
||||||
nil, label,
|
nil, label,
|
||||||
extNode.Content[u].Line, extNode.Content[u],
|
extNode.Content[u].Line, extNode.Content[u], 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,15 +135,19 @@ func (r *Responses) MarshalYAML() (interface{}, error) {
|
|||||||
sort.Slice(mapped, func(i, j int) bool {
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
return mapped[i].line < mapped[j].line
|
return mapped[i].line < mapped[j].line
|
||||||
})
|
})
|
||||||
for j := range mapped {
|
for _, mp := range mapped {
|
||||||
if mapped[j].resp != nil {
|
if mp.resp != nil {
|
||||||
rendered, _ := mapped[j].resp.MarshalYAML()
|
rendered, _ := mp.resp.MarshalYAML()
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code))
|
|
||||||
|
kn := utils.CreateStringNode(mp.code)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
m.Content = append(m.Content, rendered.(*yaml.Node))
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
}
|
}
|
||||||
if mapped[j].ext != nil {
|
if mp.ext != nil {
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code))
|
m.Content = append(m.Content, utils.CreateStringNode(mp.code))
|
||||||
m.Content = append(m.Content, mapped[j].ext)
|
m.Content = append(m.Content, mp.ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -151,23 +158,26 @@ func (r *Responses) MarshalYAMLInline() (interface{}, error) {
|
|||||||
// map keys correctly.
|
// map keys correctly.
|
||||||
m := utils.CreateEmptyMapNode()
|
m := utils.CreateEmptyMapNode()
|
||||||
type responseItem struct {
|
type responseItem struct {
|
||||||
resp *Response
|
resp *Response
|
||||||
code string
|
code string
|
||||||
line int
|
line int
|
||||||
ext *yaml.Node
|
ext *yaml.Node
|
||||||
|
style yaml.Style
|
||||||
}
|
}
|
||||||
var mapped []*responseItem
|
var mapped []*responseItem
|
||||||
|
|
||||||
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(r.Codes); pair != nil; pair = pair.Next() {
|
||||||
ln := 9999 // default to a high value to weight new content to the bottom.
|
ln := 9999 // default to a high value to weight new content to the bottom.
|
||||||
|
var style yaml.Style
|
||||||
if r.low != nil {
|
if r.low != nil {
|
||||||
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
|
for lPair := orderedmap.First(r.low.Codes); lPair != nil; lPair = lPair.Next() {
|
||||||
if lPair.Key().Value == pair.Key() {
|
if lPair.Key().Value == pair.Key() {
|
||||||
ln = lPair.Key().KeyNode.Line
|
ln = lPair.Key().KeyNode.Line
|
||||||
|
style = lPair.Key().KeyNode.Style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil})
|
mapped = append(mapped, &responseItem{pair.Value(), pair.Key(), ln, nil, style})
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract extensions
|
// extract extensions
|
||||||
@@ -183,7 +193,7 @@ func (r *Responses) MarshalYAMLInline() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
mapped = append(mapped, &responseItem{
|
mapped = append(mapped, &responseItem{
|
||||||
nil, label,
|
nil, label,
|
||||||
extNode.Content[u].Line, extNode.Content[u],
|
extNode.Content[u].Line, extNode.Content[u], 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,16 +201,20 @@ func (r *Responses) MarshalYAMLInline() (interface{}, error) {
|
|||||||
sort.Slice(mapped, func(i, j int) bool {
|
sort.Slice(mapped, func(i, j int) bool {
|
||||||
return mapped[i].line < mapped[j].line
|
return mapped[i].line < mapped[j].line
|
||||||
})
|
})
|
||||||
for j := range mapped {
|
for _, mp := range mapped {
|
||||||
if mapped[j].resp != nil {
|
if mp.resp != nil {
|
||||||
rendered, _ := mapped[j].resp.MarshalYAMLInline()
|
rendered, _ := mp.resp.MarshalYAMLInline()
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code))
|
|
||||||
|
kn := utils.CreateStringNode(mp.code)
|
||||||
|
kn.Style = mp.style
|
||||||
|
|
||||||
|
m.Content = append(m.Content, kn)
|
||||||
m.Content = append(m.Content, rendered.(*yaml.Node))
|
m.Content = append(m.Content, rendered.(*yaml.Node))
|
||||||
|
|
||||||
}
|
}
|
||||||
if mapped[j].ext != nil {
|
if mp.ext != nil {
|
||||||
m.Content = append(m.Content, utils.CreateStringNode(mapped[j].code))
|
m.Content = append(m.Content, utils.CreateStringNode(mp.code))
|
||||||
m.Content = append(m.Content, mapped[j].ext)
|
m.Content = append(m.Content, mp.ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package v3
|
|||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/high"
|
"github.com/pb33f/libopenapi/datamodel/high"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,15 +21,15 @@ import (
|
|||||||
// Recommended for most use case is Authorization Code Grant flow with PKCE.
|
// Recommended for most use case is Authorization Code Grant flow with PKCE.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#security-scheme-object
|
// - https://spec.openapis.org/oas/v3.1.0#security-scheme-object
|
||||||
type SecurityScheme struct {
|
type SecurityScheme struct {
|
||||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||||
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
|
Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
|
||||||
BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
|
BearerFormat string `json:"bearerFormat,omitempty" yaml:"bearerFormat,omitempty"`
|
||||||
Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
|
Flows *OAuthFlows `json:"flows,omitempty" yaml:"flows,omitempty"`
|
||||||
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"`
|
OpenIdConnectUrl string `json:"openIdConnectUrl,omitempty" yaml:"openIdConnectUrl,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.SecurityScheme
|
low *low.SecurityScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
// Server represents a high-level OpenAPI 3+ Server object, that is backed by a low level one.
|
// Server represents a high-level OpenAPI 3+ Server object, that is backed by a low level one.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#server-object
|
// - https://spec.openapis.org/oas/v3.1.0#server-object
|
||||||
type Server struct {
|
type Server struct {
|
||||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
Variables orderedmap.Map[string, *ServerVariable] `json:"variables,omitempty" yaml:"variables,omitempty"`
|
Variables *orderedmap.Map[string, *ServerVariable] `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||||
Extensions map[string]any `json:"-" yaml:"-"`
|
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
|
||||||
low *low.Server
|
low *low.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ import (
|
|||||||
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
|
// v3 - https://spec.openapis.org/oas/v3.1.0#discriminator-object
|
||||||
type Discriminator struct {
|
type Discriminator struct {
|
||||||
PropertyName low.NodeReference[string]
|
PropertyName low.NodeReference[string]
|
||||||
Mapping low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
Mapping low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
||||||
low.Reference
|
low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindMappingValue will return a ValueReference containing the string mapping value
|
// FindMappingValue will return a ValueReference containing the string mapping value
|
||||||
func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] {
|
func (d *Discriminator) FindMappingValue(key string) *low.ValueReference[string] {
|
||||||
for pair := d.Mapping.Value.First(); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(d.Mapping.Value); pair != nil; pair = pair.Next() {
|
||||||
if pair.Key().Value == key {
|
if pair.Key().Value == key {
|
||||||
v := pair.Value()
|
v := pair.Value()
|
||||||
return &v
|
return &v
|
||||||
@@ -45,7 +45,7 @@ func (d *Discriminator) Hash() [32]byte {
|
|||||||
f = append(f, d.PropertyName.Value)
|
f = append(f, d.PropertyName.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
for pair := orderedmap.First(d.Mapping.Value); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(orderedmap.SortAlpha(d.Mapping.Value)); pair != nil; pair = pair.Next() {
|
||||||
f = append(f, pair.Value().Value)
|
f = append(f, pair.Value().Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -23,15 +22,15 @@ import (
|
|||||||
type Example struct {
|
type Example struct {
|
||||||
Summary low.NodeReference[string]
|
Summary low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
Value low.NodeReference[any]
|
Value low.NodeReference[*yaml.Node]
|
||||||
ExternalValue low.NodeReference[string]
|
ExternalValue low.NodeReference[string]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
func (ex *Example) FindExtension(ext string) *low.ValueReference[any] {
|
func (ex *Example) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, ex.Extensions)
|
return low.FindItemInOrderedMap[*yaml.Node](ext, ex.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash will return a consistent SHA256 Hash of the Discriminator object
|
// Hash will return a consistent SHA256 Hash of the Discriminator object
|
||||||
@@ -43,21 +42,15 @@ func (ex *Example) Hash() [32]byte {
|
|||||||
if ex.Description.Value != "" {
|
if ex.Description.Value != "" {
|
||||||
f = append(f, ex.Description.Value)
|
f = append(f, ex.Description.Value)
|
||||||
}
|
}
|
||||||
if ex.Value.Value != "" {
|
if ex.Value.Value != nil && !ex.Value.Value.IsZero() {
|
||||||
// this could be anything!
|
// this could be anything!
|
||||||
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(ex.Value.Value)))))
|
b, _ := yaml.Marshal(ex.Value.Value)
|
||||||
|
f = append(f, fmt.Sprintf("%x", sha256.Sum256(b)))
|
||||||
}
|
}
|
||||||
if ex.ExternalValue.Value != "" {
|
if ex.ExternalValue.Value != "" {
|
||||||
f = append(f, ex.ExternalValue.Value)
|
f = append(f, ex.ExternalValue.Value)
|
||||||
}
|
}
|
||||||
keys := make([]string, len(ex.Extensions))
|
f = append(f, low.HashExtensions(ex.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range ex.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ex.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,32 +63,8 @@ func (ex *Example) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecInd
|
|||||||
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
|
_, ln, vn := utils.FindKeyNodeFull(ValueLabel, root.Content)
|
||||||
|
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
var n map[string]interface{}
|
ex.Value = low.NodeReference[*yaml.Node]{
|
||||||
err := vn.Decode(&n)
|
Value: vn,
|
||||||
if err != nil {
|
|
||||||
// if not a map, then try an array
|
|
||||||
var k []interface{}
|
|
||||||
err = vn.Decode(&k)
|
|
||||||
if err != nil {
|
|
||||||
// lets just default to interface
|
|
||||||
var j interface{}
|
|
||||||
_ = vn.Decode(&j)
|
|
||||||
ex.Value = low.NodeReference[any]{
|
|
||||||
Value: j,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ex.Value = low.NodeReference[any]{
|
|
||||||
Value: k,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ex.Value = low.NodeReference[any]{
|
|
||||||
Value: n,
|
|
||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
@@ -105,33 +74,6 @@ func (ex *Example) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecInd
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions will return Example extensions to satisfy the HasExtensions interface.
|
// GetExtensions will return Example extensions to satisfy the HasExtensions interface.
|
||||||
func (ex *Example) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (ex *Example) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return ex.Extensions
|
return ex.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractExampleValue will extract a primitive example value (if possible), or just the raw Value property if not.
|
|
||||||
func ExtractExampleValue(exp *yaml.Node) any {
|
|
||||||
if utils.IsNodeBoolValue(exp) {
|
|
||||||
v, _ := strconv.ParseBool(exp.Value)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if utils.IsNodeIntValue(exp) {
|
|
||||||
v, _ := strconv.ParseInt(exp.Value, 10, 64)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if utils.IsNodeFloatValue(exp) {
|
|
||||||
v, _ := strconv.ParseFloat(exp.Value, 64)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
if utils.IsNodeMap(exp) {
|
|
||||||
var m map[string]interface{}
|
|
||||||
_ = exp.Decode(&m)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
if utils.IsNodeArray(exp) {
|
|
||||||
var m []interface{}
|
|
||||||
_ = exp.Decode(&m)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
return exp.Value
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,15 +5,17 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExample_Build_Success_NoValue(t *testing.T) {
|
func TestExample_Build_Success_NoValue(t *testing.T) {
|
||||||
|
|
||||||
yml := `summary: hot
|
yml := `summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
x-cake: hot`
|
x-cake: hot`
|
||||||
@@ -32,13 +34,13 @@ x-cake: hot`
|
|||||||
assert.Equal(t, "hot", n.Summary.Value)
|
assert.Equal(t, "hot", n.Summary.Value)
|
||||||
assert.Equal(t, "cakes", n.Description.Value)
|
assert.Equal(t, "cakes", n.Description.Value)
|
||||||
assert.Nil(t, n.Value.Value)
|
assert.Nil(t, n.Value.Value)
|
||||||
ext := n.FindExtension("x-cake")
|
|
||||||
assert.NotNil(t, ext)
|
var xCake string
|
||||||
assert.Equal(t, "hot", ext.Value)
|
_ = n.FindExtension("x-cake").Value.Decode(&xCake)
|
||||||
|
assert.Equal(t, "hot", xCake)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExample_Build_Success_Simple(t *testing.T) {
|
func TestExample_Build_Success_Simple(t *testing.T) {
|
||||||
|
|
||||||
yml := `summary: hot
|
yml := `summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
value: a string example
|
value: a string example
|
||||||
@@ -57,14 +59,17 @@ x-cake: hot`
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "hot", n.Summary.Value)
|
assert.Equal(t, "hot", n.Summary.Value)
|
||||||
assert.Equal(t, "cakes", n.Description.Value)
|
assert.Equal(t, "cakes", n.Description.Value)
|
||||||
assert.Equal(t, "a string example", n.Value.Value)
|
|
||||||
ext := n.FindExtension("x-cake")
|
var example string
|
||||||
assert.NotNil(t, ext)
|
err = n.Value.Value.Decode(&example)
|
||||||
assert.Equal(t, "hot", ext.Value)
|
assert.Equal(t, "a string example", example)
|
||||||
|
|
||||||
|
var xCake string
|
||||||
|
_ = n.FindExtension("x-cake").Value.Decode(&xCake)
|
||||||
|
assert.Equal(t, "hot", xCake)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExample_Build_Success_Object(t *testing.T) {
|
func TestExample_Build_Success_Object(t *testing.T) {
|
||||||
|
|
||||||
yml := `summary: hot
|
yml := `summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
value:
|
value:
|
||||||
@@ -85,17 +90,15 @@ value:
|
|||||||
assert.Equal(t, "hot", n.Summary.Value)
|
assert.Equal(t, "hot", n.Summary.Value)
|
||||||
assert.Equal(t, "cakes", n.Description.Value)
|
assert.Equal(t, "cakes", n.Description.Value)
|
||||||
|
|
||||||
if v, ok := n.Value.Value.(map[string]interface{}); ok {
|
var m map[string]interface{}
|
||||||
assert.Equal(t, "oven", v["pizza"])
|
err = n.Value.Value.Decode(&m)
|
||||||
assert.Equal(t, "pizza", v["yummy"])
|
require.NoError(t, err)
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assert.Equal(t, "oven", m["pizza"])
|
||||||
|
assert.Equal(t, "pizza", m["yummy"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExample_Build_Success_Array(t *testing.T) {
|
func TestExample_Build_Success_Array(t *testing.T) {
|
||||||
|
|
||||||
yml := `summary: hot
|
yml := `summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
value:
|
value:
|
||||||
@@ -116,16 +119,15 @@ value:
|
|||||||
assert.Equal(t, "hot", n.Summary.Value)
|
assert.Equal(t, "hot", n.Summary.Value)
|
||||||
assert.Equal(t, "cakes", n.Description.Value)
|
assert.Equal(t, "cakes", n.Description.Value)
|
||||||
|
|
||||||
if v, ok := n.Value.Value.([]interface{}); ok {
|
var a []any
|
||||||
assert.Equal(t, "wow", v[0])
|
err = n.Value.Value.Decode(&a)
|
||||||
assert.Equal(t, "such array", v[1])
|
require.NoError(t, err)
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
assert.Equal(t, "wow", a[0])
|
||||||
}
|
assert.Equal(t, "such array", a[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExample_Build_Success_MergeNode(t *testing.T) {
|
func TestExample_Build_Success_MergeNode(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-things: &things
|
yml := `x-things: &things
|
||||||
summary: hot
|
summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
@@ -148,71 +150,15 @@ func TestExample_Build_Success_MergeNode(t *testing.T) {
|
|||||||
assert.Equal(t, "hot", n.Summary.Value)
|
assert.Equal(t, "hot", n.Summary.Value)
|
||||||
assert.Equal(t, "cakes", n.Description.Value)
|
assert.Equal(t, "cakes", n.Description.Value)
|
||||||
|
|
||||||
if v, ok := n.Value.Value.([]interface{}); ok {
|
var a []any
|
||||||
assert.Equal(t, "wow", v[0])
|
err = n.Value.GetValue().Decode(&a)
|
||||||
assert.Equal(t, "such array", v[1])
|
require.NoError(t, err)
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
assert.Equal(t, "wow", a[0])
|
||||||
|
assert.Equal(t, "such array", a[1])
|
||||||
func TestExample_ExtractExampleValue_Map(t *testing.T) {
|
|
||||||
|
|
||||||
yml := `hot:
|
|
||||||
summer: nights
|
|
||||||
pizza: oven`
|
|
||||||
|
|
||||||
var idxNode yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
|
||||||
|
|
||||||
val := ExtractExampleValue(idxNode.Content[0])
|
|
||||||
if v, ok := val.(map[string]interface{}); ok {
|
|
||||||
if r, rok := v["hot"].(map[string]interface{}); rok {
|
|
||||||
assert.Equal(t, "nights", r["summer"])
|
|
||||||
assert.Equal(t, "oven", r["pizza"])
|
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExample_ExtractExampleValue_Slice(t *testing.T) {
|
|
||||||
|
|
||||||
yml := `- hot:
|
|
||||||
summer: nights
|
|
||||||
- hotter:
|
|
||||||
pizza: oven`
|
|
||||||
|
|
||||||
var idxNode yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
|
||||||
|
|
||||||
val := ExtractExampleValue(idxNode.Content[0])
|
|
||||||
if v, ok := val.([]interface{}); ok {
|
|
||||||
for w := range v {
|
|
||||||
if r, rok := v[w].(map[string]interface{}); rok {
|
|
||||||
for k := range r {
|
|
||||||
if k == "hotter" {
|
|
||||||
assert.Equal(t, "oven", r[k].(map[string]interface{})["pizza"])
|
|
||||||
}
|
|
||||||
if k == "hot" {
|
|
||||||
assert.Equal(t, "nights", r[k].(map[string]interface{})["summer"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
assert.Fail(t, "failed to decode correctly.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExample_Hash(t *testing.T) {
|
func TestExample_Hash(t *testing.T) {
|
||||||
|
|
||||||
left := `summary: hot
|
left := `summary: hot
|
||||||
description: cakes
|
description: cakes
|
||||||
x-burger: nice
|
x-burger: nice
|
||||||
@@ -242,13 +188,5 @@ x-burger: nice`
|
|||||||
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
||||||
|
|
||||||
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
||||||
assert.Len(t, lDoc.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(lDoc.GetExtensions()))
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractExampleValue(t *testing.T) {
|
|
||||||
assert.True(t, ExtractExampleValue(&yaml.Node{Tag: "!!bool", Value: "true"}).(bool))
|
|
||||||
assert.Equal(t, int64(10), ExtractExampleValue(&yaml.Node{Tag: "!!int", Value: "10"}).(int64))
|
|
||||||
assert.Equal(t, 33.2, ExtractExampleValue(&yaml.Node{Tag: "!!float", Value: "33.2"}).(float64))
|
|
||||||
assert.Equal(t, "WHAT A NICE COW", ExtractExampleValue(&yaml.Node{Tag: "!!str", Value: "WHAT A NICE COW"}))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ package base
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExternalDoc represents a low-level External Documentation object as defined by OpenAPI 2 and 3
|
// ExternalDoc represents a low-level External Documentation object as defined by OpenAPI 2 and 3
|
||||||
@@ -24,13 +24,13 @@ import (
|
|||||||
type ExternalDoc struct {
|
type ExternalDoc struct {
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
URL low.NodeReference[string]
|
URL low.NodeReference[string]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
func (ex *ExternalDoc) FindExtension(ext string) *low.ValueReference[any] {
|
func (ex *ExternalDoc) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, ex.Extensions)
|
return low.FindItemInOrderedMap[*yaml.Node](ext, ex.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions from the ExternalDoc instance.
|
// Build will extract extensions from the ExternalDoc instance.
|
||||||
@@ -43,7 +43,7 @@ func (ex *ExternalDoc) Build(_ context.Context, _, root *yaml.Node, idx *index.S
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all ExternalDoc extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all ExternalDoc extensions and satisfies the low.HasExtensions interface.
|
||||||
func (ex *ExternalDoc) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (ex *ExternalDoc) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return ex.Extensions
|
return ex.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +53,6 @@ func (ex *ExternalDoc) Hash() [32]byte {
|
|||||||
ex.Description.Value,
|
ex.Description.Value,
|
||||||
ex.URL.Value,
|
ex.URL.Value,
|
||||||
}
|
}
|
||||||
keys := make([]string, len(ex.Extensions))
|
f = append(f, low.HashExtensions(ex.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range ex.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(ex.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExternalDoc_FindExtension(t *testing.T) {
|
func TestExternalDoc_FindExtension(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-fish: cake`
|
yml := `x-fish: cake`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -26,12 +27,14 @@ func TestExternalDoc_FindExtension(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "cake", n.FindExtension("x-fish").Value)
|
|
||||||
|
|
||||||
|
var xFish string
|
||||||
|
_ = n.FindExtension("x-fish").Value.Decode(&xFish)
|
||||||
|
|
||||||
|
assert.Equal(t, "cake", xFish)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExternalDoc_Build(t *testing.T) {
|
func TestExternalDoc_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `url: https://pb33f.io
|
yml := `url: https://pb33f.io
|
||||||
description: the ranch
|
description: the ranch
|
||||||
x-b33f: princess`
|
x-b33f: princess`
|
||||||
@@ -49,14 +52,13 @@ x-b33f: princess`
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "https://pb33f.io", n.URL.Value)
|
assert.Equal(t, "https://pb33f.io", n.URL.Value)
|
||||||
assert.Equal(t, "the ranch", n.Description.Value)
|
assert.Equal(t, "the ranch", n.Description.Value)
|
||||||
ext := n.FindExtension("x-b33f")
|
|
||||||
assert.NotNil(t, ext)
|
|
||||||
assert.Equal(t, "princess", ext.Value)
|
|
||||||
|
|
||||||
|
var xB33f string
|
||||||
|
_ = n.FindExtension("x-b33f").Value.Decode(&xB33f)
|
||||||
|
assert.Equal(t, "princess", xB33f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExternalDoc_Hash(t *testing.T) {
|
func TestExternalDoc_Hash(t *testing.T) {
|
||||||
|
|
||||||
left := `url: https://pb33f.io
|
left := `url: https://pb33f.io
|
||||||
description: the ranch
|
description: the ranch
|
||||||
x-b33f: princess`
|
x-b33f: princess`
|
||||||
@@ -78,5 +80,5 @@ description: the ranch`
|
|||||||
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
||||||
|
|
||||||
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
||||||
assert.Len(t, lDoc.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(lDoc.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ package base
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -31,17 +31,17 @@ type Info struct {
|
|||||||
Contact low.NodeReference[*Contact]
|
Contact low.NodeReference[*Contact]
|
||||||
License low.NodeReference[*License]
|
License low.NodeReference[*License]
|
||||||
Version low.NodeReference[string]
|
Version low.NodeReference[string]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension attempts to locate an extension with the supplied key
|
// FindExtension attempts to locate an extension with the supplied key
|
||||||
func (i *Info) FindExtension(ext string) *low.ValueReference[any] {
|
func (i *Info) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap(ext, i.Extensions)
|
return low.FindItemInOrderedMap(ext, i.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all extensions for Info
|
// GetExtensions returns all extensions for Info
|
||||||
func (i *Info) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (i *Info) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return i.Extensions
|
return i.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,13 +87,6 @@ func (i *Info) Hash() [32]byte {
|
|||||||
if !i.Version.IsEmpty() {
|
if !i.Version.IsEmpty() {
|
||||||
f = append(f, i.Version.Value)
|
f = append(f, i.Version.Value)
|
||||||
}
|
}
|
||||||
keys := make([]string, len(i.Extensions))
|
f = append(f, low.HashExtensions(i.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range i.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(i.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -54,10 +55,11 @@ x-cli-name: pizza cli`
|
|||||||
assert.Equal(t, "magic", lic.Name.Value)
|
assert.Equal(t, "magic", lic.Name.Value)
|
||||||
assert.Equal(t, "https://pb33f.io/license", lic.URL.Value)
|
assert.Equal(t, "https://pb33f.io/license", lic.URL.Value)
|
||||||
|
|
||||||
cliName := n.FindExtension("x-cli-name")
|
var xCliName string
|
||||||
assert.NotNil(t, cliName)
|
_ = n.FindExtension("x-cli-name").Value.Decode(&xCliName)
|
||||||
assert.Equal(t, "pizza cli", cliName.Value)
|
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
assert.Equal(t, "pizza cli", xCliName)
|
||||||
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContact_Build(t *testing.T) {
|
func TestContact_Build(t *testing.T) {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ type Schema struct {
|
|||||||
Discriminator low.NodeReference[*Discriminator]
|
Discriminator low.NodeReference[*Discriminator]
|
||||||
|
|
||||||
// in 3.1 examples can be an array (which is recommended)
|
// in 3.1 examples can be an array (which is recommended)
|
||||||
Examples low.NodeReference[[]low.ValueReference[any]]
|
Examples low.NodeReference[[]low.ValueReference[*yaml.Node]]
|
||||||
// in 3.1 PrefixItems provides tuple validation using prefixItems.
|
// in 3.1 PrefixItems provides tuple validation using prefixItems.
|
||||||
PrefixItems low.NodeReference[[]low.ValueReference[*SchemaProxy]]
|
PrefixItems low.NodeReference[[]low.ValueReference[*SchemaProxy]]
|
||||||
// in 3.1 Contains is used by arrays and points to a Schema.
|
// in 3.1 Contains is used by arrays and points to a Schema.
|
||||||
@@ -97,8 +97,8 @@ type Schema struct {
|
|||||||
If low.NodeReference[*SchemaProxy]
|
If low.NodeReference[*SchemaProxy]
|
||||||
Else low.NodeReference[*SchemaProxy]
|
Else low.NodeReference[*SchemaProxy]
|
||||||
Then low.NodeReference[*SchemaProxy]
|
Then low.NodeReference[*SchemaProxy]
|
||||||
DependentSchemas low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
DependentSchemas low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
||||||
PatternProperties low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
PatternProperties low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
||||||
PropertyNames low.NodeReference[*SchemaProxy]
|
PropertyNames low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
UnevaluatedItems low.NodeReference[*SchemaProxy]
|
||||||
UnevaluatedProperties low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]
|
UnevaluatedProperties low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]
|
||||||
@@ -119,23 +119,23 @@ type Schema struct {
|
|||||||
MaxProperties low.NodeReference[int64]
|
MaxProperties low.NodeReference[int64]
|
||||||
MinProperties low.NodeReference[int64]
|
MinProperties low.NodeReference[int64]
|
||||||
Required low.NodeReference[[]low.ValueReference[string]]
|
Required low.NodeReference[[]low.ValueReference[string]]
|
||||||
Enum low.NodeReference[[]low.ValueReference[any]]
|
Enum low.NodeReference[[]low.ValueReference[*yaml.Node]]
|
||||||
Not low.NodeReference[*SchemaProxy]
|
Not low.NodeReference[*SchemaProxy]
|
||||||
Properties low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
Properties low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]
|
||||||
AdditionalProperties low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]
|
AdditionalProperties low.NodeReference[*SchemaDynamicValue[*SchemaProxy, bool]]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
ContentEncoding low.NodeReference[string]
|
ContentEncoding low.NodeReference[string]
|
||||||
ContentMediaType low.NodeReference[string]
|
ContentMediaType low.NodeReference[string]
|
||||||
Default low.NodeReference[any]
|
Default low.NodeReference[*yaml.Node]
|
||||||
Const low.NodeReference[any]
|
Const low.NodeReference[*yaml.Node]
|
||||||
Nullable low.NodeReference[bool]
|
Nullable low.NodeReference[bool]
|
||||||
ReadOnly low.NodeReference[bool]
|
ReadOnly low.NodeReference[bool]
|
||||||
WriteOnly low.NodeReference[bool]
|
WriteOnly low.NodeReference[bool]
|
||||||
XML low.NodeReference[*XML]
|
XML low.NodeReference[*XML]
|
||||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||||
Example low.NodeReference[any]
|
Example low.NodeReference[*yaml.Node]
|
||||||
Deprecated low.NodeReference[bool]
|
Deprecated low.NodeReference[bool]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
|
|
||||||
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
// Parent Proxy refers back to the low level SchemaProxy that is proxying this schema.
|
||||||
ParentProxy *SchemaProxy
|
ParentProxy *SchemaProxy
|
||||||
@@ -255,23 +255,13 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
|
|
||||||
keys = make([]string, len(s.Enum.Value))
|
keys = make([]string, len(s.Enum.Value))
|
||||||
for i := range s.Enum.Value {
|
for i := range s.Enum.Value {
|
||||||
keys[i] = fmt.Sprint(s.Enum.Value[i].Value)
|
keys[i] = low.ValueToString(s.Enum.Value[i].Value)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
d = append(d, keys...)
|
d = append(d, keys...)
|
||||||
|
|
||||||
for i := range s.Enum.Value {
|
for pair := orderedmap.First(orderedmap.SortAlpha(s.Properties.Value)); pair != nil; pair = pair.Next() {
|
||||||
d = append(d, fmt.Sprint(s.Enum.Value[i].Value))
|
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
|
||||||
}
|
|
||||||
propKeys := make([]string, orderedmap.Len(s.Properties.Value))
|
|
||||||
z := 0
|
|
||||||
for pair := orderedmap.First(s.Properties.Value); pair != nil; pair = pair.Next() {
|
|
||||||
propKeys[z] = pair.Key().Value
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(propKeys)
|
|
||||||
for k := range propKeys {
|
|
||||||
d = append(d, low.GenerateHashString(s.FindProperty(propKeys[k]).Value))
|
|
||||||
}
|
}
|
||||||
if s.XML.Value != nil {
|
if s.XML.Value != nil {
|
||||||
d = append(d, low.GenerateHashString(s.XML.Value))
|
d = append(d, low.GenerateHashString(s.XML.Value))
|
||||||
@@ -287,7 +277,7 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
if len(s.OneOf.Value) > 0 {
|
if len(s.OneOf.Value) > 0 {
|
||||||
oneOfKeys := make([]string, len(s.OneOf.Value))
|
oneOfKeys := make([]string, len(s.OneOf.Value))
|
||||||
oneOfEntities := make(map[string]*SchemaProxy)
|
oneOfEntities := make(map[string]*SchemaProxy)
|
||||||
z = 0
|
z := 0
|
||||||
for i := range s.OneOf.Value {
|
for i := range s.OneOf.Value {
|
||||||
g := s.OneOf.Value[i].Value
|
g := s.OneOf.Value[i].Value
|
||||||
r := low.GenerateHashString(g)
|
r := low.GenerateHashString(g)
|
||||||
@@ -305,7 +295,7 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
if len(s.AllOf.Value) > 0 {
|
if len(s.AllOf.Value) > 0 {
|
||||||
allOfKeys := make([]string, len(s.AllOf.Value))
|
allOfKeys := make([]string, len(s.AllOf.Value))
|
||||||
allOfEntities := make(map[string]*SchemaProxy)
|
allOfEntities := make(map[string]*SchemaProxy)
|
||||||
z = 0
|
z := 0
|
||||||
for i := range s.AllOf.Value {
|
for i := range s.AllOf.Value {
|
||||||
g := s.AllOf.Value[i].Value
|
g := s.AllOf.Value[i].Value
|
||||||
r := low.GenerateHashString(g)
|
r := low.GenerateHashString(g)
|
||||||
@@ -323,7 +313,7 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
if len(s.AnyOf.Value) > 0 {
|
if len(s.AnyOf.Value) > 0 {
|
||||||
anyOfKeys := make([]string, len(s.AnyOf.Value))
|
anyOfKeys := make([]string, len(s.AnyOf.Value))
|
||||||
anyOfEntities := make(map[string]*SchemaProxy)
|
anyOfEntities := make(map[string]*SchemaProxy)
|
||||||
z = 0
|
z := 0
|
||||||
for i := range s.AnyOf.Value {
|
for i := range s.AnyOf.Value {
|
||||||
g := s.AnyOf.Value[i].Value
|
g := s.AnyOf.Value[i].Value
|
||||||
r := low.GenerateHashString(g)
|
r := low.GenerateHashString(g)
|
||||||
@@ -372,32 +362,18 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
d = append(d, fmt.Sprint(s.Anchor.Value))
|
d = append(d, fmt.Sprint(s.Anchor.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
depSchemasKeys := make([]string, orderedmap.Len(s.DependentSchemas.Value))
|
for pair := orderedmap.First(orderedmap.SortAlpha(s.DependentSchemas.Value)); pair != nil; pair = pair.Next() {
|
||||||
z = 0
|
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
|
||||||
for pair := orderedmap.First(s.DependentSchemas.Value); pair != nil; pair = pair.Next() {
|
|
||||||
depSchemasKeys[z] = pair.Key().Value
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(depSchemasKeys)
|
|
||||||
for k := range depSchemasKeys {
|
|
||||||
d = append(d, low.GenerateHashString(s.FindDependentSchema(depSchemasKeys[k]).Value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
patternPropsKeys := make([]string, orderedmap.Len(s.PatternProperties.Value))
|
for pair := orderedmap.First(orderedmap.SortAlpha(s.PatternProperties.Value)); pair != nil; pair = pair.Next() {
|
||||||
z = 0
|
d = append(d, fmt.Sprintf("%s-%s", pair.Key().Value, low.GenerateHashString(pair.Value().Value)))
|
||||||
for pair := orderedmap.First(s.PatternProperties.Value); pair != nil; pair = pair.Next() {
|
|
||||||
patternPropsKeys[z] = pair.Key().Value
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(patternPropsKeys)
|
|
||||||
for k := range patternPropsKeys {
|
|
||||||
d = append(d, low.GenerateHashString(s.FindPatternProperty(patternPropsKeys[k]).Value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.PrefixItems.Value) > 0 {
|
if len(s.PrefixItems.Value) > 0 {
|
||||||
itemsKeys := make([]string, len(s.PrefixItems.Value))
|
itemsKeys := make([]string, len(s.PrefixItems.Value))
|
||||||
itemsEntities := make(map[string]*SchemaProxy)
|
itemsEntities := make(map[string]*SchemaProxy)
|
||||||
z = 0
|
z := 0
|
||||||
for i := range s.PrefixItems.Value {
|
for i := range s.PrefixItems.Value {
|
||||||
g := s.PrefixItems.Value[i].Value
|
g := s.PrefixItems.Value[i].Value
|
||||||
r := low.GenerateHashString(g)
|
r := low.GenerateHashString(g)
|
||||||
@@ -411,15 +387,7 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add extensions to hash
|
d = append(d, low.HashExtensions(s.Extensions)...)
|
||||||
keys = make([]string, len(s.Extensions))
|
|
||||||
z = 0
|
|
||||||
for k := range s.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(s.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
d = append(d, keys...)
|
|
||||||
if s.Example.Value != nil {
|
if s.Example.Value != nil {
|
||||||
d = append(d, low.GenerateHashString(s.Example.Value))
|
d = append(d, low.GenerateHashString(s.Example.Value))
|
||||||
}
|
}
|
||||||
@@ -435,12 +403,9 @@ func (s *Schema) Hash() [32]byte {
|
|||||||
d = append(d, fmt.Sprint(s.MaxContains.Value))
|
d = append(d, fmt.Sprint(s.MaxContains.Value))
|
||||||
}
|
}
|
||||||
if !s.Examples.IsEmpty() {
|
if !s.Examples.IsEmpty() {
|
||||||
var xph []string
|
for _, ex := range s.Examples.Value {
|
||||||
for w := range s.Examples.Value {
|
d = append(d, low.GenerateHashString(ex.Value))
|
||||||
xph = append(xph, low.GenerateHashString(s.Examples.Value[w].Value))
|
|
||||||
}
|
}
|
||||||
sort.Strings(xph)
|
|
||||||
d = append(d, strings.Join(xph, "|"))
|
|
||||||
}
|
}
|
||||||
return sha256.Sum256([]byte(strings.Join(d, "|")))
|
return sha256.Sum256([]byte(strings.Join(d, "|")))
|
||||||
}
|
}
|
||||||
@@ -464,7 +429,7 @@ func (s *Schema) FindPatternProperty(name string) *low.ValueReference[*SchemaPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all extensions for Schema
|
// GetExtensions returns all extensions for Schema
|
||||||
func (s *Schema) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (s *Schema) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return s.Extensions
|
return s.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,20 +614,20 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle example if set. (3.0)
|
// handle example if set. (3.0)
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFullTop(ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
s.Example = low.NodeReference[any]{Value: ExtractExampleValue(expNode), KeyNode: expLabel, ValueNode: expNode}
|
s.Example = low.NodeReference[*yaml.Node]{Value: expNode, KeyNode: expLabel, ValueNode: expNode}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle examples if set.(3.1)
|
// handle examples if set.(3.1)
|
||||||
_, expArrLabel, expArrNode := utils.FindKeyNodeFullTop(ExamplesLabel, root.Content)
|
_, expArrLabel, expArrNode := utils.FindKeyNodeFullTop(ExamplesLabel, root.Content)
|
||||||
if expArrNode != nil {
|
if expArrNode != nil {
|
||||||
if utils.IsNodeArray(expArrNode) {
|
if utils.IsNodeArray(expArrNode) {
|
||||||
var examples []low.ValueReference[any]
|
var examples []low.ValueReference[*yaml.Node]
|
||||||
for i := range expArrNode.Content {
|
for i := range expArrNode.Content {
|
||||||
examples = append(examples, low.ValueReference[any]{Value: ExtractExampleValue(expArrNode.Content[i]), ValueNode: expArrNode.Content[i]})
|
examples = append(examples, low.ValueReference[*yaml.Node]{Value: expArrNode.Content[i], ValueNode: expArrNode.Content[i]})
|
||||||
}
|
}
|
||||||
s.Examples = low.NodeReference[[]low.ValueReference[any]]{
|
s.Examples = low.NodeReference[[]low.ValueReference[*yaml.Node]]{
|
||||||
Value: examples,
|
Value: examples,
|
||||||
ValueNode: expArrNode,
|
ValueNode: expArrNode,
|
||||||
KeyNode: expArrLabel,
|
KeyNode: expArrLabel,
|
||||||
@@ -1035,7 +1000,7 @@ func (s *Schema) Build(ctx context.Context, root *yaml.Node, idx *index.SpecInde
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) {
|
func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, label string) (*low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]], error) {
|
||||||
_, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content)
|
_, propLabel, propsNode := utils.FindKeyNodeFullTop(label, root.Content)
|
||||||
if propsNode != nil {
|
if propsNode != nil {
|
||||||
propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]()
|
propertyMap := orderedmap.New[low.KeyReference[string], low.ValueReference[*SchemaProxy]]()
|
||||||
@@ -1047,12 +1012,12 @@ func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check our prop isn't reference
|
// check our prop isn't reference
|
||||||
isRef := false
|
|
||||||
refString := ""
|
refString := ""
|
||||||
|
var refNode *yaml.Node
|
||||||
if h, _, l := utils.IsNodeRefValue(prop); h {
|
if h, _, l := utils.IsNodeRefValue(prop); h {
|
||||||
ref, _, _, _ := low.LocateRefNodeWithContext(ctx, prop, idx)
|
ref, _, _, _ := low.LocateRefNodeWithContext(ctx, prop, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
isRef = true
|
refNode = prop
|
||||||
prop = ref
|
prop = ref
|
||||||
refString = l
|
refString = l
|
||||||
} else {
|
} else {
|
||||||
@@ -1061,16 +1026,19 @@ func buildPropertyMap(ctx context.Context, root *yaml.Node, idx *index.SpecIndex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp := &SchemaProxy{ctx: ctx, kn: currentProp, vn: prop, idx: idx}
|
||||||
|
sp.SetReference(refString, refNode)
|
||||||
|
|
||||||
propertyMap.Set(low.KeyReference[string]{
|
propertyMap.Set(low.KeyReference[string]{
|
||||||
KeyNode: currentProp,
|
KeyNode: currentProp,
|
||||||
Value: currentProp.Value,
|
Value: currentProp.Value,
|
||||||
}, low.ValueReference[*SchemaProxy]{
|
}, low.ValueReference[*SchemaProxy]{
|
||||||
Value: &SchemaProxy{ctx: ctx, kn: currentProp, vn: prop, idx: idx, isReference: isRef, referenceLookup: refString},
|
Value: sp,
|
||||||
ValueNode: prop,
|
ValueNode: prop,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &low.NodeReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]{
|
return &low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[*SchemaProxy]]]{
|
||||||
Value: propertyMap,
|
Value: propertyMap,
|
||||||
KeyNode: propLabel,
|
KeyNode: propLabel,
|
||||||
ValueNode: propsNode,
|
ValueNode: propsNode,
|
||||||
@@ -1112,7 +1080,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
syncChan := make(chan buildResult)
|
syncChan := make(chan buildResult)
|
||||||
|
|
||||||
// build out a SchemaProxy for every sub-schema.
|
// build out a SchemaProxy for every sub-schema.
|
||||||
build := func(pctx context.Context, kn *yaml.Node, vn *yaml.Node, schemaIdx int, c chan buildResult,
|
build := func(pctx context.Context, kn, vn *yaml.Node, rf *yaml.Node, schemaIdx int, c chan buildResult,
|
||||||
isRef bool, refLocation string,
|
isRef bool, refLocation string,
|
||||||
) {
|
) {
|
||||||
// a proxy design works best here. polymorphism, pretty much guarantees that a sub-schema can
|
// a proxy design works best here. polymorphism, pretty much guarantees that a sub-schema can
|
||||||
@@ -1127,8 +1095,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
sp.idx = idx
|
sp.idx = idx
|
||||||
sp.ctx = pctx
|
sp.ctx = pctx
|
||||||
if isRef {
|
if isRef {
|
||||||
sp.referenceLookup = refLocation
|
sp.SetReference(refLocation, rf)
|
||||||
sp.isReference = true
|
|
||||||
}
|
}
|
||||||
res := &low.ValueReference[*SchemaProxy]{
|
res := &low.ValueReference[*SchemaProxy]{
|
||||||
Value: sp,
|
Value: sp,
|
||||||
@@ -1142,6 +1109,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
|
|
||||||
isRef := false
|
isRef := false
|
||||||
refLocation := ""
|
refLocation := ""
|
||||||
|
var refNode *yaml.Node
|
||||||
foundCtx := ctx
|
foundCtx := ctx
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
h := false
|
h := false
|
||||||
@@ -1149,6 +1117,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
isRef = true
|
isRef = true
|
||||||
ref, _, _, fctx := low.LocateRefNodeWithContext(ctx, valueNode, idx)
|
ref, _, _, fctx := low.LocateRefNodeWithContext(ctx, valueNode, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = valueNode
|
||||||
valueNode = ref
|
valueNode = ref
|
||||||
foundCtx = fctx
|
foundCtx = fctx
|
||||||
} else {
|
} else {
|
||||||
@@ -1159,7 +1128,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
|
|
||||||
// this only runs once, however to keep things consistent, it makes sense to use the same async method
|
// this only runs once, however to keep things consistent, it makes sense to use the same async method
|
||||||
// that arrays will use.
|
// that arrays will use.
|
||||||
go build(foundCtx, labelNode, valueNode, -1, syncChan, isRef, refLocation)
|
go build(foundCtx, labelNode, valueNode, refNode, -1, syncChan, isRef, refLocation)
|
||||||
select {
|
select {
|
||||||
case r := <-syncChan:
|
case r := <-syncChan:
|
||||||
schemas <- schemaProxyBuildResult{
|
schemas <- schemaProxyBuildResult{
|
||||||
@@ -1181,6 +1150,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
isRef = true
|
isRef = true
|
||||||
ref, _, _, fctx := low.LocateRefNodeWithContext(ctx, vn, idx)
|
ref, _, _, fctx := low.LocateRefNodeWithContext(ctx, vn, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = vn
|
||||||
vn = ref
|
vn = ref
|
||||||
foundCtx = fctx
|
foundCtx = fctx
|
||||||
} else {
|
} else {
|
||||||
@@ -1191,7 +1161,7 @@ func buildSchema(ctx context.Context, schemas chan schemaProxyBuildResult, label
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
refBuilds++
|
refBuilds++
|
||||||
go build(foundCtx, vn, vn, i, syncChan, isRef, refLocation)
|
go build(foundCtx, vn, vn, refNode, i, syncChan, isRef, refLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
completedBuilds := 0
|
completedBuilds := 0
|
||||||
@@ -1225,12 +1195,11 @@ func ExtractSchema(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (
|
|||||||
var schLabel, schNode *yaml.Node
|
var schLabel, schNode *yaml.Node
|
||||||
errStr := "schema build failed: reference '%s' cannot be found at line %d, col %d"
|
errStr := "schema build failed: reference '%s' cannot be found at line %d, col %d"
|
||||||
|
|
||||||
isRef := false
|
|
||||||
refLocation := ""
|
refLocation := ""
|
||||||
|
var refNode *yaml.Node
|
||||||
|
|
||||||
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
|
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
|
||||||
// locate reference in index.
|
// locate reference in index.
|
||||||
isRef = true
|
|
||||||
ref, fIdx, _, nCtx := low.LocateRefNodeWithContext(ctx, root, idx)
|
ref, fIdx, _, nCtx := low.LocateRefNodeWithContext(ctx, root, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
schNode = ref
|
schNode = ref
|
||||||
@@ -1250,9 +1219,9 @@ func ExtractSchema(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (
|
|||||||
if schNode != nil {
|
if schNode != nil {
|
||||||
h := false
|
h := false
|
||||||
if h, _, refLocation = utils.IsNodeRefValue(schNode); h {
|
if h, _, refLocation = utils.IsNodeRefValue(schNode); h {
|
||||||
isRef = true
|
|
||||||
ref, foundIdx, _, nCtx := low.LocateRefNodeWithContext(ctx, schNode, idx)
|
ref, foundIdx, _, nCtx := low.LocateRefNodeWithContext(ctx, schNode, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = schNode
|
||||||
schNode = ref
|
schNode = ref
|
||||||
if foundIdx != nil {
|
if foundIdx != nil {
|
||||||
// TODO: check on this
|
// TODO: check on this
|
||||||
@@ -1273,11 +1242,16 @@ func ExtractSchema(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (
|
|||||||
|
|
||||||
if schNode != nil {
|
if schNode != nil {
|
||||||
// check if schema has already been built.
|
// check if schema has already been built.
|
||||||
schema := &SchemaProxy{kn: schLabel, vn: schNode, idx: idx, ctx: ctx, isReference: isRef, referenceLookup: refLocation}
|
schema := &SchemaProxy{kn: schLabel, vn: schNode, idx: idx, ctx: ctx}
|
||||||
return &low.NodeReference[*SchemaProxy]{
|
schema.SetReference(refLocation, refNode)
|
||||||
Value: schema, KeyNode: schLabel, ValueNode: schNode, ReferenceNode: isRef,
|
|
||||||
Reference: refLocation,
|
n := &low.NodeReference[*SchemaProxy]{
|
||||||
}, nil
|
Value: schema,
|
||||||
|
KeyNode: schLabel,
|
||||||
|
ValueNode: schNode,
|
||||||
|
}
|
||||||
|
n.SetReference(refLocation, refNode)
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ package base
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -44,14 +46,13 @@ import (
|
|||||||
// it's not actually JSONSchema until 3.1, so lots of times a bad schema will break parsing. Errors are only found
|
// it's not actually JSONSchema until 3.1, so lots of times a bad schema will break parsing. Errors are only found
|
||||||
// when a schema is needed, so the rest of the document is parsed and ready to use.
|
// when a schema is needed, so the rest of the document is parsed and ready to use.
|
||||||
type SchemaProxy struct {
|
type SchemaProxy struct {
|
||||||
kn *yaml.Node
|
low.Reference
|
||||||
vn *yaml.Node
|
kn *yaml.Node
|
||||||
idx *index.SpecIndex
|
vn *yaml.Node
|
||||||
rendered *Schema
|
idx *index.SpecIndex
|
||||||
buildError error
|
rendered *Schema
|
||||||
isReference bool // Is the schema underneath originally a $ref?
|
buildError error
|
||||||
referenceLookup string // If the schema is a $ref, what's its name?
|
ctx context.Context
|
||||||
ctx context.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will prepare the SchemaProxy for rendering, it does not build the Schema, only sets up internal state.
|
// Build will prepare the SchemaProxy for rendering, it does not build the Schema, only sets up internal state.
|
||||||
@@ -62,8 +63,7 @@ func (sp *SchemaProxy) Build(ctx context.Context, key, value *yaml.Node, idx *in
|
|||||||
sp.idx = idx
|
sp.idx = idx
|
||||||
sp.ctx = ctx
|
sp.ctx = ctx
|
||||||
if rf, _, r := utils.IsNodeRefValue(value); rf {
|
if rf, _, r := utils.IsNodeRefValue(value); rf {
|
||||||
sp.isReference = true
|
sp.SetReference(r, value)
|
||||||
sp.referenceLookup = r
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -101,36 +101,6 @@ func (sp *SchemaProxy) GetBuildError() error {
|
|||||||
return sp.buildError
|
return sp.buildError
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSchemaReference returns true if the Schema that this SchemaProxy represents, is actually a reference to
|
|
||||||
// a Schema contained within Components or Definitions. There is no difference in the mechanism used to resolve the
|
|
||||||
// Schema when calling Schema(), however if we want to know if this schema was originally a reference, we won't
|
|
||||||
// be able to determine that from the model, without this bit.
|
|
||||||
func (sp *SchemaProxy) IsSchemaReference() bool {
|
|
||||||
return sp.isReference
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsReference is an alias for IsSchemaReference() except it's compatible wih the IsReferenced interface type.
|
|
||||||
func (sp *SchemaProxy) IsReference() bool {
|
|
||||||
return sp.IsSchemaReference()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReference is an alias for GetSchemaReference() except it's compatible wih the IsReferenced interface type.
|
|
||||||
func (sp *SchemaProxy) GetReference() string {
|
|
||||||
return sp.GetSchemaReference()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetReference will set the reference lookup for this SchemaProxy.
|
|
||||||
func (sp *SchemaProxy) SetReference(ref string) {
|
|
||||||
sp.referenceLookup = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSchemaReference will return the lookup defined by the $ref that this schema points to. If the schema
|
|
||||||
// is inline, and not a reference, then this method returns an empty string. Only useful when combined with
|
|
||||||
// IsSchemaReference()
|
|
||||||
func (sp *SchemaProxy) GetSchemaReference() string {
|
|
||||||
return sp.referenceLookup
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *SchemaProxy) GetSchemaReferenceLocation() *index.NodeOrigin {
|
func (sp *SchemaProxy) GetSchemaReferenceLocation() *index.NodeOrigin {
|
||||||
if sp.idx != nil {
|
if sp.idx != nil {
|
||||||
origin := sp.idx.FindNodeOrigin(sp.vn)
|
origin := sp.idx.FindNodeOrigin(sp.vn)
|
||||||
@@ -158,11 +128,11 @@ func (sp *SchemaProxy) GetValueNode() *yaml.Node {
|
|||||||
// Hash will return a consistent SHA256 Hash of the SchemaProxy object (it will resolve it)
|
// Hash will return a consistent SHA256 Hash of the SchemaProxy object (it will resolve it)
|
||||||
func (sp *SchemaProxy) Hash() [32]byte {
|
func (sp *SchemaProxy) Hash() [32]byte {
|
||||||
if sp.rendered != nil {
|
if sp.rendered != nil {
|
||||||
if !sp.isReference {
|
if !sp.IsReference() {
|
||||||
return sp.rendered.Hash()
|
return sp.rendered.Hash()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !sp.isReference {
|
if !sp.IsReference() {
|
||||||
// only resolve this proxy if it's not a ref.
|
// only resolve this proxy if it's not a ref.
|
||||||
sch := sp.Schema()
|
sch := sp.Schema()
|
||||||
sp.rendered = sch
|
sp.rendered = sch
|
||||||
@@ -170,5 +140,5 @@ func (sp *SchemaProxy) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// hash reference value only, do not resolve!
|
// hash reference value only, do not resolve!
|
||||||
return sha256.Sum256([]byte(sp.referenceLookup))
|
return sha256.Sum256([]byte(sp.GetReference()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSchemaProxy_Build(t *testing.T) {
|
func TestSchemaProxy_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-windows: washed
|
yml := `x-windows: washed
|
||||||
description: something`
|
description: something`
|
||||||
|
|
||||||
@@ -24,29 +25,25 @@ description: something`
|
|||||||
err := sch.Build(context.Background(), &idxNode, idxNode.Content[0], nil)
|
err := sch.Build(context.Background(), &idxNode, idxNode.Content[0], nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, "db2a35dd6fb3d9481d0682571b9d687616bb2a34c1887f7863f0b2e769ca7b23",
|
assert.Equal(t, "e20c009d370944d177c0b46e8fa29e15fadc3a6f9cca6bb251ff9e120265fc96",
|
||||||
low.GenerateHashString(&sch))
|
low.GenerateHashString(&sch))
|
||||||
|
|
||||||
assert.Equal(t, "something", sch.Schema().Description.Value)
|
assert.Equal(t, "something", sch.Schema().Description.GetValue())
|
||||||
assert.Empty(t, sch.GetSchemaReference())
|
assert.Empty(t, sch.GetReference())
|
||||||
assert.NotNil(t, sch.GetKeyNode())
|
assert.NotNil(t, sch.GetKeyNode())
|
||||||
assert.NotNil(t, sch.GetValueNode())
|
assert.NotNil(t, sch.GetValueNode())
|
||||||
assert.False(t, sch.IsSchemaReference())
|
|
||||||
assert.False(t, sch.IsReference())
|
assert.False(t, sch.IsReference())
|
||||||
assert.Empty(t, sch.GetReference())
|
sch.SetReference("coffee", nil)
|
||||||
sch.SetReference("coffee")
|
|
||||||
assert.Equal(t, "coffee", sch.GetReference())
|
assert.Equal(t, "coffee", sch.GetReference())
|
||||||
|
|
||||||
// already rendered, should spit out the same
|
// already rendered, should spit out the same
|
||||||
assert.Equal(t, "db2a35dd6fb3d9481d0682571b9d687616bb2a34c1887f7863f0b2e769ca7b23",
|
assert.Equal(t, "37290d74ac4d186e3a8e5785d259d2ec04fac91ae28092e7620ec8bc99e830aa",
|
||||||
low.GenerateHashString(&sch))
|
low.GenerateHashString(&sch))
|
||||||
|
|
||||||
assert.Len(t, sch.Schema().GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(sch.Schema().GetExtensions()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaProxy_Build_CheckRef(t *testing.T) {
|
func TestSchemaProxy_Build_CheckRef(t *testing.T) {
|
||||||
|
|
||||||
yml := `$ref: wat`
|
yml := `$ref: wat`
|
||||||
|
|
||||||
var sch SchemaProxy
|
var sch SchemaProxy
|
||||||
@@ -55,14 +52,13 @@ func TestSchemaProxy_Build_CheckRef(t *testing.T) {
|
|||||||
|
|
||||||
err := sch.Build(context.Background(), nil, idxNode.Content[0], nil)
|
err := sch.Build(context.Background(), nil, idxNode.Content[0], nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, sch.IsSchemaReference())
|
assert.True(t, sch.IsReference())
|
||||||
assert.Equal(t, "wat", sch.GetSchemaReference())
|
assert.Equal(t, "wat", sch.GetReference())
|
||||||
assert.Equal(t, "f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4",
|
assert.Equal(t, "f00a787f7492a95e165b470702f4fe9373583fbdc025b2c8bdf0262cc48fcff4",
|
||||||
low.GenerateHashString(&sch))
|
low.GenerateHashString(&sch))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaProxy_Build_HashInline(t *testing.T) {
|
func TestSchemaProxy_Build_HashInline(t *testing.T) {
|
||||||
|
|
||||||
yml := `type: int`
|
yml := `type: int`
|
||||||
|
|
||||||
var sch SchemaProxy
|
var sch SchemaProxy
|
||||||
@@ -71,14 +67,13 @@ func TestSchemaProxy_Build_HashInline(t *testing.T) {
|
|||||||
|
|
||||||
err := sch.Build(context.Background(), nil, idxNode.Content[0], nil)
|
err := sch.Build(context.Background(), nil, idxNode.Content[0], nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, sch.IsSchemaReference())
|
assert.False(t, sch.IsReference())
|
||||||
assert.NotNil(t, sch.Schema())
|
assert.NotNil(t, sch.Schema())
|
||||||
assert.Equal(t, "6da88c34ba124c41f977db66a4fc5c1a951708d285c81bb0d47c3206f4c27ca8",
|
assert.Equal(t, "6da88c34ba124c41f977db66a4fc5c1a951708d285c81bb0d47c3206f4c27ca8",
|
||||||
low.GenerateHashString(&sch))
|
low.GenerateHashString(&sch))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaProxy_Build_UsingMergeNodes(t *testing.T) {
|
func TestSchemaProxy_Build_UsingMergeNodes(t *testing.T) {
|
||||||
|
|
||||||
yml := `
|
yml := `
|
||||||
x-common-definitions:
|
x-common-definitions:
|
||||||
life_cycle_types: &life_cycle_types_def
|
life_cycle_types: &life_cycle_types_def
|
||||||
@@ -95,11 +90,9 @@ x-common-definitions:
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, sch.Schema().Enum.Value, 3)
|
assert.Len(t, sch.Schema().Enum.Value, 3)
|
||||||
assert.Equal(t, "The type of life cycle", sch.Schema().Description.Value)
|
assert.Equal(t, "The type of life cycle", sch.Schema().Description.Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchemaProxy_GetSchemaReferenceLocation(t *testing.T) {
|
func TestSchemaProxy_GetSchemaReferenceLocation(t *testing.T) {
|
||||||
|
|
||||||
yml := `type: object
|
yml := `type: object
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
@@ -159,5 +152,4 @@ properties:
|
|||||||
err = schC.Build(context.Background(), nil, idxNodeA.Content[0], nil)
|
err = schC.Build(context.Background(), nil, idxNodeA.Content[0], nil)
|
||||||
origin = schC.GetSchemaReferenceLocation()
|
origin = schC.GetSchemaReferenceLocation()
|
||||||
assert.Nil(t, origin)
|
assert.Nil(t, origin)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel"
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
@@ -9,7 +11,6 @@ import (
|
|||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func test_get_schema_blob() string {
|
func test_get_schema_blob() string {
|
||||||
@@ -192,8 +193,8 @@ func Test_Schema(t *testing.T) {
|
|||||||
assert.Equal(t, "an xml namespace", j.XML.Value.Namespace.Value)
|
assert.Equal(t, "an xml namespace", j.XML.Value.Namespace.Value)
|
||||||
assert.Equal(t, "a prefix", j.XML.Value.Prefix.Value)
|
assert.Equal(t, "a prefix", j.XML.Value.Prefix.Value)
|
||||||
assert.Equal(t, true, j.XML.Value.Attribute.Value)
|
assert.Equal(t, true, j.XML.Value.Attribute.Value)
|
||||||
assert.Len(t, j.XML.Value.Extensions, 1)
|
assert.Equal(t, 1, orderedmap.Len(j.XML.Value.Extensions))
|
||||||
assert.Len(t, j.XML.Value.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(j.XML.Value.GetExtensions()))
|
||||||
|
|
||||||
assert.NotNil(t, v.Value.Schema().AdditionalProperties.Value)
|
assert.NotNil(t, v.Value.Schema().AdditionalProperties.Value)
|
||||||
|
|
||||||
@@ -213,12 +214,20 @@ func Test_Schema(t *testing.T) {
|
|||||||
io := v.Value.Schema()
|
io := v.Value.Schema()
|
||||||
|
|
||||||
assert.Equal(t, "allOfA description", io.Description.Value)
|
assert.Equal(t, "allOfA description", io.Description.Value)
|
||||||
assert.Equal(t, "allOfAExp", io.Example.Value)
|
|
||||||
|
var ioExample string
|
||||||
|
_ = io.Example.GetValueNode().Decode(&ioExample)
|
||||||
|
|
||||||
|
assert.Equal(t, "allOfAExp", ioExample)
|
||||||
|
|
||||||
qw := f.FindProperty("allOfB").Value.Schema()
|
qw := f.FindProperty("allOfB").Value.Schema()
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "allOfB description", qw.Description.Value)
|
assert.Equal(t, "allOfB description", qw.Description.Value)
|
||||||
assert.Equal(t, "allOfBExp", qw.Example.Value)
|
|
||||||
|
var qwExample string
|
||||||
|
_ = qw.Example.GetValueNode().Decode(&qwExample)
|
||||||
|
|
||||||
|
assert.Equal(t, "allOfBExp", qwExample)
|
||||||
|
|
||||||
// check polymorphic values anyOf
|
// check polymorphic values anyOf
|
||||||
assert.Equal(t, "an anyOf thing", sch.AnyOf.Value[0].Value.Schema().Description.Value)
|
assert.Equal(t, "an anyOf thing", sch.AnyOf.Value[0].Value.Schema().Description.Value)
|
||||||
@@ -227,12 +236,18 @@ func Test_Schema(t *testing.T) {
|
|||||||
v = sch.AnyOf.Value[0].Value.Schema().FindProperty("anyOfA")
|
v = sch.AnyOf.Value[0].Value.Schema().FindProperty("anyOfA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "anyOfA description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "anyOfA description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "anyOfAExp", v.Value.Schema().Example.Value)
|
|
||||||
|
var vSchemaExample string
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
|
||||||
|
assert.Equal(t, "anyOfAExp", vSchemaExample)
|
||||||
|
|
||||||
v = sch.AnyOf.Value[0].Value.Schema().FindProperty("anyOfB")
|
v = sch.AnyOf.Value[0].Value.Schema().FindProperty("anyOfB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "anyOfB description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "anyOfB description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "anyOfBExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "anyOfBExp", vSchemaExample)
|
||||||
|
|
||||||
// check polymorphic values oneOf
|
// check polymorphic values oneOf
|
||||||
assert.Equal(t, "a oneof thing", sch.OneOf.Value[0].Value.Schema().Description.Value)
|
assert.Equal(t, "a oneof thing", sch.OneOf.Value[0].Value.Schema().Description.Value)
|
||||||
@@ -241,12 +256,16 @@ func Test_Schema(t *testing.T) {
|
|||||||
v = sch.OneOf.Value[0].Value.Schema().FindProperty("oneOfA")
|
v = sch.OneOf.Value[0].Value.Schema().FindProperty("oneOfA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "oneOfA description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "oneOfA description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "oneOfAExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "oneOfAExp", vSchemaExample)
|
||||||
|
|
||||||
v = sch.OneOf.Value[0].Value.Schema().FindProperty("oneOfB")
|
v = sch.OneOf.Value[0].Value.Schema().FindProperty("oneOfB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "oneOfB description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "oneOfB description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "oneOfBExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "oneOfBExp", vSchemaExample)
|
||||||
|
|
||||||
// check values NOT
|
// check values NOT
|
||||||
assert.Equal(t, "a not thing", sch.Not.Value.Schema().Description.Value)
|
assert.Equal(t, "a not thing", sch.Not.Value.Schema().Description.Value)
|
||||||
@@ -255,12 +274,16 @@ func Test_Schema(t *testing.T) {
|
|||||||
v = sch.Not.Value.Schema().FindProperty("notA")
|
v = sch.Not.Value.Schema().FindProperty("notA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "notA description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "notA description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "notAExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "notAExp", vSchemaExample)
|
||||||
|
|
||||||
v = sch.Not.Value.Schema().FindProperty("notB")
|
v = sch.Not.Value.Schema().FindProperty("notB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "notB description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "notB description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "notBExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "notBExp", vSchemaExample)
|
||||||
|
|
||||||
// check values Items
|
// check values Items
|
||||||
assert.Equal(t, "an items thing", sch.Items.Value.A.Schema().Description.Value)
|
assert.Equal(t, "an items thing", sch.Items.Value.A.Schema().Description.Value)
|
||||||
@@ -269,12 +292,16 @@ func Test_Schema(t *testing.T) {
|
|||||||
v = sch.Items.Value.A.Schema().FindProperty("itemsA")
|
v = sch.Items.Value.A.Schema().FindProperty("itemsA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsA description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "itemsA description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "itemsAExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "itemsAExp", vSchemaExample)
|
||||||
|
|
||||||
v = sch.Items.Value.A.Schema().FindProperty("itemsB")
|
v = sch.Items.Value.A.Schema().FindProperty("itemsB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsB description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "itemsB description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "itemsBExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "itemsBExp", vSchemaExample)
|
||||||
|
|
||||||
// check values PrefixItems
|
// check values PrefixItems
|
||||||
assert.Equal(t, "an items thing", sch.PrefixItems.Value[0].Value.Schema().Description.Value)
|
assert.Equal(t, "an items thing", sch.PrefixItems.Value[0].Value.Schema().Description.Value)
|
||||||
@@ -283,17 +310,21 @@ func Test_Schema(t *testing.T) {
|
|||||||
v = sch.PrefixItems.Value[0].Value.Schema().FindProperty("itemsA")
|
v = sch.PrefixItems.Value[0].Value.Schema().FindProperty("itemsA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsA description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "itemsA description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "itemsAExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValueNode().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "itemsAExp", vSchemaExample)
|
||||||
|
|
||||||
v = sch.PrefixItems.Value[0].Value.Schema().FindProperty("itemsB")
|
v = sch.PrefixItems.Value[0].Value.Schema().FindProperty("itemsB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsB description", v.Value.Schema().Description.Value)
|
assert.Equal(t, "itemsB description", v.Value.Schema().Description.Value)
|
||||||
assert.Equal(t, "itemsBExp", v.Value.Schema().Example.Value)
|
|
||||||
|
_ = v.GetValue().Schema().Example.GetValue().Decode(&vSchemaExample)
|
||||||
|
assert.Equal(t, "itemsBExp", vSchemaExample)
|
||||||
|
|
||||||
// check discriminator
|
// check discriminator
|
||||||
assert.NotNil(t, sch.Discriminator.Value)
|
assert.NotNil(t, sch.Discriminator.Value)
|
||||||
assert.Equal(t, "athing", sch.Discriminator.Value.PropertyName.Value)
|
assert.Equal(t, "athing", sch.Discriminator.Value.PropertyName.Value)
|
||||||
assert.Len(t, sch.Discriminator.Value.Mapping.Value, 2)
|
assert.Equal(t, 2, sch.Discriminator.GetValue().Mapping.GetValue().Len())
|
||||||
mv := sch.Discriminator.Value.FindMappingValue("log")
|
mv := sch.Discriminator.Value.FindMappingValue("log")
|
||||||
assert.Equal(t, "cat", mv.Value)
|
assert.Equal(t, "cat", mv.Value)
|
||||||
mv = sch.Discriminator.Value.FindMappingValue("pizza")
|
mv = sch.Discriminator.Value.FindMappingValue("pizza")
|
||||||
@@ -429,12 +460,20 @@ const: tasty`
|
|||||||
assert.Equal(t, float64(12), sch.ExclusiveMinimum.Value.B)
|
assert.Equal(t, float64(12), sch.ExclusiveMinimum.Value.B)
|
||||||
assert.Equal(t, float64(13), sch.ExclusiveMaximum.Value.B)
|
assert.Equal(t, float64(13), sch.ExclusiveMaximum.Value.B)
|
||||||
assert.Len(t, sch.Examples.Value, 1)
|
assert.Len(t, sch.Examples.Value, 1)
|
||||||
assert.Equal(t, "testing", sch.Examples.Value[0].Value)
|
|
||||||
|
var example0 string
|
||||||
|
_ = sch.Examples.GetValue()[0].GetValue().Decode(&example0)
|
||||||
|
|
||||||
|
assert.Equal(t, "testing", example0)
|
||||||
assert.Equal(t, "fish64", sch.ContentEncoding.Value)
|
assert.Equal(t, "fish64", sch.ContentEncoding.Value)
|
||||||
assert.Equal(t, "fish/paste", sch.ContentMediaType.Value)
|
assert.Equal(t, "fish/paste", sch.ContentMediaType.Value)
|
||||||
assert.True(t, sch.Items.Value.IsB())
|
assert.True(t, sch.Items.Value.IsB())
|
||||||
assert.True(t, sch.Items.Value.B)
|
assert.True(t, sch.Items.Value.B)
|
||||||
assert.Equal(t, "tasty", sch.Const.Value)
|
|
||||||
|
var schConst string
|
||||||
|
_ = sch.Const.GetValue().Decode(&schConst)
|
||||||
|
|
||||||
|
assert.Equal(t, "tasty", schConst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchema_Build_PropsLookup(t *testing.T) {
|
func TestSchema_Build_PropsLookup(t *testing.T) {
|
||||||
@@ -986,7 +1025,11 @@ schema:
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res.Value)
|
assert.NotNil(t, res.Value)
|
||||||
sch := res.Value.Schema()
|
sch := res.Value.Schema()
|
||||||
assert.Equal(t, 5, sch.Default.Value)
|
|
||||||
|
var def int
|
||||||
|
_ = sch.Default.GetValueNode().Decode(&def)
|
||||||
|
|
||||||
|
assert.Equal(t, 5, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractSchema_ConstPrimitive(t *testing.T) {
|
func TestExtractSchema_ConstPrimitive(t *testing.T) {
|
||||||
@@ -1002,7 +1045,11 @@ schema:
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res.Value)
|
assert.NotNil(t, res.Value)
|
||||||
sch := res.Value.Schema()
|
sch := res.Value.Schema()
|
||||||
assert.Equal(t, 5, sch.Const.Value)
|
|
||||||
|
var cnst int
|
||||||
|
_ = sch.Const.GetValueNode().Decode(&cnst)
|
||||||
|
|
||||||
|
assert.Equal(t, 5, cnst)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractSchema_Ref(t *testing.T) {
|
func TestExtractSchema_Ref(t *testing.T) {
|
||||||
@@ -1785,7 +1832,6 @@ components:
|
|||||||
res, e := ExtractSchema(context.Background(), idxNode.Content[0], idx)
|
res, e := ExtractSchema(context.Background(), idxNode.Content[0], idx)
|
||||||
assert.Nil(t, res)
|
assert.Nil(t, res)
|
||||||
assert.Equal(t, "schema build failed: reference '[empty]' cannot be found at line 2, col 9", e.Error())
|
assert.Equal(t, "schema build failed: reference '[empty]' cannot be found at line 2, col 9", e.Error())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSchema_EmptyRef(t *testing.T) {
|
func TestSchema_EmptyRef(t *testing.T) {
|
||||||
@@ -1814,5 +1860,4 @@ components:
|
|||||||
res, e := ExtractSchema(context.Background(), idxNode.Content[0], idx)
|
res, e := ExtractSchema(context.Background(), idxNode.Content[0], idx)
|
||||||
assert.Nil(t, res)
|
assert.Nil(t, res)
|
||||||
assert.Equal(t, "schema build failed: reference '[empty]' cannot be found at line 1, col 7", e.Error())
|
assert.Equal(t, "schema build failed: reference '[empty]' cannot be found at line 1, col 7", e.Error())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
||||||
// - https://swagger.io/specification/#security-requirement-object
|
// - https://swagger.io/specification/#security-requirement-object
|
||||||
type SecurityRequirement struct {
|
type SecurityRequirement struct {
|
||||||
Requirements low.ValueReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]]
|
Requirements low.ValueReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ func (s *SecurityRequirement) Build(_ context.Context, _, root *yaml.Node, _ *in
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
s.Requirements = low.ValueReference[orderedmap.Map[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]]{
|
s.Requirements = low.ValueReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[[]low.ValueReference[string]]]]{
|
||||||
Value: valueMap,
|
Value: valueMap,
|
||||||
ValueNode: root,
|
ValueNode: root,
|
||||||
}
|
}
|
||||||
@@ -91,22 +91,14 @@ func (s *SecurityRequirement) GetKeys() []string {
|
|||||||
// Hash will return a consistent SHA256 Hash of the SecurityRequirement object
|
// Hash will return a consistent SHA256 Hash of the SecurityRequirement object
|
||||||
func (s *SecurityRequirement) Hash() [32]byte {
|
func (s *SecurityRequirement) Hash() [32]byte {
|
||||||
var f []string
|
var f []string
|
||||||
values := make(map[string][]string, orderedmap.Len(s.Requirements.Value))
|
for pair := orderedmap.First(orderedmap.SortAlpha(s.Requirements.Value)); pair != nil; pair = pair.Next() {
|
||||||
var valKeys []string
|
|
||||||
for pair := orderedmap.First(s.Requirements.Value); pair != nil; pair = pair.Next() {
|
|
||||||
var vals []string
|
var vals []string
|
||||||
for y := range pair.Value().Value {
|
for y := range pair.Value().Value {
|
||||||
vals = append(vals, pair.Value().Value[y].Value)
|
vals = append(vals, pair.Value().Value[y].Value)
|
||||||
}
|
}
|
||||||
sort.Strings(vals)
|
sort.Strings(vals)
|
||||||
valKeys = append(valKeys, pair.Key().Value)
|
|
||||||
if len(vals) > 0 {
|
f = append(f, fmt.Sprintf("%s-%s", pair.Key().Value, strings.Join(vals, "|")))
|
||||||
values[pair.Key().Value] = vals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(valKeys)
|
|
||||||
for val := range valKeys {
|
|
||||||
f = append(f, fmt.Sprintf("%s-%s", valKeys[val], strings.Join(values[valKeys[val]], "|")))
|
|
||||||
}
|
}
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ package base
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tag represents a low-level Tag instance that is backed by a low-level one.
|
// Tag represents a low-level Tag instance that is backed by a low-level one.
|
||||||
@@ -25,13 +25,13 @@ type Tag struct {
|
|||||||
Name low.NodeReference[string]
|
Name low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
ExternalDocs low.NodeReference[*ExternalDoc]
|
ExternalDocs low.NodeReference[*ExternalDoc]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension returns a ValueReference containing the extension value, if found.
|
// FindExtension returns a ValueReference containing the extension value, if found.
|
||||||
func (t *Tag) FindExtension(ext string) *low.ValueReference[any] {
|
func (t *Tag) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, t.Extensions)
|
return low.FindItemInOrderedMap(ext, t.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions and external docs for the Tag.
|
// Build will extract extensions and external docs for the Tag.
|
||||||
@@ -48,7 +48,7 @@ func (t *Tag) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecInde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface.
|
||||||
func (t *Tag) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (t *Tag) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return t.Extensions
|
return t.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,13 +64,6 @@ func (t *Tag) Hash() [32]byte {
|
|||||||
if !t.ExternalDocs.IsEmpty() {
|
if !t.ExternalDocs.IsEmpty() {
|
||||||
f = append(f, low.GenerateHashString(t.ExternalDocs.Value))
|
f = append(f, low.GenerateHashString(t.ExternalDocs.Value))
|
||||||
}
|
}
|
||||||
keys := make([]string, len(t.Extensions))
|
f = append(f, low.HashExtensions(t.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range t.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(t.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package base
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTag_Build(t *testing.T) {
|
func TestTag_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `name: a tag
|
yml := `name: a tag
|
||||||
description: a description
|
description: a description
|
||||||
externalDocs:
|
externalDocs:
|
||||||
@@ -33,13 +34,15 @@ x-coffee: tasty`
|
|||||||
assert.Equal(t, "a tag", n.Name.Value)
|
assert.Equal(t, "a tag", n.Name.Value)
|
||||||
assert.Equal(t, "a description", n.Description.Value)
|
assert.Equal(t, "a description", n.Description.Value)
|
||||||
assert.Equal(t, "https://pb33f.io", n.ExternalDocs.Value.URL.Value)
|
assert.Equal(t, "https://pb33f.io", n.ExternalDocs.Value.URL.Value)
|
||||||
assert.Equal(t, "tasty", n.FindExtension("x-coffee").Value)
|
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
|
||||||
|
|
||||||
|
var xCoffee string
|
||||||
|
_ = n.FindExtension("x-coffee").GetValue().Decode(&xCoffee)
|
||||||
|
|
||||||
|
assert.Equal(t, "tasty", xCoffee)
|
||||||
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTag_Build_Error(t *testing.T) {
|
func TestTag_Build_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `name: a tag
|
yml := `name: a tag
|
||||||
description: a description
|
description: a description
|
||||||
externalDocs:
|
externalDocs:
|
||||||
@@ -58,7 +61,6 @@ externalDocs:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTag_Hash(t *testing.T) {
|
func TestTag_Hash(t *testing.T) {
|
||||||
|
|
||||||
left := `name: melody
|
left := `name: melody
|
||||||
description: my princess
|
description: my princess
|
||||||
externalDocs:
|
externalDocs:
|
||||||
@@ -84,5 +86,4 @@ x-b33f: princess`
|
|||||||
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
_ = rDoc.Build(context.Background(), nil, rNode.Content[0], nil)
|
||||||
|
|
||||||
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
assert.Equal(t, lDoc.Hash(), rDoc.Hash())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ package base
|
|||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// XML represents a low-level representation of an XML object defined by all versions of OpenAPI.
|
// XML represents a low-level representation of an XML object defined by all versions of OpenAPI.
|
||||||
@@ -26,7 +27,7 @@ type XML struct {
|
|||||||
Prefix low.NodeReference[string]
|
Prefix low.NodeReference[string]
|
||||||
Attribute low.NodeReference[bool]
|
Attribute low.NodeReference[bool]
|
||||||
Wrapped low.NodeReference[bool]
|
Wrapped low.NodeReference[bool]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ func (x *XML) Build(root *yaml.Node, _ *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Tag extensions and satisfies the low.HasExtensions interface.
|
||||||
func (x *XML) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (x *XML) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return x.Extensions
|
return x.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +63,6 @@ func (x *XML) Hash() [32]byte {
|
|||||||
if !x.Wrapped.IsEmpty() {
|
if !x.Wrapped.IsEmpty() {
|
||||||
f = append(f, fmt.Sprint(x.Wrapped.Value))
|
f = append(f, fmt.Sprint(x.Wrapped.Value))
|
||||||
}
|
}
|
||||||
keys := make([]string, len(x.Extensions))
|
f = append(f, low.HashExtensions(x.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range x.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(x.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,37 +7,24 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FindItemInMap accepts a string key and a collection of KeyReference[string] and ValueReference[T]. Every
|
|
||||||
// KeyReference will have its value checked against the string key and if there is a match, it will be returned.
|
|
||||||
func FindItemInMap[T any](item string, collection map[KeyReference[string]]ValueReference[T]) *ValueReference[T] {
|
|
||||||
for n, o := range collection {
|
|
||||||
if n.Value == item {
|
|
||||||
return &o
|
|
||||||
}
|
|
||||||
if strings.EqualFold(item, n.Value) {
|
|
||||||
return &o
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindItemInOrderedMap accepts a string key and a collection of KeyReference[string] and ValueReference[T].
|
// FindItemInOrderedMap accepts a string key and a collection of KeyReference[string] and ValueReference[T].
|
||||||
// Every KeyReference will have its value checked against the string key and if there is a match, it will be
|
// Every KeyReference will have its value checked against the string key and if there is a match, it will be
|
||||||
// returned.
|
// returned.
|
||||||
func FindItemInOrderedMap[T any](item string, collection orderedmap.Map[KeyReference[string], ValueReference[T]]) *ValueReference[T] {
|
func FindItemInOrderedMap[T any](item string, collection *orderedmap.Map[KeyReference[string], ValueReference[T]]) *ValueReference[T] {
|
||||||
for pair := orderedmap.First(collection); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(collection); pair != nil; pair = pair.Next() {
|
||||||
n := pair.Key()
|
n := pair.Key()
|
||||||
if n.Value == item {
|
if n.Value == item {
|
||||||
@@ -50,6 +37,18 @@ func FindItemInOrderedMap[T any](item string, collection orderedmap.Map[KeyRefer
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashExtensions will generate a hash from the low representation of extensions.
|
||||||
|
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))))
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
// helper function to generate a list of all the things an index should be searched for.
|
// helper function to generate a list of all the things an index should be searched for.
|
||||||
func generateIndexCollection(idx *index.SpecIndex) []func() map[string]*index.Reference {
|
func generateIndexCollection(idx *index.SpecIndex) []func() map[string]*index.Reference {
|
||||||
return []func() map[string]*index.Reference{
|
return []func() map[string]*index.Reference{
|
||||||
@@ -68,7 +67,6 @@ func generateIndexCollection(idx *index.SpecIndex) []func() map[string]*index.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (*yaml.Node, *index.SpecIndex, error, context.Context) {
|
func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.SpecIndex) (*yaml.Node, *index.SpecIndex, error, context.Context) {
|
||||||
|
|
||||||
if rf, _, rv := utils.IsNodeRefValue(root); rf {
|
if rf, _, rv := utils.IsNodeRefValue(root); rf {
|
||||||
|
|
||||||
if rv == "" {
|
if rv == "" {
|
||||||
@@ -112,9 +110,7 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
explodedRefValue := strings.Split(rv, "#")
|
explodedRefValue := strings.Split(rv, "#")
|
||||||
if len(explodedRefValue) == 2 {
|
if len(explodedRefValue) == 2 {
|
||||||
if !strings.HasPrefix(explodedRefValue[0], "http") {
|
if !strings.HasPrefix(explodedRefValue[0], "http") {
|
||||||
|
|
||||||
if !filepath.IsAbs(explodedRefValue[0]) {
|
if !filepath.IsAbs(explodedRefValue[0]) {
|
||||||
|
|
||||||
if strings.HasPrefix(specPath, "http") {
|
if strings.HasPrefix(specPath, "http") {
|
||||||
u, _ := url.Parse(specPath)
|
u, _ := url.Parse(specPath)
|
||||||
p := ""
|
p := ""
|
||||||
@@ -137,7 +133,6 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
}
|
}
|
||||||
rv = fmt.Sprintf("%s#%s", abs, explodedRefValue[1])
|
rv = fmt.Sprintf("%s#%s", abs, explodedRefValue[1])
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// check for a config baseURL and use that if it exists.
|
// check for a config baseURL and use that if it exists.
|
||||||
if idx.GetConfig().BaseURL != nil {
|
if idx.GetConfig().BaseURL != nil {
|
||||||
|
|
||||||
@@ -154,11 +149,8 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if !strings.HasPrefix(explodedRefValue[0], "http") {
|
if !strings.HasPrefix(explodedRefValue[0], "http") {
|
||||||
|
|
||||||
if !filepath.IsAbs(explodedRefValue[0]) {
|
if !filepath.IsAbs(explodedRefValue[0]) {
|
||||||
|
|
||||||
if strings.HasPrefix(specPath, "http") {
|
if strings.HasPrefix(specPath, "http") {
|
||||||
u, _ := url.Parse(specPath)
|
u, _ := url.Parse(specPath)
|
||||||
p := filepath.Dir(u.Path)
|
p := filepath.Dir(u.Path)
|
||||||
@@ -173,7 +165,6 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
rv = abs
|
rv = abs
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// check for a config baseURL and use that if it exists.
|
// check for a config baseURL and use that if it exists.
|
||||||
if idx.GetConfig().BaseURL != nil {
|
if idx.GetConfig().BaseURL != nil {
|
||||||
u := *idx.GetConfig().BaseURL
|
u := *idx.GetConfig().BaseURL
|
||||||
@@ -211,7 +202,6 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
rv, root.Line, root.Column), ctx
|
rv, root.Line, root.Column), ctx
|
||||||
}
|
}
|
||||||
return nil, idx, nil, ctx
|
return nil, idx, nil, ctx
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocateRefNode will perform a complete lookup for a $ref node. This function searches the entire index for
|
// LocateRefNode will perform a complete lookup for a $ref node. This function searches the entire index for
|
||||||
@@ -227,10 +217,12 @@ func ExtractObjectRaw[T Buildable[N], N any](ctx context.Context, key, root *yam
|
|||||||
var circError error
|
var circError error
|
||||||
var isReference bool
|
var isReference bool
|
||||||
var referenceValue string
|
var referenceValue string
|
||||||
|
var refNode *yaml.Node
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
if h, _, rv := utils.IsNodeRefValue(root); h {
|
if h, _, rv := utils.IsNodeRefValue(root); h {
|
||||||
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, root, idx)
|
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, root, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = root
|
||||||
root = ref
|
root = ref
|
||||||
isReference = true
|
isReference = true
|
||||||
referenceValue = rv
|
referenceValue = rv
|
||||||
@@ -257,7 +249,7 @@ func ExtractObjectRaw[T Buildable[N], N any](ctx context.Context, key, root *yam
|
|||||||
|
|
||||||
// if this is a reference, keep track of the reference in the value
|
// if this is a reference, keep track of the reference in the value
|
||||||
if isReference {
|
if isReference {
|
||||||
SetReference(n, referenceValue)
|
SetReference(n, referenceValue, refNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we want to throw an error as well if circular error reporting is on?
|
// do we want to throw an error as well if circular error reporting is on?
|
||||||
@@ -274,10 +266,12 @@ func ExtractObject[T Buildable[N], N any](ctx context.Context, label string, roo
|
|||||||
var circError error
|
var circError error
|
||||||
var isReference bool
|
var isReference bool
|
||||||
var referenceValue string
|
var referenceValue string
|
||||||
|
var refNode *yaml.Node
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
if rf, rl, refVal := utils.IsNodeRefValue(root); rf {
|
if rf, rl, refVal := utils.IsNodeRefValue(root); rf {
|
||||||
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, root, idx)
|
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, root, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = root
|
||||||
vn = ref
|
vn = ref
|
||||||
ln = rl
|
ln = rl
|
||||||
isReference = true
|
isReference = true
|
||||||
@@ -298,6 +292,7 @@ func ExtractObject[T Buildable[N], N any](ctx context.Context, label string, roo
|
|||||||
if h, _, rVal := utils.IsNodeRefValue(vn); h {
|
if h, _, rVal := utils.IsNodeRefValue(vn); h {
|
||||||
ref, fIdx, lerr, nCtx := LocateRefNodeWithContext(ctx, vn, idx)
|
ref, fIdx, lerr, nCtx := LocateRefNodeWithContext(ctx, vn, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = vn
|
||||||
vn = ref
|
vn = ref
|
||||||
if fIdx != nil {
|
if fIdx != nil {
|
||||||
idx = fIdx
|
idx = fIdx
|
||||||
@@ -331,16 +326,15 @@ func ExtractObject[T Buildable[N], N any](ctx context.Context, label string, roo
|
|||||||
|
|
||||||
// if this is a reference, keep track of the reference in the value
|
// if this is a reference, keep track of the reference in the value
|
||||||
if isReference {
|
if isReference {
|
||||||
SetReference(n, referenceValue)
|
SetReference(n, referenceValue, refNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := NodeReference[T]{
|
res := NodeReference[T]{
|
||||||
Value: n,
|
Value: n,
|
||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
ReferenceNode: isReference,
|
|
||||||
Reference: referenceValue,
|
|
||||||
}
|
}
|
||||||
|
res.SetReference(referenceValue, refNode)
|
||||||
|
|
||||||
// do we want to throw an error as well if circular error reporting is on?
|
// do we want to throw an error as well if circular error reporting is on?
|
||||||
if circError != nil && !idx.AllowCircularReferenceResolving() {
|
if circError != nil && !idx.AllowCircularReferenceResolving() {
|
||||||
@@ -349,12 +343,13 @@ func ExtractObject[T Buildable[N], N any](ctx context.Context, label string, roo
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetReference(obj any, ref string) {
|
func SetReference(obj any, ref string, refNode *yaml.Node) {
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r, ok := obj.(IsReferenced); ok {
|
|
||||||
r.SetReference(ref)
|
if r, ok := obj.(SetReferencer); ok {
|
||||||
|
r.SetReference(ref, refNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,9 +424,12 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
foundCtx := ctx
|
foundCtx := ctx
|
||||||
foundIndex := idx
|
foundIndex := idx
|
||||||
|
|
||||||
|
var refNode *yaml.Node
|
||||||
|
|
||||||
if rf, _, rv := utils.IsNodeRefValue(node); rf {
|
if rf, _, rv := utils.IsNodeRefValue(node); rf {
|
||||||
refg, fIdx, err, nCtx := LocateRefEnd(ctx, node, idx, 0)
|
refg, fIdx, err, nCtx := LocateRefEnd(ctx, node, idx, 0)
|
||||||
if refg != nil {
|
if refg != nil {
|
||||||
|
refNode = node
|
||||||
node = refg
|
node = refg
|
||||||
localReferenceValue = rv
|
localReferenceValue = rv
|
||||||
foundIndex = fIdx
|
foundIndex = fIdx
|
||||||
@@ -457,15 +455,16 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
}
|
}
|
||||||
|
|
||||||
if localReferenceValue != "" {
|
if localReferenceValue != "" {
|
||||||
SetReference(n, localReferenceValue)
|
SetReference(n, localReferenceValue, refNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
items = append(items, ValueReference[T]{
|
v := ValueReference[T]{
|
||||||
Value: n,
|
Value: n,
|
||||||
ValueNode: node,
|
ValueNode: node,
|
||||||
ReferenceNode: localReferenceValue != "",
|
}
|
||||||
Reference: localReferenceValue,
|
v.SetReference(localReferenceValue, refNode)
|
||||||
})
|
|
||||||
|
items = append(items, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// include circular errors?
|
// include circular errors?
|
||||||
@@ -475,23 +474,6 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
return items, ln, vn, nil
|
return items, ln, vn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractExample will extract a value supplied as an example into a NodeReference. Value can be anything.
|
|
||||||
// the node value is untyped, so casting will be required when trying to use it.
|
|
||||||
func ExtractExample(expNode, expLabel *yaml.Node) NodeReference[any] {
|
|
||||||
ref := NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
|
||||||
if utils.IsNodeMap(expNode) {
|
|
||||||
var decoded map[string]interface{}
|
|
||||||
_ = expNode.Decode(&decoded)
|
|
||||||
ref.Value = decoded
|
|
||||||
}
|
|
||||||
if utils.IsNodeArray(expNode) {
|
|
||||||
var decoded []interface{}
|
|
||||||
_ = expNode.Decode(&decoded)
|
|
||||||
ref.Value = decoded
|
|
||||||
}
|
|
||||||
return ref
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractMapNoLookupExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
// ExtractMapNoLookupExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
||||||
// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the
|
// refers to the fact that there is no key supplied as part of the extraction, there is no lookup performed and the
|
||||||
// root yaml.Node pointer is used directly. Pass a true bit to includeExtensions to include extension keys in the map.
|
// root yaml.Node pointer is used directly. Pass a true bit to includeExtensions to include extension keys in the map.
|
||||||
@@ -502,7 +484,7 @@ func ExtractMapNoLookupExtensions[PT Buildable[N], N any](
|
|||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
includeExtensions bool,
|
includeExtensions bool,
|
||||||
) (orderedmap.Map[KeyReference[string], ValueReference[PT]], error) {
|
) (*orderedmap.Map[KeyReference[string], ValueReference[PT]], error) {
|
||||||
valueMap := orderedmap.New[KeyReference[string], ValueReference[PT]]()
|
valueMap := orderedmap.New[KeyReference[string], ValueReference[PT]]()
|
||||||
var circError error
|
var circError error
|
||||||
if utils.IsNodeMap(root) {
|
if utils.IsNodeMap(root) {
|
||||||
@@ -540,10 +522,12 @@ func ExtractMapNoLookupExtensions[PT Buildable[N], N any](
|
|||||||
|
|
||||||
var isReference bool
|
var isReference bool
|
||||||
var referenceValue string
|
var referenceValue string
|
||||||
|
var refNode *yaml.Node
|
||||||
// if value is a reference, we have to look it up in the index!
|
// if value is a reference, we have to look it up in the index!
|
||||||
if h, _, rv := utils.IsNodeRefValue(node); h {
|
if h, _, rv := utils.IsNodeRefValue(node); h {
|
||||||
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, node, idx)
|
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, node, idx)
|
||||||
if ref != nil {
|
if ref != nil {
|
||||||
|
refNode = node
|
||||||
node = ref
|
node = ref
|
||||||
isReference = true
|
isReference = true
|
||||||
referenceValue = rv
|
referenceValue = rv
|
||||||
@@ -570,19 +554,21 @@ func ExtractMapNoLookupExtensions[PT Buildable[N], N any](
|
|||||||
return nil, berr
|
return nil, berr
|
||||||
}
|
}
|
||||||
if isReference {
|
if isReference {
|
||||||
SetReference(n, referenceValue)
|
SetReference(n, referenceValue, refNode)
|
||||||
}
|
}
|
||||||
if currentKey != nil {
|
if currentKey != nil {
|
||||||
|
v := ValueReference[PT]{
|
||||||
|
Value: n,
|
||||||
|
ValueNode: node,
|
||||||
|
}
|
||||||
|
v.SetReference(referenceValue, refNode)
|
||||||
|
|
||||||
valueMap.Set(
|
valueMap.Set(
|
||||||
KeyReference[string]{
|
KeyReference[string]{
|
||||||
Value: currentKey.Value,
|
Value: currentKey.Value,
|
||||||
KeyNode: currentKey,
|
KeyNode: currentKey,
|
||||||
},
|
},
|
||||||
ValueReference[PT]{
|
v,
|
||||||
Value: n,
|
|
||||||
ValueNode: node,
|
|
||||||
Reference: referenceValue,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,7 +577,6 @@ func ExtractMapNoLookupExtensions[PT Buildable[N], N any](
|
|||||||
return valueMap, circError
|
return valueMap, circError
|
||||||
}
|
}
|
||||||
return valueMap, nil
|
return valueMap, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractMapNoLookup will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
// ExtractMapNoLookup will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'NoLookup' part
|
||||||
@@ -603,7 +588,7 @@ func ExtractMapNoLookup[PT Buildable[N], N any](
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
) (orderedmap.Map[KeyReference[string], ValueReference[PT]], error) {
|
) (*orderedmap.Map[KeyReference[string], ValueReference[PT]], error) {
|
||||||
return ExtractMapNoLookupExtensions[PT, N](ctx, root, idx, false)
|
return ExtractMapNoLookupExtensions[PT, N](ctx, root, idx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +609,186 @@ func ExtractMapExtensions[PT Buildable[N], N any](
|
|||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
extensions bool,
|
extensions bool,
|
||||||
) (orderedmap.Map[KeyReference[string], ValueReference[PT]], *yaml.Node, *yaml.Node, error) {
|
) (*orderedmap.Map[KeyReference[string], ValueReference[PT]], *yaml.Node, *yaml.Node, error) {
|
||||||
|
var labelNode, valueNode *yaml.Node
|
||||||
|
var circError error
|
||||||
|
root = utils.NodeAlias(root)
|
||||||
|
if rf, rl, _ := utils.IsNodeRefValue(root); rf {
|
||||||
|
// locate reference in index.
|
||||||
|
ref, fIdx, err, fCtx := LocateRefNodeWithContext(ctx, root, idx)
|
||||||
|
if ref != nil {
|
||||||
|
valueNode = ref
|
||||||
|
labelNode = rl
|
||||||
|
ctx = fCtx
|
||||||
|
idx = fIdx
|
||||||
|
if err != nil {
|
||||||
|
circError = err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, labelNode, valueNode, fmt.Errorf("map build failed: reference cannot be found: %s",
|
||||||
|
root.Content[1].Value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
|
||||||
|
valueNode = utils.NodeAlias(valueNode)
|
||||||
|
if valueNode != nil {
|
||||||
|
if h, _, _ := utils.IsNodeRefValue(valueNode); h {
|
||||||
|
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, valueNode, idx)
|
||||||
|
if ref != nil {
|
||||||
|
valueNode = ref
|
||||||
|
idx = fIdx
|
||||||
|
ctx = nCtx
|
||||||
|
if err != nil {
|
||||||
|
circError = err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
return nil, labelNode, valueNode, fmt.Errorf("map build failed: reference cannot be found: %s",
|
||||||
|
err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if valueNode != nil {
|
||||||
|
valueMap := orderedmap.New[KeyReference[string], ValueReference[PT]]()
|
||||||
|
|
||||||
|
type buildInput struct {
|
||||||
|
label *yaml.Node
|
||||||
|
value *yaml.Node
|
||||||
|
}
|
||||||
|
in := make(chan buildInput)
|
||||||
|
out := make(chan mappingResult[PT])
|
||||||
|
done := make(chan struct{})
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2) // input and output goroutines.
|
||||||
|
|
||||||
|
// TranslatePipeline input.
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
close(in)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
var currentLabelNode *yaml.Node
|
||||||
|
for i, en := range valueNode.Content {
|
||||||
|
if !extensions {
|
||||||
|
if strings.HasPrefix(en.Value, "x-") {
|
||||||
|
continue // yo, don't pay any attention to extensions, not here anyway.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
en = utils.NodeAlias(en)
|
||||||
|
if i%2 == 0 {
|
||||||
|
currentLabelNode = en
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case in <- buildInput{
|
||||||
|
label: currentLabelNode,
|
||||||
|
value: en,
|
||||||
|
}:
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TranslatePipeline output.
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
result, ok := <-out
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
valueMap.Set(result.k, result.v)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
translateFunc := func(input buildInput) (mappingResult[PT], error) {
|
||||||
|
foundIndex := idx
|
||||||
|
foundContext := ctx
|
||||||
|
|
||||||
|
en := input.value
|
||||||
|
|
||||||
|
var refNode *yaml.Node
|
||||||
|
var referenceValue string
|
||||||
|
// check our valueNode isn't a reference still.
|
||||||
|
if h, _, refVal := utils.IsNodeRefValue(en); h {
|
||||||
|
ref, fIdx, err, nCtx := LocateRefNodeWithContext(ctx, en, idx)
|
||||||
|
if ref != nil {
|
||||||
|
refNode = en
|
||||||
|
en = ref
|
||||||
|
referenceValue = refVal
|
||||||
|
if fIdx != nil {
|
||||||
|
foundIndex = fIdx
|
||||||
|
}
|
||||||
|
foundContext = nCtx
|
||||||
|
if err != nil {
|
||||||
|
circError = err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
return mappingResult[PT]{}, fmt.Errorf("flat map build failed: reference cannot be found: %s",
|
||||||
|
err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var n PT = new(N)
|
||||||
|
en = utils.NodeAlias(en)
|
||||||
|
_ = BuildModel(en, n)
|
||||||
|
err := n.Build(foundContext, input.label, en, foundIndex)
|
||||||
|
if err != nil {
|
||||||
|
return mappingResult[PT]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if referenceValue != "" {
|
||||||
|
SetReference(n, referenceValue, refNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
v := ValueReference[PT]{
|
||||||
|
Value: n,
|
||||||
|
ValueNode: en,
|
||||||
|
}
|
||||||
|
v.SetReference(referenceValue, refNode)
|
||||||
|
|
||||||
|
return mappingResult[PT]{
|
||||||
|
k: KeyReference[string]{
|
||||||
|
KeyNode: input.label,
|
||||||
|
Value: input.label.Value,
|
||||||
|
},
|
||||||
|
v: v,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
err := datamodel.TranslatePipeline[buildInput, mappingResult[PT]](in, out, translateFunc)
|
||||||
|
wg.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return nil, labelNode, valueNode, err
|
||||||
|
}
|
||||||
|
if circError != nil && !idx.AllowCircularReferenceResolving() {
|
||||||
|
return valueMap, labelNode, valueNode, circError
|
||||||
|
}
|
||||||
|
return valueMap, labelNode, valueNode, nil
|
||||||
|
}
|
||||||
|
return nil, labelNode, valueNode, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractMapExtensions will extract a map of KeyReference and ValueReference from a root yaml.Node. The 'label' is
|
||||||
|
// used to locate the node to be extracted from the root node supplied. Supply a bit to decide if extensions should
|
||||||
|
// be included or not. required in some use cases.
|
||||||
|
//
|
||||||
|
// The second return value is the yaml.Node found for the 'label' and the third return value is the yaml.Node
|
||||||
|
// found for the value extracted from the label node.
|
||||||
|
func ExtractMapExtensionsOld[PT Buildable[N], N any](
|
||||||
|
ctx context.Context,
|
||||||
|
label string,
|
||||||
|
root *yaml.Node,
|
||||||
|
idx *index.SpecIndex,
|
||||||
|
extensions bool,
|
||||||
|
) (*orderedmap.Map[KeyReference[string], ValueReference[PT]], *yaml.Node, *yaml.Node, error) {
|
||||||
var referenceValue string
|
var referenceValue string
|
||||||
var labelNode, valueNode *yaml.Node
|
var labelNode, valueNode *yaml.Node
|
||||||
var circError error
|
var circError error
|
||||||
@@ -687,7 +851,7 @@ func ExtractMapExtensions[PT Buildable[N], N any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ref != "" {
|
if ref != "" {
|
||||||
SetReference(n, ref)
|
SetReference(n, ref, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
c <- mappingResult[PT]{
|
c <- mappingResult[PT]{
|
||||||
@@ -698,7 +862,7 @@ func ExtractMapExtensions[PT Buildable[N], N any](
|
|||||||
v: ValueReference[PT]{
|
v: ValueReference[PT]{
|
||||||
Value: n,
|
Value: n,
|
||||||
ValueNode: value,
|
ValueNode: value,
|
||||||
Reference: ref,
|
// Reference: ref,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -773,7 +937,7 @@ func ExtractMap[PT Buildable[N], N any](
|
|||||||
label string,
|
label string,
|
||||||
root *yaml.Node,
|
root *yaml.Node,
|
||||||
idx *index.SpecIndex,
|
idx *index.SpecIndex,
|
||||||
) (orderedmap.Map[KeyReference[string], ValueReference[PT]], *yaml.Node, *yaml.Node, error) {
|
) (*orderedmap.Map[KeyReference[string], ValueReference[PT]], *yaml.Node, *yaml.Node, error) {
|
||||||
return ExtractMapExtensions[PT, N](ctx, label, root, idx, false)
|
return ExtractMapExtensions[PT, N](ctx, label, root, idx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,7 +945,7 @@ func ExtractMap[PT Buildable[N], N any](
|
|||||||
//
|
//
|
||||||
// Maps
|
// Maps
|
||||||
//
|
//
|
||||||
// map[string]interface{} for maps
|
// *orderedmap.Map[string, *yaml.Node] for maps
|
||||||
//
|
//
|
||||||
// Slices
|
// Slices
|
||||||
//
|
//
|
||||||
@@ -790,54 +954,15 @@ func ExtractMap[PT Buildable[N], N any](
|
|||||||
// int, float, bool, string
|
// int, float, bool, string
|
||||||
//
|
//
|
||||||
// int64, float64, bool, string
|
// int64, float64, bool, string
|
||||||
func ExtractExtensions(root *yaml.Node) map[KeyReference[string]]ValueReference[any] {
|
func ExtractExtensions(root *yaml.Node) *orderedmap.Map[KeyReference[string], ValueReference[*yaml.Node]] {
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
extensions := utils.FindExtensionNodes(root.Content)
|
extensions := utils.FindExtensionNodes(root.Content)
|
||||||
extensionMap := make(map[KeyReference[string]]ValueReference[any])
|
extensionMap := orderedmap.New[KeyReference[string], ValueReference[*yaml.Node]]()
|
||||||
for _, ext := range extensions {
|
for _, ext := range extensions {
|
||||||
if utils.IsNodeMap(ext.Value) {
|
extensionMap.Set(KeyReference[string]{
|
||||||
var v interface{}
|
Value: ext.Key.Value,
|
||||||
_ = ext.Value.Decode(&v)
|
KeyNode: ext.Key,
|
||||||
extensionMap[KeyReference[string]{
|
}, ValueReference[*yaml.Node]{Value: ext.Value, ValueNode: ext.Value})
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: v, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
if utils.IsNodeStringValue(ext.Value) {
|
|
||||||
extensionMap[KeyReference[string]{
|
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: ext.Value.Value, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
if utils.IsNodeFloatValue(ext.Value) {
|
|
||||||
fv, _ := strconv.ParseFloat(ext.Value.Value, 64)
|
|
||||||
extensionMap[KeyReference[string]{
|
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: fv, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
if utils.IsNodeIntValue(ext.Value) {
|
|
||||||
iv, _ := strconv.ParseInt(ext.Value.Value, 10, 64)
|
|
||||||
extensionMap[KeyReference[string]{
|
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: iv, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
if utils.IsNodeBoolValue(ext.Value) {
|
|
||||||
bv, _ := strconv.ParseBool(ext.Value.Value)
|
|
||||||
extensionMap[KeyReference[string]{
|
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: bv, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
if utils.IsNodeArray(ext.Value) {
|
|
||||||
var v []interface{}
|
|
||||||
_ = ext.Value.Decode(&v)
|
|
||||||
extensionMap[KeyReference[string]{
|
|
||||||
Value: ext.Key.Value,
|
|
||||||
KeyNode: ext.Key,
|
|
||||||
}] = ValueReference[any]{Value: v, ValueNode: ext.Value}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return extensionMap
|
return extensionMap
|
||||||
}
|
}
|
||||||
@@ -869,6 +994,10 @@ func GenerateHashString(v any) string {
|
|||||||
return fmt.Sprintf(HASH, h.Hash())
|
return fmt.Sprintf(HASH, h.Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if n, ok := v.(*yaml.Node); ok {
|
||||||
|
b, _ := yaml.Marshal(n)
|
||||||
|
return fmt.Sprintf(HASH, sha256.Sum256(b))
|
||||||
|
}
|
||||||
// if we get here, we're a primitive, check if we're a pointer and de-point
|
// if we get here, we're a primitive, check if we're a pointer and de-point
|
||||||
if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
if reflect.TypeOf(v).Kind() == reflect.Ptr {
|
||||||
v = reflect.ValueOf(v).Elem().Interface()
|
v = reflect.ValueOf(v).Elem().Interface()
|
||||||
@@ -876,6 +1005,15 @@ func GenerateHashString(v any) string {
|
|||||||
return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v))))
|
return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValueToString(v any) string {
|
||||||
|
if n, ok := v.(*yaml.Node); ok {
|
||||||
|
b, _ := yaml.Marshal(n)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
|
||||||
// LocateRefEnd will perform a complete lookup for a $ref node. This function searches the entire index for
|
// LocateRefEnd will perform a complete lookup for a $ref node. This function searches the entire index for
|
||||||
// the reference being supplied. If there is a match found, the reference *yaml.Node is returned.
|
// the reference being supplied. If there is a match found, the reference *yaml.Node is returned.
|
||||||
// the function operates recursively and will keep iterating through references until it finds a non-reference
|
// the function operates recursively and will keep iterating through references until it finds a non-reference
|
||||||
|
|||||||
@@ -7,51 +7,52 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/sync/syncmap"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/sync/syncmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFindItemInMap(t *testing.T) {
|
func TestFindItemInOrderedMap(t *testing.T) {
|
||||||
v := make(map[KeyReference[string]]ValueReference[string])
|
v := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
v[KeyReference[string]{
|
v.Set(KeyReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}] = ValueReference[string]{
|
}, ValueReference[string]{
|
||||||
Value: "pie",
|
Value: "pie",
|
||||||
}
|
})
|
||||||
assert.Equal(t, "pie", FindItemInMap("pizza", v).Value)
|
assert.Equal(t, "pie", FindItemInOrderedMap("pizza", v).Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindItemInMap_WrongCase(t *testing.T) {
|
func TestFindItemInOrderedMap_WrongCase(t *testing.T) {
|
||||||
v := make(map[KeyReference[string]]ValueReference[string])
|
v := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
v[KeyReference[string]{
|
v.Set(KeyReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}] = ValueReference[string]{
|
}, ValueReference[string]{
|
||||||
Value: "pie",
|
Value: "pie",
|
||||||
}
|
})
|
||||||
assert.Equal(t, "pie", FindItemInMap("PIZZA", v).Value)
|
assert.Equal(t, "pie", FindItemInOrderedMap("PIZZA", v).Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindItemInMap_Error(t *testing.T) {
|
func TestFindItemInOrderedMap_Error(t *testing.T) {
|
||||||
v := make(map[KeyReference[string]]ValueReference[string])
|
v := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
v[KeyReference[string]{
|
v.Set(KeyReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}] = ValueReference[string]{
|
}, ValueReference[string]{
|
||||||
Value: "pie",
|
Value: "pie",
|
||||||
}
|
})
|
||||||
assert.Nil(t, FindItemInMap("nuggets", v))
|
assert.Nil(t, FindItemInOrderedMap("nuggets", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode(t *testing.T) {
|
func TestLocateRefNode(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
cake:
|
cake:
|
||||||
@@ -69,11 +70,9 @@ func TestLocateRefNode(t *testing.T) {
|
|||||||
|
|
||||||
located, _, _ := LocateRefNode(cNode.Content[0], idx)
|
located, _, _ := LocateRefNode(cNode.Content[0], idx)
|
||||||
assert.NotNil(t, located)
|
assert.NotNil(t, located)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_BadNode(t *testing.T) {
|
func TestLocateRefNode_BadNode(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
cake:
|
cake:
|
||||||
@@ -94,11 +93,9 @@ func TestLocateRefNode_BadNode(t *testing.T) {
|
|||||||
// should both be empty.
|
// should both be empty.
|
||||||
assert.Nil(t, located)
|
assert.Nil(t, located)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_Path(t *testing.T) {
|
func TestLocateRefNode_Path(t *testing.T) {
|
||||||
|
|
||||||
yml := `paths:
|
yml := `paths:
|
||||||
/burger/time:
|
/burger/time:
|
||||||
description: hello`
|
description: hello`
|
||||||
@@ -115,11 +112,9 @@ func TestLocateRefNode_Path(t *testing.T) {
|
|||||||
|
|
||||||
located, _, _ := LocateRefNode(cNode.Content[0], idx)
|
located, _, _ := LocateRefNode(cNode.Content[0], idx)
|
||||||
assert.NotNil(t, located)
|
assert.NotNil(t, located)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_Path_NotFound(t *testing.T) {
|
func TestLocateRefNode_Path_NotFound(t *testing.T) {
|
||||||
|
|
||||||
yml := `paths:
|
yml := `paths:
|
||||||
/burger/time:
|
/burger/time:
|
||||||
description: hello`
|
description: hello`
|
||||||
@@ -137,7 +132,6 @@ func TestLocateRefNode_Path_NotFound(t *testing.T) {
|
|||||||
located, _, err := LocateRefNode(cNode.Content[0], idx)
|
located, _, err := LocateRefNode(cNode.Content[0], idx)
|
||||||
assert.Nil(t, located)
|
assert.Nil(t, located)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type pizza struct {
|
type pizza struct {
|
||||||
@@ -149,7 +143,6 @@ func (p *pizza) Build(_ context.Context, _, _ *yaml.Node, _ *index.SpecIndex) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject(t *testing.T) {
|
func TestExtractObject(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -173,7 +166,6 @@ func TestExtractObject(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_Ref(t *testing.T) {
|
func TestExtractObject_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -197,7 +189,6 @@ func TestExtractObject_Ref(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_DoubleRef(t *testing.T) {
|
func TestExtractObject_DoubleRef(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
cake:
|
cake:
|
||||||
@@ -282,7 +273,6 @@ func TestExtractObject_DoubleRef_Circular_Fail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_DoubleRef_Circular_Direct(t *testing.T) {
|
func TestExtractObject_DoubleRef_Circular_Direct(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
loopy:
|
loopy:
|
||||||
@@ -312,7 +302,6 @@ func TestExtractObject_DoubleRef_Circular_Direct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_DoubleRef_Circular_Direct_Fail(t *testing.T) {
|
func TestExtractObject_DoubleRef_Circular_Direct_Fail(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
loopy:
|
loopy:
|
||||||
@@ -338,7 +327,6 @@ func TestExtractObject_DoubleRef_Circular_Direct_Fail(t *testing.T) {
|
|||||||
|
|
||||||
_, err := ExtractObject[*pizza](context.Background(), "tags", cNode.Content[0], idx)
|
_, err := ExtractObject[*pizza](context.Background(), "tags", cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type test_borked struct {
|
type test_borked struct {
|
||||||
@@ -374,7 +362,6 @@ func (t *test_Good) Build(_ context.Context, _, root *yaml.Node, idx *index.Spec
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_BadLowLevelModel(t *testing.T) {
|
func TestExtractObject_BadLowLevelModel(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
hey:`
|
hey:`
|
||||||
@@ -391,11 +378,9 @@ func TestExtractObject_BadLowLevelModel(t *testing.T) {
|
|||||||
|
|
||||||
_, err := ExtractObject[*test_noGood](context.Background(), "thing", &cNode, idx)
|
_, err := ExtractObject[*test_noGood](context.Background(), "thing", &cNode, idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_BadBuild(t *testing.T) {
|
func TestExtractObject_BadBuild(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
hey:`
|
hey:`
|
||||||
@@ -412,11 +397,9 @@ func TestExtractObject_BadBuild(t *testing.T) {
|
|||||||
|
|
||||||
_, err := ExtractObject[*test_almostGood](context.Background(), "thing", &cNode, idx)
|
_, err := ExtractObject[*test_almostGood](context.Background(), "thing", &cNode, idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_BadLabel(t *testing.T) {
|
func TestExtractObject_BadLabel(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
hey:`
|
hey:`
|
||||||
@@ -434,11 +417,9 @@ func TestExtractObject_BadLabel(t *testing.T) {
|
|||||||
res, err := ExtractObject[*test_almostGood](context.Background(), "ding", &cNode, idx)
|
res, err := ExtractObject[*test_almostGood](context.Background(), "ding", &cNode, idx)
|
||||||
assert.Nil(t, res.Value)
|
assert.Nil(t, res.Value)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_PathIsCircular(t *testing.T) {
|
func TestExtractObject_PathIsCircular(t *testing.T) {
|
||||||
|
|
||||||
// first we need an index.
|
// first we need an index.
|
||||||
yml := `paths:
|
yml := `paths:
|
||||||
'/something/here':
|
'/something/here':
|
||||||
@@ -467,11 +448,9 @@ func TestExtractObject_PathIsCircular(t *testing.T) {
|
|||||||
res, err := ExtractObject[*test_Good](context.Background(), "thing", &rootNode, idx)
|
res, err := ExtractObject[*test_Good](context.Background(), "thing", &rootNode, idx)
|
||||||
assert.NotNil(t, res.Value)
|
assert.NotNil(t, res.Value)
|
||||||
assert.Error(t, err) // circular error would have been thrown.
|
assert.Error(t, err) // circular error would have been thrown.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObject_PathIsCircular_IgnoreErrors(t *testing.T) {
|
func TestExtractObject_PathIsCircular_IgnoreErrors(t *testing.T) {
|
||||||
|
|
||||||
// first we need an index.
|
// first we need an index.
|
||||||
yml := `paths:
|
yml := `paths:
|
||||||
'/something/here':
|
'/something/here':
|
||||||
@@ -503,11 +482,9 @@ func TestExtractObject_PathIsCircular_IgnoreErrors(t *testing.T) {
|
|||||||
res, err := ExtractObject[*test_Good](context.Background(), "thing", &rootNode, idx)
|
res, err := ExtractObject[*test_Good](context.Background(), "thing", &rootNode, idx)
|
||||||
assert.NotNil(t, res.Value)
|
assert.NotNil(t, res.Value)
|
||||||
assert.NoError(t, err) // circular error would have been thrown, but we're ignoring them.
|
assert.NoError(t, err) // circular error would have been thrown, but we're ignoring them.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw(t *testing.T) {
|
func TestExtractObjectRaw(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -530,7 +507,6 @@ func TestExtractObjectRaw(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw_With_Ref(t *testing.T) {
|
func TestExtractObjectRaw_With_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -555,7 +531,6 @@ func TestExtractObjectRaw_With_Ref(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw_Ref_Circular(t *testing.T) {
|
func TestExtractObjectRaw_Ref_Circular(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -579,11 +554,9 @@ func TestExtractObjectRaw_Ref_Circular(t *testing.T) {
|
|||||||
tag, err, _, _ := ExtractObjectRaw[*pizza](context.Background(), nil, cNode.Content[0], idx)
|
tag, err, _, _ := ExtractObjectRaw[*pizza](context.Background(), nil, cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.NotNil(t, tag)
|
assert.NotNil(t, tag)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw_RefBroken(t *testing.T) {
|
func TestExtractObjectRaw_RefBroken(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -601,11 +574,9 @@ func TestExtractObjectRaw_RefBroken(t *testing.T) {
|
|||||||
tag, err, _, _ := ExtractObjectRaw[*pizza](context.Background(), nil, cNode.Content[0], idx)
|
tag, err, _, _ := ExtractObjectRaw[*pizza](context.Background(), nil, cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Nil(t, tag)
|
assert.Nil(t, tag)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw_Ref_NonBuildable(t *testing.T) {
|
func TestExtractObjectRaw_Ref_NonBuildable(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -622,11 +593,9 @@ func TestExtractObjectRaw_Ref_NonBuildable(t *testing.T) {
|
|||||||
|
|
||||||
_, err, _, _ := ExtractObjectRaw[*test_noGood](context.Background(), nil, cNode.Content[0], idx)
|
_, err, _, _ := ExtractObjectRaw[*test_noGood](context.Background(), nil, cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractObjectRaw_Ref_AlmostBuildable(t *testing.T) {
|
func TestExtractObjectRaw_Ref_AlmostBuildable(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -643,11 +612,9 @@ func TestExtractObjectRaw_Ref_AlmostBuildable(t *testing.T) {
|
|||||||
|
|
||||||
_, err, _, _ := ExtractObjectRaw[*test_almostGood](context.Background(), nil, cNode.Content[0], idx)
|
_, err, _, _ := ExtractObjectRaw[*test_almostGood](context.Background(), nil, cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray(t *testing.T) {
|
func TestExtractArray(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -675,7 +642,6 @@ func TestExtractArray(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref(t *testing.T) {
|
func TestExtractArray_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
things:
|
things:
|
||||||
@@ -702,7 +668,6 @@ func TestExtractArray_Ref(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Unbuildable(t *testing.T) {
|
func TestExtractArray_Ref_Unbuildable(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
things:
|
things:
|
||||||
@@ -726,7 +691,6 @@ func TestExtractArray_Ref_Unbuildable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Circular(t *testing.T) {
|
func TestExtractArray_Ref_Circular(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -754,7 +718,6 @@ func TestExtractArray_Ref_Circular(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Bad(t *testing.T) {
|
func TestExtractArray_Ref_Bad(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -782,7 +745,6 @@ func TestExtractArray_Ref_Bad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Nested(t *testing.T) {
|
func TestExtractArray_Ref_Nested(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -811,7 +773,6 @@ func TestExtractArray_Ref_Nested(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Nested_Circular(t *testing.T) {
|
func TestExtractArray_Ref_Nested_Circular(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -840,7 +801,6 @@ func TestExtractArray_Ref_Nested_Circular(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Nested_BadRef(t *testing.T) {
|
func TestExtractArray_Ref_Nested_BadRef(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -867,7 +827,6 @@ func TestExtractArray_Ref_Nested_BadRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_Ref_Nested_CircularFlat(t *testing.T) {
|
func TestExtractArray_Ref_Nested_CircularFlat(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -896,7 +855,6 @@ func TestExtractArray_Ref_Nested_CircularFlat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_BadBuild(t *testing.T) {
|
func TestExtractArray_BadBuild(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:`
|
thongs:`
|
||||||
@@ -918,7 +876,6 @@ func TestExtractArray_BadBuild(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractArray_BadRefPropsTupe(t *testing.T) {
|
func TestExtractArray_BadRefPropsTupe(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
parameters:
|
parameters:
|
||||||
cakes:
|
cakes:
|
||||||
@@ -940,45 +897,7 @@ func TestExtractArray_BadRefPropsTupe(t *testing.T) {
|
|||||||
assert.Len(t, things, 0)
|
assert.Len(t, things, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractExample_String(t *testing.T) {
|
|
||||||
yml := `hi`
|
|
||||||
var e yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &e)
|
|
||||||
|
|
||||||
exp := ExtractExample(e.Content[0], e.Content[0])
|
|
||||||
assert.NotNil(t, exp.Value)
|
|
||||||
assert.Equal(t, "hi", exp.Value)
|
|
||||||
}
|
|
||||||
func TestExtractExample_Map(t *testing.T) {
|
|
||||||
yml := `one: two`
|
|
||||||
var e yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &e)
|
|
||||||
|
|
||||||
exp := ExtractExample(e.Content[0], e.Content[0])
|
|
||||||
assert.NotNil(t, exp.Value)
|
|
||||||
if n, ok := exp.Value.(map[string]interface{}); ok {
|
|
||||||
assert.Equal(t, "two", n["one"])
|
|
||||||
} else {
|
|
||||||
panic("example unpacked incorrectly.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractExample_Array(t *testing.T) {
|
|
||||||
yml := `- hello`
|
|
||||||
var e yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &e)
|
|
||||||
|
|
||||||
exp := ExtractExample(e.Content[0], e.Content[0])
|
|
||||||
assert.NotNil(t, exp.Value)
|
|
||||||
if n, ok := exp.Value.([]interface{}); ok {
|
|
||||||
assert.Equal(t, "hello", n[0])
|
|
||||||
} else {
|
|
||||||
panic("example unpacked incorrectly.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup(t *testing.T) {
|
func TestExtractMapFlatNoLookup(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -997,11 +916,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, orderedmap.Len(things))
|
assert.Equal(t, 1, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMap_NoLookupWithExtensions(t *testing.T) {
|
func TestExtractMap_NoLookupWithExtensions(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1031,7 +948,6 @@ one:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMap_NoLookupWithExtensions_UsingMerge(t *testing.T) {
|
func TestExtractMap_NoLookupWithExtensions_UsingMerge(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1053,11 +969,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookupExtensions[*test_Good](context.Background(), cNode.Content[0], idx, true)
|
things, err := ExtractMapNoLookupExtensions[*test_Good](context.Background(), cNode.Content[0], idx, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 4, orderedmap.Len(things))
|
assert.Equal(t, 4, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMap_NoLookupWithoutExtensions(t *testing.T) {
|
func TestExtractMap_NoLookupWithoutExtensions(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1083,7 +997,6 @@ one:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMap_WithExtensions(t *testing.T) {
|
func TestExtractMap_WithExtensions(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1105,7 +1018,6 @@ one:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMap_WithoutExtensions(t *testing.T) {
|
func TestExtractMap_WithoutExtensions(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1127,7 +1039,6 @@ one:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -1149,11 +1060,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, orderedmap.Len(things))
|
assert.Equal(t, 1, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref_Bad(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref_Bad(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -1175,11 +1084,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref_Circular(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref_Circular(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
thongs:
|
thongs:
|
||||||
@@ -1207,11 +1114,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_Good](context.Background(), cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 1, orderedmap.Len(things))
|
assert.Equal(t, 1, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref_BadBuild(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref_BadBuild(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -1233,11 +1138,9 @@ hello:
|
|||||||
things, err := ExtractMapNoLookup[*test_noGood](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_noGood](context.Background(), cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlatNoLookup_Ref_AlmostBuild(t *testing.T) {
|
func TestExtractMapFlatNoLookup_Ref_AlmostBuild(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -1259,11 +1162,9 @@ one:
|
|||||||
things, err := ExtractMapNoLookup[*test_almostGood](context.Background(), cNode.Content[0], idx)
|
things, err := ExtractMapNoLookup[*test_almostGood](context.Background(), cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat(t *testing.T) {
|
func TestExtractMapFlat(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:`
|
yml := `components:`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -1282,11 +1183,9 @@ one:
|
|||||||
things, _, _, err := ExtractMap[*test_Good](context.Background(), "one", cNode.Content[0], idx)
|
things, _, _, err := ExtractMap[*test_Good](context.Background(), "one", cNode.Content[0], idx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, orderedmap.Len(things))
|
assert.Equal(t, 1, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref(t *testing.T) {
|
func TestExtractMapFlat_Ref(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stank:
|
stank:
|
||||||
@@ -1313,11 +1212,9 @@ one:
|
|||||||
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(things); pair != nil; pair = pair.Next() {
|
||||||
assert.Equal(t, 99, pair.Value().Value.AlmostWork.Value)
|
assert.Equal(t, 99, pair.Value().Value.AlmostWork.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_DoubleRef(t *testing.T) {
|
func TestExtractMapFlat_DoubleRef(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stank:
|
stank:
|
||||||
@@ -1346,7 +1243,6 @@ func TestExtractMapFlat_DoubleRef(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_DoubleRef_Error(t *testing.T) {
|
func TestExtractMapFlat_DoubleRef_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stank:
|
stank:
|
||||||
@@ -1369,11 +1265,9 @@ func TestExtractMapFlat_DoubleRef_Error(t *testing.T) {
|
|||||||
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_DoubleRef_Error_NotFound(t *testing.T) {
|
func TestExtractMapFlat_DoubleRef_Error_NotFound(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stank:
|
stank:
|
||||||
@@ -1396,11 +1290,9 @@ func TestExtractMapFlat_DoubleRef_Error_NotFound(t *testing.T) {
|
|||||||
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_DoubleRef_Circles(t *testing.T) {
|
func TestExtractMapFlat_DoubleRef_Circles(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stonk:
|
stonk:
|
||||||
@@ -1428,11 +1320,9 @@ func TestExtractMapFlat_DoubleRef_Circles(t *testing.T) {
|
|||||||
things, _, _, err := ExtractMap[*test_Good](context.Background(), "one", cNode.Content[0], idx)
|
things, _, _, err := ExtractMap[*test_Good](context.Background(), "one", cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 1, orderedmap.Len(things))
|
assert.Equal(t, 1, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref_Error(t *testing.T) {
|
func TestExtractMapFlat_Ref_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stank:
|
stank:
|
||||||
@@ -1455,11 +1345,9 @@ func TestExtractMapFlat_Ref_Error(t *testing.T) {
|
|||||||
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
things, _, _, err := ExtractMap[*test_almostGood](context.Background(), "one", cNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Zero(t, orderedmap.Len(things))
|
assert.Zero(t, orderedmap.Len(things))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref_Circ_Error(t *testing.T) {
|
func TestExtractMapFlat_Ref_Circ_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stink:
|
stink:
|
||||||
@@ -1488,7 +1376,6 @@ func TestExtractMapFlat_Ref_Circ_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref_Nested_Circ_Error(t *testing.T) {
|
func TestExtractMapFlat_Ref_Nested_Circ_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stink:
|
stink:
|
||||||
@@ -1518,7 +1405,6 @@ func TestExtractMapFlat_Ref_Nested_Circ_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref_Nested_Error(t *testing.T) {
|
func TestExtractMapFlat_Ref_Nested_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stink:
|
stink:
|
||||||
@@ -1544,7 +1430,6 @@ func TestExtractMapFlat_Ref_Nested_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_BadKey_Ref_Nested_Error(t *testing.T) {
|
func TestExtractMapFlat_BadKey_Ref_Nested_Error(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stink:
|
stink:
|
||||||
@@ -1570,7 +1455,6 @@ func TestExtractMapFlat_BadKey_Ref_Nested_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractMapFlat_Ref_Bad(t *testing.T) {
|
func TestExtractMapFlat_Ref_Bad(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
stink:
|
stink:
|
||||||
@@ -1599,7 +1483,6 @@ func TestExtractMapFlat_Ref_Bad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractExtensions(t *testing.T) {
|
func TestExtractExtensions(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-bing: ding
|
yml := `x-bing: ding
|
||||||
x-bong: 1
|
x-bong: 1
|
||||||
x-ling: true
|
x-ling: true
|
||||||
@@ -1612,25 +1495,27 @@ x-tacos: [1,2,3]`
|
|||||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
|
||||||
r := ExtractExtensions(idxNode.Content[0])
|
r := ExtractExtensions(idxNode.Content[0])
|
||||||
assert.Len(t, r, 6)
|
assert.Equal(t, 6, orderedmap.Len(r))
|
||||||
for i := range r {
|
for pair := orderedmap.First(r); pair != nil; pair = pair.Next() {
|
||||||
switch i.Value {
|
var v any
|
||||||
|
_ = pair.Value().Value.Decode(&v)
|
||||||
|
|
||||||
|
switch pair.Key().Value {
|
||||||
case "x-bing":
|
case "x-bing":
|
||||||
assert.Equal(t, "ding", r[i].Value)
|
assert.Equal(t, "ding", v)
|
||||||
case "x-bong":
|
case "x-bong":
|
||||||
assert.Equal(t, int64(1), r[i].Value)
|
assert.Equal(t, 1, v)
|
||||||
case "x-ling":
|
case "x-ling":
|
||||||
assert.Equal(t, true, r[i].Value)
|
assert.Equal(t, true, v)
|
||||||
case "x-long":
|
case "x-long":
|
||||||
assert.Equal(t, 0.99, r[i].Value)
|
assert.Equal(t, 0.99, v)
|
||||||
case "x-fish":
|
case "x-fish":
|
||||||
if a, ok := r[i].Value.(map[string]interface{}); ok {
|
var m map[string]any
|
||||||
assert.Equal(t, "yeah", a["woo"])
|
err := pair.Value().Value.Decode(&m)
|
||||||
} else {
|
require.NoError(t, err)
|
||||||
panic("should not fail casting")
|
assert.Equal(t, "yeah", m["woo"])
|
||||||
}
|
|
||||||
case "x-tacos":
|
case "x-tacos":
|
||||||
assert.Len(t, r[i].Value, 3)
|
assert.Len(t, v, 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1650,8 +1535,8 @@ func (f test_fresh) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
return sha256.Sum256([]byte(strings.Join(data, "|")))
|
return sha256.Sum256([]byte(strings.Join(data, "|")))
|
||||||
}
|
}
|
||||||
func TestAreEqual(t *testing.T) {
|
|
||||||
|
|
||||||
|
func TestAreEqual(t *testing.T) {
|
||||||
var hey *test_fresh
|
var hey *test_fresh
|
||||||
|
|
||||||
assert.True(t, AreEqual(test_fresh{val: "hello"}, test_fresh{val: "hello"}))
|
assert.True(t, AreEqual(test_fresh{val: "hello"}, test_fresh{val: "hello"}))
|
||||||
@@ -1664,7 +1549,6 @@ func TestAreEqual(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateHashString(t *testing.T) {
|
func TestGenerateHashString(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
||||||
GenerateHashString(test_fresh{val: "hello"}))
|
GenerateHashString(test_fresh{val: "hello"}))
|
||||||
|
|
||||||
@@ -1676,46 +1560,39 @@ func TestGenerateHashString(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, "",
|
assert.Equal(t, "",
|
||||||
GenerateHashString(nil))
|
GenerateHashString(nil))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateHashString_Pointer(t *testing.T) {
|
func TestGenerateHashString_Pointer(t *testing.T) {
|
||||||
|
|
||||||
val := true
|
val := true
|
||||||
assert.Equal(t, "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b",
|
assert.Equal(t, "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b",
|
||||||
GenerateHashString(test_fresh{thang: &val}))
|
GenerateHashString(test_fresh{thang: &val}))
|
||||||
|
|
||||||
assert.Equal(t, "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b",
|
assert.Equal(t, "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b",
|
||||||
GenerateHashString(&val))
|
GenerateHashString(&val))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetReference(t *testing.T) {
|
func TestSetReference(t *testing.T) {
|
||||||
|
|
||||||
type testObj struct {
|
type testObj struct {
|
||||||
*Reference
|
*Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
n := testObj{Reference: &Reference{}}
|
n := testObj{Reference: &Reference{}}
|
||||||
SetReference(&n, "#/pigeon/street")
|
SetReference(&n, "#/pigeon/street", nil)
|
||||||
|
|
||||||
assert.Equal(t, "#/pigeon/street", n.GetReference())
|
assert.Equal(t, "#/pigeon/street", n.GetReference())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetReference_nil(t *testing.T) {
|
func TestSetReference_nil(t *testing.T) {
|
||||||
|
|
||||||
type testObj struct {
|
type testObj struct {
|
||||||
*Reference
|
*Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
n := testObj{Reference: &Reference{}}
|
n := testObj{Reference: &Reference{}}
|
||||||
SetReference(nil, "#/pigeon/street")
|
SetReference(nil, "#/pigeon/street", nil)
|
||||||
assert.NotEqual(t, "#/pigeon/street", n.GetReference())
|
assert.NotEqual(t, "#/pigeon/street", n.GetReference())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_HttpLink(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_HttpLink(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1741,7 +1618,6 @@ func TestLocateRefNode_CurrentPathKey_HttpLink(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_HttpLink_Local(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_HttpLink_Local(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1767,7 +1643,6 @@ func TestLocateRefNode_CurrentPathKey_HttpLink_Local(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1792,7 +1667,6 @@ func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx_WithPath(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx_WithPath(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1817,7 +1691,6 @@ func TestLocateRefNode_CurrentPathKey_HttpLink_RemoteCtx_WithPath(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_Path_Link(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_Path_Link(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1842,7 +1715,6 @@ func TestLocateRefNode_CurrentPathKey_Path_Link(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_Path_URL(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_Path_URL(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1869,7 +1741,6 @@ func TestLocateRefNode_CurrentPathKey_Path_URL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_CurrentPathKey_DeeperPath_URL(t *testing.T) {
|
func TestLocateRefNode_CurrentPathKey_DeeperPath_URL(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1896,7 +1767,6 @@ func TestLocateRefNode_CurrentPathKey_DeeperPath_URL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_NoExplode(t *testing.T) {
|
func TestLocateRefNode_NoExplode(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1923,7 +1793,6 @@ func TestLocateRefNode_NoExplode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_NoExplode_HTTP(t *testing.T) {
|
func TestLocateRefNode_NoExplode_HTTP(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1951,7 +1820,6 @@ func TestLocateRefNode_NoExplode_HTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_NoExplode_NoSpecPath(t *testing.T) {
|
func TestLocateRefNode_NoExplode_NoSpecPath(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -1979,7 +1847,6 @@ func TestLocateRefNode_NoExplode_NoSpecPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefNode_DoARealLookup(t *testing.T) {
|
func TestLocateRefNode_DoARealLookup(t *testing.T) {
|
||||||
|
|
||||||
no := yaml.Node{
|
no := yaml.Node{
|
||||||
Kind: yaml.MappingNode,
|
Kind: yaml.MappingNode,
|
||||||
Content: []*yaml.Node{
|
Content: []*yaml.Node{
|
||||||
@@ -2020,7 +1887,6 @@ func TestLocateRefNode_DoARealLookup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefEndNoRef_NoName(t *testing.T) {
|
func TestLocateRefEndNoRef_NoName(t *testing.T) {
|
||||||
|
|
||||||
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: ""}}}
|
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: ""}}}
|
||||||
n, i, e, c := LocateRefEnd(nil, r, nil, 0)
|
n, i, e, c := LocateRefEnd(nil, r, nil, 0)
|
||||||
assert.Nil(t, n)
|
assert.Nil(t, n)
|
||||||
@@ -2030,7 +1896,6 @@ func TestLocateRefEndNoRef_NoName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefEndNoRef(t *testing.T) {
|
func TestLocateRefEndNoRef(t *testing.T) {
|
||||||
|
|
||||||
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: "cake"}}}
|
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: "cake"}}}
|
||||||
n, i, e, c := LocateRefEnd(context.Background(), r, index.NewSpecIndexWithConfig(r, index.CreateClosedAPIIndexConfig()), 0)
|
n, i, e, c := LocateRefEnd(context.Background(), r, index.NewSpecIndexWithConfig(r, index.CreateClosedAPIIndexConfig()), 0)
|
||||||
assert.Nil(t, n)
|
assert.Nil(t, n)
|
||||||
@@ -2049,7 +1914,6 @@ func TestLocateRefEnd_TooDeep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefEnd_Loop(t *testing.T) {
|
func TestLocateRefEnd_Loop(t *testing.T) {
|
||||||
|
|
||||||
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
||||||
var bsn yaml.Node
|
var bsn yaml.Node
|
||||||
_ = yaml.Unmarshal(yml, &bsn)
|
_ = yaml.Unmarshal(yml, &bsn)
|
||||||
@@ -2094,7 +1958,6 @@ func TestLocateRefEnd_Loop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefEnd_Loop_WithResolve(t *testing.T) {
|
func TestLocateRefEnd_Loop_WithResolve(t *testing.T) {
|
||||||
|
|
||||||
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
||||||
var bsn yaml.Node
|
var bsn yaml.Node
|
||||||
_ = yaml.Unmarshal(yml, &bsn)
|
_ = yaml.Unmarshal(yml, &bsn)
|
||||||
@@ -2139,7 +2002,6 @@ func TestLocateRefEnd_Loop_WithResolve(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLocateRefEnd_Empty(t *testing.T) {
|
func TestLocateRefEnd_Empty(t *testing.T) {
|
||||||
|
|
||||||
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
||||||
var bsn yaml.Node
|
var bsn yaml.Node
|
||||||
_ = yaml.Unmarshal(yml, &bsn)
|
_ = yaml.Unmarshal(yml, &bsn)
|
||||||
@@ -2184,7 +2046,6 @@ func TestLocateRefEnd_Empty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestArray_NotRefNotArray(t *testing.T) {
|
func TestArray_NotRefNotArray(t *testing.T) {
|
||||||
|
|
||||||
yml := ``
|
yml := ``
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
mErr := yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
@@ -2201,5 +2062,4 @@ func TestArray_NotRefNotArray(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, err.Error(), "array build failed, input is not an array, line 2, column 3")
|
assert.Equal(t, err.Error(), "array build failed, input is not an array, line 2, column 3")
|
||||||
assert.Len(t, things, 0)
|
assert.Len(t, things, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,72 +78,63 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
|
|||||||
|
|
||||||
switch field.Type() {
|
switch field.Type() {
|
||||||
|
|
||||||
case reflect.TypeOf(map[string]NodeReference[any]{}):
|
case reflect.TypeOf(orderedmap.New[string, NodeReference[*yaml.Node]]()):
|
||||||
|
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[string]NodeReference[any])
|
items := orderedmap.New[string, NodeReference[*yaml.Node]]()
|
||||||
var currentLabel string
|
var currentLabel string
|
||||||
for i, sliceItem := range valueNode.Content {
|
for i, sliceItem := range valueNode.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentLabel = sliceItem.Value
|
currentLabel = sliceItem.Value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var decoded map[string]interface{}
|
items.Set(currentLabel, NodeReference[*yaml.Node]{
|
||||||
// I cannot think of a way to make this error out by this point.
|
Value: sliceItem,
|
||||||
_ = sliceItem.Decode(&decoded)
|
|
||||||
items[currentLabel] = NodeReference[any]{
|
|
||||||
Value: decoded,
|
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
KeyNode: valueNode,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(items))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.TypeOf(map[string]NodeReference[string]{}):
|
case reflect.TypeOf(orderedmap.New[string, NodeReference[string]]()):
|
||||||
|
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := make(map[string]NodeReference[string])
|
items := orderedmap.New[string, NodeReference[string]]()
|
||||||
var currentLabel string
|
var currentLabel string
|
||||||
for i, sliceItem := range valueNode.Content {
|
for i, sliceItem := range valueNode.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentLabel = sliceItem.Value
|
currentLabel = sliceItem.Value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
items[currentLabel] = NodeReference[string]{
|
items.Set(currentLabel, NodeReference[string]{
|
||||||
Value: fmt.Sprintf("%v", sliceItem.Value),
|
Value: fmt.Sprintf("%v", sliceItem.Value),
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
KeyNode: valueNode,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
field.Set(reflect.ValueOf(items))
|
field.Set(reflect.ValueOf(items))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.TypeOf(NodeReference[any]{}):
|
case reflect.TypeOf(NodeReference[*yaml.Node]{}):
|
||||||
|
|
||||||
var decoded interface{}
|
|
||||||
_ = valueNode.Decode(&decoded)
|
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
or := NodeReference[any]{Value: decoded, ValueNode: valueNode, KeyNode: keyNode}
|
or := NodeReference[*yaml.Node]{Value: valueNode, ValueNode: valueNode, KeyNode: keyNode}
|
||||||
field.Set(reflect.ValueOf(or))
|
field.Set(reflect.ValueOf(or))
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.TypeOf([]NodeReference[any]{}):
|
case reflect.TypeOf([]NodeReference[*yaml.Node]{}):
|
||||||
|
|
||||||
if utils.IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []NodeReference[any]
|
var items []NodeReference[*yaml.Node]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
var decoded map[string]interface{}
|
items = append(items, NodeReference[*yaml.Node]{
|
||||||
err := sliceItem.Decode(&decoded)
|
Value: sliceItem,
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
items = append(items, NodeReference[any]{
|
|
||||||
Value: decoded,
|
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
KeyNode: valueNode,
|
KeyNode: valueNode,
|
||||||
})
|
})
|
||||||
@@ -340,57 +331,9 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for unpacking string maps.
|
// helper for unpacking string maps.
|
||||||
case reflect.TypeOf(map[KeyReference[string]]ValueReference[string]{}):
|
case reflect.TypeOf(orderedmap.New[KeyReference[string], ValueReference[string]]()):
|
||||||
|
|
||||||
if utils.IsNodeMap(valueNode) {
|
|
||||||
if field.CanSet() {
|
|
||||||
items := make(map[KeyReference[string]]ValueReference[string])
|
|
||||||
var cf *yaml.Node
|
|
||||||
for i, sliceItem := range valueNode.Content {
|
|
||||||
if i%2 == 0 {
|
|
||||||
cf = sliceItem
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
items[KeyReference[string]{
|
|
||||||
Value: cf.Value,
|
|
||||||
KeyNode: cf,
|
|
||||||
}] = ValueReference[string]{
|
|
||||||
Value: sliceItem.Value,
|
|
||||||
ValueNode: sliceItem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
field.Set(reflect.ValueOf(items))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case reflect.TypeOf(KeyReference[map[KeyReference[string]]ValueReference[string]]{}):
|
|
||||||
|
|
||||||
if utils.IsNodeMap(valueNode) {
|
|
||||||
if field.CanSet() {
|
|
||||||
items := make(map[KeyReference[string]]ValueReference[string])
|
|
||||||
var cf *yaml.Node
|
|
||||||
for i, sliceItem := range valueNode.Content {
|
|
||||||
if i%2 == 0 {
|
|
||||||
cf = sliceItem
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
items[KeyReference[string]{
|
|
||||||
Value: cf.Value,
|
|
||||||
KeyNode: cf,
|
|
||||||
}] = ValueReference[string]{
|
|
||||||
Value: sliceItem.Value,
|
|
||||||
ValueNode: sliceItem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ref := KeyReference[map[KeyReference[string]]ValueReference[string]]{
|
|
||||||
Value: items,
|
|
||||||
KeyNode: keyNode,
|
|
||||||
}
|
|
||||||
field.Set(reflect.ValueOf(ref))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.TypeOf(NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]{}):
|
|
||||||
if utils.IsNodeMap(valueNode) {
|
if utils.IsNodeMap(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
items := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
items := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
@@ -408,7 +351,55 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
|
|||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ref := NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]{
|
field.Set(reflect.ValueOf(items))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.TypeOf(KeyReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]{}):
|
||||||
|
|
||||||
|
if utils.IsNodeMap(valueNode) {
|
||||||
|
if field.CanSet() {
|
||||||
|
items := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
|
var cf *yaml.Node
|
||||||
|
for i, sliceItem := range valueNode.Content {
|
||||||
|
if i%2 == 0 {
|
||||||
|
cf = sliceItem
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
items.Set(KeyReference[string]{
|
||||||
|
Value: cf.Value,
|
||||||
|
KeyNode: cf,
|
||||||
|
}, ValueReference[string]{
|
||||||
|
Value: sliceItem.Value,
|
||||||
|
ValueNode: sliceItem,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ref := KeyReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]{
|
||||||
|
Value: items,
|
||||||
|
KeyNode: keyNode,
|
||||||
|
}
|
||||||
|
field.Set(reflect.ValueOf(ref))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.TypeOf(NodeReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]{}):
|
||||||
|
if utils.IsNodeMap(valueNode) {
|
||||||
|
if field.CanSet() {
|
||||||
|
items := orderedmap.New[KeyReference[string], ValueReference[string]]()
|
||||||
|
var cf *yaml.Node
|
||||||
|
for i, sliceItem := range valueNode.Content {
|
||||||
|
if i%2 == 0 {
|
||||||
|
cf = sliceItem
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
items.Set(KeyReference[string]{
|
||||||
|
Value: cf.Value,
|
||||||
|
KeyNode: cf,
|
||||||
|
}, ValueReference[string]{
|
||||||
|
Value: sliceItem.Value,
|
||||||
|
ValueNode: sliceItem,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ref := NodeReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]{
|
||||||
Value: items,
|
Value: items,
|
||||||
KeyNode: keyNode,
|
KeyNode: keyNode,
|
||||||
ValueNode: valueNode,
|
ValueNode: valueNode,
|
||||||
@@ -436,34 +427,18 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.TypeOf(NodeReference[[]ValueReference[any]]{}):
|
case reflect.TypeOf(NodeReference[[]ValueReference[*yaml.Node]]{}):
|
||||||
|
|
||||||
if utils.IsNodeArray(valueNode) {
|
if utils.IsNodeArray(valueNode) {
|
||||||
if field.CanSet() {
|
if field.CanSet() {
|
||||||
var items []ValueReference[any]
|
var items []ValueReference[*yaml.Node]
|
||||||
for _, sliceItem := range valueNode.Content {
|
for _, sliceItem := range valueNode.Content {
|
||||||
|
items = append(items, ValueReference[*yaml.Node]{
|
||||||
var val any
|
Value: sliceItem,
|
||||||
if utils.IsNodeIntValue(sliceItem) || utils.IsNodeFloatValue(sliceItem) {
|
|
||||||
if utils.IsNodeIntValue(sliceItem) {
|
|
||||||
val, _ = strconv.ParseInt(sliceItem.Value, 10, 64)
|
|
||||||
} else {
|
|
||||||
val, _ = strconv.ParseFloat(sliceItem.Value, 64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if utils.IsNodeBoolValue(sliceItem) {
|
|
||||||
val, _ = strconv.ParseBool(sliceItem.Value)
|
|
||||||
}
|
|
||||||
if utils.IsNodeStringValue(sliceItem) {
|
|
||||||
val = sliceItem.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
items = append(items, ValueReference[any]{
|
|
||||||
Value: val,
|
|
||||||
ValueNode: sliceItem,
|
ValueNode: sliceItem,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
n := NodeReference[[]ValueReference[any]]{
|
n := NodeReference[[]ValueReference[*yaml.Node]]{
|
||||||
Value: items,
|
Value: items,
|
||||||
KeyNode: keyNode,
|
KeyNode: keyNode,
|
||||||
ValueNode: valueNode,
|
ValueNode: valueNode,
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ type hotdog struct {
|
|||||||
Temps []NodeReference[int]
|
Temps []NodeReference[int]
|
||||||
HighTemps []NodeReference[int64]
|
HighTemps []NodeReference[int64]
|
||||||
Buns []NodeReference[bool]
|
Buns []NodeReference[bool]
|
||||||
UnknownElements NodeReference[any]
|
UnknownElements NodeReference[*yaml.Node]
|
||||||
LotsOfUnknowns []NodeReference[any]
|
LotsOfUnknowns []NodeReference[*yaml.Node]
|
||||||
Where map[string]NodeReference[any]
|
Where *orderedmap.Map[string, NodeReference[*yaml.Node]]
|
||||||
There map[string]NodeReference[string]
|
There *orderedmap.Map[string, NodeReference[string]]
|
||||||
AllTheThings NodeReference[orderedmap.Map[KeyReference[string], ValueReference[string]]]
|
AllTheThings NodeReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuildModel_Mismatch(t *testing.T) {
|
func TestBuildModel_Mismatch(t *testing.T) {
|
||||||
@@ -126,11 +126,15 @@ allTheThings:
|
|||||||
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
assert.Equal(t, int64(7392837462032342), hd.MaxTempHigh.Value)
|
||||||
assert.Equal(t, 2, hd.Temps[1].Value)
|
assert.Equal(t, 2, hd.Temps[1].Value)
|
||||||
assert.Equal(t, 27, hd.Temps[1].ValueNode.Line)
|
assert.Equal(t, 27, hd.Temps[1].ValueNode.Line)
|
||||||
assert.Len(t, hd.UnknownElements.Value, 2)
|
|
||||||
|
var unknownElements map[string]any
|
||||||
|
_ = hd.UnknownElements.Value.Decode(&unknownElements)
|
||||||
|
|
||||||
|
assert.Len(t, unknownElements, 2)
|
||||||
assert.Len(t, hd.LotsOfUnknowns, 3)
|
assert.Len(t, hd.LotsOfUnknowns, 3)
|
||||||
assert.Len(t, hd.Where, 2)
|
assert.Equal(t, 2, orderedmap.Len(hd.Where))
|
||||||
assert.Len(t, hd.There, 2)
|
assert.Equal(t, 2, orderedmap.Len(hd.There))
|
||||||
assert.Equal(t, "bear", hd.There["care"].Value)
|
assert.Equal(t, "bear", hd.There.GetOrZero("care").Value)
|
||||||
assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value)
|
assert.Equal(t, 324938249028.98234892374892374923874823974, hd.Mustard.Value)
|
||||||
|
|
||||||
allTheThings := hd.AllTheThings.Value
|
allTheThings := hd.AllTheThings.Value
|
||||||
@@ -201,27 +205,9 @@ thing: yeah`
|
|||||||
assert.Equal(t, "yeah", ins.Thing.Value)
|
assert.Equal(t, "yeah", ins.Thing.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetField_NodeRefAny_Error(t *testing.T) {
|
|
||||||
type internal struct {
|
|
||||||
Thing []NodeReference[any]
|
|
||||||
}
|
|
||||||
|
|
||||||
yml := `thing:
|
|
||||||
- 999
|
|
||||||
- false`
|
|
||||||
|
|
||||||
ins := new(internal)
|
|
||||||
var rootNode yaml.Node
|
|
||||||
mErr := yaml.Unmarshal([]byte(yml), &rootNode)
|
|
||||||
assert.NoError(t, mErr)
|
|
||||||
|
|
||||||
try := BuildModel(rootNode.Content[0], ins)
|
|
||||||
assert.Error(t, try)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetField_MapHelperWrapped(t *testing.T) {
|
func TestSetField_MapHelperWrapped(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing KeyReference[map[KeyReference[string]]ValueReference[string]]
|
Thing KeyReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -236,12 +222,12 @@ func TestSetField_MapHelperWrapped(t *testing.T) {
|
|||||||
|
|
||||||
try := BuildModel(rootNode.Content[0], ins)
|
try := BuildModel(rootNode.Content[0], ins)
|
||||||
assert.NoError(t, try)
|
assert.NoError(t, try)
|
||||||
assert.Len(t, ins.Thing.Value, 3)
|
assert.Equal(t, 3, orderedmap.Len(ins.Thing.Value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetField_MapHelper(t *testing.T) {
|
func TestSetField_MapHelper(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing map[KeyReference[string]]ValueReference[string]
|
Thing *orderedmap.Map[KeyReference[string], ValueReference[string]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -256,7 +242,7 @@ func TestSetField_MapHelper(t *testing.T) {
|
|||||||
|
|
||||||
try := BuildModel(rootNode.Content[0], ins)
|
try := BuildModel(rootNode.Content[0], ins)
|
||||||
assert.NoError(t, try)
|
assert.NoError(t, try)
|
||||||
assert.Len(t, ins.Thing, 3)
|
assert.Equal(t, 3, orderedmap.Len(ins.Thing))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetField_ArrayHelper(t *testing.T) {
|
func TestSetField_ArrayHelper(t *testing.T) {
|
||||||
@@ -281,7 +267,7 @@ func TestSetField_ArrayHelper(t *testing.T) {
|
|||||||
|
|
||||||
func TestSetField_Enum_Helper(t *testing.T) {
|
func TestSetField_Enum_Helper(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing NodeReference[[]ValueReference[any]]
|
Thing NodeReference[[]ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -324,7 +310,7 @@ func TestSetField_Default_Helper(t *testing.T) {
|
|||||||
|
|
||||||
func TestHandleSlicesOfInts(t *testing.T) {
|
func TestHandleSlicesOfInts(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing NodeReference[[]ValueReference[any]]
|
Thing NodeReference[[]ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -338,13 +324,20 @@ func TestHandleSlicesOfInts(t *testing.T) {
|
|||||||
|
|
||||||
try := BuildModel(rootNode.Content[0], ins)
|
try := BuildModel(rootNode.Content[0], ins)
|
||||||
assert.NoError(t, try)
|
assert.NoError(t, try)
|
||||||
assert.Equal(t, int64(5), ins.Thing.Value[0].Value)
|
|
||||||
assert.Equal(t, 1.234, ins.Thing.Value[1].Value)
|
var thing0 int64
|
||||||
|
_ = ins.Thing.GetValue()[0].Value.Decode(&thing0)
|
||||||
|
|
||||||
|
var thing1 float64
|
||||||
|
_ = ins.Thing.GetValue()[1].Value.Decode(&thing1)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(5), thing0)
|
||||||
|
assert.Equal(t, 1.234, thing1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleSlicesOfBools(t *testing.T) {
|
func TestHandleSlicesOfBools(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing NodeReference[[]ValueReference[any]]
|
Thing NodeReference[[]ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -357,9 +350,16 @@ func TestHandleSlicesOfBools(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
|
|
||||||
try := BuildModel(rootNode.Content[0], ins)
|
try := BuildModel(rootNode.Content[0], ins)
|
||||||
|
|
||||||
|
var thing0 bool
|
||||||
|
_ = ins.Thing.GetValue()[0].Value.Decode(&thing0)
|
||||||
|
|
||||||
|
var thing1 bool
|
||||||
|
_ = ins.Thing.GetValue()[1].Value.Decode(&thing1)
|
||||||
|
|
||||||
assert.NoError(t, try)
|
assert.NoError(t, try)
|
||||||
assert.Equal(t, true, ins.Thing.Value[0].Value)
|
assert.Equal(t, true, thing0)
|
||||||
assert.Equal(t, false, ins.Thing.Value[1].Value)
|
assert.Equal(t, false, thing1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetField_Ignore(t *testing.T) {
|
func TestSetField_Ignore(t *testing.T) {
|
||||||
@@ -387,7 +387,7 @@ func TestSetField_Ignore(t *testing.T) {
|
|||||||
|
|
||||||
func TestBuildModelAsync(t *testing.T) {
|
func TestBuildModelAsync(t *testing.T) {
|
||||||
type internal struct {
|
type internal struct {
|
||||||
Thing KeyReference[map[KeyReference[string]]ValueReference[string]]
|
Thing KeyReference[*orderedmap.Map[KeyReference[string], ValueReference[string]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
yml := `thing:
|
yml := `thing:
|
||||||
@@ -405,28 +405,5 @@ func TestBuildModelAsync(t *testing.T) {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
BuildModelAsync(rootNode.Content[0], ins, &wg, &errors)
|
BuildModelAsync(rootNode.Content[0], ins, &wg, &errors)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
assert.Len(t, ins.Thing.Value, 3)
|
assert.Equal(t, 3, orderedmap.Len(ins.Thing.Value))
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuildModelAsync_Error(t *testing.T) {
|
|
||||||
type internal struct {
|
|
||||||
Thing []NodeReference[any]
|
|
||||||
}
|
|
||||||
|
|
||||||
yml := `thing:
|
|
||||||
- 999
|
|
||||||
- false`
|
|
||||||
|
|
||||||
ins := new(internal)
|
|
||||||
var rootNode yaml.Node
|
|
||||||
mErr := yaml.Unmarshal([]byte(yml), &rootNode)
|
|
||||||
assert.NoError(t, mErr)
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
var errors []error
|
|
||||||
wg.Add(1)
|
|
||||||
BuildModelAsync(rootNode.Content[0], ins, &wg, &errors)
|
|
||||||
wg.Wait()
|
|
||||||
assert.Len(t, errors, 1)
|
|
||||||
assert.Len(t, ins.Thing, 0)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
package low
|
package low
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
type SharedParameters interface {
|
type SharedParameters interface {
|
||||||
HasDescription
|
HasDescription
|
||||||
Hash() [32]byte
|
Hash() [32]byte
|
||||||
@@ -30,7 +35,7 @@ type SwaggerParameter interface {
|
|||||||
GetType() *NodeReference[string]
|
GetType() *NodeReference[string]
|
||||||
GetFormat() *NodeReference[string]
|
GetFormat() *NodeReference[string]
|
||||||
GetCollectionFormat() *NodeReference[string]
|
GetCollectionFormat() *NodeReference[string]
|
||||||
GetDefault() *NodeReference[any]
|
GetDefault() *NodeReference[*yaml.Node]
|
||||||
GetMaximum() *NodeReference[int]
|
GetMaximum() *NodeReference[int]
|
||||||
GetExclusiveMaximum() *NodeReference[bool]
|
GetExclusiveMaximum() *NodeReference[bool]
|
||||||
GetMinimum() *NodeReference[int]
|
GetMinimum() *NodeReference[int]
|
||||||
@@ -41,7 +46,7 @@ type SwaggerParameter interface {
|
|||||||
GetMaxItems() *NodeReference[int]
|
GetMaxItems() *NodeReference[int]
|
||||||
GetMinItems() *NodeReference[int]
|
GetMinItems() *NodeReference[int]
|
||||||
GetUniqueItems() *NodeReference[bool]
|
GetUniqueItems() *NodeReference[bool]
|
||||||
GetEnum() *NodeReference[[]ValueReference[any]]
|
GetEnum() *NodeReference[[]ValueReference[*yaml.Node]]
|
||||||
GetMultipleOf() *NodeReference[int]
|
GetMultipleOf() *NodeReference[int]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +56,7 @@ type SwaggerHeader interface {
|
|||||||
GetType() *NodeReference[string]
|
GetType() *NodeReference[string]
|
||||||
GetFormat() *NodeReference[string]
|
GetFormat() *NodeReference[string]
|
||||||
GetCollectionFormat() *NodeReference[string]
|
GetCollectionFormat() *NodeReference[string]
|
||||||
GetDefault() *NodeReference[any]
|
GetDefault() *NodeReference[*yaml.Node]
|
||||||
GetMaximum() *NodeReference[int]
|
GetMaximum() *NodeReference[int]
|
||||||
GetExclusiveMaximum() *NodeReference[bool]
|
GetExclusiveMaximum() *NodeReference[bool]
|
||||||
GetMinimum() *NodeReference[int]
|
GetMinimum() *NodeReference[int]
|
||||||
@@ -62,7 +67,7 @@ type SwaggerHeader interface {
|
|||||||
GetMaxItems() *NodeReference[int]
|
GetMaxItems() *NodeReference[int]
|
||||||
GetMinItems() *NodeReference[int]
|
GetMinItems() *NodeReference[int]
|
||||||
GetUniqueItems() *NodeReference[bool]
|
GetUniqueItems() *NodeReference[bool]
|
||||||
GetEnum() *NodeReference[[]ValueReference[any]]
|
GetEnum() *NodeReference[[]ValueReference[*yaml.Node]]
|
||||||
GetMultipleOf() *NodeReference[int]
|
GetMultipleOf() *NodeReference[int]
|
||||||
GetItems() *NodeReference[any] // requires cast.
|
GetItems() *NodeReference[any] // requires cast.
|
||||||
}
|
}
|
||||||
@@ -74,7 +79,7 @@ type OpenAPIHeader interface {
|
|||||||
GetStyle() *NodeReference[string]
|
GetStyle() *NodeReference[string]
|
||||||
GetAllowReserved() *NodeReference[bool]
|
GetAllowReserved() *NodeReference[bool]
|
||||||
GetExplode() *NodeReference[bool]
|
GetExplode() *NodeReference[bool]
|
||||||
GetExample() *NodeReference[any]
|
GetExample() *NodeReference[*yaml.Node]
|
||||||
GetRequired() *NodeReference[bool]
|
GetRequired() *NodeReference[bool]
|
||||||
GetAllowEmptyValue() *NodeReference[bool]
|
GetAllowEmptyValue() *NodeReference[bool]
|
||||||
GetSchema() *NodeReference[any] // requires cast.
|
GetSchema() *NodeReference[any] // requires cast.
|
||||||
@@ -88,13 +93,12 @@ type OpenAPIParameter interface {
|
|||||||
GetStyle() *NodeReference[string]
|
GetStyle() *NodeReference[string]
|
||||||
GetAllowReserved() *NodeReference[bool]
|
GetAllowReserved() *NodeReference[bool]
|
||||||
GetExplode() *NodeReference[bool]
|
GetExplode() *NodeReference[bool]
|
||||||
GetExample() *NodeReference[any]
|
GetExample() *NodeReference[*yaml.Node]
|
||||||
GetExamples() *NodeReference[any] // requires cast.
|
GetExamples() *NodeReference[any] // requires cast.
|
||||||
GetContent() *NodeReference[any] // requires cast.
|
GetContent() *NodeReference[any] // requires cast.
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: this needs to be fixed, move returns to pointers.
|
// TODO: this needs to be fixed, move returns to pointers.
|
||||||
|
|
||||||
type SharedOperations interface {
|
type SharedOperations interface {
|
||||||
GetOperationId() NodeReference[string]
|
GetOperationId() NodeReference[string]
|
||||||
GetExternalDocs() NodeReference[any]
|
GetExternalDocs() NodeReference[any]
|
||||||
@@ -102,7 +106,7 @@ type SharedOperations interface {
|
|||||||
GetTags() NodeReference[[]ValueReference[string]]
|
GetTags() NodeReference[[]ValueReference[string]]
|
||||||
GetSummary() NodeReference[string]
|
GetSummary() NodeReference[string]
|
||||||
GetDeprecated() NodeReference[bool]
|
GetDeprecated() NodeReference[bool]
|
||||||
GetExtensions() map[KeyReference[string]]ValueReference[any]
|
GetExtensions() *orderedmap.Map[KeyReference[string], ValueReference[*yaml.Node]]
|
||||||
GetResponses() NodeReference[any] // requires cast.
|
GetResponses() NodeReference[any] // requires cast.
|
||||||
GetParameters() NodeReference[any] // requires cast.
|
GetParameters() NodeReference[any] // requires cast.
|
||||||
GetSecurity() NodeReference[any] // requires cast.
|
GetSecurity() NodeReference[any] // requires cast.
|
||||||
@@ -117,6 +121,6 @@ type SwaggerOperations interface {
|
|||||||
|
|
||||||
type OpenAPIOperations interface {
|
type OpenAPIOperations interface {
|
||||||
SharedOperations
|
SharedOperations
|
||||||
GetCallbacks() NodeReference[map[KeyReference[string]]ValueReference[any]] // requires cast
|
GetCallbacks() NodeReference[*orderedmap.Map[KeyReference[string], ValueReference[any]]] // requires cast
|
||||||
GetServers() NodeReference[any] // requires cast.
|
GetServers() NodeReference[any] // requires cast.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package low
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -13,25 +15,35 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Reference struct {
|
type Reference struct {
|
||||||
Reference string `json:"-" yaml:"-"`
|
refNode *yaml.Node
|
||||||
|
reference string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reference) GetReference() string {
|
func (r Reference) GetReference() string {
|
||||||
return r.Reference
|
return r.reference
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reference) IsReference() bool {
|
func (r Reference) IsReference() bool {
|
||||||
return r.Reference != ""
|
return r.reference != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reference) SetReference(ref string) {
|
func (r Reference) GetReferenceNode() *yaml.Node {
|
||||||
r.Reference = ref
|
return r.refNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reference) SetReference(ref string, node *yaml.Node) {
|
||||||
|
r.reference = ref
|
||||||
|
r.refNode = node
|
||||||
}
|
}
|
||||||
|
|
||||||
type IsReferenced interface {
|
type IsReferenced interface {
|
||||||
IsReference() bool
|
IsReference() bool
|
||||||
GetReference() string
|
GetReference() string
|
||||||
SetReference(string)
|
GetReferenceNode() *yaml.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetReferencer interface {
|
||||||
|
SetReference(ref string, node *yaml.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buildable is an interface for any struct that can be 'built out'. This means that a struct can accept
|
// Buildable is an interface for any struct that can be 'built out'. This means that a struct can accept
|
||||||
@@ -63,16 +75,14 @@ type Hashable interface {
|
|||||||
|
|
||||||
// HasExtensions is implemented by any object that exposes extensions
|
// HasExtensions is implemented by any object that exposes extensions
|
||||||
type HasExtensions[T any] interface {
|
type HasExtensions[T any] interface {
|
||||||
|
|
||||||
// GetExtensions returns generic low level extensions
|
// GetExtensions returns generic low level extensions
|
||||||
GetExtensions() map[KeyReference[string]]ValueReference[any]
|
GetExtensions() *orderedmap.Map[KeyReference[string], ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasExtensionsUntyped is implemented by any object that exposes extensions
|
// HasExtensionsUntyped is implemented by any object that exposes extensions
|
||||||
type HasExtensionsUntyped interface {
|
type HasExtensionsUntyped interface {
|
||||||
|
|
||||||
// GetExtensions returns generic low level extensions
|
// GetExtensions returns generic low level extensions
|
||||||
GetExtensions() map[KeyReference[string]]ValueReference[any]
|
GetExtensions() *orderedmap.Map[KeyReference[string], ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasValue is implemented by NodeReference and ValueReference to return the yaml.Node backing the value.
|
// HasValue is implemented by NodeReference and ValueReference to return the yaml.Node backing the value.
|
||||||
@@ -98,6 +108,7 @@ type HasKeyNode interface {
|
|||||||
// a key yaml.Node that points to the key node that contains the value node, and the value node that contains
|
// a key yaml.Node that points to the key node that contains the value node, and the value node that contains
|
||||||
// the actual value.
|
// the actual value.
|
||||||
type NodeReference[T any] struct {
|
type NodeReference[T any] struct {
|
||||||
|
Reference
|
||||||
|
|
||||||
// The value being referenced
|
// The value being referenced
|
||||||
Value T
|
Value T
|
||||||
@@ -108,19 +119,14 @@ type NodeReference[T any] struct {
|
|||||||
// The yaml.Node that is the key, that contains the value.
|
// The yaml.Node that is the key, that contains the value.
|
||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
|
|
||||||
// Is this value actually a reference in the original tree?
|
|
||||||
ReferenceNode bool
|
|
||||||
|
|
||||||
// If HasReference is true, then Reference contains the original $ref value.
|
|
||||||
Reference string
|
|
||||||
|
|
||||||
Context context.Context
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ HasValueNodeUntyped = &NodeReference[any]{}
|
||||||
|
|
||||||
// KeyReference is a low-level container for key nodes holding a Value of type T. A KeyNode is a pointer to the
|
// KeyReference is a low-level container for key nodes holding a Value of type T. A KeyNode is a pointer to the
|
||||||
// yaml.Node that holds a key to a value.
|
// yaml.Node that holds a key to a value.
|
||||||
type KeyReference[T any] struct {
|
type KeyReference[T any] struct {
|
||||||
|
|
||||||
// The value being referenced.
|
// The value being referenced.
|
||||||
Value T
|
Value T
|
||||||
|
|
||||||
@@ -131,18 +137,13 @@ type KeyReference[T any] struct {
|
|||||||
// ValueReference is a low-level container for value nodes that hold a Value of type T. A ValueNode is a pointer
|
// ValueReference is a low-level container for value nodes that hold a Value of type T. A ValueNode is a pointer
|
||||||
// to the yaml.Node that holds the value.
|
// to the yaml.Node that holds the value.
|
||||||
type ValueReference[T any] struct {
|
type ValueReference[T any] struct {
|
||||||
|
Reference
|
||||||
|
|
||||||
// The value being referenced.
|
// The value being referenced.
|
||||||
Value T
|
Value T
|
||||||
|
|
||||||
// The yaml.Node that holds the referenced value
|
// The yaml.Node that holds the referenced value
|
||||||
ValueNode *yaml.Node
|
ValueNode *yaml.Node
|
||||||
|
|
||||||
// Is this value actually a reference in the original tree?
|
|
||||||
ReferenceNode bool
|
|
||||||
|
|
||||||
// If HasReference is true, then Reference contains the original $ref value.
|
|
||||||
Reference string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
|
// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
|
||||||
@@ -158,32 +159,6 @@ func (n NodeReference[T]) NodeLineNumber() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NodeReference[T]) GetReference() string {
|
|
||||||
return n.Reference
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n NodeReference[T]) SetReference(ref string) {
|
|
||||||
n.Reference = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsReference will return true if the key node contains a $ref key.
|
|
||||||
func (n NodeReference[T]) IsReference() bool {
|
|
||||||
if n.ReferenceNode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if n.KeyNode != nil {
|
|
||||||
for k := range n.KeyNode.Content {
|
|
||||||
if k%2 == 0 {
|
|
||||||
if n.KeyNode.Content[k].Value == "$ref" {
|
|
||||||
n.ReferenceNode = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateMapKey will return a string based on the line and column number of the node, e.g. 33:56 for line 33, col 56.
|
// GenerateMapKey will return a string based on the line and column number of the node, e.g. 33:56 for line 33, col 56.
|
||||||
func (n NodeReference[T]) GenerateMapKey() string {
|
func (n NodeReference[T]) GenerateMapKey() string {
|
||||||
return fmt.Sprintf("%d:%d", n.ValueNode.Line, n.ValueNode.Column)
|
return fmt.Sprintf("%d:%d", n.ValueNode.Line, n.ValueNode.Column)
|
||||||
@@ -251,36 +226,19 @@ func (n ValueReference[T]) GetValueUntyped() any {
|
|||||||
return n.Value
|
return n.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n ValueReference[T]) GetReference() string {
|
|
||||||
return n.Reference
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ValueReference[T]) SetReference(ref string) {
|
|
||||||
n.Reference = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsReference will return true if the key node contains a $ref
|
|
||||||
func (n ValueReference[T]) IsReference() bool {
|
|
||||||
if n.Reference != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ValueReference[T]) MarshalYAML() (interface{}, error) {
|
func (n ValueReference[T]) MarshalYAML() (interface{}, error) {
|
||||||
if n.IsReference() {
|
if n.IsReference() {
|
||||||
nodes := make([]*yaml.Node, 2)
|
return n.GetReferenceNode(), nil
|
||||||
nodes[0] = utils.CreateStringNode("$ref")
|
|
||||||
nodes[1] = utils.CreateStringNode(n.Reference)
|
|
||||||
m := utils.CreateEmptyMapNode()
|
|
||||||
m.Content = nodes
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
var h yaml.Node
|
var h yaml.Node
|
||||||
e := n.ValueNode.Decode(&h)
|
e := n.ValueNode.Decode(&h)
|
||||||
return h, e
|
return h, e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n KeyReference[T]) MarshalYAML() (interface{}, error) {
|
||||||
|
return n.KeyNode, nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
|
// IsEmpty will return true if this reference has no key or value nodes assigned (it's been ignored)
|
||||||
func (n KeyReference[T]) IsEmpty() bool {
|
func (n KeyReference[T]) IsEmpty() bool {
|
||||||
return n.KeyNode == nil
|
return n.KeyNode == nil
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ package low
|
|||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -99,7 +100,6 @@ func TestKeyReference_GenerateMapKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsCircular_LookupFromJourney(t *testing.T) {
|
func TestIsCircular_LookupFromJourney(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
Something:
|
Something:
|
||||||
@@ -136,7 +136,6 @@ func TestIsCircular_LookupFromJourney(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsCircular_LookupFromJourney_Optional(t *testing.T) {
|
func TestIsCircular_LookupFromJourney_Optional(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
Something:
|
Something:
|
||||||
@@ -237,7 +236,6 @@ func TestIsCircular_LookupFromLoopPoint_Optional(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsCircular_FromRefLookup(t *testing.T) {
|
func TestIsCircular_FromRefLookup(t *testing.T) {
|
||||||
|
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
NotCircle:
|
NotCircle:
|
||||||
@@ -558,21 +556,17 @@ func TestGetCircularReferenceResult_NothingFound(t *testing.T) {
|
|||||||
func TestHashToString(t *testing.T) {
|
func TestHashToString(t *testing.T) {
|
||||||
assert.Equal(t, "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5",
|
assert.Equal(t, "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5",
|
||||||
HashToString(sha256.Sum256([]byte("12345"))))
|
HashToString(sha256.Sum256([]byte("12345"))))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReference_IsReference(t *testing.T) {
|
func TestReference_IsReference(t *testing.T) {
|
||||||
ref := Reference{
|
ref := Reference{}
|
||||||
Reference: "#/components/schemas/SomeSchema",
|
ref.SetReference("#/components/schemas/SomeSchema", nil)
|
||||||
}
|
|
||||||
assert.True(t, ref.IsReference())
|
assert.True(t, ref.IsReference())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_NodeLineNumber(t *testing.T) {
|
func TestNodeReference_NodeLineNumber(t *testing.T) {
|
||||||
|
|
||||||
n := utils.CreateStringNode("pizza")
|
n := utils.CreateStringNode("pizza")
|
||||||
nr := NodeReference[string]{
|
nr := &NodeReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
ValueNode: n,
|
ValueNode: n,
|
||||||
}
|
}
|
||||||
@@ -582,51 +576,36 @@ func TestNodeReference_NodeLineNumber(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_NodeLineNumberEmpty(t *testing.T) {
|
func TestNodeReference_NodeLineNumberEmpty(t *testing.T) {
|
||||||
|
nr := &NodeReference[string]{
|
||||||
nr := NodeReference[string]{
|
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}
|
}
|
||||||
assert.Equal(t, 0, nr.NodeLineNumber())
|
assert.Equal(t, 0, nr.NodeLineNumber())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_GetReference(t *testing.T) {
|
func TestNodeReference_GetReference(t *testing.T) {
|
||||||
|
nr := &NodeReference[string]{}
|
||||||
nr := NodeReference[string]{
|
nr.SetReference("#/happy/sunday", nil)
|
||||||
Reference: "#/happy/sunday",
|
|
||||||
}
|
|
||||||
assert.Equal(t, "#/happy/sunday", nr.GetReference())
|
assert.Equal(t, "#/happy/sunday", nr.GetReference())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_SetReference(t *testing.T) {
|
func TestNodeReference_SetReference(t *testing.T) {
|
||||||
|
nr := &NodeReference[string]{}
|
||||||
nr := NodeReference[string]{}
|
nr.SetReference("#/happy/sunday", nil)
|
||||||
nr.SetReference("#/happy/sunday")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNodeReference_IsReference(t *testing.T) {
|
|
||||||
|
|
||||||
nr := NodeReference[string]{
|
|
||||||
ReferenceNode: true,
|
|
||||||
}
|
|
||||||
assert.True(t, nr.IsReference())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_GetKeyNode(t *testing.T) {
|
func TestNodeReference_GetKeyNode(t *testing.T) {
|
||||||
|
nr := &NodeReference[string]{
|
||||||
nr := NodeReference[string]{
|
|
||||||
KeyNode: utils.CreateStringNode("pizza"),
|
KeyNode: utils.CreateStringNode("pizza"),
|
||||||
}
|
}
|
||||||
assert.Equal(t, "pizza", nr.GetKeyNode().Value)
|
assert.Equal(t, "pizza", nr.GetKeyNode().Value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeReference_GetValueUntyped(t *testing.T) {
|
func TestNodeReference_GetValueUntyped(t *testing.T) {
|
||||||
|
|
||||||
type anything struct {
|
type anything struct {
|
||||||
thing string
|
thing string
|
||||||
}
|
}
|
||||||
|
|
||||||
nr := NodeReference[any]{
|
nr := &NodeReference[any]{
|
||||||
Value: anything{thing: "ding"},
|
Value: anything{thing: "ding"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +613,6 @@ func TestNodeReference_GetValueUntyped(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_NodeLineNumber(t *testing.T) {
|
func TestValueReference_NodeLineNumber(t *testing.T) {
|
||||||
|
|
||||||
n := utils.CreateStringNode("pizza")
|
n := utils.CreateStringNode("pizza")
|
||||||
nr := ValueReference[string]{
|
nr := ValueReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
@@ -646,7 +624,6 @@ func TestValueReference_NodeLineNumber(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_NodeLineNumber_Nil(t *testing.T) {
|
func TestValueReference_NodeLineNumber_Nil(t *testing.T) {
|
||||||
|
|
||||||
nr := ValueReference[string]{
|
nr := ValueReference[string]{
|
||||||
Value: "pizza",
|
Value: "pizza",
|
||||||
}
|
}
|
||||||
@@ -655,21 +632,12 @@ func TestValueReference_NodeLineNumber_Nil(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_GetReference(t *testing.T) {
|
func TestValueReference_GetReference(t *testing.T) {
|
||||||
|
nr := ValueReference[string]{}
|
||||||
nr := ValueReference[string]{
|
nr.SetReference("#/happy/sunday", nil)
|
||||||
Reference: "#/happy/sunday",
|
|
||||||
}
|
|
||||||
assert.Equal(t, "#/happy/sunday", nr.GetReference())
|
assert.Equal(t, "#/happy/sunday", nr.GetReference())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_SetReference(t *testing.T) {
|
|
||||||
|
|
||||||
nr := ValueReference[string]{}
|
|
||||||
nr.SetReference("#/happy/sunday")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValueReference_GetValueUntyped(t *testing.T) {
|
func TestValueReference_GetValueUntyped(t *testing.T) {
|
||||||
|
|
||||||
type anything struct {
|
type anything struct {
|
||||||
thing string
|
thing string
|
||||||
}
|
}
|
||||||
@@ -681,28 +649,15 @@ func TestValueReference_GetValueUntyped(t *testing.T) {
|
|||||||
assert.Equal(t, "{ding}", fmt.Sprint(nr.GetValueUntyped()))
|
assert.Equal(t, "{ding}", fmt.Sprint(nr.GetValueUntyped()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_IsReference(t *testing.T) {
|
|
||||||
|
|
||||||
nr := NodeReference[string]{
|
|
||||||
ReferenceNode: true,
|
|
||||||
}
|
|
||||||
assert.True(t, nr.IsReference())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValueReference_MarshalYAML_Ref(t *testing.T) {
|
func TestValueReference_MarshalYAML_Ref(t *testing.T) {
|
||||||
|
nr := ValueReference[string]{}
|
||||||
nr := ValueReference[string]{
|
nr.SetReference("#/burgers/beer", nil)
|
||||||
ReferenceNode: true,
|
|
||||||
Reference: "#/burgers/beer",
|
|
||||||
}
|
|
||||||
|
|
||||||
data, _ := yaml.Marshal(nr)
|
data, _ := yaml.Marshal(nr)
|
||||||
assert.Equal(t, `$ref: '#/burgers/beer'`, strings.TrimSpace(string(data)))
|
assert.Equal(t, `$ref: '#/burgers/beer'`, strings.TrimSpace(string(data)))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueReference_MarshalYAML(t *testing.T) {
|
func TestValueReference_MarshalYAML(t *testing.T) {
|
||||||
|
|
||||||
v := map[string]interface{}{
|
v := map[string]interface{}{
|
||||||
"beer": "burger",
|
"beer": "burger",
|
||||||
"wine": "cheese",
|
"wine": "cheese",
|
||||||
@@ -725,7 +680,6 @@ wine: cheese`
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyReference_GetValueUntyped(t *testing.T) {
|
func TestKeyReference_GetValueUntyped(t *testing.T) {
|
||||||
|
|
||||||
type anything struct {
|
type anything struct {
|
||||||
thing string
|
thing string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
@@ -23,7 +24,7 @@ import (
|
|||||||
// referenced to the ones defined here. It does not define global operation parameters
|
// referenced to the ones defined here. It does not define global operation parameters
|
||||||
// - https://swagger.io/specification/v2/#parametersDefinitionsObject
|
// - https://swagger.io/specification/v2/#parametersDefinitionsObject
|
||||||
type ParameterDefinitions struct {
|
type ParameterDefinitions struct {
|
||||||
Definitions orderedmap.Map[low.KeyReference[string], low.ValueReference[*Parameter]]
|
Definitions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*Parameter]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResponsesDefinitions is a low-level representation of a Swagger / OpenAPI 2 Responses Definitions object.
|
// ResponsesDefinitions is a low-level representation of a Swagger / OpenAPI 2 Responses Definitions object.
|
||||||
@@ -32,7 +33,7 @@ type ParameterDefinitions struct {
|
|||||||
// referenced to the ones defined here. It does not define global operation responses
|
// referenced to the ones defined here. It does not define global operation responses
|
||||||
// - https://swagger.io/specification/v2/#responsesDefinitionsObject
|
// - https://swagger.io/specification/v2/#responsesDefinitionsObject
|
||||||
type ResponsesDefinitions struct {
|
type ResponsesDefinitions struct {
|
||||||
Definitions orderedmap.Map[low.KeyReference[string], low.ValueReference[*Response]]
|
Definitions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*Response]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecurityDefinitions is a low-level representation of a Swagger / OpenAPI 2 Security Definitions object.
|
// SecurityDefinitions is a low-level representation of a Swagger / OpenAPI 2 Security Definitions object.
|
||||||
@@ -41,7 +42,7 @@ type ResponsesDefinitions struct {
|
|||||||
// schemes on the operations and only serves to provide the relevant details for each scheme
|
// schemes on the operations and only serves to provide the relevant details for each scheme
|
||||||
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
// - https://swagger.io/specification/v2/#securityDefinitionsObject
|
||||||
type SecurityDefinitions struct {
|
type SecurityDefinitions struct {
|
||||||
Definitions orderedmap.Map[low.KeyReference[string], low.ValueReference[*SecurityScheme]]
|
Definitions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*SecurityScheme]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definitions is a low-level representation of a Swagger / OpenAPI 2 Definitions object
|
// Definitions is a low-level representation of a Swagger / OpenAPI 2 Definitions object
|
||||||
@@ -50,7 +51,7 @@ type SecurityDefinitions struct {
|
|||||||
// arrays or models.
|
// arrays or models.
|
||||||
// - https://swagger.io/specification/v2/#definitionsObject
|
// - https://swagger.io/specification/v2/#definitionsObject
|
||||||
type Definitions struct {
|
type Definitions struct {
|
||||||
Schemas orderedmap.Map[low.KeyReference[string], low.ValueReference[*base.SchemaProxy]]
|
Schemas *orderedmap.Map[low.KeyReference[string], low.ValueReference[*base.SchemaProxy]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindSchema will attempt to locate a base.SchemaProxy instance using a name.
|
// FindSchema will attempt to locate a base.SchemaProxy instance using a name.
|
||||||
@@ -77,46 +78,79 @@ func (s *SecurityDefinitions) FindSecurityDefinition(securityDef string) *low.Va
|
|||||||
func (d *Definitions) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIndex) error {
|
func (d *Definitions) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
// TODO: Refactor with orderedmap.TranslatePipeline.
|
type buildInput struct {
|
||||||
errorChan := make(chan error)
|
label *yaml.Node
|
||||||
resultChan := make(chan definitionResult[*base.SchemaProxy])
|
value *yaml.Node
|
||||||
var defLabel *yaml.Node
|
|
||||||
totalDefinitions := 0
|
|
||||||
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
|
||||||
r chan definitionResult[*base.SchemaProxy], e chan error) {
|
|
||||||
|
|
||||||
obj, err, _, rv := low.ExtractObjectRaw[*base.SchemaProxy](ctx, label, value, idx)
|
|
||||||
if err != nil {
|
|
||||||
e <- err
|
|
||||||
}
|
|
||||||
r <- definitionResult[*base.SchemaProxy]{k: label, v: low.ValueReference[*base.SchemaProxy]{
|
|
||||||
Value: obj, ValueNode: value, Reference: rv,
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
for i := range root.Content {
|
|
||||||
if i%2 == 0 {
|
|
||||||
defLabel = root.Content[i]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
totalDefinitions++
|
|
||||||
go buildFunc(defLabel, root.Content[i], idx, resultChan, errorChan)
|
|
||||||
}
|
|
||||||
|
|
||||||
completedDefs := 0
|
|
||||||
results := orderedmap.New[low.KeyReference[string], low.ValueReference[*base.SchemaProxy]]()
|
results := orderedmap.New[low.KeyReference[string], low.ValueReference[*base.SchemaProxy]]()
|
||||||
for completedDefs < totalDefinitions {
|
in := make(chan buildInput)
|
||||||
select {
|
out := make(chan definitionResult[*base.SchemaProxy])
|
||||||
case err := <-errorChan:
|
done := make(chan struct{})
|
||||||
return err
|
var wg sync.WaitGroup
|
||||||
case sch := <-resultChan:
|
wg.Add(2) // input and output goroutines.
|
||||||
completedDefs++
|
|
||||||
key := low.KeyReference[string]{
|
// TranslatePipeline input.
|
||||||
Value: sch.k.Value,
|
go func() {
|
||||||
KeyNode: sch.k,
|
defer func() {
|
||||||
|
close(in)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
var label *yaml.Node
|
||||||
|
for i, value := range root.Content {
|
||||||
|
if i%2 == 0 {
|
||||||
|
label = value
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case in <- buildInput{
|
||||||
|
label: label,
|
||||||
|
value: value,
|
||||||
|
}:
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
results.Set(key, sch.v)
|
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TranslatePipeline output.
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
result, ok := <-out
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
key := low.KeyReference[string]{
|
||||||
|
Value: result.k.Value,
|
||||||
|
KeyNode: result.k,
|
||||||
|
}
|
||||||
|
results.Set(key, result.v)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
translateFunc := func(value buildInput) (definitionResult[*base.SchemaProxy], error) {
|
||||||
|
obj, err, _, rv := low.ExtractObjectRaw[*base.SchemaProxy](ctx, value.label, value.value, idx)
|
||||||
|
if err != nil {
|
||||||
|
return definitionResult[*base.SchemaProxy]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := low.ValueReference[*base.SchemaProxy]{
|
||||||
|
Value: obj, ValueNode: value.value,
|
||||||
|
}
|
||||||
|
v.SetReference(rv, value.value)
|
||||||
|
|
||||||
|
return definitionResult[*base.SchemaProxy]{k: value.label, v: v}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := datamodel.TranslatePipeline[buildInput, definitionResult[*base.SchemaProxy]](in, out, translateFunc)
|
||||||
|
wg.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
d.Schemas = results
|
d.Schemas = results
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -124,15 +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
|
// Hash will return a consistent SHA256 Hash of the Definitions object
|
||||||
func (d *Definitions) Hash() [32]byte {
|
func (d *Definitions) Hash() [32]byte {
|
||||||
var f []string
|
var f []string
|
||||||
keys := make([]string, orderedmap.Len(d.Schemas))
|
for pair := orderedmap.First(orderedmap.SortAlpha(d.Schemas)); pair != nil; pair = pair.Next() {
|
||||||
z := 0
|
f = append(f, low.GenerateHashString(d.FindSchema(pair.Key().Value).Value))
|
||||||
for pair := orderedmap.First(d.Schemas); pair != nil; pair = pair.Next() {
|
|
||||||
keys[z] = pair.Key().Value
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for k := range keys {
|
|
||||||
f = append(f, low.GenerateHashString(d.FindSchema(keys[k]).Value))
|
|
||||||
}
|
}
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
@@ -143,15 +170,21 @@ func (pd *ParameterDefinitions) Build(ctx context.Context, _, root *yaml.Node, i
|
|||||||
resultChan := make(chan definitionResult[*Parameter])
|
resultChan := make(chan definitionResult[*Parameter])
|
||||||
var defLabel *yaml.Node
|
var defLabel *yaml.Node
|
||||||
totalDefinitions := 0
|
totalDefinitions := 0
|
||||||
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
buildFunc := func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
||||||
r chan definitionResult[*Parameter], e chan error) {
|
r chan definitionResult[*Parameter], e chan error,
|
||||||
|
) {
|
||||||
obj, err, _, rv := low.ExtractObjectRaw[*Parameter](ctx, label, value, idx)
|
obj, err, _, rv := low.ExtractObjectRaw[*Parameter](ctx, label, value, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e <- err
|
e <- err
|
||||||
}
|
}
|
||||||
r <- definitionResult[*Parameter]{k: label, v: low.ValueReference[*Parameter]{Value: obj,
|
|
||||||
ValueNode: value, Reference: rv}}
|
v := low.ValueReference[*Parameter]{
|
||||||
|
Value: obj,
|
||||||
|
ValueNode: value,
|
||||||
|
}
|
||||||
|
v.SetReference(rv, value)
|
||||||
|
|
||||||
|
r <- definitionResult[*Parameter]{k: label, v: v}
|
||||||
}
|
}
|
||||||
for i := range root.Content {
|
for i := range root.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
@@ -193,15 +226,21 @@ func (r *ResponsesDefinitions) Build(ctx context.Context, _, root *yaml.Node, id
|
|||||||
resultChan := make(chan definitionResult[*Response])
|
resultChan := make(chan definitionResult[*Response])
|
||||||
var defLabel *yaml.Node
|
var defLabel *yaml.Node
|
||||||
totalDefinitions := 0
|
totalDefinitions := 0
|
||||||
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
buildFunc := func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
||||||
r chan definitionResult[*Response], e chan error) {
|
r chan definitionResult[*Response], e chan error,
|
||||||
|
) {
|
||||||
obj, err, _, rv := low.ExtractObjectRaw[*Response](ctx, label, value, idx)
|
obj, err, _, rv := low.ExtractObjectRaw[*Response](ctx, label, value, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e <- err
|
e <- err
|
||||||
}
|
}
|
||||||
r <- definitionResult[*Response]{k: label, v: low.ValueReference[*Response]{Value: obj,
|
|
||||||
ValueNode: value, Reference: rv}}
|
v := low.ValueReference[*Response]{
|
||||||
|
Value: obj,
|
||||||
|
ValueNode: value,
|
||||||
|
}
|
||||||
|
v.SetReference(rv, value)
|
||||||
|
|
||||||
|
r <- definitionResult[*Response]{k: label, v: v}
|
||||||
}
|
}
|
||||||
for i := range root.Content {
|
for i := range root.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
@@ -238,16 +277,20 @@ func (s *SecurityDefinitions) Build(ctx context.Context, _, root *yaml.Node, idx
|
|||||||
var defLabel *yaml.Node
|
var defLabel *yaml.Node
|
||||||
totalDefinitions := 0
|
totalDefinitions := 0
|
||||||
|
|
||||||
var buildFunc = func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
buildFunc := func(label *yaml.Node, value *yaml.Node, idx *index.SpecIndex,
|
||||||
r chan definitionResult[*SecurityScheme], e chan error) {
|
r chan definitionResult[*SecurityScheme], e chan error,
|
||||||
|
) {
|
||||||
obj, err, _, rv := low.ExtractObjectRaw[*SecurityScheme](ctx, label, value, idx)
|
obj, err, _, rv := low.ExtractObjectRaw[*SecurityScheme](ctx, label, value, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e <- err
|
e <- err
|
||||||
}
|
}
|
||||||
r <- definitionResult[*SecurityScheme]{k: label, v: low.ValueReference[*SecurityScheme]{
|
|
||||||
Value: obj, ValueNode: value, Reference: rv,
|
v := low.ValueReference[*SecurityScheme]{
|
||||||
}}
|
Value: obj, ValueNode: value,
|
||||||
|
}
|
||||||
|
v.SetReference(rv, value)
|
||||||
|
|
||||||
|
r <- definitionResult[*SecurityScheme]{k: label, v: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range root.Content {
|
for i := range root.Content {
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
@@ -21,12 +19,12 @@ import (
|
|||||||
// Allows sharing examples for operation responses
|
// Allows sharing examples for operation responses
|
||||||
// - https://swagger.io/specification/v2/#exampleObject
|
// - https://swagger.io/specification/v2/#exampleObject
|
||||||
type Examples struct {
|
type Examples struct {
|
||||||
Values orderedmap.Map[low.KeyReference[string], low.ValueReference[any]]
|
Values *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExample attempts to locate an example value, using a key label.
|
// FindExample attempts to locate an example value, using a key label.
|
||||||
func (e *Examples) FindExample(name string) *low.ValueReference[any] {
|
func (e *Examples) FindExample(name string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInOrderedMap[any](name, e.Values)
|
return low.FindItemInOrderedMap(name, e.Values)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract all examples and will attempt to unmarshal content into a map or slice based on type.
|
// Build will extract all examples and will attempt to unmarshal content into a map or slice based on type.
|
||||||
@@ -34,54 +32,21 @@ func (e *Examples) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecInd
|
|||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
var keyNode, currNode *yaml.Node
|
var keyNode, currNode *yaml.Node
|
||||||
var err error
|
e.Values = orderedmap.New[low.KeyReference[string], low.ValueReference[*yaml.Node]]()
|
||||||
e.Values = orderedmap.New[low.KeyReference[string], low.ValueReference[any]]()
|
|
||||||
for i := range root.Content {
|
for i := range root.Content {
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
keyNode = root.Content[i]
|
keyNode = root.Content[i]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
currNode = root.Content[i]
|
currNode = root.Content[i]
|
||||||
var n map[string]interface{}
|
|
||||||
err = currNode.Decode(&n)
|
|
||||||
if err != nil {
|
|
||||||
var k []interface{}
|
|
||||||
err = currNode.Decode(&k)
|
|
||||||
if err != nil {
|
|
||||||
// lets just default to interface
|
|
||||||
var j interface{}
|
|
||||||
_ = currNode.Decode(&j)
|
|
||||||
e.Values.Set(
|
|
||||||
low.KeyReference[string]{
|
|
||||||
Value: keyNode.Value,
|
|
||||||
KeyNode: keyNode,
|
|
||||||
},
|
|
||||||
low.ValueReference[any]{
|
|
||||||
Value: j,
|
|
||||||
ValueNode: currNode,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
e.Values.Set(
|
|
||||||
low.KeyReference[string]{
|
|
||||||
Value: keyNode.Value,
|
|
||||||
KeyNode: keyNode,
|
|
||||||
},
|
|
||||||
low.ValueReference[any]{
|
|
||||||
Value: k,
|
|
||||||
ValueNode: currNode,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
e.Values.Set(
|
e.Values.Set(
|
||||||
low.KeyReference[string]{
|
low.KeyReference[string]{
|
||||||
Value: keyNode.Value,
|
Value: keyNode.Value,
|
||||||
KeyNode: keyNode,
|
KeyNode: keyNode,
|
||||||
},
|
},
|
||||||
low.ValueReference[any]{
|
low.ValueReference[*yaml.Node]{
|
||||||
Value: n,
|
Value: currNode,
|
||||||
ValueNode: currNode,
|
ValueNode: currNode,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -92,15 +57,8 @@ func (e *Examples) Build(_ context.Context, _, root *yaml.Node, _ *index.SpecInd
|
|||||||
// Hash will return a consistent SHA256 Hash of the Examples object
|
// Hash will return a consistent SHA256 Hash of the Examples object
|
||||||
func (e *Examples) Hash() [32]byte {
|
func (e *Examples) Hash() [32]byte {
|
||||||
var f []string
|
var f []string
|
||||||
keys := make([]string, orderedmap.Len(e.Values))
|
for pair := orderedmap.First(orderedmap.SortAlpha(e.Values)); pair != nil; pair = pair.Next() {
|
||||||
z := 0
|
f = append(f, low.GenerateHashString(pair.Value().Value))
|
||||||
for pair := orderedmap.First(e.Values); pair != nil; pair = pair.Next() {
|
|
||||||
keys[z] = pair.Key().Value
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for k := range keys {
|
|
||||||
f = append(f, fmt.Sprintf("%v", e.FindExample(keys[k]).Value))
|
|
||||||
}
|
}
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Header Represents a low-level Swagger / OpenAPI 2 Header object.
|
// Header Represents a low-level Swagger / OpenAPI 2 Header object.
|
||||||
@@ -25,7 +27,7 @@ type Header struct {
|
|||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
Items low.NodeReference[*Items]
|
Items low.NodeReference[*Items]
|
||||||
CollectionFormat low.NodeReference[string]
|
CollectionFormat low.NodeReference[string]
|
||||||
Default low.NodeReference[any]
|
Default low.NodeReference[*yaml.Node]
|
||||||
Maximum low.NodeReference[int]
|
Maximum low.NodeReference[int]
|
||||||
ExclusiveMaximum low.NodeReference[bool]
|
ExclusiveMaximum low.NodeReference[bool]
|
||||||
Minimum low.NodeReference[int]
|
Minimum low.NodeReference[int]
|
||||||
@@ -36,18 +38,18 @@ type Header struct {
|
|||||||
MaxItems low.NodeReference[int]
|
MaxItems low.NodeReference[int]
|
||||||
MinItems low.NodeReference[int]
|
MinItems low.NodeReference[int]
|
||||||
UniqueItems low.NodeReference[bool]
|
UniqueItems low.NodeReference[bool]
|
||||||
Enum low.NodeReference[[]low.ValueReference[any]]
|
Enum low.NodeReference[[]low.ValueReference[*yaml.Node]]
|
||||||
MultipleOf low.NodeReference[int]
|
MultipleOf low.NodeReference[int]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension will attempt to locate an extension value using a name lookup.
|
// FindExtension will attempt to locate an extension value using a name lookup.
|
||||||
func (h *Header) FindExtension(ext string) *low.ValueReference[any] {
|
func (h *Header) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, h.Extensions)
|
return low.FindItemInOrderedMap(ext, h.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Header extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Header extensions and satisfies the low.HasExtensions interface.
|
||||||
func (h *Header) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (h *Header) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return h.Extensions
|
return h.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,37 +66,14 @@ func (h *Header) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecI
|
|||||||
|
|
||||||
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
var n map[string]interface{}
|
h.Default = low.NodeReference[*yaml.Node]{
|
||||||
err = vn.Decode(&n)
|
Value: vn,
|
||||||
if err != nil {
|
|
||||||
// if not a map, then try an array
|
|
||||||
var k []interface{}
|
|
||||||
err = vn.Decode(&k)
|
|
||||||
if err != nil {
|
|
||||||
// lets just default to interface
|
|
||||||
var j interface{}
|
|
||||||
_ = vn.Decode(&j)
|
|
||||||
h.Default = low.NodeReference[any]{
|
|
||||||
Value: j,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
h.Default = low.NodeReference[any]{
|
|
||||||
Value: k,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
h.Default = low.NodeReference[any]{
|
|
||||||
Value: n,
|
|
||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +92,8 @@ func (h *Header) Hash() [32]byte {
|
|||||||
if h.CollectionFormat.Value != "" {
|
if h.CollectionFormat.Value != "" {
|
||||||
f = append(f, h.CollectionFormat.Value)
|
f = append(f, h.CollectionFormat.Value)
|
||||||
}
|
}
|
||||||
if h.Default.Value != "" {
|
if h.Default.Value != nil && !h.Default.Value.IsZero() {
|
||||||
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(h.Default.Value)))))
|
f = append(f, low.GenerateHashString(h.Default.Value))
|
||||||
}
|
}
|
||||||
f = append(f, fmt.Sprint(h.Maximum.Value))
|
f = append(f, fmt.Sprint(h.Maximum.Value))
|
||||||
f = append(f, fmt.Sprint(h.Minimum.Value))
|
f = append(f, fmt.Sprint(h.Minimum.Value))
|
||||||
@@ -129,24 +108,17 @@ func (h *Header) Hash() [32]byte {
|
|||||||
if h.Pattern.Value != "" {
|
if h.Pattern.Value != "" {
|
||||||
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(h.Pattern.Value)))))
|
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(h.Pattern.Value)))))
|
||||||
}
|
}
|
||||||
|
f = append(f, low.HashExtensions(h.Extensions)...)
|
||||||
|
|
||||||
keys := make([]string, len(h.Extensions))
|
keys := make([]string, len(h.Enum.Value))
|
||||||
z := 0
|
z := 0
|
||||||
for k := range h.Extensions {
|
for k := range h.Enum.Value {
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(h.Extensions[k].Value))))
|
keys[z] = low.ValueToString(h.Enum.Value[k].Value)
|
||||||
z++
|
z++
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
f = append(f, keys...)
|
f = append(f, keys...)
|
||||||
|
|
||||||
keys = make([]string, len(h.Enum.Value))
|
|
||||||
z = 0
|
|
||||||
for k := range h.Enum.Value {
|
|
||||||
keys[z] = fmt.Sprint(h.Enum.Value[k].Value)
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
if h.Items.Value != nil {
|
if h.Items.Value != nil {
|
||||||
f = append(f, low.GenerateHashString(h.Items.Value))
|
f = append(f, low.GenerateHashString(h.Items.Value))
|
||||||
}
|
}
|
||||||
@@ -158,12 +130,15 @@ func (h *Header) Hash() [32]byte {
|
|||||||
func (h *Header) GetType() *low.NodeReference[string] {
|
func (h *Header) GetType() *low.NodeReference[string] {
|
||||||
return &h.Type
|
return &h.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetDescription() *low.NodeReference[string] {
|
func (h *Header) GetDescription() *low.NodeReference[string] {
|
||||||
return &h.Description
|
return &h.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetFormat() *low.NodeReference[string] {
|
func (h *Header) GetFormat() *low.NodeReference[string] {
|
||||||
return &h.Format
|
return &h.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetItems() *low.NodeReference[any] {
|
func (h *Header) GetItems() *low.NodeReference[any] {
|
||||||
i := low.NodeReference[any]{
|
i := low.NodeReference[any]{
|
||||||
KeyNode: h.Items.KeyNode,
|
KeyNode: h.Items.KeyNode,
|
||||||
@@ -172,45 +147,59 @@ func (h *Header) GetItems() *low.NodeReference[any] {
|
|||||||
}
|
}
|
||||||
return &i
|
return &i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetCollectionFormat() *low.NodeReference[string] {
|
func (h *Header) GetCollectionFormat() *low.NodeReference[string] {
|
||||||
return &h.CollectionFormat
|
return &h.CollectionFormat
|
||||||
}
|
}
|
||||||
func (h *Header) GetDefault() *low.NodeReference[any] {
|
|
||||||
|
func (h *Header) GetDefault() *low.NodeReference[*yaml.Node] {
|
||||||
return &h.Default
|
return &h.Default
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMaximum() *low.NodeReference[int] {
|
func (h *Header) GetMaximum() *low.NodeReference[int] {
|
||||||
return &h.Maximum
|
return &h.Maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetExclusiveMaximum() *low.NodeReference[bool] {
|
func (h *Header) GetExclusiveMaximum() *low.NodeReference[bool] {
|
||||||
return &h.ExclusiveMaximum
|
return &h.ExclusiveMaximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMinimum() *low.NodeReference[int] {
|
func (h *Header) GetMinimum() *low.NodeReference[int] {
|
||||||
return &h.Minimum
|
return &h.Minimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetExclusiveMinimum() *low.NodeReference[bool] {
|
func (h *Header) GetExclusiveMinimum() *low.NodeReference[bool] {
|
||||||
return &h.ExclusiveMinimum
|
return &h.ExclusiveMinimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMaxLength() *low.NodeReference[int] {
|
func (h *Header) GetMaxLength() *low.NodeReference[int] {
|
||||||
return &h.MaxLength
|
return &h.MaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMinLength() *low.NodeReference[int] {
|
func (h *Header) GetMinLength() *low.NodeReference[int] {
|
||||||
return &h.MinLength
|
return &h.MinLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetPattern() *low.NodeReference[string] {
|
func (h *Header) GetPattern() *low.NodeReference[string] {
|
||||||
return &h.Pattern
|
return &h.Pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMaxItems() *low.NodeReference[int] {
|
func (h *Header) GetMaxItems() *low.NodeReference[int] {
|
||||||
return &h.MaxItems
|
return &h.MaxItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMinItems() *low.NodeReference[int] {
|
func (h *Header) GetMinItems() *low.NodeReference[int] {
|
||||||
return &h.MinItems
|
return &h.MinItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetUniqueItems() *low.NodeReference[bool] {
|
func (h *Header) GetUniqueItems() *low.NodeReference[bool] {
|
||||||
return &h.UniqueItems
|
return &h.UniqueItems
|
||||||
}
|
}
|
||||||
func (h *Header) GetEnum() *low.NodeReference[[]low.ValueReference[any]] {
|
|
||||||
|
func (h *Header) GetEnum() *low.NodeReference[[]low.ValueReference[*yaml.Node]] {
|
||||||
return &h.Enum
|
return &h.Enum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Header) GetMultipleOf() *low.NodeReference[int] {
|
func (h *Header) GetMultipleOf() *low.NodeReference[int] {
|
||||||
return &h.MultipleOf
|
return &h.MultipleOf
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHeader_Build(t *testing.T) {
|
func TestHeader_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `items:
|
yml := `items:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -28,11 +29,9 @@ func TestHeader_Build(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeader_DefaultAsSlice(t *testing.T) {
|
func TestHeader_DefaultAsSlice(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-ext: thing
|
yml := `x-ext: thing
|
||||||
default:
|
default:
|
||||||
- why
|
- why
|
||||||
@@ -48,12 +47,15 @@ default:
|
|||||||
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
|
|
||||||
assert.NotNil(t, n.Default.Value)
|
assert.NotNil(t, n.Default.Value)
|
||||||
assert.Len(t, n.Default.Value, 3)
|
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
var def []string
|
||||||
|
_ = n.Default.GetValue().Decode(&def)
|
||||||
|
|
||||||
|
assert.Len(t, def, 3)
|
||||||
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeader_DefaultAsObject(t *testing.T) {
|
func TestHeader_DefaultAsObject(t *testing.T) {
|
||||||
|
|
||||||
yml := `default:
|
yml := `default:
|
||||||
lets:
|
lets:
|
||||||
create:
|
create:
|
||||||
@@ -72,7 +74,6 @@ func TestHeader_DefaultAsObject(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHeader_NoDefault(t *testing.T) {
|
func TestHeader_NoDefault(t *testing.T) {
|
||||||
|
|
||||||
yml := `minimum: 12`
|
yml := `minimum: 12`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -87,7 +88,6 @@ func TestHeader_NoDefault(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHeader_Hash_n_Grab(t *testing.T) {
|
func TestHeader_Hash_n_Grab(t *testing.T) {
|
||||||
|
|
||||||
yml := `description: head
|
yml := `description: head
|
||||||
type: string
|
type: string
|
||||||
format: left
|
format: left
|
||||||
@@ -160,7 +160,11 @@ pattern: wow
|
|||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
||||||
assert.Equal(t, "shut that door!", n.GetDefault().Value)
|
|
||||||
|
var def string
|
||||||
|
_ = n.GetDefault().Value.Decode(&def)
|
||||||
|
assert.Equal(t, "shut that door!", def)
|
||||||
|
|
||||||
assert.Equal(t, 10, n.GetMaximum().Value)
|
assert.Equal(t, 10, n.GetMaximum().Value)
|
||||||
assert.Equal(t, 1, n.GetMinimum().Value)
|
assert.Equal(t, 1, n.GetMinimum().Value)
|
||||||
assert.True(t, n.GetExclusiveMinimum().Value)
|
assert.True(t, n.GetExclusiveMinimum().Value)
|
||||||
@@ -174,6 +178,8 @@ pattern: wow
|
|||||||
assert.Equal(t, "wow", n.GetPattern().Value)
|
assert.Equal(t, "wow", n.GetPattern().Value)
|
||||||
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
||||||
assert.Len(t, n.GetEnum().Value, 2)
|
assert.Len(t, n.GetEnum().Value, 2)
|
||||||
assert.Equal(t, "large", n.FindExtension("x-belly").Value)
|
|
||||||
|
|
||||||
|
var xBelly string
|
||||||
|
_ = n.FindExtension("x-belly").GetValue().Decode(&xBelly)
|
||||||
|
assert.Equal(t, "large", xBelly)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Items is a low-level representation of a Swagger / OpenAPI 2 Items object.
|
// Items is a low-level representation of a Swagger / OpenAPI 2 Items object.
|
||||||
@@ -25,7 +27,7 @@ type Items struct {
|
|||||||
Format low.NodeReference[string]
|
Format low.NodeReference[string]
|
||||||
CollectionFormat low.NodeReference[string]
|
CollectionFormat low.NodeReference[string]
|
||||||
Items low.NodeReference[*Items]
|
Items low.NodeReference[*Items]
|
||||||
Default low.NodeReference[any]
|
Default low.NodeReference[*yaml.Node]
|
||||||
Maximum low.NodeReference[int]
|
Maximum low.NodeReference[int]
|
||||||
ExclusiveMaximum low.NodeReference[bool]
|
ExclusiveMaximum low.NodeReference[bool]
|
||||||
Minimum low.NodeReference[int]
|
Minimum low.NodeReference[int]
|
||||||
@@ -36,18 +38,18 @@ type Items struct {
|
|||||||
MaxItems low.NodeReference[int]
|
MaxItems low.NodeReference[int]
|
||||||
MinItems low.NodeReference[int]
|
MinItems low.NodeReference[int]
|
||||||
UniqueItems low.NodeReference[bool]
|
UniqueItems low.NodeReference[bool]
|
||||||
Enum low.NodeReference[[]low.ValueReference[any]]
|
Enum low.NodeReference[[]low.ValueReference[*yaml.Node]]
|
||||||
MultipleOf low.NodeReference[int]
|
MultipleOf low.NodeReference[int]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension will attempt to locate an extension value using a name lookup.
|
// FindExtension will attempt to locate an extension value using a name lookup.
|
||||||
func (i *Items) FindExtension(ext string) *low.ValueReference[any] {
|
func (i *Items) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, i.Extensions)
|
return low.FindItemInOrderedMap(ext, i.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Items extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Items extensions and satisfies the low.HasExtensions interface.
|
||||||
func (i *Items) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (i *Items) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return i.Extensions
|
return i.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +65,8 @@ func (i *Items) Hash() [32]byte {
|
|||||||
if i.CollectionFormat.Value != "" {
|
if i.CollectionFormat.Value != "" {
|
||||||
f = append(f, i.CollectionFormat.Value)
|
f = append(f, i.CollectionFormat.Value)
|
||||||
}
|
}
|
||||||
if i.Default.Value != "" {
|
if i.Default.Value != nil && !i.Default.Value.IsZero() {
|
||||||
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(i.Default.Value)))))
|
f = append(f, low.GenerateHashString(i.Default.Value))
|
||||||
}
|
}
|
||||||
f = append(f, fmt.Sprint(i.Maximum.Value))
|
f = append(f, fmt.Sprint(i.Maximum.Value))
|
||||||
f = append(f, fmt.Sprint(i.Minimum.Value))
|
f = append(f, fmt.Sprint(i.Minimum.Value))
|
||||||
@@ -82,7 +84,7 @@ func (i *Items) Hash() [32]byte {
|
|||||||
keys := make([]string, len(i.Enum.Value))
|
keys := make([]string, len(i.Enum.Value))
|
||||||
z := 0
|
z := 0
|
||||||
for k := range i.Enum.Value {
|
for k := range i.Enum.Value {
|
||||||
keys[z] = fmt.Sprint(i.Enum.Value[k].Value)
|
keys[z] = low.ValueToString(i.Enum.Value[k].Value)
|
||||||
z++
|
z++
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
@@ -91,14 +93,7 @@ func (i *Items) Hash() [32]byte {
|
|||||||
if i.Items.Value != nil {
|
if i.Items.Value != nil {
|
||||||
f = append(f, low.GenerateHashString(i.Items.Value))
|
f = append(f, low.GenerateHashString(i.Items.Value))
|
||||||
}
|
}
|
||||||
keys = make([]string, len(i.Extensions))
|
f = append(f, low.HashExtensions(i.Extensions)...)
|
||||||
z = 0
|
|
||||||
for k := range i.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(i.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,32 +110,8 @@ func (i *Items) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIn
|
|||||||
|
|
||||||
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
var n map[string]interface{}
|
i.Default = low.NodeReference[*yaml.Node]{
|
||||||
err := vn.Decode(&n)
|
Value: vn,
|
||||||
if err != nil {
|
|
||||||
// if not a map, then try an array
|
|
||||||
var k []interface{}
|
|
||||||
err = vn.Decode(&k)
|
|
||||||
if err != nil {
|
|
||||||
// lets just default to interface
|
|
||||||
var j interface{}
|
|
||||||
_ = vn.Decode(&j)
|
|
||||||
i.Default = low.NodeReference[any]{
|
|
||||||
Value: j,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
i.Default = low.NodeReference[any]{
|
|
||||||
Value: k,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
i.Default = low.NodeReference[any]{
|
|
||||||
Value: n,
|
|
||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
@@ -154,9 +125,11 @@ func (i *Items) Build(ctx context.Context, _, root *yaml.Node, idx *index.SpecIn
|
|||||||
func (i *Items) GetType() *low.NodeReference[string] {
|
func (i *Items) GetType() *low.NodeReference[string] {
|
||||||
return &i.Type
|
return &i.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetFormat() *low.NodeReference[string] {
|
func (i *Items) GetFormat() *low.NodeReference[string] {
|
||||||
return &i.Format
|
return &i.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetItems() *low.NodeReference[any] {
|
func (i *Items) GetItems() *low.NodeReference[any] {
|
||||||
k := low.NodeReference[any]{
|
k := low.NodeReference[any]{
|
||||||
KeyNode: i.Items.KeyNode,
|
KeyNode: i.Items.KeyNode,
|
||||||
@@ -165,48 +138,63 @@ func (i *Items) GetItems() *low.NodeReference[any] {
|
|||||||
}
|
}
|
||||||
return &k
|
return &k
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetCollectionFormat() *low.NodeReference[string] {
|
func (i *Items) GetCollectionFormat() *low.NodeReference[string] {
|
||||||
return &i.CollectionFormat
|
return &i.CollectionFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetDescription() *low.NodeReference[string] {
|
func (i *Items) GetDescription() *low.NodeReference[string] {
|
||||||
return nil // not implemented, but required to align with header contract
|
return nil // not implemented, but required to align with header contract
|
||||||
}
|
}
|
||||||
func (i *Items) GetDefault() *low.NodeReference[any] {
|
|
||||||
|
func (i *Items) GetDefault() *low.NodeReference[*yaml.Node] {
|
||||||
return &i.Default
|
return &i.Default
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMaximum() *low.NodeReference[int] {
|
func (i *Items) GetMaximum() *low.NodeReference[int] {
|
||||||
return &i.Maximum
|
return &i.Maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetExclusiveMaximum() *low.NodeReference[bool] {
|
func (i *Items) GetExclusiveMaximum() *low.NodeReference[bool] {
|
||||||
return &i.ExclusiveMaximum
|
return &i.ExclusiveMaximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMinimum() *low.NodeReference[int] {
|
func (i *Items) GetMinimum() *low.NodeReference[int] {
|
||||||
return &i.Minimum
|
return &i.Minimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetExclusiveMinimum() *low.NodeReference[bool] {
|
func (i *Items) GetExclusiveMinimum() *low.NodeReference[bool] {
|
||||||
return &i.ExclusiveMinimum
|
return &i.ExclusiveMinimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMaxLength() *low.NodeReference[int] {
|
func (i *Items) GetMaxLength() *low.NodeReference[int] {
|
||||||
return &i.MaxLength
|
return &i.MaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMinLength() *low.NodeReference[int] {
|
func (i *Items) GetMinLength() *low.NodeReference[int] {
|
||||||
return &i.MinLength
|
return &i.MinLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetPattern() *low.NodeReference[string] {
|
func (i *Items) GetPattern() *low.NodeReference[string] {
|
||||||
return &i.Pattern
|
return &i.Pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMaxItems() *low.NodeReference[int] {
|
func (i *Items) GetMaxItems() *low.NodeReference[int] {
|
||||||
return &i.MaxItems
|
return &i.MaxItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMinItems() *low.NodeReference[int] {
|
func (i *Items) GetMinItems() *low.NodeReference[int] {
|
||||||
return &i.MinItems
|
return &i.MinItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetUniqueItems() *low.NodeReference[bool] {
|
func (i *Items) GetUniqueItems() *low.NodeReference[bool] {
|
||||||
return &i.UniqueItems
|
return &i.UniqueItems
|
||||||
}
|
}
|
||||||
func (i *Items) GetEnum() *low.NodeReference[[]low.ValueReference[any]] {
|
|
||||||
|
func (i *Items) GetEnum() *low.NodeReference[[]low.ValueReference[*yaml.Node]] {
|
||||||
return &i.Enum
|
return &i.Enum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Items) GetMultipleOf() *low.NodeReference[int] {
|
func (i *Items) GetMultipleOf() *low.NodeReference[int] {
|
||||||
return &i.MultipleOf
|
return &i.MultipleOf
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestItems_Build(t *testing.T) {
|
func TestItems_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `items:
|
yml := `items:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -31,7 +32,6 @@ func TestItems_Build(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestItems_DefaultAsSlice(t *testing.T) {
|
func TestItems_DefaultAsSlice(t *testing.T) {
|
||||||
|
|
||||||
yml := `x-thing: thing
|
yml := `x-thing: thing
|
||||||
default:
|
default:
|
||||||
- pizza
|
- pizza
|
||||||
@@ -45,12 +45,14 @@ default:
|
|||||||
_ = low.BuildModel(&idxNode, &n)
|
_ = low.BuildModel(&idxNode, &n)
|
||||||
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
|
|
||||||
assert.Len(t, n.Default.Value, 2)
|
var def []string
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
_ = n.Default.Value.Decode(&def)
|
||||||
|
|
||||||
|
assert.Len(t, def, 2)
|
||||||
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestItems_DefaultAsMap(t *testing.T) {
|
func TestItems_DefaultAsMap(t *testing.T) {
|
||||||
|
|
||||||
yml := `default:
|
yml := `default:
|
||||||
hot: pizza
|
hot: pizza
|
||||||
tasty: beer`
|
tasty: beer`
|
||||||
@@ -63,12 +65,13 @@ func TestItems_DefaultAsMap(t *testing.T) {
|
|||||||
_ = low.BuildModel(&idxNode, &n)
|
_ = low.BuildModel(&idxNode, &n)
|
||||||
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
|
|
||||||
assert.Len(t, n.Default.Value, 2)
|
var def map[string]string
|
||||||
|
_ = n.Default.GetValue().Decode(&def)
|
||||||
|
|
||||||
|
assert.Len(t, def, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestItems_Hash_n_Grab(t *testing.T) {
|
func TestItems_Hash_n_Grab(t *testing.T) {
|
||||||
|
|
||||||
yml := `type: string
|
yml := `type: string
|
||||||
format: left
|
format: left
|
||||||
collectionFormat: nice
|
collectionFormat: nice
|
||||||
@@ -138,7 +141,10 @@ pattern: wow
|
|||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
||||||
assert.Equal(t, "shut that door!", n.GetDefault().Value)
|
|
||||||
|
var def string
|
||||||
|
_ = n.GetDefault().Value.Decode(&def)
|
||||||
|
assert.Equal(t, "shut that door!", def)
|
||||||
assert.Equal(t, 10, n.GetMaximum().Value)
|
assert.Equal(t, 10, n.GetMaximum().Value)
|
||||||
assert.Equal(t, 1, n.GetMinimum().Value)
|
assert.Equal(t, 1, n.GetMinimum().Value)
|
||||||
assert.True(t, n.GetExclusiveMinimum().Value)
|
assert.True(t, n.GetExclusiveMinimum().Value)
|
||||||
@@ -152,7 +158,8 @@ pattern: wow
|
|||||||
assert.Equal(t, "wow", n.GetPattern().Value)
|
assert.Equal(t, "wow", n.GetPattern().Value)
|
||||||
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
||||||
assert.Len(t, n.GetEnum().Value, 2)
|
assert.Len(t, n.GetEnum().Value, 2)
|
||||||
assert.Equal(t, "large", n.FindExtension("x-belly").Value)
|
|
||||||
assert.Nil(t, n.GetDescription())
|
|
||||||
|
|
||||||
|
var xBelly string
|
||||||
|
_ = n.FindExtension("x-belly").GetValue().Decode(&xBelly)
|
||||||
|
assert.Equal(t, "large", xBelly)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Operation represents a low-level Swagger / OpenAPI 2 Operation object.
|
// Operation represents a low-level Swagger / OpenAPI 2 Operation object.
|
||||||
@@ -33,7 +35,7 @@ type Operation struct {
|
|||||||
Schemes low.NodeReference[[]low.ValueReference[string]]
|
Schemes low.NodeReference[[]low.ValueReference[string]]
|
||||||
Deprecated low.NodeReference[bool]
|
Deprecated low.NodeReference[bool]
|
||||||
Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]
|
Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract external docs, extensions, parameters, responses and security requirements.
|
// Build will extract external docs, extensions, parameters, responses and security requirements.
|
||||||
@@ -150,14 +152,7 @@ func (o *Operation) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
f = append(f, keys...)
|
f = append(f, keys...)
|
||||||
keys = make([]string, len(o.Extensions))
|
f = append(f, low.HashExtensions(o.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range o.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(o.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +180,7 @@ func (o *Operation) GetOperationId() low.NodeReference[string] {
|
|||||||
func (o *Operation) GetDeprecated() low.NodeReference[bool] {
|
func (o *Operation) GetDeprecated() low.NodeReference[bool] {
|
||||||
return o.Deprecated
|
return o.Deprecated
|
||||||
}
|
}
|
||||||
func (o *Operation) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (o *Operation) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return o.Extensions
|
return o.Extensions
|
||||||
}
|
}
|
||||||
func (o *Operation) GetResponses() low.NodeReference[any] {
|
func (o *Operation) GetResponses() low.NodeReference[any] {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestOperation_Build_ExternalDocs(t *testing.T) {
|
func TestOperation_Build_ExternalDocs(t *testing.T) {
|
||||||
|
|
||||||
yml := `externalDocs:
|
yml := `externalDocs:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -31,11 +30,9 @@ func TestOperation_Build_ExternalDocs(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_Build_Params(t *testing.T) {
|
func TestOperation_Build_Params(t *testing.T) {
|
||||||
|
|
||||||
yml := `parameters:
|
yml := `parameters:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -50,11 +47,9 @@ func TestOperation_Build_Params(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_Build_Responses(t *testing.T) {
|
func TestOperation_Build_Responses(t *testing.T) {
|
||||||
|
|
||||||
yml := `responses:
|
yml := `responses:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -69,11 +64,9 @@ func TestOperation_Build_Responses(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_Build_Security(t *testing.T) {
|
func TestOperation_Build_Security(t *testing.T) {
|
||||||
|
|
||||||
yml := `security:
|
yml := `security:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -88,11 +81,9 @@ func TestOperation_Build_Security(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperation_Hash_n_Grab(t *testing.T) {
|
func TestOperation_Hash_n_Grab(t *testing.T) {
|
||||||
|
|
||||||
yml := `tags:
|
yml := `tags:
|
||||||
- nice
|
- nice
|
||||||
- hat
|
- hat
|
||||||
@@ -185,5 +176,5 @@ security:
|
|||||||
assert.True(t, n.GetDeprecated().Value)
|
assert.True(t, n.GetDeprecated().Value)
|
||||||
assert.Equal(t, 1, orderedmap.Len(n.GetResponses().Value.(*Responses).Codes))
|
assert.Equal(t, 1, orderedmap.Len(n.GetResponses().Value.(*Responses).Codes))
|
||||||
assert.Len(t, n.GetSecurity().Value, 1)
|
assert.Len(t, n.GetSecurity().Value, 1)
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parameter represents a low-level Swagger / OpenAPI 2 Parameter object.
|
// Parameter represents a low-level Swagger / OpenAPI 2 Parameter object.
|
||||||
@@ -68,7 +70,7 @@ type Parameter struct {
|
|||||||
Schema low.NodeReference[*base.SchemaProxy]
|
Schema low.NodeReference[*base.SchemaProxy]
|
||||||
Items low.NodeReference[*Items]
|
Items low.NodeReference[*Items]
|
||||||
CollectionFormat low.NodeReference[string]
|
CollectionFormat low.NodeReference[string]
|
||||||
Default low.NodeReference[any]
|
Default low.NodeReference[*yaml.Node]
|
||||||
Maximum low.NodeReference[int]
|
Maximum low.NodeReference[int]
|
||||||
ExclusiveMaximum low.NodeReference[bool]
|
ExclusiveMaximum low.NodeReference[bool]
|
||||||
Minimum low.NodeReference[int]
|
Minimum low.NodeReference[int]
|
||||||
@@ -79,18 +81,18 @@ type Parameter struct {
|
|||||||
MaxItems low.NodeReference[int]
|
MaxItems low.NodeReference[int]
|
||||||
MinItems low.NodeReference[int]
|
MinItems low.NodeReference[int]
|
||||||
UniqueItems low.NodeReference[bool]
|
UniqueItems low.NodeReference[bool]
|
||||||
Enum low.NodeReference[[]low.ValueReference[any]]
|
Enum low.NodeReference[[]low.ValueReference[*yaml.Node]]
|
||||||
MultipleOf low.NodeReference[int]
|
MultipleOf low.NodeReference[int]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension attempts to locate a extension value given a name.
|
// FindExtension attempts to locate a extension value given a name.
|
||||||
func (p *Parameter) FindExtension(ext string) *low.ValueReference[any] {
|
func (p *Parameter) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, p.Extensions)
|
return low.FindItemInOrderedMap(ext, p.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Parameter extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Parameter extensions and satisfies the low.HasExtensions interface.
|
||||||
func (p *Parameter) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (p *Parameter) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return p.Extensions
|
return p.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,30 +116,8 @@ func (p *Parameter) Build(ctx context.Context, _, root *yaml.Node, idx *index.Sp
|
|||||||
|
|
||||||
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
_, ln, vn := utils.FindKeyNodeFull(DefaultLabel, root.Content)
|
||||||
if vn != nil {
|
if vn != nil {
|
||||||
var n map[string]interface{}
|
p.Default = low.NodeReference[*yaml.Node]{
|
||||||
err := vn.Decode(&n)
|
Value: vn,
|
||||||
if err != nil {
|
|
||||||
var k []interface{}
|
|
||||||
err = vn.Decode(&k)
|
|
||||||
if err != nil {
|
|
||||||
var j interface{}
|
|
||||||
_ = vn.Decode(&j)
|
|
||||||
p.Default = low.NodeReference[any]{
|
|
||||||
Value: j,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
p.Default = low.NodeReference[any]{
|
|
||||||
Value: k,
|
|
||||||
KeyNode: ln,
|
|
||||||
ValueNode: vn,
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
p.Default = low.NodeReference[any]{
|
|
||||||
Value: n,
|
|
||||||
KeyNode: ln,
|
KeyNode: ln,
|
||||||
ValueNode: vn,
|
ValueNode: vn,
|
||||||
}
|
}
|
||||||
@@ -172,8 +152,8 @@ func (p *Parameter) Hash() [32]byte {
|
|||||||
if p.CollectionFormat.Value != "" {
|
if p.CollectionFormat.Value != "" {
|
||||||
f = append(f, p.CollectionFormat.Value)
|
f = append(f, p.CollectionFormat.Value)
|
||||||
}
|
}
|
||||||
if p.Default.Value != "" {
|
if p.Default.Value != nil && !p.Default.Value.IsZero() {
|
||||||
f = append(f, fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprint(p.Default.Value)))))
|
f = append(f, low.GenerateHashString(p.Default.Value))
|
||||||
}
|
}
|
||||||
f = append(f, fmt.Sprint(p.Maximum.Value))
|
f = append(f, fmt.Sprint(p.Maximum.Value))
|
||||||
f = append(f, fmt.Sprint(p.Minimum.Value))
|
f = append(f, fmt.Sprint(p.Minimum.Value))
|
||||||
@@ -192,20 +172,13 @@ func (p *Parameter) Hash() [32]byte {
|
|||||||
keys := make([]string, len(p.Enum.Value))
|
keys := make([]string, len(p.Enum.Value))
|
||||||
z := 0
|
z := 0
|
||||||
for k := range p.Enum.Value {
|
for k := range p.Enum.Value {
|
||||||
keys[z] = fmt.Sprint(p.Enum.Value[k].Value)
|
keys[z] = low.ValueToString(p.Enum.Value[k].Value)
|
||||||
z++
|
z++
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
f = append(f, keys...)
|
f = append(f, keys...)
|
||||||
|
|
||||||
keys = make([]string, len(p.Extensions))
|
f = append(f, low.HashExtensions(p.Extensions)...)
|
||||||
z = 0
|
|
||||||
for k := range p.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
if p.Items.Value != nil {
|
if p.Items.Value != nil {
|
||||||
f = append(f, fmt.Sprintf("%x", p.Items.Value.Hash()))
|
f = append(f, fmt.Sprintf("%x", p.Items.Value.Hash()))
|
||||||
}
|
}
|
||||||
@@ -217,21 +190,27 @@ func (p *Parameter) Hash() [32]byte {
|
|||||||
func (p *Parameter) GetName() *low.NodeReference[string] {
|
func (p *Parameter) GetName() *low.NodeReference[string] {
|
||||||
return &p.Name
|
return &p.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetIn() *low.NodeReference[string] {
|
func (p *Parameter) GetIn() *low.NodeReference[string] {
|
||||||
return &p.In
|
return &p.In
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetType() *low.NodeReference[string] {
|
func (p *Parameter) GetType() *low.NodeReference[string] {
|
||||||
return &p.Type
|
return &p.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetDescription() *low.NodeReference[string] {
|
func (p *Parameter) GetDescription() *low.NodeReference[string] {
|
||||||
return &p.Description
|
return &p.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetRequired() *low.NodeReference[bool] {
|
func (p *Parameter) GetRequired() *low.NodeReference[bool] {
|
||||||
return &p.Required
|
return &p.Required
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetAllowEmptyValue() *low.NodeReference[bool] {
|
func (p *Parameter) GetAllowEmptyValue() *low.NodeReference[bool] {
|
||||||
return &p.AllowEmptyValue
|
return &p.AllowEmptyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetSchema() *low.NodeReference[any] {
|
func (p *Parameter) GetSchema() *low.NodeReference[any] {
|
||||||
i := low.NodeReference[any]{
|
i := low.NodeReference[any]{
|
||||||
KeyNode: p.Schema.KeyNode,
|
KeyNode: p.Schema.KeyNode,
|
||||||
@@ -240,9 +219,11 @@ func (p *Parameter) GetSchema() *low.NodeReference[any] {
|
|||||||
}
|
}
|
||||||
return &i
|
return &i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetFormat() *low.NodeReference[string] {
|
func (p *Parameter) GetFormat() *low.NodeReference[string] {
|
||||||
return &p.Format
|
return &p.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetItems() *low.NodeReference[any] {
|
func (p *Parameter) GetItems() *low.NodeReference[any] {
|
||||||
i := low.NodeReference[any]{
|
i := low.NodeReference[any]{
|
||||||
KeyNode: p.Items.KeyNode,
|
KeyNode: p.Items.KeyNode,
|
||||||
@@ -251,45 +232,59 @@ func (p *Parameter) GetItems() *low.NodeReference[any] {
|
|||||||
}
|
}
|
||||||
return &i
|
return &i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetCollectionFormat() *low.NodeReference[string] {
|
func (p *Parameter) GetCollectionFormat() *low.NodeReference[string] {
|
||||||
return &p.CollectionFormat
|
return &p.CollectionFormat
|
||||||
}
|
}
|
||||||
func (p *Parameter) GetDefault() *low.NodeReference[any] {
|
|
||||||
|
func (p *Parameter) GetDefault() *low.NodeReference[*yaml.Node] {
|
||||||
return &p.Default
|
return &p.Default
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMaximum() *low.NodeReference[int] {
|
func (p *Parameter) GetMaximum() *low.NodeReference[int] {
|
||||||
return &p.Maximum
|
return &p.Maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetExclusiveMaximum() *low.NodeReference[bool] {
|
func (p *Parameter) GetExclusiveMaximum() *low.NodeReference[bool] {
|
||||||
return &p.ExclusiveMaximum
|
return &p.ExclusiveMaximum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMinimum() *low.NodeReference[int] {
|
func (p *Parameter) GetMinimum() *low.NodeReference[int] {
|
||||||
return &p.Minimum
|
return &p.Minimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetExclusiveMinimum() *low.NodeReference[bool] {
|
func (p *Parameter) GetExclusiveMinimum() *low.NodeReference[bool] {
|
||||||
return &p.ExclusiveMinimum
|
return &p.ExclusiveMinimum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMaxLength() *low.NodeReference[int] {
|
func (p *Parameter) GetMaxLength() *low.NodeReference[int] {
|
||||||
return &p.MaxLength
|
return &p.MaxLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMinLength() *low.NodeReference[int] {
|
func (p *Parameter) GetMinLength() *low.NodeReference[int] {
|
||||||
return &p.MinLength
|
return &p.MinLength
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetPattern() *low.NodeReference[string] {
|
func (p *Parameter) GetPattern() *low.NodeReference[string] {
|
||||||
return &p.Pattern
|
return &p.Pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMaxItems() *low.NodeReference[int] {
|
func (p *Parameter) GetMaxItems() *low.NodeReference[int] {
|
||||||
return &p.MaxItems
|
return &p.MaxItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMinItems() *low.NodeReference[int] {
|
func (p *Parameter) GetMinItems() *low.NodeReference[int] {
|
||||||
return &p.MinItems
|
return &p.MinItems
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetUniqueItems() *low.NodeReference[bool] {
|
func (p *Parameter) GetUniqueItems() *low.NodeReference[bool] {
|
||||||
return &p.UniqueItems
|
return &p.UniqueItems
|
||||||
}
|
}
|
||||||
func (p *Parameter) GetEnum() *low.NodeReference[[]low.ValueReference[any]] {
|
|
||||||
|
func (p *Parameter) GetEnum() *low.NodeReference[[]low.ValueReference[*yaml.Node]] {
|
||||||
return &p.Enum
|
return &p.Enum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parameter) GetMultipleOf() *low.NodeReference[int] {
|
func (p *Parameter) GetMultipleOf() *low.NodeReference[int] {
|
||||||
return &p.MultipleOf
|
return &p.MultipleOf
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,17 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParameter_Build(t *testing.T) {
|
func TestParameter_Build(t *testing.T) {
|
||||||
|
|
||||||
yml := `$ref: break`
|
yml := `$ref: break`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -28,11 +29,9 @@ func TestParameter_Build(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_Build_Items(t *testing.T) {
|
func TestParameter_Build_Items(t *testing.T) {
|
||||||
|
|
||||||
yml := `items:
|
yml := `items:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -47,11 +46,9 @@ func TestParameter_Build_Items(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_DefaultSlice(t *testing.T) {
|
func TestParameter_DefaultSlice(t *testing.T) {
|
||||||
|
|
||||||
yml := `default:
|
yml := `default:
|
||||||
- things
|
- things
|
||||||
- junk
|
- junk
|
||||||
@@ -65,11 +62,14 @@ func TestParameter_DefaultSlice(t *testing.T) {
|
|||||||
_ = low.BuildModel(&idxNode, &n)
|
_ = low.BuildModel(&idxNode, &n)
|
||||||
|
|
||||||
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Len(t, n.Default.Value.([]any), 3)
|
|
||||||
|
var a []any
|
||||||
|
_ = n.Default.Value.Decode(&a)
|
||||||
|
|
||||||
|
assert.Len(t, a, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_DefaultMap(t *testing.T) {
|
func TestParameter_DefaultMap(t *testing.T) {
|
||||||
|
|
||||||
yml := `default:
|
yml := `default:
|
||||||
things: junk
|
things: junk
|
||||||
stuff: more junk`
|
stuff: more junk`
|
||||||
@@ -82,11 +82,14 @@ func TestParameter_DefaultMap(t *testing.T) {
|
|||||||
_ = low.BuildModel(&idxNode, &n)
|
_ = low.BuildModel(&idxNode, &n)
|
||||||
|
|
||||||
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
_ = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Len(t, n.Default.Value.(map[string]any), 2)
|
|
||||||
|
var m map[string]any
|
||||||
|
_ = n.Default.Value.Decode(&m)
|
||||||
|
|
||||||
|
assert.Len(t, m, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_NoDefaultNoError(t *testing.T) {
|
func TestParameter_NoDefaultNoError(t *testing.T) {
|
||||||
|
|
||||||
yml := `name: pizza-pie`
|
yml := `name: pizza-pie`
|
||||||
|
|
||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
@@ -101,7 +104,6 @@ func TestParameter_NoDefaultNoError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParameter_Hash_n_Grab(t *testing.T) {
|
func TestParameter_Hash_n_Grab(t *testing.T) {
|
||||||
|
|
||||||
yml := `name: mcmuffin
|
yml := `name: mcmuffin
|
||||||
in: my-belly
|
in: my-belly
|
||||||
description: tasty!
|
description: tasty!
|
||||||
@@ -185,7 +187,10 @@ allowEmptyValue: true
|
|||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "left", n.GetFormat().Value)
|
assert.Equal(t, "left", n.GetFormat().Value)
|
||||||
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
assert.Equal(t, "nice", n.GetCollectionFormat().Value)
|
||||||
assert.Equal(t, "shut that door!", n.GetDefault().Value)
|
|
||||||
|
var def string
|
||||||
|
_ = n.GetDefault().Value.Decode(&def)
|
||||||
|
assert.Equal(t, "shut that door!", def)
|
||||||
assert.Equal(t, 10, n.GetMaximum().Value)
|
assert.Equal(t, 10, n.GetMaximum().Value)
|
||||||
assert.Equal(t, 1, n.GetMinimum().Value)
|
assert.Equal(t, 1, n.GetMinimum().Value)
|
||||||
assert.True(t, n.GetExclusiveMinimum().Value)
|
assert.True(t, n.GetExclusiveMinimum().Value)
|
||||||
@@ -199,7 +204,10 @@ allowEmptyValue: true
|
|||||||
assert.Equal(t, "wow", n.GetPattern().Value)
|
assert.Equal(t, "wow", n.GetPattern().Value)
|
||||||
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
assert.Equal(t, "int", n.GetItems().Value.(*Items).Type.Value)
|
||||||
assert.Len(t, n.GetEnum().Value, 2)
|
assert.Len(t, n.GetEnum().Value, 2)
|
||||||
assert.Equal(t, "large", n.FindExtension("x-belly").Value)
|
|
||||||
|
var xBelly string
|
||||||
|
_ = n.FindExtension("x-belly").Value.Decode(&xBelly)
|
||||||
|
assert.Equal(t, "large", xBelly)
|
||||||
assert.Equal(t, "tasty!", n.GetDescription().Value)
|
assert.Equal(t, "tasty!", n.GetDescription().Value)
|
||||||
assert.Equal(t, "mcmuffin", n.GetName().Value)
|
assert.Equal(t, "mcmuffin", n.GetName().Value)
|
||||||
assert.Equal(t, "my-belly", n.GetIn().Value)
|
assert.Equal(t, "my-belly", n.GetIn().Value)
|
||||||
@@ -208,6 +216,5 @@ allowEmptyValue: true
|
|||||||
assert.Equal(t, "int", v.Value.A) // A is v2
|
assert.Equal(t, "int", v.Value.A) // A is v2
|
||||||
assert.True(t, n.GetRequired().Value)
|
assert.True(t, n.GetRequired().Value)
|
||||||
assert.True(t, n.GetAllowEmptyValue().Value)
|
assert.True(t, n.GetAllowEmptyValue().Value)
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -34,16 +35,16 @@ type PathItem struct {
|
|||||||
Head low.NodeReference[*Operation]
|
Head low.NodeReference[*Operation]
|
||||||
Patch low.NodeReference[*Operation]
|
Patch low.NodeReference[*Operation]
|
||||||
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
|
Parameters low.NodeReference[[]low.ValueReference[*Parameter]]
|
||||||
Extensions map[low.KeyReference[string]]low.ValueReference[any]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension will attempt to locate an extension given a name.
|
// FindExtension will attempt to locate an extension given a name.
|
||||||
func (p *PathItem) FindExtension(ext string) *low.ValueReference[any] {
|
func (p *PathItem) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInMap[any](ext, p.Extensions)
|
return low.FindItemInOrderedMap(ext, p.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all PathItem extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all PathItem extensions and satisfies the low.HasExtensions interface.
|
||||||
func (p *PathItem) GetExtensions() map[low.KeyReference[string]]low.ValueReference[any] {
|
func (p *PathItem) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return p.Extensions
|
return p.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +154,8 @@ func (p *PathItem) Build(ctx context.Context, _, root *yaml.Node, idx *index.Spe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//all operations have been superficially built,
|
// all operations have been superficially built,
|
||||||
//now we need to build out the operation, we will do this asynchronously for speed.
|
// now we need to build out the operation, we will do this asynchronously for speed.
|
||||||
opBuildChan := make(chan bool)
|
opBuildChan := make(chan bool)
|
||||||
opErrorChan := make(chan error)
|
opErrorChan := make(chan error)
|
||||||
|
|
||||||
@@ -223,13 +224,6 @@ func (p *PathItem) Hash() [32]byte {
|
|||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
f = append(f, keys...)
|
f = append(f, keys...)
|
||||||
keys = make([]string, len(p.Extensions))
|
f = append(f, low.HashExtensions(p.Extensions)...)
|
||||||
z := 0
|
|
||||||
for k := range p.Extensions {
|
|
||||||
keys[z] = fmt.Sprintf("%s-%x", k.Value, sha256.Sum256([]byte(fmt.Sprint(p.Extensions[k].Value))))
|
|
||||||
z++
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
f = append(f, keys...)
|
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,16 @@ package v2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPathItem_Build_Params(t *testing.T) {
|
func TestPathItem_Build_Params(t *testing.T) {
|
||||||
|
|
||||||
yml := `parameters:
|
yml := `parameters:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -28,11 +29,9 @@ func TestPathItem_Build_Params(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathItem_Build_MethodFail(t *testing.T) {
|
func TestPathItem_Build_MethodFail(t *testing.T) {
|
||||||
|
|
||||||
yml := `post:
|
yml := `post:
|
||||||
$ref: break`
|
$ref: break`
|
||||||
|
|
||||||
@@ -47,11 +46,9 @@ func TestPathItem_Build_MethodFail(t *testing.T) {
|
|||||||
|
|
||||||
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
err = n.Build(context.Background(), nil, idxNode.Content[0], idx)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathItem_Hash(t *testing.T) {
|
func TestPathItem_Hash(t *testing.T) {
|
||||||
|
|
||||||
yml := `get:
|
yml := `get:
|
||||||
description: get me up
|
description: get me up
|
||||||
put:
|
put:
|
||||||
@@ -108,6 +105,5 @@ parameters:
|
|||||||
|
|
||||||
// hash
|
// hash
|
||||||
assert.Equal(t, n.Hash(), n2.Hash())
|
assert.Equal(t, n.Hash(), n2.Hash())
|
||||||
assert.Len(t, n.GetExtensions(), 1)
|
assert.Equal(t, 1, orderedmap.Len(n.GetExtensions()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user