mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-10 12:37:48 +00:00
Schemas now working, still need to check polymorphic work
However the painbarrier seems to have been smashed, now all polymorphic references can be tracked to circular references. confidence is now up 100%.
This commit is contained in:
@@ -121,13 +121,50 @@ func TestNewDocument_Tags(t *testing.T) {
|
|||||||
assert.Equal(t, 20, wentLower.Description.ValueNode.Column)
|
assert.Equal(t, 20, wentLower.Description.ValueNode.Column)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDocument_Components(t *testing.T) {
|
func TestNewDocument_Components_Links(t *testing.T) {
|
||||||
h := NewDocument(doc)
|
h := NewDocument(doc)
|
||||||
assert.Len(t, h.Components.Links, 2)
|
assert.Len(t, h.Components.Links, 2)
|
||||||
assert.Equal(t, "locateBurger", h.Components.Links["LocateBurger"].OperationId)
|
assert.Equal(t, "locateBurger", h.Components.Links["LocateBurger"].OperationId)
|
||||||
assert.Equal(t, "$response.body#/id", h.Components.Links["LocateBurger"].Parameters["burgerId"])
|
assert.Equal(t, "$response.body#/id", h.Components.Links["LocateBurger"].Parameters["burgerId"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDocument_Components_Callbacks(t *testing.T) {
|
||||||
|
h := NewDocument(doc)
|
||||||
assert.Len(t, h.Components.Callbacks, 1)
|
assert.Len(t, h.Components.Callbacks, 1)
|
||||||
assert.Equal(t, "Callback payload",
|
assert.Equal(t, "Callback payload",
|
||||||
h.Components.Callbacks["BurgerCallback"].Expression["{$request.query.queryUrl}"].Post.RequestBody.Description)
|
h.Components.Callbacks["BurgerCallback"].Expression["{$request.query.queryUrl}"].Post.RequestBody.Description)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewDocument_Components_Schemas(t *testing.T) {
|
||||||
|
h := NewDocument(doc)
|
||||||
|
assert.Len(t, h.Components.Schemas, 6)
|
||||||
|
|
||||||
|
a := h.Components.Schemas["Error"]
|
||||||
|
assert.Equal(t, "No such burger as 'Big-Whopper'", a.Properties["message"].Example)
|
||||||
|
|
||||||
|
b := h.Components.Schemas["Burger"]
|
||||||
|
assert.Len(t, b.Required, 2)
|
||||||
|
assert.Equal(t, "golden slices of happy fun joy", b.Properties["fries"].Description)
|
||||||
|
assert.Equal(t, int64(2), b.Properties["numPatties"].Example)
|
||||||
|
|
||||||
|
f := h.Components.Schemas["Fries"]
|
||||||
|
assert.Equal(t, "salt", f.Properties["seasoning"].Items.Example)
|
||||||
|
assert.Len(t, f.Properties["favoriteDrink"].Properties["drinkType"].Enum, 2)
|
||||||
|
|
||||||
|
d := h.Components.Schemas["Drink"]
|
||||||
|
assert.Len(t, d.Required, 2)
|
||||||
|
assert.True(t, d.AdditionalProperties.(bool))
|
||||||
|
assert.Equal(t, "drinkType", d.Discriminator.PropertyName)
|
||||||
|
assert.Equal(t, "some value", d.Discriminator.Mapping["drink"])
|
||||||
|
|
||||||
|
ext := h.Components.Extensions
|
||||||
|
assert.Equal(t, "loud", ext["x-screaming-baby"])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDocument_Components_Headers(t *testing.T) {
|
||||||
|
h := NewDocument(doc)
|
||||||
|
assert.Len(t, h.Components.Headers, 1)
|
||||||
|
assert.Equal(t, "this is a header", h.Components.Headers["UseOil"].Description)
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ type Schema struct {
|
|||||||
OneOf []*Schema
|
OneOf []*Schema
|
||||||
AnyOf []*Schema
|
AnyOf []*Schema
|
||||||
Not []*Schema
|
Not []*Schema
|
||||||
Items []*Schema
|
Items *Schema
|
||||||
Properties map[string]*Schema
|
Properties map[string]*Schema
|
||||||
AdditionalProperties any
|
AdditionalProperties any
|
||||||
Description string
|
Description string
|
||||||
@@ -94,7 +94,7 @@ func NewSchema(schema *low.Schema) *Schema {
|
|||||||
|
|
||||||
var enum []string
|
var enum []string
|
||||||
for i := range schema.Enum.Value {
|
for i := range schema.Enum.Value {
|
||||||
enum = append(req, schema.Enum.Value[i].Value)
|
enum = append(enum, schema.Enum.Value[i].Value)
|
||||||
}
|
}
|
||||||
s.Enum = enum
|
s.Enum = enum
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ func NewSchema(schema *low.Schema) *Schema {
|
|||||||
bChan := make(chan *Schema)
|
bChan := make(chan *Schema)
|
||||||
|
|
||||||
// for every item, build schema async
|
// for every item, build schema async
|
||||||
buildSchema := func(sch lowmodel.NodeReference[*low.Schema], bChan chan *Schema) {
|
buildSchemaChild := func(sch lowmodel.NodeReference[*low.Schema], bChan chan *Schema) {
|
||||||
if ss := getSeenSchema(sch.GenerateMapKey()); ss != nil {
|
if ss := getSeenSchema(sch.GenerateMapKey()); ss != nil {
|
||||||
bChan <- ss
|
bChan <- ss
|
||||||
return
|
return
|
||||||
@@ -122,7 +122,7 @@ func NewSchema(schema *low.Schema) *Schema {
|
|||||||
}
|
}
|
||||||
totalSchemas := len(schemas)
|
totalSchemas := len(schemas)
|
||||||
for v := range schemas {
|
for v := range schemas {
|
||||||
go buildSchema(schemas[v], bChan)
|
go buildSchemaChild(schemas[v], bChan)
|
||||||
}
|
}
|
||||||
j := 0
|
j := 0
|
||||||
for j < totalSchemas {
|
for j < totalSchemas {
|
||||||
@@ -178,15 +178,23 @@ func NewSchema(schema *low.Schema) *Schema {
|
|||||||
go buildOutSchema(schema.Not.Value, ¬, polyCompletedChan)
|
go buildOutSchema(schema.Not.Value, ¬, polyCompletedChan)
|
||||||
}
|
}
|
||||||
if !schema.Items.IsEmpty() {
|
if !schema.Items.IsEmpty() {
|
||||||
go buildOutSchema(schema.Items.Value, &items, polyCompletedChan)
|
// items is only a single prop, however the method uses an array, so pack it up in one.
|
||||||
|
var itms []lowmodel.NodeReference[*low.Schema]
|
||||||
|
itms = append(itms, lowmodel.NodeReference[*low.Schema]{
|
||||||
|
Value: schema.Items.Value,
|
||||||
|
KeyNode: schema.Items.KeyNode,
|
||||||
|
ValueNode: schema.Items.ValueNode,
|
||||||
|
})
|
||||||
|
go buildOutSchema(itms, &items, polyCompletedChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
completePoly := 0
|
completePoly := 0
|
||||||
completedProps := 0
|
completedProps := 0
|
||||||
totalProps := len(schema.Properties.Value)
|
totalProps := len(schema.Properties.Value)
|
||||||
totalPoly := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Not.Value) +
|
totalPoly := len(schema.AllOf.Value) + len(schema.OneOf.Value) + len(schema.AnyOf.Value) + len(schema.Not.Value)
|
||||||
len(schema.Items.Value)
|
if !schema.Items.IsEmpty() {
|
||||||
|
totalPoly++ // only a single item can be present.
|
||||||
|
}
|
||||||
if totalProps+totalPoly > 0 {
|
if totalProps+totalPoly > 0 {
|
||||||
allDone:
|
allDone:
|
||||||
for true {
|
for true {
|
||||||
@@ -208,7 +216,10 @@ func NewSchema(schema *low.Schema) *Schema {
|
|||||||
s.AnyOf = anyOf
|
s.AnyOf = anyOf
|
||||||
s.AllOf = allOf
|
s.AllOf = allOf
|
||||||
s.Not = not
|
s.Not = not
|
||||||
s.Items = items
|
if len(items) > 0 {
|
||||||
|
s.Items = items[0] // there will only ever be one.
|
||||||
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"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"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -205,16 +206,20 @@ func extractComponentValues[T low.Buildable[N], N any](label string, root *yaml.
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
totalComponents := 0
|
||||||
for i, v := range nodeValue.Content {
|
for i, v := range nodeValue.Content {
|
||||||
|
// always ignore extensions
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
currentLabel = v
|
currentLabel = v
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(strings.ToLower(currentLabel.Value), "x-") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
totalComponents++
|
||||||
go buildComponent(currentLabel, v, bChan, errorChan)
|
go buildComponent(currentLabel, v, bChan, errorChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalComponents := len(nodeValue.Content) / 2
|
|
||||||
completedComponents := 0
|
completedComponents := 0
|
||||||
for completedComponents < totalComponents {
|
for completedComponents < totalComponents {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"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"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -67,3 +68,19 @@ func (ex *Example) Build(root *yaml.Node, idx *index.SpecIndex) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return exp.Value
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ type Schema struct {
|
|||||||
OneOf low.NodeReference[[]low.NodeReference[*Schema]]
|
OneOf low.NodeReference[[]low.NodeReference[*Schema]]
|
||||||
AnyOf low.NodeReference[[]low.NodeReference[*Schema]]
|
AnyOf low.NodeReference[[]low.NodeReference[*Schema]]
|
||||||
Not low.NodeReference[[]low.NodeReference[*Schema]]
|
Not low.NodeReference[[]low.NodeReference[*Schema]]
|
||||||
Items low.NodeReference[[]low.NodeReference[*Schema]]
|
Items low.NodeReference[*Schema]
|
||||||
Properties low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Schema]]
|
Properties low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Schema]]
|
||||||
AdditionalProperties low.NodeReference[any]
|
AdditionalProperties low.NodeReference[any]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
@@ -93,7 +93,7 @@ func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) er
|
|||||||
// handle example if set.
|
// handle example if set.
|
||||||
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
_, expLabel, expNode := utils.FindKeyNodeFull(ExampleLabel, root.Content)
|
||||||
if expNode != nil {
|
if expNode != nil {
|
||||||
s.Example = low.NodeReference[any]{Value: expNode.Value, KeyNode: expLabel, ValueNode: expNode}
|
s.Example = low.NodeReference[any]{Value: ExtractExampleValue(expNode), KeyNode: expLabel, ValueNode: expNode}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
|
_, addPLabel, addPNode := utils.FindKeyNodeFull(AdditionalPropertiesLabel, root.Content)
|
||||||
@@ -265,8 +265,9 @@ func (s *Schema) BuildLevel(root *yaml.Node, idx *index.SpecIndex, level int) er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(items) > 0 {
|
if len(items) > 0 {
|
||||||
s.Items = low.NodeReference[[]low.NodeReference[*Schema]]{
|
// items can only be a single def, so only extract a single value
|
||||||
Value: items,
|
s.Items = low.NodeReference[*Schema]{
|
||||||
|
Value: items[0].Value,
|
||||||
KeyNode: itemsLabel,
|
KeyNode: itemsLabel,
|
||||||
ValueNode: itemsValue,
|
ValueNode: itemsValue,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,15 +197,15 @@ additionalProperties: true `
|
|||||||
assert.Equal(t, "notBExp", v.Value.Example.Value)
|
assert.Equal(t, "notBExp", v.Value.Example.Value)
|
||||||
|
|
||||||
// check values Items
|
// check values Items
|
||||||
assert.Equal(t, "an items thing", sch.Items.Value[0].Value.Description.Value)
|
assert.Equal(t, "an items thing", sch.Items.Value.Description.Value)
|
||||||
assert.Len(t, sch.Items.Value[0].Value.Properties.Value, 2)
|
assert.Len(t, sch.Items.Value.Properties.Value, 2)
|
||||||
|
|
||||||
v = sch.Items.Value[0].Value.FindProperty("itemsA")
|
v = sch.Items.Value.FindProperty("itemsA")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsA description", v.Value.Description.Value)
|
assert.Equal(t, "itemsA description", v.Value.Description.Value)
|
||||||
assert.Equal(t, "itemsAExp", v.Value.Example.Value)
|
assert.Equal(t, "itemsAExp", v.Value.Example.Value)
|
||||||
|
|
||||||
v = sch.Items.Value[0].Value.FindProperty("itemsB")
|
v = sch.Items.Value.FindProperty("itemsB")
|
||||||
assert.NotNil(t, v)
|
assert.NotNil(t, v)
|
||||||
assert.Equal(t, "itemsB description", v.Value.Description.Value)
|
assert.Equal(t, "itemsB description", v.Value.Description.Value)
|
||||||
assert.Equal(t, "itemsBExp", v.Value.Example.Value)
|
assert.Equal(t, "itemsBExp", v.Value.Example.Value)
|
||||||
@@ -456,7 +456,7 @@ items:
|
|||||||
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.Items.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.Items.Value.Description.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Schema_Polymorphism_Array_Ref_Fail(t *testing.T) {
|
func Test_Schema_Polymorphism_Array_Ref_Fail(t *testing.T) {
|
||||||
@@ -546,7 +546,7 @@ items:
|
|||||||
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.AnyOf.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.AllOf.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.Not.Value[0].Value.Description.Value)
|
||||||
assert.Equal(t, desc, sch.Items.Value[0].Value.Description.Value)
|
assert.Equal(t, desc, sch.Items.Value.Description.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_Schema_Polymorphism_Map_Ref_Fail(t *testing.T) {
|
func Test_Schema_Polymorphism_Map_Ref_Fail(t *testing.T) {
|
||||||
|
|||||||
@@ -511,6 +511,7 @@ components:
|
|||||||
SomePayload:
|
SomePayload:
|
||||||
type: string
|
type: string
|
||||||
description: some kind of payload for something.
|
description: some kind of payload for something.
|
||||||
|
x-screaming-baby: loud
|
||||||
x-something-something: darkside
|
x-something-something: darkside
|
||||||
externalDocs:
|
externalDocs:
|
||||||
description: "Find out more information about our products)"
|
description: "Find out more information about our products)"
|
||||||
|
|||||||
Reference in New Issue
Block a user