mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
Major surgery on the index and resolver. A complete flip in design.
Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
@@ -52,6 +52,11 @@ type DocumentConfiguration struct {
|
|||||||
// So if libopenapi is returning circular references for this use case, then this option should be enabled.
|
// So if libopenapi is returning circular references for this use case, then this option should be enabled.
|
||||||
// this is disabled by default, which means array circular references will be checked.
|
// this is disabled by default, which means array circular references will be checked.
|
||||||
IgnoreArrayCircularReferences bool
|
IgnoreArrayCircularReferences bool
|
||||||
|
|
||||||
|
// SkipCircularReferenceCheck will skip over checking for circular references. This is disabled by default, which
|
||||||
|
// means circular references will be checked. This is useful for developers building out models that should be
|
||||||
|
// indexed later on.
|
||||||
|
SkipCircularReferenceCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOpenDocumentConfiguration() *DocumentConfiguration {
|
func NewOpenDocumentConfiguration() *DocumentConfiguration {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
"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"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func test_get_schema_blob() string {
|
func test_get_schema_blob() string {
|
||||||
@@ -901,7 +900,7 @@ func Test_Schema_RefMadnessIllegal_Circular(t *testing.T) {
|
|||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -933,7 +932,7 @@ func Test_Schema_RefMadnessIllegal_Nonexist(t *testing.T) {
|
|||||||
var idxNode yaml.Node
|
var idxNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
_ = yaml.Unmarshal([]byte(yml), &idxNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1074,7 +1073,7 @@ func TestExtractSchema_CheckChildPropCircular(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Something'`
|
yml = `$ref: '#/components/schemas/Something'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -57,14 +57,14 @@ func LocateRefNode(root *yaml.Node, idx *index.SpecIndex) (*yaml.Node, error) {
|
|||||||
|
|
||||||
// if there are any external indexes being used by remote
|
// if there are any external indexes being used by remote
|
||||||
// documents, then we need to search through them also.
|
// documents, then we need to search through them also.
|
||||||
externalIndexes := idx.GetAllExternalIndexes()
|
//externalIndexes := idx.GetAllExternalIndexes()
|
||||||
if len(externalIndexes) > 0 {
|
//if len(externalIndexes) > 0 {
|
||||||
var extCollection []func() map[string]*index.Reference
|
// var extCollection []func() map[string]*index.Reference
|
||||||
for _, extIndex := range externalIndexes {
|
// for _, extIndex := range externalIndexes {
|
||||||
extCollection = generateIndexCollection(extIndex)
|
// extCollection = generateIndexCollection(extIndex)
|
||||||
collections = append(collections, extCollection...)
|
// collections = append(collections, extCollection...)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
var found map[string]*index.Reference
|
var found map[string]*index.Reference
|
||||||
for _, collection := range collections {
|
for _, collection := range collections {
|
||||||
@@ -501,6 +501,7 @@ func ExtractMapExtensions[PT Buildable[N], N any](
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
|
_, labelNode, valueNode = utils.FindKeyNodeFull(label, root.Content)
|
||||||
|
valueNode = utils.NodeAlias(valueNode)
|
||||||
if valueNode != nil {
|
if valueNode != nil {
|
||||||
if h, _, rvt := utils.IsNodeRefValue(valueNode); h {
|
if h, _, rvt := utils.IsNodeRefValue(valueNode); h {
|
||||||
ref, err := LocateRefNode(valueNode, idx)
|
ref, err := LocateRefNode(valueNode, idx)
|
||||||
|
|||||||
@@ -4,16 +4,15 @@
|
|||||||
package low
|
package low
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/assert"
|
"gopkg.in/yaml.v3"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFindItemInMap(t *testing.T) {
|
func TestFindItemInMap(t *testing.T) {
|
||||||
@@ -234,7 +233,7 @@ func TestExtractObject_DoubleRef_Circular(t *testing.T) {
|
|||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
// circular references are detected by the resolver, so lets run it!
|
// circular references are detected by the resolver, so lets run it!
|
||||||
resolv := resolver.NewResolver(idx)
|
resolv := index.NewResolver(idx)
|
||||||
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
||||||
|
|
||||||
yml = `tags:
|
yml = `tags:
|
||||||
@@ -264,7 +263,7 @@ func TestExtractObject_DoubleRef_Circular_Fail(t *testing.T) {
|
|||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
// circular references are detected by the resolver, so lets run it!
|
// circular references are detected by the resolver, so lets run it!
|
||||||
resolv := resolver.NewResolver(idx)
|
resolv := index.NewResolver(idx)
|
||||||
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
||||||
|
|
||||||
yml = `tags:
|
yml = `tags:
|
||||||
@@ -294,7 +293,7 @@ func TestExtractObject_DoubleRef_Circular_Direct(t *testing.T) {
|
|||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
// circular references are detected by the resolver, so lets run it!
|
// circular references are detected by the resolver, so lets run it!
|
||||||
resolv := resolver.NewResolver(idx)
|
resolv := index.NewResolver(idx)
|
||||||
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
||||||
|
|
||||||
yml = `$ref: '#/components/schemas/pizza'`
|
yml = `$ref: '#/components/schemas/pizza'`
|
||||||
@@ -324,7 +323,7 @@ func TestExtractObject_DoubleRef_Circular_Direct_Fail(t *testing.T) {
|
|||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
// circular references are detected by the resolver, so lets run it!
|
// circular references are detected by the resolver, so lets run it!
|
||||||
resolv := resolver.NewResolver(idx)
|
resolv := index.NewResolver(idx)
|
||||||
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
assert.Len(t, resolv.CheckForCircularReferences(), 1)
|
||||||
|
|
||||||
yml = `$ref: '#/components/schemas/why-did-westworld-have-to-end-so-poorly-ffs'`
|
yml = `$ref: '#/components/schemas/why-did-westworld-have-to-end-so-poorly-ffs'`
|
||||||
@@ -449,7 +448,7 @@ func TestExtractObject_PathIsCircular(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -485,7 +484,7 @@ func TestExtractObject_PathIsCircular_IgnoreErrors(t *testing.T) {
|
|||||||
// disable circular ref checking.
|
// disable circular ref checking.
|
||||||
idx.SetAllowCircularReferenceResolving(true)
|
idx.SetAllowCircularReferenceResolving(true)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -563,7 +562,7 @@ func TestExtractObjectRaw_Ref_Circular(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -735,7 +734,7 @@ func TestExtractArray_Ref_Circular(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -763,7 +762,7 @@ func TestExtractArray_Ref_Bad(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -791,7 +790,7 @@ func TestExtractArray_Ref_Nested(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -820,7 +819,7 @@ func TestExtractArray_Ref_Nested_Circular(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -876,7 +875,7 @@ func TestExtractArray_Ref_Nested_CircularFlat(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1165,7 +1164,7 @@ func TestExtractMapFlatNoLookup_Ref_Circular(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1386,7 +1385,7 @@ func TestExtractMapFlat_DoubleRef_Circles(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1445,7 +1444,7 @@ func TestExtractMapFlat_Ref_Circ_Error(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1474,7 +1473,7 @@ func TestExtractMapFlat_Ref_Nested_Circ_Error(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -1556,7 +1555,7 @@ func TestExtractMapFlat_Ref_Bad(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
idx := index.NewSpecIndexWithConfig(&idxNode, index.CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,15 @@
|
|||||||
package low
|
package low
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/assert"
|
"gopkg.in/yaml.v3"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNodeReference_IsEmpty(t *testing.T) {
|
func TestNodeReference_IsEmpty(t *testing.T) {
|
||||||
@@ -124,7 +123,7 @@ func TestIsCircular_LookupFromJourney(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Something'`
|
yml = `$ref: '#/components/schemas/Something'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -157,7 +156,7 @@ func TestIsCircular_LookupFromJourney_Optional(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Something'`
|
yml = `$ref: '#/components/schemas/Something'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -193,7 +192,7 @@ func TestIsCircular_LookupFromLoopPoint(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -225,7 +224,7 @@ func TestIsCircular_LookupFromLoopPoint_Optional(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -262,7 +261,7 @@ func TestIsCircular_FromRefLookup(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&iNode)
|
idx := index.NewSpecIndex(&iNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -298,7 +297,7 @@ func TestIsCircular_FromRefLookup_Optional(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&iNode)
|
idx := index.NewSpecIndex(&iNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -346,7 +345,7 @@ func TestGetCircularReferenceResult_FromJourney(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Something'`
|
yml = `$ref: '#/components/schemas/Something'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -380,7 +379,7 @@ func TestGetCircularReferenceResult_FromJourney_Optional(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Something'`
|
yml = `$ref: '#/components/schemas/Something'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -418,7 +417,7 @@ func TestGetCircularReferenceResult_FromLoopPoint(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -452,7 +451,7 @@ func TestGetCircularReferenceResult_FromLoopPoint_Optional(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -490,7 +489,7 @@ func TestGetCircularReferenceResult_FromMappedRef(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -522,7 +521,7 @@ func TestGetCircularReferenceResult_FromMappedRef_Optional(t *testing.T) {
|
|||||||
|
|
||||||
yml = `$ref: '#/components/schemas/Nothing'`
|
yml = `$ref: '#/components/schemas/Nothing'`
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
@@ -545,7 +544,7 @@ func TestGetCircularReferenceResult_NothingFound(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&iNode)
|
idx := index.NewSpecIndex(&iNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 0)
|
assert.Len(t, errs, 0)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"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/resolver"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
|
|||||||
doc.ExternalDocs = extDocs
|
doc.ExternalDocs = extDocs
|
||||||
|
|
||||||
// create resolver and check for circular references.
|
// create resolver and check for circular references.
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
resolvingErrors := resolve.CheckForCircularReferences()
|
resolvingErrors := resolve.CheckForCircularReferences()
|
||||||
|
|
||||||
if len(resolvingErrors) > 0 {
|
if len(resolvingErrors) > 0 {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package v3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ func initTest() {
|
|||||||
}
|
}
|
||||||
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
||||||
info, _ := datamodel.ExtractSpecInfo(data)
|
info, _ := datamodel.ExtractSpecInfo(data)
|
||||||
var err []error
|
var err error
|
||||||
// deprecated function test.
|
// deprecated function test.
|
||||||
doc, err = CreateDocument(info)
|
doc, err = CreateDocument(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,10 +30,7 @@ func BenchmarkCreateDocument(b *testing.B) {
|
|||||||
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
||||||
info, _ := datamodel.ExtractSpecInfo(data)
|
info, _ := datamodel.ExtractSpecInfo(data)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
doc, _ = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
doc, _ = CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
||||||
AllowFileReferences: false,
|
|
||||||
AllowRemoteReferences: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,28 +38,9 @@ func BenchmarkCreateDocument_Circular(b *testing.B) {
|
|||||||
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
||||||
info, _ := datamodel.ExtractSpecInfo(data)
|
info, _ := datamodel.ExtractSpecInfo(data)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err := CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
||||||
AllowFileReferences: false,
|
if err == nil {
|
||||||
AllowRemoteReferences: false,
|
panic("this should error, it has circular references")
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic("this should not error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkCreateDocument_k8s(b *testing.B) {
|
|
||||||
data, _ := os.ReadFile("../../../test_specs/k8s.json")
|
|
||||||
info, _ := datamodel.ExtractSpecInfo(data)
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
|
|
||||||
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
||||||
AllowFileReferences: false,
|
|
||||||
AllowRemoteReferences: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic("this should not error")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,12 +48,12 @@ func BenchmarkCreateDocument_k8s(b *testing.B) {
|
|||||||
func TestCircularReferenceError(t *testing.T) {
|
func TestCircularReferenceError(t *testing.T) {
|
||||||
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
||||||
info, _ := datamodel.ExtractSpecInfo(data)
|
info, _ := datamodel.ExtractSpecInfo(data)
|
||||||
circDoc, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
circDoc, err := CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
||||||
AllowFileReferences: false,
|
|
||||||
AllowRemoteReferences: false,
|
|
||||||
})
|
|
||||||
assert.NotNil(t, circDoc)
|
assert.NotNil(t, circDoc)
|
||||||
assert.Len(t, err, 3)
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, utils.UnwrapErrors(err), 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularReference_IgnoreArray(t *testing.T) {
|
func TestCircularReference_IgnoreArray(t *testing.T) {
|
||||||
@@ -102,7 +81,7 @@ components:
|
|||||||
IgnoreArrayCircularReferences: true,
|
IgnoreArrayCircularReferences: true,
|
||||||
})
|
})
|
||||||
assert.NotNil(t, circDoc)
|
assert.NotNil(t, circDoc)
|
||||||
assert.Len(t, err, 0)
|
assert.Len(t, utils.UnwrapErrors(err), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularReference_IgnorePoly(t *testing.T) {
|
func TestCircularReference_IgnorePoly(t *testing.T) {
|
||||||
@@ -130,7 +109,7 @@ components:
|
|||||||
IgnorePolymorphicCircularReferences: true,
|
IgnorePolymorphicCircularReferences: true,
|
||||||
})
|
})
|
||||||
assert.NotNil(t, circDoc)
|
assert.NotNil(t, circDoc)
|
||||||
assert.Len(t, err, 0)
|
assert.Len(t, utils.UnwrapErrors(err), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCreateDocument_Stripe(b *testing.B) {
|
func BenchmarkCreateDocument_Stripe(b *testing.B) {
|
||||||
@@ -231,7 +210,7 @@ func TestCreateDocument_WebHooks_Error(t *testing.T) {
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
@@ -610,12 +589,12 @@ components:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 0)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ob := doc.Components.Value.FindSchema("bork").Value
|
ob := doc.Components.Value.FindSchema("bork").Value
|
||||||
ob.Schema()
|
ob.Schema()
|
||||||
@@ -629,12 +608,13 @@ webhooks:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t, "flat map build failed: reference cannot be found: reference '' at line 4, column 5 was not found",
|
||||||
|
err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
||||||
@@ -645,12 +625,12 @@ components:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t, "reference '' at line 5, column 7 was not found", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Paths_Errors(t *testing.T) {
|
func TestCreateDocument_Paths_Errors(t *testing.T) {
|
||||||
@@ -660,12 +640,13 @@ paths:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t,
|
||||||
|
"path item build failed: cannot find reference: at line 4, col 10", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Tags_Errors(t *testing.T) {
|
func TestCreateDocument_Tags_Errors(t *testing.T) {
|
||||||
@@ -674,12 +655,13 @@ tags:
|
|||||||
- $ref: #bork`
|
- $ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t,
|
||||||
|
"object extraction failed: reference '' at line 3, column 5 was not found", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_Security_Error(t *testing.T) {
|
func TestCreateDocument_Security_Error(t *testing.T) {
|
||||||
@@ -688,12 +670,14 @@ security:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t,
|
||||||
|
"array build failed: reference cannot be found: reference '' at line 3, column 3 was not found",
|
||||||
|
err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_ExternalDoc_Error(t *testing.T) {
|
func TestCreateDocument_ExternalDoc_Error(t *testing.T) {
|
||||||
@@ -702,12 +686,12 @@ externalDocs:
|
|||||||
$ref: #bork`
|
$ref: #bork`
|
||||||
|
|
||||||
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
||||||
var err []error
|
var err error
|
||||||
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
assert.Len(t, err, 1)
|
assert.Equal(t, "object extraction failed: reference '' at line 3, column 3 was not found", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDocument_YamlAnchor(t *testing.T) {
|
func TestCreateDocument_YamlAnchor(t *testing.T) {
|
||||||
@@ -718,16 +702,13 @@ func TestCreateDocument_YamlAnchor(t *testing.T) {
|
|||||||
info, _ := datamodel.ExtractSpecInfo(anchorDocument)
|
info, _ := datamodel.ExtractSpecInfo(anchorDocument)
|
||||||
|
|
||||||
// build low-level document model
|
// build low-level document model
|
||||||
document, errors := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
// if something went wrong, a slice of errors is returned
|
if err != nil {
|
||||||
if len(errors) > 0 {
|
fmt.Printf("error: %s\n", err.Error())
|
||||||
for i := range errors {
|
|
||||||
fmt.Printf("error: %s\n", errors[i].Error())
|
|
||||||
}
|
|
||||||
panic("cannot build document")
|
panic("cannot build document")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,8 +740,9 @@ func TestCreateDocument_YamlAnchor(t *testing.T) {
|
|||||||
assert.NotNil(t, jsonGet)
|
assert.NotNil(t, jsonGet)
|
||||||
|
|
||||||
// Should this work? It doesn't
|
// Should this work? It doesn't
|
||||||
// postJsonType := examplePath.GetValue().Post.GetValue().RequestBody.GetValue().FindContent("application/json")
|
// update from quobix 10/14/2023: It does now!
|
||||||
// assert.NotNil(t, postJsonType)
|
postJsonType := examplePath.GetValue().Post.GetValue().RequestBody.GetValue().FindContent("application/json")
|
||||||
|
assert.NotNil(t, postJsonType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleCreateDocument() {
|
func ExampleCreateDocument() {
|
||||||
@@ -773,16 +755,13 @@ func ExampleCreateDocument() {
|
|||||||
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
|
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
|
||||||
|
|
||||||
// build low-level document model
|
// build low-level document model
|
||||||
document, errors := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
||||||
AllowFileReferences: false,
|
AllowFileReferences: false,
|
||||||
AllowRemoteReferences: false,
|
AllowRemoteReferences: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
// if something went wrong, a slice of errors is returned
|
if err != nil {
|
||||||
if len(errors) > 0 {
|
fmt.Printf("error: %s\n", err.Error())
|
||||||
for i := range errors {
|
|
||||||
fmt.Printf("error: %s\n", errors[i].Error())
|
|
||||||
}
|
|
||||||
panic("cannot build document")
|
panic("cannot build document")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ func Example_createLowLevelOpenAPIDocument() {
|
|||||||
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
|
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
|
||||||
|
|
||||||
// build low-level document model
|
// build low-level document model
|
||||||
document, errors := CreateDocument(info)
|
document, errs := CreateDocument(info)
|
||||||
|
|
||||||
// if something went wrong, a slice of errors is returned
|
// if something went wrong, a slice of errors is returned
|
||||||
if len(errors) > 0 {
|
if errs != nil {
|
||||||
for i := range errors {
|
fmt.Printf("error: %s\n", errs.Error())
|
||||||
fmt.Printf("error: %s\n", errors[i].Error())
|
|
||||||
}
|
|
||||||
panic("cannot build document")
|
panic("cannot build document")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ 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/resolver"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -358,7 +357,7 @@ func TestPath_Build_Using_CircularRef(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&idxNode)
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
@@ -394,7 +393,7 @@ func TestPath_Build_Using_CircularRefWithOp(t *testing.T) {
|
|||||||
assert.NoError(t, mErr)
|
assert.NoError(t, mErr)
|
||||||
idx := index.NewSpecIndex(&idxNode)
|
idx := index.NewSpecIndex(&idxNode)
|
||||||
|
|
||||||
resolve := resolver.NewResolver(idx)
|
resolve := index.NewResolver(idx)
|
||||||
errs := resolve.CheckForCircularReferences()
|
errs := resolve.CheckForCircularReferences()
|
||||||
assert.Len(t, errs, 1)
|
assert.Len(t, errs, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -55,21 +55,21 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
|
|
||||||
var parsedSpec yaml.Node
|
var parsedSpec yaml.Node
|
||||||
|
|
||||||
specVersion := &SpecInfo{}
|
specInfo := &SpecInfo{}
|
||||||
specVersion.JsonParsingChannel = make(chan bool)
|
specInfo.JsonParsingChannel = make(chan bool)
|
||||||
|
|
||||||
// set original bytes
|
// set original bytes
|
||||||
specVersion.SpecBytes = &spec
|
specInfo.SpecBytes = &spec
|
||||||
|
|
||||||
runes := []rune(strings.TrimSpace(string(spec)))
|
runes := []rune(strings.TrimSpace(string(spec)))
|
||||||
if len(runes) <= 0 {
|
if len(runes) <= 0 {
|
||||||
return specVersion, errors.New("there is nothing in the spec, it's empty - so there is nothing to be done")
|
return specInfo, errors.New("there is nothing in the spec, it's empty - so there is nothing to be done")
|
||||||
}
|
}
|
||||||
|
|
||||||
if runes[0] == '{' && runes[len(runes)-1] == '}' {
|
if runes[0] == '{' && runes[len(runes)-1] == '}' {
|
||||||
specVersion.SpecFileType = JSONFileType
|
specInfo.SpecFileType = JSONFileType
|
||||||
} else {
|
} else {
|
||||||
specVersion.SpecFileType = YAMLFileType
|
specInfo.SpecFileType = YAMLFileType
|
||||||
}
|
}
|
||||||
|
|
||||||
err := yaml.Unmarshal(spec, &parsedSpec)
|
err := yaml.Unmarshal(spec, &parsedSpec)
|
||||||
@@ -77,7 +77,7 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
return nil, fmt.Errorf("unable to parse specification: %s", err.Error())
|
return nil, fmt.Errorf("unable to parse specification: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
specVersion.RootNode = &parsedSpec
|
specInfo.RootNode = &parsedSpec
|
||||||
|
|
||||||
_, openAPI3 := utils.FindKeyNode(utils.OpenApi3, parsedSpec.Content)
|
_, openAPI3 := utils.FindKeyNode(utils.OpenApi3, parsedSpec.Content)
|
||||||
_, openAPI2 := utils.FindKeyNode(utils.OpenApi2, parsedSpec.Content)
|
_, openAPI2 := utils.FindKeyNode(utils.OpenApi2, parsedSpec.Content)
|
||||||
@@ -122,17 +122,17 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
return nil, versionError
|
return nil, versionError
|
||||||
}
|
}
|
||||||
|
|
||||||
specVersion.SpecType = utils.OpenApi3
|
specInfo.SpecType = utils.OpenApi3
|
||||||
specVersion.Version = version
|
specInfo.Version = version
|
||||||
specVersion.SpecFormat = OAS3
|
specInfo.SpecFormat = OAS3
|
||||||
|
|
||||||
// parse JSON
|
// parse JSON
|
||||||
parseJSON(spec, specVersion, &parsedSpec)
|
parseJSON(spec, specInfo, &parsedSpec)
|
||||||
|
|
||||||
// double check for the right version, people mix this up.
|
// double check for the right version, people mix this up.
|
||||||
if majorVersion < 3 {
|
if majorVersion < 3 {
|
||||||
specVersion.Error = errors.New("spec is defined as an openapi spec, but is using a swagger (2.0), or unknown version")
|
specInfo.Error = errors.New("spec is defined as an openapi spec, but is using a swagger (2.0), or unknown version")
|
||||||
return specVersion, specVersion.Error
|
return specInfo, specInfo.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,17 +142,17 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
return nil, versionError
|
return nil, versionError
|
||||||
}
|
}
|
||||||
|
|
||||||
specVersion.SpecType = utils.OpenApi2
|
specInfo.SpecType = utils.OpenApi2
|
||||||
specVersion.Version = version
|
specInfo.Version = version
|
||||||
specVersion.SpecFormat = OAS2
|
specInfo.SpecFormat = OAS2
|
||||||
|
|
||||||
// parse JSON
|
// parse JSON
|
||||||
parseJSON(spec, specVersion, &parsedSpec)
|
parseJSON(spec, specInfo, &parsedSpec)
|
||||||
|
|
||||||
// I am not certain this edge-case is very frequent, but let's make sure we handle it anyway.
|
// I am not certain this edge-case is very frequent, but let's make sure we handle it anyway.
|
||||||
if majorVersion > 2 {
|
if majorVersion > 2 {
|
||||||
specVersion.Error = errors.New("spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version")
|
specInfo.Error = errors.New("spec is defined as a swagger (openapi 2.0) spec, but is an openapi 3 or unknown version")
|
||||||
return specVersion, specVersion.Error
|
return specInfo, specInfo.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if asyncAPI != nil {
|
if asyncAPI != nil {
|
||||||
@@ -161,45 +161,45 @@ func ExtractSpecInfoWithDocumentCheck(spec []byte, bypass bool) (*SpecInfo, erro
|
|||||||
return nil, versionErr
|
return nil, versionErr
|
||||||
}
|
}
|
||||||
|
|
||||||
specVersion.SpecType = utils.AsyncApi
|
specInfo.SpecType = utils.AsyncApi
|
||||||
specVersion.Version = version
|
specInfo.Version = version
|
||||||
// TODO: format for AsyncAPI.
|
// TODO: format for AsyncAPI.
|
||||||
|
|
||||||
// parse JSON
|
// parse JSON
|
||||||
parseJSON(spec, specVersion, &parsedSpec)
|
parseJSON(spec, specInfo, &parsedSpec)
|
||||||
|
|
||||||
// so far there is only 2 as a major release of AsyncAPI
|
// so far there is only 2 as a major release of AsyncAPI
|
||||||
if majorVersion > 2 {
|
if majorVersion > 2 {
|
||||||
specVersion.Error = errors.New("spec is defined as asyncapi, but has a major version that is invalid")
|
specInfo.Error = errors.New("spec is defined as asyncapi, but has a major version that is invalid")
|
||||||
return specVersion, specVersion.Error
|
return specInfo, specInfo.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if specVersion.SpecType == "" {
|
if specInfo.SpecType == "" {
|
||||||
// parse JSON
|
// parse JSON
|
||||||
parseJSON(spec, specVersion, &parsedSpec)
|
parseJSON(spec, specInfo, &parsedSpec)
|
||||||
specVersion.Error = errors.New("spec type not supported by libopenapi, sorry")
|
specInfo.Error = errors.New("spec type not supported by libopenapi, sorry")
|
||||||
return specVersion, specVersion.Error
|
return specInfo, specInfo.Error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var jsonSpec map[string]interface{}
|
var jsonSpec map[string]interface{}
|
||||||
if utils.IsYAML(string(spec)) {
|
if utils.IsYAML(string(spec)) {
|
||||||
_ = parsedSpec.Decode(&jsonSpec)
|
_ = parsedSpec.Decode(&jsonSpec)
|
||||||
b, _ := json.Marshal(&jsonSpec)
|
b, _ := json.Marshal(&jsonSpec)
|
||||||
specVersion.SpecJSONBytes = &b
|
specInfo.SpecJSONBytes = &b
|
||||||
specVersion.SpecJSON = &jsonSpec
|
specInfo.SpecJSON = &jsonSpec
|
||||||
} else {
|
} else {
|
||||||
_ = json.Unmarshal(spec, &jsonSpec)
|
_ = json.Unmarshal(spec, &jsonSpec)
|
||||||
specVersion.SpecJSONBytes = &spec
|
specInfo.SpecJSONBytes = &spec
|
||||||
specVersion.SpecJSON = &jsonSpec
|
specInfo.SpecJSON = &jsonSpec
|
||||||
}
|
}
|
||||||
close(specVersion.JsonParsingChannel) // this needs removing at some point
|
close(specInfo.JsonParsingChannel) // this needs removing at some point
|
||||||
}
|
}
|
||||||
|
|
||||||
// detect the original whitespace indentation
|
// detect the original whitespace indentation
|
||||||
specVersion.OriginalIndentation = utils.DetermineWhitespaceLength(string(spec))
|
specInfo.OriginalIndentation = utils.DetermineWhitespaceLength(string(spec))
|
||||||
|
|
||||||
return specVersion, nil
|
return specInfo, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
document.go
13
document.go
@@ -24,7 +24,6 @@ import (
|
|||||||
v3high "github.com/pb33f/libopenapi/datamodel/high/v3"
|
v3high "github.com/pb33f/libopenapi/datamodel/high/v3"
|
||||||
v2low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2low "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
v3low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3low "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
what_changed "github.com/pb33f/libopenapi/what-changed"
|
what_changed "github.com/pb33f/libopenapi/what-changed"
|
||||||
"github.com/pb33f/libopenapi/what-changed/model"
|
"github.com/pb33f/libopenapi/what-changed/model"
|
||||||
@@ -44,6 +43,10 @@ type Document interface {
|
|||||||
// allowing remote or local references, as well as a BaseURL to allow for relative file references.
|
// allowing remote or local references, as well as a BaseURL to allow for relative file references.
|
||||||
SetConfiguration(configuration *datamodel.DocumentConfiguration)
|
SetConfiguration(configuration *datamodel.DocumentConfiguration)
|
||||||
|
|
||||||
|
// GetConfiguration will return the configuration for the document. This allows for finer grained control over
|
||||||
|
// allowing remote or local references, as well as a BaseURL to allow for relative file references.
|
||||||
|
GetConfiguration() *datamodel.DocumentConfiguration
|
||||||
|
|
||||||
// BuildV2Model will build out a Swagger (version 2) model from the specification used to create the document
|
// BuildV2Model will build out a Swagger (version 2) model from the specification used to create the document
|
||||||
// If there are any issues, then no model will be returned, instead a slice of errors will explain all the
|
// If there are any issues, then no model will be returned, instead a slice of errors will explain all the
|
||||||
// problems that occurred. This method will only support version 2 specifications and will throw an error for
|
// problems that occurred. This method will only support version 2 specifications and will throw an error for
|
||||||
@@ -166,6 +169,10 @@ func (d *document) GetSpecInfo() *datamodel.SpecInfo {
|
|||||||
return d.info
|
return d.info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *document) GetConfiguration() *datamodel.DocumentConfiguration {
|
||||||
|
return d.config
|
||||||
|
}
|
||||||
|
|
||||||
func (d *document) SetConfiguration(configuration *datamodel.DocumentConfiguration) {
|
func (d *document) SetConfiguration(configuration *datamodel.DocumentConfiguration) {
|
||||||
d.config = configuration
|
d.config = configuration
|
||||||
}
|
}
|
||||||
@@ -254,7 +261,7 @@ func (d *document) BuildV2Model() (*DocumentModel[v2high.Swagger], []error) {
|
|||||||
// Do not short-circuit on circular reference errors, so the client
|
// Do not short-circuit on circular reference errors, so the client
|
||||||
// has the option of ignoring them.
|
// has the option of ignoring them.
|
||||||
for _, err := range errors {
|
for _, err := range errors {
|
||||||
if refErr, ok := err.(*resolver.ResolvingError); ok {
|
if refErr, ok := err.(*index.ResolvingError); ok {
|
||||||
if refErr.CircularReference == nil {
|
if refErr.CircularReference == nil {
|
||||||
return nil, errors
|
return nil, errors
|
||||||
}
|
}
|
||||||
@@ -297,7 +304,7 @@ func (d *document) BuildV3Model() (*DocumentModel[v3high.Document], []error) {
|
|||||||
// Do not short-circuit on circular reference errors, so the client
|
// Do not short-circuit on circular reference errors, so the client
|
||||||
// has the option of ignoring them.
|
// has the option of ignoring them.
|
||||||
for _, err := range errors {
|
for _, err := range errors {
|
||||||
if refErr, ok := err.(*resolver.ResolvingError); ok {
|
if refErr, ok := err.(*index.ResolvingError); ok {
|
||||||
if refErr.CircularReference == nil {
|
if refErr.CircularReference == nil {
|
||||||
return nil, errors
|
return nil, errors
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package libopenapi
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pb33f/libopenapi/datamodel"
|
"github.com/pb33f/libopenapi/datamodel"
|
||||||
|
"github.com/pb33f/libopenapi/index"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -15,7 +16,6 @@ import (
|
|||||||
v3high "github.com/pb33f/libopenapi/datamodel/high/v3"
|
v3high "github.com/pb33f/libopenapi/datamodel/high/v3"
|
||||||
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
low "github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -433,7 +433,7 @@ components:
|
|||||||
|
|
||||||
// resolving error is a pointer to *resolver.ResolvingError
|
// resolving error is a pointer to *resolver.ResolvingError
|
||||||
// which provides access to rich details about the error.
|
// which provides access to rich details about the error.
|
||||||
circularReference := resolvingError.(*resolver.ResolvingError).CircularReference
|
circularReference := resolvingError.(*index.ResolvingError).CircularReference
|
||||||
|
|
||||||
// capture the journey with all details
|
// capture the journey with all details
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// Copyright 2022 Dave Shanley / Quobix
|
// Copyright 2022 Dave Shanley / Quobix
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package resolver
|
package index
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@@ -23,7 +23,7 @@ type ResolvingError struct {
|
|||||||
Path string
|
Path string
|
||||||
|
|
||||||
// CircularReference is set if the error is a reference to the circular reference.
|
// CircularReference is set if the error is a reference to the circular reference.
|
||||||
CircularReference *index.CircularReferenceResult
|
CircularReference *CircularReferenceResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ResolvingError) Error() string {
|
func (r *ResolvingError) Error() string {
|
||||||
@@ -34,20 +34,22 @@ func (r *ResolvingError) Error() string {
|
|||||||
// Resolver will use a *index.SpecIndex to stitch together a resolved root tree using all the discovered
|
// Resolver will use a *index.SpecIndex to stitch together a resolved root tree using all the discovered
|
||||||
// references in the doc.
|
// references in the doc.
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
specIndex *index.SpecIndex
|
specIndex *SpecIndex
|
||||||
resolvedRoot *yaml.Node
|
resolvedRoot *yaml.Node
|
||||||
resolvingErrors []*ResolvingError
|
resolvingErrors []*ResolvingError
|
||||||
circularReferences []*index.CircularReferenceResult
|
circularReferences []*CircularReferenceResult
|
||||||
referencesVisited int
|
ignoredPolyReferences []*CircularReferenceResult
|
||||||
indexesVisited int
|
ignoredArrayReferences []*CircularReferenceResult
|
||||||
journeysTaken int
|
referencesVisited int
|
||||||
relativesSeen int
|
indexesVisited int
|
||||||
ignorePoly bool
|
journeysTaken int
|
||||||
ignoreArray bool
|
relativesSeen int
|
||||||
|
IgnorePoly bool
|
||||||
|
IgnoreArray bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResolver will create a new resolver from a *index.SpecIndex
|
// NewResolver will create a new resolver from a *index.SpecIndex
|
||||||
func NewResolver(index *index.SpecIndex) *Resolver {
|
func NewResolver(index *SpecIndex) *Resolver {
|
||||||
if index == nil {
|
if index == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -63,13 +65,13 @@ func (resolver *Resolver) GetResolvingErrors() []*ResolvingError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCircularErrors returns all circular reference errors found.
|
// GetCircularErrors returns all circular reference errors found.
|
||||||
func (resolver *Resolver) GetCircularErrors() []*index.CircularReferenceResult {
|
func (resolver *Resolver) GetCircularErrors() []*CircularReferenceResult {
|
||||||
return resolver.circularReferences
|
return resolver.circularReferences
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPolymorphicCircularErrors returns all circular errors that stem from polymorphism
|
// GetPolymorphicCircularErrors returns all circular errors that stem from polymorphism
|
||||||
func (resolver *Resolver) GetPolymorphicCircularErrors() []*index.CircularReferenceResult {
|
func (resolver *Resolver) GetPolymorphicCircularErrors() []*CircularReferenceResult {
|
||||||
var res []*index.CircularReferenceResult
|
var res []*CircularReferenceResult
|
||||||
for i := range resolver.circularReferences {
|
for i := range resolver.circularReferences {
|
||||||
if !resolver.circularReferences[i].IsInfiniteLoop {
|
if !resolver.circularReferences[i].IsInfiniteLoop {
|
||||||
continue
|
continue
|
||||||
@@ -83,8 +85,8 @@ func (resolver *Resolver) GetPolymorphicCircularErrors() []*index.CircularRefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetNonPolymorphicCircularErrors returns all circular errors that DO NOT stem from polymorphism
|
// GetNonPolymorphicCircularErrors returns all circular errors that DO NOT stem from polymorphism
|
||||||
func (resolver *Resolver) GetNonPolymorphicCircularErrors() []*index.CircularReferenceResult {
|
func (resolver *Resolver) GetNonPolymorphicCircularErrors() []*CircularReferenceResult {
|
||||||
var res []*index.CircularReferenceResult
|
var res []*CircularReferenceResult
|
||||||
for i := range resolver.circularReferences {
|
for i := range resolver.circularReferences {
|
||||||
if !resolver.circularReferences[i].IsInfiniteLoop {
|
if !resolver.circularReferences[i].IsInfiniteLoop {
|
||||||
continue
|
continue
|
||||||
@@ -100,13 +102,13 @@ func (resolver *Resolver) GetNonPolymorphicCircularErrors() []*index.CircularRef
|
|||||||
// IgnorePolymorphicCircularReferences will ignore any circular references that are polymorphic (oneOf, anyOf, allOf)
|
// IgnorePolymorphicCircularReferences will ignore any circular references that are polymorphic (oneOf, anyOf, allOf)
|
||||||
// This must be set before any resolving is done.
|
// This must be set before any resolving is done.
|
||||||
func (resolver *Resolver) IgnorePolymorphicCircularReferences() {
|
func (resolver *Resolver) IgnorePolymorphicCircularReferences() {
|
||||||
resolver.ignorePoly = true
|
resolver.IgnorePoly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IgnoreArrayCircularReferences will ignore any circular references that stem from arrays. This must be set before
|
// IgnoreArrayCircularReferences will ignore any circular references that stem from arrays. This must be set before
|
||||||
// any resolving is done.
|
// any resolving is done.
|
||||||
func (resolver *Resolver) IgnoreArrayCircularReferences() {
|
func (resolver *Resolver) IgnoreArrayCircularReferences() {
|
||||||
resolver.ignoreArray = true
|
resolver.IgnoreArray = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetJourneysTaken returns the number of journeys taken by the resolver
|
// GetJourneysTaken returns the number of journeys taken by the resolver
|
||||||
@@ -174,13 +176,13 @@ func (resolver *Resolver) CheckForCircularReferences() []*ResolvingError {
|
|||||||
return resolver.resolvingErrors
|
return resolver.resolvingErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
func visitIndexWithoutDamagingIt(res *Resolver, idx *index.SpecIndex) {
|
func visitIndexWithoutDamagingIt(res *Resolver, idx *SpecIndex) {
|
||||||
mapped := idx.GetMappedReferencesSequenced()
|
mapped := idx.GetMappedReferencesSequenced()
|
||||||
mappedIndex := idx.GetMappedReferences()
|
mappedIndex := idx.GetMappedReferences()
|
||||||
res.indexesVisited++
|
res.indexesVisited++
|
||||||
for _, ref := range mapped {
|
for _, ref := range mapped {
|
||||||
seenReferences := make(map[string]bool)
|
seenReferences := make(map[string]bool)
|
||||||
var journey []*index.Reference
|
var journey []*Reference
|
||||||
res.journeysTaken++
|
res.journeysTaken++
|
||||||
res.VisitReference(ref.Reference, seenReferences, journey, false)
|
res.VisitReference(ref.Reference, seenReferences, journey, false)
|
||||||
}
|
}
|
||||||
@@ -188,24 +190,24 @@ func visitIndexWithoutDamagingIt(res *Resolver, idx *index.SpecIndex) {
|
|||||||
for s, schemaRef := range schemas {
|
for s, schemaRef := range schemas {
|
||||||
if mappedIndex[s] == nil {
|
if mappedIndex[s] == nil {
|
||||||
seenReferences := make(map[string]bool)
|
seenReferences := make(map[string]bool)
|
||||||
var journey []*index.Reference
|
var journey []*Reference
|
||||||
res.journeysTaken++
|
res.journeysTaken++
|
||||||
res.VisitReference(schemaRef, seenReferences, journey, false)
|
res.VisitReference(schemaRef, seenReferences, journey, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, c := range idx.GetChildren() {
|
//for _, c := range idx.GetChildren() {
|
||||||
visitIndexWithoutDamagingIt(res, c)
|
// visitIndexWithoutDamagingIt(res, c)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
func visitIndex(res *Resolver, idx *index.SpecIndex) {
|
func visitIndex(res *Resolver, idx *SpecIndex) {
|
||||||
mapped := idx.GetMappedReferencesSequenced()
|
mapped := idx.GetMappedReferencesSequenced()
|
||||||
mappedIndex := idx.GetMappedReferences()
|
mappedIndex := idx.GetMappedReferences()
|
||||||
res.indexesVisited++
|
res.indexesVisited++
|
||||||
|
|
||||||
for _, ref := range mapped {
|
for _, ref := range mapped {
|
||||||
seenReferences := make(map[string]bool)
|
seenReferences := make(map[string]bool)
|
||||||
var journey []*index.Reference
|
var journey []*Reference
|
||||||
res.journeysTaken++
|
res.journeysTaken++
|
||||||
if ref != nil && ref.Reference != nil {
|
if ref != nil && ref.Reference != nil {
|
||||||
ref.Reference.Node.Content = res.VisitReference(ref.Reference, seenReferences, journey, true)
|
ref.Reference.Node.Content = res.VisitReference(ref.Reference, seenReferences, journey, true)
|
||||||
@@ -216,7 +218,7 @@ func visitIndex(res *Resolver, idx *index.SpecIndex) {
|
|||||||
for s, schemaRef := range schemas {
|
for s, schemaRef := range schemas {
|
||||||
if mappedIndex[s] == nil {
|
if mappedIndex[s] == nil {
|
||||||
seenReferences := make(map[string]bool)
|
seenReferences := make(map[string]bool)
|
||||||
var journey []*index.Reference
|
var journey []*Reference
|
||||||
res.journeysTaken++
|
res.journeysTaken++
|
||||||
schemaRef.Node.Content = res.VisitReference(schemaRef, seenReferences, journey, true)
|
schemaRef.Node.Content = res.VisitReference(schemaRef, seenReferences, journey, true)
|
||||||
}
|
}
|
||||||
@@ -231,13 +233,13 @@ func visitIndex(res *Resolver, idx *index.SpecIndex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, c := range idx.GetChildren() {
|
//for _, c := range idx.GetChildren() {
|
||||||
visitIndex(res, c)
|
// visitIndex(res, c)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisitReference will visit a reference as part of a journey and will return resolved nodes.
|
// VisitReference will visit a reference as part of a journey and will return resolved nodes.
|
||||||
func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]bool, journey []*index.Reference, resolve bool) []*yaml.Node {
|
func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, journey []*Reference, resolve bool) []*yaml.Node {
|
||||||
resolver.referencesVisited++
|
resolver.referencesVisited++
|
||||||
if ref.Resolved || ref.Seen {
|
if ref.Resolved || ref.Seen {
|
||||||
return ref.Node.Content
|
return ref.Node.Content
|
||||||
@@ -255,13 +257,13 @@ func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]b
|
|||||||
for i, j := range journey {
|
for i, j := range journey {
|
||||||
if j.Definition == r.Definition {
|
if j.Definition == r.Definition {
|
||||||
|
|
||||||
var foundDup *index.Reference
|
var foundDup *Reference
|
||||||
foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition)
|
foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition)
|
||||||
if len(foundRefs) > 0 {
|
if len(foundRefs) > 0 {
|
||||||
foundDup = foundRefs[0]
|
foundDup = foundRefs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
var circRef *index.CircularReferenceResult
|
var circRef *CircularReferenceResult
|
||||||
if !foundDup.Circular {
|
if !foundDup.Circular {
|
||||||
loop := append(journey, foundDup)
|
loop := append(journey, foundDup)
|
||||||
|
|
||||||
@@ -272,7 +274,7 @@ func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]b
|
|||||||
if r.ParentNodeSchemaType == "array" {
|
if r.ParentNodeSchemaType == "array" {
|
||||||
isArray = true
|
isArray = true
|
||||||
}
|
}
|
||||||
circRef = &index.CircularReferenceResult{
|
circRef = &CircularReferenceResult{
|
||||||
Journey: loop,
|
Journey: loop,
|
||||||
Start: foundDup,
|
Start: foundDup,
|
||||||
LoopIndex: i,
|
LoopIndex: i,
|
||||||
@@ -280,7 +282,14 @@ func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]b
|
|||||||
IsArrayResult: isArray,
|
IsArrayResult: isArray,
|
||||||
IsInfiniteLoop: isInfiniteLoop,
|
IsInfiniteLoop: isInfiniteLoop,
|
||||||
}
|
}
|
||||||
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
|
||||||
|
if resolver.IgnoreArray && isArray {
|
||||||
|
fmt.Printf("Ignored: %s\n", circRef.GenerateJourneyPath())
|
||||||
|
resolver.ignoredArrayReferences = append(resolver.ignoredArrayReferences, circRef)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Not Ignored: %s\n", circRef.GenerateJourneyPath())
|
||||||
|
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
||||||
|
}
|
||||||
|
|
||||||
foundDup.Seen = true
|
foundDup.Seen = true
|
||||||
foundDup.Circular = true
|
foundDup.Circular = true
|
||||||
@@ -290,13 +299,13 @@ func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]b
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !skip {
|
if !skip {
|
||||||
var original *index.Reference
|
var original *Reference
|
||||||
foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition)
|
foundRefs := resolver.specIndex.SearchIndexForReference(r.Definition)
|
||||||
if len(foundRefs) > 0 {
|
if len(foundRefs) > 0 {
|
||||||
original = foundRefs[0]
|
original = foundRefs[0]
|
||||||
}
|
}
|
||||||
resolved := resolver.VisitReference(original, seen, journey, resolve)
|
resolved := resolver.VisitReference(original, seen, journey, resolve)
|
||||||
if resolve {
|
if resolve && !original.Circular {
|
||||||
r.Node.Content = resolved // this is where we perform the actual resolving.
|
r.Node.Content = resolved // this is where we perform the actual resolving.
|
||||||
}
|
}
|
||||||
r.Seen = true
|
r.Seen = true
|
||||||
@@ -309,7 +318,7 @@ func (resolver *Resolver) VisitReference(ref *index.Reference, seen map[string]b
|
|||||||
return ref.Node.Content
|
return ref.Node.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resolver *Resolver) isInfiniteCircularDependency(ref *index.Reference, visitedDefinitions map[string]bool, initialRef *index.Reference) (bool, map[string]bool) {
|
func (resolver *Resolver) isInfiniteCircularDependency(ref *Reference, visitedDefinitions map[string]bool, initialRef *Reference) (bool, map[string]bool) {
|
||||||
if ref == nil {
|
if ref == nil {
|
||||||
return false, visitedDefinitions
|
return false, visitedDefinitions
|
||||||
}
|
}
|
||||||
@@ -342,38 +351,41 @@ func (resolver *Resolver) isInfiniteCircularDependency(ref *index.Reference, vis
|
|||||||
|
|
||||||
func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
||||||
foundRelatives map[string]bool,
|
foundRelatives map[string]bool,
|
||||||
journey []*index.Reference, resolve bool) []*index.Reference {
|
journey []*Reference, resolve bool) []*Reference {
|
||||||
|
|
||||||
if len(journey) > 100 {
|
if len(journey) > 100 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var found []*index.Reference
|
var found []*Reference
|
||||||
|
//var ignoredPoly []*index.Reference
|
||||||
|
//var ignoredArray []*index.Reference
|
||||||
|
|
||||||
if len(node.Content) > 0 {
|
if len(node.Content) > 0 {
|
||||||
for i, n := range node.Content {
|
for i, n := range node.Content {
|
||||||
if utils.IsNodeMap(n) || utils.IsNodeArray(n) {
|
if utils.IsNodeMap(n) || utils.IsNodeArray(n) {
|
||||||
|
|
||||||
var anyvn, allvn, onevn, arrayTypevn *yaml.Node
|
//var anyvn, allvn, onevn, arrayTypevn *yaml.Node
|
||||||
|
|
||||||
// extract polymorphic references
|
// extract polymorphic references
|
||||||
if len(n.Content) > 1 {
|
if len(n.Content) > 1 {
|
||||||
_, anyvn = utils.FindKeyNodeTop("anyOf", n.Content)
|
//_, anyvn = utils.FindKeyNodeTop("anyOf", n.Content)
|
||||||
_, allvn = utils.FindKeyNodeTop("allOf", n.Content)
|
//_, allvn = utils.FindKeyNodeTop("allOf", n.Content)
|
||||||
_, onevn = utils.FindKeyNodeTop("oneOf", n.Content)
|
//_, onevn = utils.FindKeyNodeTop("oneOf", n.Content)
|
||||||
_, arrayTypevn = utils.FindKeyNodeTop("type", n.Content)
|
//_, arrayTypevn = utils.FindKeyNodeTop("type", n.Content)
|
||||||
}
|
|
||||||
if anyvn != nil || allvn != nil || onevn != nil {
|
|
||||||
if resolver.ignorePoly {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if arrayTypevn != nil {
|
|
||||||
if arrayTypevn.Value == "array" {
|
|
||||||
if resolver.ignoreArray {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//if anyvn != nil || allvn != nil || onevn != nil {
|
||||||
|
// if resolver.IgnorePoly {
|
||||||
|
// ignoredPoly = append(ignoredPoly, resolver.extractRelatives(n, node, foundRelatives, journey, resolve)...)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//if arrayTypevn != nil {
|
||||||
|
// if arrayTypevn.Value == "array" {
|
||||||
|
// if resolver.IgnoreArray {
|
||||||
|
// ignoredArray = append(ignoredArray, resolver.extractRelatives(n, node, foundRelatives, journey, resolve)...)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
found = append(found, resolver.extractRelatives(n, node, foundRelatives, journey, resolve)...)
|
found = append(found, resolver.extractRelatives(n, node, foundRelatives, journey, resolve)...)
|
||||||
}
|
}
|
||||||
@@ -409,7 +421,7 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &index.Reference{
|
r := &Reference{
|
||||||
Definition: value,
|
Definition: value,
|
||||||
Name: value,
|
Name: value,
|
||||||
Node: node,
|
Node: node,
|
||||||
@@ -447,7 +459,7 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
resolver.VisitReference(ref, foundRelatives, journey, resolve)
|
resolver.VisitReference(ref, foundRelatives, journey, resolve)
|
||||||
} else {
|
} else {
|
||||||
loop := append(journey, ref)
|
loop := append(journey, ref)
|
||||||
circRef := &index.CircularReferenceResult{
|
circRef := &CircularReferenceResult{
|
||||||
Journey: loop,
|
Journey: loop,
|
||||||
Start: ref,
|
Start: ref,
|
||||||
LoopIndex: i,
|
LoopIndex: i,
|
||||||
@@ -458,7 +470,11 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
|
|
||||||
ref.Seen = true
|
ref.Seen = true
|
||||||
ref.Circular = true
|
ref.Circular = true
|
||||||
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
if resolver.IgnorePoly {
|
||||||
|
resolver.ignoredPolyReferences = append(resolver.ignoredPolyReferences, circRef)
|
||||||
|
} else {
|
||||||
|
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,6 +488,11 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
v := node.Content[i+1].Content[q]
|
v := node.Content[i+1].Content[q]
|
||||||
if utils.IsNodeMap(v) {
|
if utils.IsNodeMap(v) {
|
||||||
if d, _, l := utils.IsNodeRefValue(v); d {
|
if d, _, l := utils.IsNodeRefValue(v); d {
|
||||||
|
strangs := strings.Split(l, "/#")
|
||||||
|
if len(strangs) == 2 {
|
||||||
|
fmt.Println("wank")
|
||||||
|
}
|
||||||
|
|
||||||
ref := resolver.specIndex.GetMappedReferences()[l]
|
ref := resolver.specIndex.GetMappedReferences()[l]
|
||||||
if ref != nil && !ref.Circular {
|
if ref != nil && !ref.Circular {
|
||||||
circ := false
|
circ := false
|
||||||
@@ -485,7 +506,8 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
resolver.VisitReference(ref, foundRelatives, journey, resolve)
|
resolver.VisitReference(ref, foundRelatives, journey, resolve)
|
||||||
} else {
|
} else {
|
||||||
loop := append(journey, ref)
|
loop := append(journey, ref)
|
||||||
circRef := &index.CircularReferenceResult{
|
|
||||||
|
circRef := &CircularReferenceResult{
|
||||||
Journey: loop,
|
Journey: loop,
|
||||||
Start: ref,
|
Start: ref,
|
||||||
LoopIndex: i,
|
LoopIndex: i,
|
||||||
@@ -496,7 +518,11 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
|
|
||||||
ref.Seen = true
|
ref.Seen = true
|
||||||
ref.Circular = true
|
ref.Circular = true
|
||||||
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
if resolver.IgnorePoly {
|
||||||
|
resolver.ignoredPolyReferences = append(resolver.ignoredPolyReferences, circRef)
|
||||||
|
} else {
|
||||||
|
resolver.circularReferences = append(resolver.circularReferences, circRef)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,6 +535,8 @@ func (resolver *Resolver) extractRelatives(node, parent *yaml.Node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//resolver.ignoredPolyReferences = ignoredPoly
|
||||||
|
|
||||||
resolver.relativesSeen += len(found)
|
resolver.relativesSeen += len(found)
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package resolver
|
package index
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -7,8 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ func Benchmark_ResolveDocumentStripe(b *testing.B) {
|
|||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(stripe, &rootNode)
|
_ = yaml.Unmarshal(stripe, &rootNode)
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
resolver.Resolve()
|
resolver.Resolve()
|
||||||
}
|
}
|
||||||
@@ -32,7 +31,7 @@ func TestResolver_ResolveComponents_CircularSpec(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -49,7 +48,7 @@ func TestResolver_CheckForCircularReferences(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -83,7 +82,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -118,7 +117,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -154,7 +153,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -190,7 +189,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -226,7 +225,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -262,7 +261,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -296,7 +295,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -318,7 +317,7 @@ func TestResolver_CheckForCircularReferences_DigitalOcean(t *testing.T) {
|
|||||||
|
|
||||||
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, &index.SpecIndexConfig{
|
idx := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
||||||
AllowRemoteLookup: true,
|
AllowRemoteLookup: true,
|
||||||
AllowFileLookup: true,
|
AllowFileLookup: true,
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
@@ -341,7 +340,7 @@ func TestResolver_CircularReferencesRequiredValid(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -358,7 +357,7 @@ func TestResolver_CircularReferencesRequiredInvalid(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(circular, &rootNode)
|
_ = yaml.Unmarshal(circular, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -371,11 +370,11 @@ func TestResolver_CircularReferencesRequiredInvalid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolver_DeepJourney(t *testing.T) {
|
func TestResolver_DeepJourney(t *testing.T) {
|
||||||
var journey []*index.Reference
|
var journey []*Reference
|
||||||
for f := 0; f < 200; f++ {
|
for f := 0; f < 200; f++ {
|
||||||
journey = append(journey, nil)
|
journey = append(journey, nil)
|
||||||
}
|
}
|
||||||
idx := index.NewSpecIndexWithConfig(nil, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(nil, CreateClosedAPIIndexConfig())
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.Nil(t, resolver.extractRelatives(nil, nil, nil, journey, false))
|
assert.Nil(t, resolver.extractRelatives(nil, nil, nil, journey, false))
|
||||||
}
|
}
|
||||||
@@ -385,7 +384,7 @@ func TestResolver_ResolveComponents_Stripe(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(stripe, &rootNode)
|
_ = yaml.Unmarshal(stripe, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -402,7 +401,7 @@ func TestResolver_ResolveComponents_BurgerShop(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(mixedref, &rootNode)
|
_ = yaml.Unmarshal(mixedref, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -435,7 +434,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -462,7 +461,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -498,7 +497,7 @@ components:
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -513,8 +512,8 @@ func TestResolver_ResolveComponents_MixedRef(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(mixedref, &rootNode)
|
_ = yaml.Unmarshal(mixedref, &rootNode)
|
||||||
|
|
||||||
b := index.CreateOpenAPIIndexConfig()
|
b := CreateOpenAPIIndexConfig()
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, b)
|
idx := NewSpecIndexWithConfig(&rootNode, b)
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -534,7 +533,7 @@ func TestResolver_ResolveComponents_k8s(t *testing.T) {
|
|||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(k8s, &rootNode)
|
_ = yaml.Unmarshal(k8s, &rootNode)
|
||||||
|
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, index.CreateClosedAPIIndexConfig())
|
idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig())
|
||||||
|
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
assert.NotNil(t, resolver)
|
assert.NotNil(t, resolver)
|
||||||
@@ -555,8 +554,8 @@ func ExampleNewResolver() {
|
|||||||
_ = yaml.Unmarshal(stripeBytes, &rootNode)
|
_ = yaml.Unmarshal(stripeBytes, &rootNode)
|
||||||
|
|
||||||
// create a new spec index (resolver depends on it)
|
// create a new spec index (resolver depends on it)
|
||||||
indexConfig := index.CreateClosedAPIIndexConfig()
|
indexConfig := CreateClosedAPIIndexConfig()
|
||||||
idx := index.NewSpecIndexWithConfig(&rootNode, indexConfig)
|
idx := NewSpecIndexWithConfig(&rootNode, indexConfig)
|
||||||
|
|
||||||
// create a new resolver using the index.
|
// create a new resolver using the index.
|
||||||
resolver := NewResolver(idx)
|
resolver := NewResolver(idx)
|
||||||
@@ -581,7 +580,7 @@ func ExampleResolvingError() {
|
|||||||
Column: 21,
|
Column: 21,
|
||||||
},
|
},
|
||||||
Path: "#/definitions/JeSuisUneErreur",
|
Path: "#/definitions/JeSuisUneErreur",
|
||||||
CircularReference: &index.CircularReferenceResult{},
|
CircularReference: &CircularReferenceResult{},
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s", re.Error())
|
fmt.Printf("%s", re.Error())
|
||||||
@@ -57,6 +57,8 @@ type Rolodex struct {
|
|||||||
indexConfig *SpecIndexConfig
|
indexConfig *SpecIndexConfig
|
||||||
indexingDuration time.Duration
|
indexingDuration time.Duration
|
||||||
indexes []*SpecIndex
|
indexes []*SpecIndex
|
||||||
|
rootIndex *SpecIndex
|
||||||
|
caughtErrors []error
|
||||||
}
|
}
|
||||||
|
|
||||||
type rolodexFile struct {
|
type rolodexFile struct {
|
||||||
@@ -204,10 +206,22 @@ func NewRolodex(indexConfig *SpecIndexConfig) *Rolodex {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Rolodex) GetIndexingDuration() time.Duration {
|
||||||
|
return r.indexingDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rolodex) GetRootIndex() *SpecIndex {
|
||||||
|
return r.rootIndex
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Rolodex) GetIndexes() []*SpecIndex {
|
func (r *Rolodex) GetIndexes() []*SpecIndex {
|
||||||
return r.indexes
|
return r.indexes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Rolodex) GetCaughtErrors() []error {
|
||||||
|
return r.caughtErrors
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Rolodex) AddLocalFS(baseDir string, fileSystem fs.FS) {
|
func (r *Rolodex) AddLocalFS(baseDir string, fileSystem fs.FS) {
|
||||||
absBaseDir, _ := filepath.Abs(baseDir)
|
absBaseDir, _ := filepath.Abs(baseDir)
|
||||||
r.localFS[absBaseDir] = fileSystem
|
r.localFS[absBaseDir] = fileSystem
|
||||||
@@ -246,6 +260,23 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
copiedConfig.SpecAbsolutePath = fullPath
|
copiedConfig.SpecAbsolutePath = fullPath
|
||||||
copiedConfig.AvoidBuildIndex = true // we will build out everything in two steps.
|
copiedConfig.AvoidBuildIndex = true // we will build out everything in two steps.
|
||||||
idx, err := idxFile.Index(&copiedConfig)
|
idx, err := idxFile.Index(&copiedConfig)
|
||||||
|
|
||||||
|
// for each index, we need a resolver
|
||||||
|
resolver := NewResolver(idx)
|
||||||
|
idx.resolver = resolver
|
||||||
|
|
||||||
|
// check if the config has been set to ignore circular references in arrays and polymorphic schemas
|
||||||
|
if copiedConfig.IgnoreArrayCircularReferences {
|
||||||
|
resolver.IgnoreArrayCircularReferences()
|
||||||
|
}
|
||||||
|
if copiedConfig.IgnorePolymorphicCircularReferences {
|
||||||
|
resolver.IgnorePolymorphicCircularReferences()
|
||||||
|
}
|
||||||
|
resolvingErrors := resolver.CheckForCircularReferences()
|
||||||
|
for e := range resolvingErrors {
|
||||||
|
caughtErrors = append(caughtErrors, resolvingErrors[e])
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
@@ -295,10 +326,29 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
// now that we have indexed all the files, we can build the index.
|
// now that we have indexed all the files, we can build the index.
|
||||||
for _, idx := range indexBuildQueue {
|
for _, idx := range indexBuildQueue {
|
||||||
idx.BuildIndex()
|
idx.BuildIndex()
|
||||||
|
|
||||||
}
|
}
|
||||||
r.indexes = indexBuildQueue
|
r.indexes = indexBuildQueue
|
||||||
|
|
||||||
|
// indexed and built every supporting file, we can build the root index (our entry point)
|
||||||
|
index := NewSpecIndexWithConfig(r.indexConfig.SpecInfo.RootNode, r.indexConfig)
|
||||||
|
resolver := NewResolver(index)
|
||||||
|
if r.indexConfig.IgnoreArrayCircularReferences {
|
||||||
|
resolver.IgnoreArrayCircularReferences()
|
||||||
|
}
|
||||||
|
if r.indexConfig.IgnorePolymorphicCircularReferences {
|
||||||
|
resolver.IgnorePolymorphicCircularReferences()
|
||||||
|
}
|
||||||
|
index.resolver = resolver
|
||||||
|
resolvingErrors := resolver.CheckForCircularReferences()
|
||||||
|
for e := range resolvingErrors {
|
||||||
|
caughtErrors = append(caughtErrors, resolvingErrors[e])
|
||||||
|
}
|
||||||
|
|
||||||
|
r.rootIndex = index
|
||||||
r.indexingDuration = time.Now().Sub(started)
|
r.indexingDuration = time.Now().Sub(started)
|
||||||
r.indexed = true
|
r.indexed = true
|
||||||
|
r.caughtErrors = caughtErrors
|
||||||
return errors.Join(caughtErrors...)
|
return errors.Join(caughtErrors...)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -363,6 +413,7 @@ func (r *Rolodex) Open(location string) (RolodexFile, error) {
|
|||||||
data: bytes,
|
data: bytes,
|
||||||
fullPath: fileLookup,
|
fullPath: fileLookup,
|
||||||
lastModified: s.ModTime(),
|
lastModified: s.ModTime(),
|
||||||
|
index: r.rootIndex,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
openapi: 3.1.0
|
openapi: 3.1.0
|
||||||
info:
|
info:
|
||||||
title: Rolodex Test Data
|
title: Dir1 Test Components
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
Ding:
|
GlobalComponent:
|
||||||
type: object
|
type: object
|
||||||
description: A thing that does nothing. Ding a ling!
|
description: Dir1 Global Component
|
||||||
properties:
|
properties:
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: I am pointless. Ding Ding!
|
description: I am pointless, but I am global dir1.
|
||||||
|
SomeUtil:
|
||||||
|
$ref: "utils/utils.yaml"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Dir1 Shared Components
|
||||||
|
version: 1.0.0
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
SharedComponent:
|
||||||
|
type: object
|
||||||
|
description: Dir1 Shared Component
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: I am pointless, but I am shared dir1.
|
||||||
|
SomeUtil:
|
||||||
|
$ref: "../utils/utils.yaml"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
type: object
|
||||||
|
description: I am a utility for dir1
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: I am pointless dir1.
|
||||||
|
properties:
|
||||||
|
link:
|
||||||
|
$ref: "../components.yaml#/components/schemas/GlobalComponent"
|
||||||
|
shared:
|
||||||
|
$ref: '../shared/shared.yaml#/components/schemas/SharedComponent'
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
openapi: 3.1.0
|
openapi: 3.1.0
|
||||||
info:
|
info:
|
||||||
title: Dir1 Test Components
|
title: Dir2 Test Components
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
GlobalComponent:
|
GlobalComponent:
|
||||||
type: object
|
type: object
|
||||||
description: Dir1 Global Component
|
description: Dir2 Global Component
|
||||||
properties:
|
properties:
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: I am pointless, but I am global dir1.
|
description: I am pointless, but I am global dir2.
|
||||||
SomeUtil:
|
SomeUtil:
|
||||||
$ref: "utils/utils.yaml"
|
$ref: "utils/utils.yaml"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Dir2 Shared Components
|
||||||
|
version: 1.0.0
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
SharedComponent:
|
||||||
|
type: object
|
||||||
|
description: Dir2 Shared Component
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: I am pointless, but I am shared dir2.
|
||||||
|
SomeUtil:
|
||||||
|
$ref: "../utils/utils.yaml"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
type: object
|
||||||
|
description: I am a utility for dir2
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: I am pointless dir2.
|
||||||
|
properties:
|
||||||
|
link:
|
||||||
|
$ref: "../components.yaml#/components/schemas/GlobalComponent"
|
||||||
|
shared:
|
||||||
|
$ref: '../shared/shared.yaml#/components/schemas/SharedComponent'
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: Rolodex Test Data
|
||||||
|
version: 1.0.0
|
||||||
|
paths:
|
||||||
|
/one/local:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Thing'
|
||||||
|
/one/file:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: 'components.yaml#/components/schemas/Ding'
|
||||||
|
/nested/files1:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: 'dir1/components.yaml#/components/schemas/GlobalComponent'
|
||||||
|
/nested/files2:
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: 'dir2/components.yaml#/components/schemas/GlobalComponent'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Thing:
|
||||||
|
type: object
|
||||||
|
description: A thing that does nothing.
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: I am pointless.
|
||||||
@@ -7,26 +7,36 @@ package index
|
|||||||
// and then externalSpecIndex for a match. If no match is found, it will recursively search the child indexes
|
// and then externalSpecIndex for a match. If no match is found, it will recursively search the child indexes
|
||||||
// extracted when parsing the OpenAPI Spec.
|
// extracted when parsing the OpenAPI Spec.
|
||||||
func (index *SpecIndex) SearchIndexForReference(ref string) []*Reference {
|
func (index *SpecIndex) SearchIndexForReference(ref string) []*Reference {
|
||||||
|
|
||||||
if r, ok := index.allMappedRefs[ref]; ok {
|
if r, ok := index.allMappedRefs[ref]; ok {
|
||||||
return []*Reference{r}
|
return []*Reference{r}
|
||||||
}
|
}
|
||||||
for c := range index.children {
|
|
||||||
found := goFindMeSomething(index.children[c], ref)
|
// TODO: look in the rolodex.
|
||||||
if found != nil {
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
//if r, ok := index.allMappedRefs[ref]; ok {
|
||||||
|
// return []*Reference{r}
|
||||||
|
//}
|
||||||
|
//for c := range index.children {
|
||||||
|
// found := goFindMeSomething(index.children[c], ref)
|
||||||
|
// if found != nil {
|
||||||
|
// return found
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (index *SpecIndex) SearchAncestryForSeenURI(uri string) *SpecIndex {
|
func (index *SpecIndex) SearchAncestryForSeenURI(uri string) *SpecIndex {
|
||||||
if index.parentIndex == nil {
|
//if index.parentIndex == nil {
|
||||||
return nil
|
// return nil
|
||||||
}
|
//}
|
||||||
if index.uri[0] != uri {
|
//if index.uri[0] != uri {
|
||||||
return index.parentIndex.SearchAncestryForSeenURI(uri)
|
// return index.parentIndex.SearchAncestryForSeenURI(uri)
|
||||||
}
|
//}
|
||||||
return index
|
//return index
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func goFindMeSomething(i *SpecIndex, ref string) []*Reference {
|
func goFindMeSomething(i *SpecIndex, ref string) []*Reference {
|
||||||
|
|||||||
@@ -13,14 +13,15 @@
|
|||||||
package index
|
package index
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"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"
|
||||||
"golang.org/x/sync/syncmap"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,13 +30,15 @@ import (
|
|||||||
// how the index is set up.
|
// how the index is set up.
|
||||||
func NewSpecIndexWithConfig(rootNode *yaml.Node, config *SpecIndexConfig) *SpecIndex {
|
func NewSpecIndexWithConfig(rootNode *yaml.Node, config *SpecIndexConfig) *SpecIndex {
|
||||||
index := new(SpecIndex)
|
index := new(SpecIndex)
|
||||||
if config != nil && config.seenRemoteSources == nil {
|
//if config != nil && config.seenRemoteSources == nil {
|
||||||
config.seenRemoteSources = &syncmap.Map{}
|
// config.seenRemoteSources = &syncmap.Map{}
|
||||||
}
|
//}
|
||||||
config.remoteLock = &sync.Mutex{}
|
//config.remoteLock = &sync.Mutex{}
|
||||||
index.config = config
|
index.config = config
|
||||||
index.parentIndex = config.ParentIndex
|
index.rolodex = config.Rolodex
|
||||||
|
//index.parentIndex = config.ParentIndex
|
||||||
index.uri = config.uri
|
index.uri = config.uri
|
||||||
|
index.specAbsolutePath = config.SpecAbsolutePath
|
||||||
if rootNode == nil || len(rootNode.Content) <= 0 {
|
if rootNode == nil || len(rootNode.Content) <= 0 {
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
@@ -89,10 +92,10 @@ func createNewIndex(rootNode *yaml.Node, index *SpecIndex, avoidBuildOut bool) *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do a copy!
|
// do a copy!
|
||||||
index.config.seenRemoteSources.Range(func(k, v any) bool {
|
//index.config.seenRemoteSources.Range(func(k, v any) bool {
|
||||||
index.seenRemoteSources[k.(string)] = v.(*yaml.Node)
|
// index.seenRemoteSources[k.(string)] = v.(*yaml.Node)
|
||||||
return true
|
// return true
|
||||||
})
|
//})
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,13 +621,34 @@ func (index *SpecIndex) GetGlobalCallbacksCount() int {
|
|||||||
return index.globalCallbacksCount
|
return index.globalCallbacksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// index.pathRefsLock.Lock()
|
index.pathRefsLock.RLock()
|
||||||
for path, p := range index.pathRefs {
|
for path, p := range index.pathRefs {
|
||||||
for _, m := range p {
|
for _, m := range p {
|
||||||
|
|
||||||
// look through method for callbacks
|
// look through method for callbacks
|
||||||
callbacks, _ := yamlpath.NewPath("$..callbacks")
|
callbacks, _ := yamlpath.NewPath("$..callbacks")
|
||||||
res, _ := callbacks.Find(m.Node)
|
// Channel used to receive the result from doSomething function
|
||||||
|
ch := make(chan string, 1)
|
||||||
|
|
||||||
|
// Create a context with a timeout of 5 seconds
|
||||||
|
ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Millisecond*500)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var res []*yaml.Node
|
||||||
|
|
||||||
|
doSomething := func(ctx context.Context, ch chan<- string) {
|
||||||
|
res, _ = callbacks.Find(m.Node)
|
||||||
|
ch <- m.Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the doSomething function
|
||||||
|
go doSomething(ctxTimeout, ch)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctxTimeout.Done():
|
||||||
|
fmt.Printf("Callback %d: Context cancelled: %v\n", m.Node.Line, ctxTimeout.Err())
|
||||||
|
case <-ch:
|
||||||
|
}
|
||||||
|
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
for _, callback := range res[0].Content {
|
for _, callback := range res[0].Content {
|
||||||
@@ -650,7 +674,7 @@ func (index *SpecIndex) GetGlobalCallbacksCount() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// index.pathRefsLock.Unlock()
|
index.pathRefsLock.RUnlock()
|
||||||
return index.globalCallbacksCount
|
return index.globalCallbacksCount
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,7 +694,29 @@ func (index *SpecIndex) GetGlobalLinksCount() int {
|
|||||||
|
|
||||||
// look through method for links
|
// look through method for links
|
||||||
links, _ := yamlpath.NewPath("$..links")
|
links, _ := yamlpath.NewPath("$..links")
|
||||||
res, _ := links.Find(m.Node)
|
|
||||||
|
// Channel used to receive the result from doSomething function
|
||||||
|
ch := make(chan string, 1)
|
||||||
|
|
||||||
|
// Create a context with a timeout of 5 seconds
|
||||||
|
ctxTimeout, cancel := context.WithTimeout(context.Background(), time.Millisecond*500)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var res []*yaml.Node
|
||||||
|
|
||||||
|
doSomething := func(ctx context.Context, ch chan<- string) {
|
||||||
|
res, _ = links.Find(m.Node)
|
||||||
|
ch <- m.Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the doSomething function
|
||||||
|
go doSomething(ctxTimeout, ch)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctxTimeout.Done():
|
||||||
|
fmt.Printf("Global links %d ref: Context cancelled: %v\n", m.Node.Line, ctxTimeout.Err())
|
||||||
|
case <-ch:
|
||||||
|
}
|
||||||
|
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
for _, link := range res[0].Content {
|
for _, link := range res[0].Content {
|
||||||
@@ -928,6 +974,8 @@ func (index *SpecIndex) GetOperationCount() int {
|
|||||||
|
|
||||||
opCount := 0
|
opCount := 0
|
||||||
|
|
||||||
|
locatedPathRefs := make(map[string]map[string]*Reference)
|
||||||
|
|
||||||
for x, p := range index.pathsNode.Content {
|
for x, p := range index.pathsNode.Content {
|
||||||
if x%2 == 0 {
|
if x%2 == 0 {
|
||||||
|
|
||||||
@@ -950,6 +998,7 @@ func (index *SpecIndex) GetOperationCount() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if valid {
|
if valid {
|
||||||
|
fmt.Sprint(p)
|
||||||
ref := &Reference{
|
ref := &Reference{
|
||||||
Definition: m.Value,
|
Definition: m.Value,
|
||||||
Name: m.Value,
|
Name: m.Value,
|
||||||
@@ -957,12 +1006,12 @@ func (index *SpecIndex) GetOperationCount() int {
|
|||||||
Path: fmt.Sprintf("$.paths.%s.%s", p.Value, m.Value),
|
Path: fmt.Sprintf("$.paths.%s.%s", p.Value, m.Value),
|
||||||
ParentNode: m,
|
ParentNode: m,
|
||||||
}
|
}
|
||||||
index.pathRefsLock.Lock()
|
//index.pathRefsLock.Lock()
|
||||||
if index.pathRefs[p.Value] == nil {
|
if locatedPathRefs[p.Value] == nil {
|
||||||
index.pathRefs[p.Value] = make(map[string]*Reference)
|
locatedPathRefs[p.Value] = make(map[string]*Reference)
|
||||||
}
|
}
|
||||||
index.pathRefs[p.Value][ref.Name] = ref
|
locatedPathRefs[p.Value][ref.Name] = ref
|
||||||
index.pathRefsLock.Unlock()
|
//index.pathRefsLock.Unlock()
|
||||||
// update
|
// update
|
||||||
opCount++
|
opCount++
|
||||||
}
|
}
|
||||||
@@ -970,7 +1019,11 @@ func (index *SpecIndex) GetOperationCount() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
index.pathRefsLock.Lock()
|
||||||
|
for k, v := range locatedPathRefs {
|
||||||
|
index.pathRefs[k] = v
|
||||||
|
}
|
||||||
|
index.pathRefsLock.Unlock()
|
||||||
index.operationCount = opCount
|
index.operationCount = opCount
|
||||||
return opCount
|
return opCount
|
||||||
}
|
}
|
||||||
@@ -1188,13 +1241,13 @@ func (index *SpecIndex) GetAllSummariesCount() int {
|
|||||||
|
|
||||||
// CheckForSeenRemoteSource will check to see if we have already seen this remote source and return it,
|
// CheckForSeenRemoteSource will check to see if we have already seen this remote source and return it,
|
||||||
// to avoid making duplicate remote calls for document data.
|
// to avoid making duplicate remote calls for document data.
|
||||||
func (index *SpecIndex) CheckForSeenRemoteSource(url string) (bool, *yaml.Node) {
|
//func (index *SpecIndex) CheckForSeenRemoteSource(url string) (bool, *yaml.Node) {
|
||||||
if index.config == nil || index.config.seenRemoteSources == nil {
|
// if index.config == nil || index.config.seenRemoteSources == nil {
|
||||||
return false, nil
|
// return false, nil
|
||||||
}
|
// }
|
||||||
j, _ := index.config.seenRemoteSources.Load(url)
|
// j, _ := index.config.seenRemoteSources.Load(url)
|
||||||
if j != nil {
|
// if j != nil {
|
||||||
return true, j.(*yaml.Node)
|
// return true, j.(*yaml.Node)
|
||||||
}
|
// }
|
||||||
return false, nil
|
// return false, nil
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|||||||
|
|
||||||
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
||||||
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
AllowRemoteLookup: true,
|
//AllowRemoteLookup: true,
|
||||||
AllowFileLookup: true,
|
//AllowFileLookup: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 291)
|
assert.Len(t, index.GetAllExternalIndexes(), 291)
|
||||||
@@ -163,9 +163,9 @@ func TestSpecIndex_BaseURLError(t *testing.T) {
|
|||||||
// anything.
|
// anything.
|
||||||
baseURL, _ := url.Parse("https://githerbs.com/fresh/herbs/for/you")
|
baseURL, _ := url.Parse("https://githerbs.com/fresh/herbs/for/you")
|
||||||
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
AllowRemoteLookup: true,
|
//AllowRemoteLookup: true,
|
||||||
AllowFileLookup: true,
|
//AllowFileLookup: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 0)
|
assert.Len(t, index.GetAllExternalIndexes(), 0)
|
||||||
@@ -441,9 +441,9 @@ func TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
|
|||||||
cwd, _ := os.Getwd()
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
||||||
AllowRemoteLookup: true,
|
//AllowRemoteLookup: true,
|
||||||
AllowFileLookup: true,
|
// AllowFileLookup: true,
|
||||||
BasePath: cwd,
|
BasePath: cwd,
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.Len(t, index.allRefs, 5)
|
assert.Len(t, index.allRefs, 5)
|
||||||
@@ -630,7 +630,7 @@ func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {
|
|||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
||||||
assert.Nil(t, index.performExternalLookup(nil, "unknown", nil, nil))
|
assert.Nil(t, index.performExternalLookup(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_Error(t *testing.T) {
|
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_Error(t *testing.T) {
|
||||||
@@ -734,7 +734,7 @@ paths:
|
|||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
||||||
index := NewSpecIndexWithConfig(nil, &SpecIndexConfig{
|
index := NewSpecIndexWithConfig(nil, &SpecIndexConfig{
|
||||||
AllowRemoteLookup: true,
|
//AllowRemoteLookup: true,
|
||||||
})
|
})
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
a, b, err := index.lookupRemoteReference("https://google.com//logos/doodles/2022/labor-day-2022-6753651837109490.3-l.png#/hey")
|
a, b, err := index.lookupRemoteReference("https://google.com//logos/doodles/2022/labor-day-2022-6753651837109490.3-l.png#/hey")
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pat
|
|||||||
Node: schema,
|
Node: schema,
|
||||||
Path: fmt.Sprintf("$.components.schemas.%s", name),
|
Path: fmt.Sprintf("$.components.schemas.%s", name),
|
||||||
ParentNode: schemasNode,
|
ParentNode: schemasNode,
|
||||||
RequiredRefProperties: index.extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}),
|
RequiredRefProperties: extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}),
|
||||||
}
|
}
|
||||||
index.allComponentSchemaDefinitions[def] = ref
|
index.allComponentSchemaDefinitions[def] = ref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractDefinitionRequiredRefProperties goes through the direct properties of a schema and extracts the map of required definitions from within it
|
// extractDefinitionRequiredRefProperties goes through the direct properties of a schema and extracts the map of required definitions from within it
|
||||||
func (index *SpecIndex) extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps map[string][]string) map[string][]string {
|
func extractDefinitionRequiredRefProperties(schemaNode *yaml.Node, reqRefProps map[string][]string) map[string][]string {
|
||||||
if schemaNode == nil {
|
if schemaNode == nil {
|
||||||
return reqRefProps
|
return reqRefProps
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ func (index *SpecIndex) extractDefinitionRequiredRefProperties(schemaNode *yaml.
|
|||||||
// Check to see if the current property is directly embedded within the current schema, and handle its properties if so
|
// Check to see if the current property is directly embedded within the current schema, and handle its properties if so
|
||||||
_, paramPropertiesMapNode := utils.FindKeyNodeTop("properties", param.Content)
|
_, paramPropertiesMapNode := utils.FindKeyNodeTop("properties", param.Content)
|
||||||
if paramPropertiesMapNode != nil {
|
if paramPropertiesMapNode != nil {
|
||||||
reqRefProps = index.extractDefinitionRequiredRefProperties(param, reqRefProps)
|
reqRefProps = extractDefinitionRequiredRefProperties(param, reqRefProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if the current property is polymorphic, and dive into that model if so
|
// Check to see if the current property is polymorphic, and dive into that model if so
|
||||||
@@ -78,7 +78,7 @@ func (index *SpecIndex) extractDefinitionRequiredRefProperties(schemaNode *yaml.
|
|||||||
_, ofNode := utils.FindKeyNodeTop(key, param.Content)
|
_, ofNode := utils.FindKeyNodeTop(key, param.Content)
|
||||||
if ofNode != nil {
|
if ofNode != nil {
|
||||||
for _, ofNodeItem := range ofNode.Content {
|
for _, ofNodeItem := range ofNode.Content {
|
||||||
reqRefProps = index.extractRequiredReferenceProperties(ofNodeItem, name, reqRefProps)
|
reqRefProps = extractRequiredReferenceProperties(ofNodeItem, name, reqRefProps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,14 +91,14 @@ func (index *SpecIndex) extractDefinitionRequiredRefProperties(schemaNode *yaml.
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
reqRefProps = index.extractRequiredReferenceProperties(requiredPropDefNode, requiredPropertyNode.Value, reqRefProps)
|
reqRefProps = extractRequiredReferenceProperties(requiredPropDefNode, requiredPropertyNode.Value, reqRefProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
return reqRefProps
|
return reqRefProps
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractRequiredReferenceProperties returns a map of definition names to the property or properties which reference it within a node
|
// extractRequiredReferenceProperties returns a map of definition names to the property or properties which reference it within a node
|
||||||
func (index *SpecIndex) extractRequiredReferenceProperties(requiredPropDefNode *yaml.Node, propName string, reqRefProps map[string][]string) map[string][]string {
|
func extractRequiredReferenceProperties(requiredPropDefNode *yaml.Node, propName string, reqRefProps map[string][]string) map[string][]string {
|
||||||
isRef, _, defPath := utils.IsNodeRefValue(requiredPropDefNode)
|
isRef, _, defPath := utils.IsNodeRefValue(requiredPropDefNode)
|
||||||
if !isRef {
|
if !isRef {
|
||||||
_, defItems := utils.FindKeyNodeTop("items", requiredPropDefNode.Content)
|
_, defItems := utils.FindKeyNodeTop("items", requiredPropDefNode.Content)
|
||||||
|
|||||||
@@ -49,7 +49,5 @@ func TestGenerateCleanSpecConfigBaseURL_HttpStrip(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_extractDefinitionRequiredRefProperties(t *testing.T) {
|
func TestSpecIndex_extractDefinitionRequiredRefProperties(t *testing.T) {
|
||||||
c := CreateOpenAPIIndexConfig()
|
assert.Nil(t, extractDefinitionRequiredRefProperties(nil, nil))
|
||||||
idx := NewSpecIndexWithConfig(nil, c)
|
|
||||||
assert.Nil(t, idx.extractDefinitionRequiredRefProperties(nil, nil))
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
utils/unwrap_errors.go
Normal file
11
utils/unwrap_errors.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
func UnwrapErrors(err error) []error {
|
||||||
|
if err == nil {
|
||||||
|
return []error{}
|
||||||
|
}
|
||||||
|
return err.(interface{ Unwrap() []error }).Unwrap()
|
||||||
|
}
|
||||||
@@ -4,14 +4,13 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"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/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"github.com/pb33f/libopenapi/index"
|
"github.com/pb33f/libopenapi/index"
|
||||||
"github.com/pb33f/libopenapi/resolver"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/assert"
|
"gopkg.in/yaml.v3"
|
||||||
"gopkg.in/yaml.v3"
|
"testing"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCompareComponents_Swagger_Definitions_Equal(t *testing.T) {
|
func TestCompareComponents_Swagger_Definitions_Equal(t *testing.T) {
|
||||||
@@ -677,8 +676,8 @@ func TestCompareComponents_OpenAPI_Responses_FullBuild_CircularRef(t *testing.T)
|
|||||||
idx2 := index.NewSpecIndex(&rNode)
|
idx2 := index.NewSpecIndex(&rNode)
|
||||||
|
|
||||||
// resolver required to check circular refs.
|
// resolver required to check circular refs.
|
||||||
re1 := resolver.NewResolver(idx)
|
re1 := index.NewResolver(idx)
|
||||||
re2 := resolver.NewResolver(idx2)
|
re2 := index.NewResolver(idx2)
|
||||||
|
|
||||||
re1.CheckForCircularReferences()
|
re1.CheckForCircularReferences()
|
||||||
re2.CheckForCircularReferences()
|
re2.CheckForCircularReferences()
|
||||||
|
|||||||
Reference in New Issue
Block a user