mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
@@ -129,10 +129,8 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
u.Path = filepath.Join(p, explodedRefValue[0])
|
u.Path = filepath.Join(p, explodedRefValue[0])
|
||||||
rv = fmt.Sprintf("%s#%s", u.String(), explodedRefValue[1])
|
rv = fmt.Sprintf("%s#%s", u.String(), explodedRefValue[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -159,7 +157,6 @@ func LocateRefNodeWithContext(ctx context.Context, root *yaml.Node, idx *index.S
|
|||||||
// check for a config baseURL and use that if it exists.
|
// check for a config baseURL and use that if it exists.
|
||||||
if idx.GetConfig().BaseURL != nil {
|
if idx.GetConfig().BaseURL != nil {
|
||||||
u := *idx.GetConfig().BaseURL
|
u := *idx.GetConfig().BaseURL
|
||||||
|
|
||||||
abs, _ := filepath.Abs(filepath.Join(u.Path, rv))
|
abs, _ := filepath.Abs(filepath.Join(u.Path, rv))
|
||||||
u.Path = abs
|
u.Path = abs
|
||||||
rv = u.String()
|
rv = u.String()
|
||||||
@@ -375,7 +372,6 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
vn = ref
|
vn = ref
|
||||||
idx = fIdx
|
idx = fIdx
|
||||||
ctx = nCtx
|
ctx = nCtx
|
||||||
//referenceValue = rVal
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
circError = err
|
circError = err
|
||||||
}
|
}
|
||||||
@@ -412,8 +408,6 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
}
|
}
|
||||||
for _, node := range vn.Content {
|
for _, node := range vn.Content {
|
||||||
localReferenceValue := ""
|
localReferenceValue := ""
|
||||||
//localIsReference := false
|
|
||||||
|
|
||||||
foundCtx := ctx
|
foundCtx := ctx
|
||||||
foundIndex := idx
|
foundIndex := idx
|
||||||
|
|
||||||
@@ -421,7 +415,6 @@ func ExtractArray[T Buildable[N], N any](ctx context.Context, label string, root
|
|||||||
refg, fIdx, err, nCtx := LocateRefEnd(ctx, node, idx, 0)
|
refg, fIdx, err, nCtx := LocateRefEnd(ctx, node, idx, 0)
|
||||||
if refg != nil {
|
if refg != nil {
|
||||||
node = refg
|
node = refg
|
||||||
//localIsReference = true
|
|
||||||
localReferenceValue = rv
|
localReferenceValue = rv
|
||||||
foundIndex = fIdx
|
foundIndex = fIdx
|
||||||
foundCtx = nCtx
|
foundCtx = nCtx
|
||||||
@@ -853,6 +846,10 @@ func GenerateHashString(v any) string {
|
|||||||
return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v))))
|
return fmt.Sprintf(HASH, sha256.Sum256([]byte(fmt.Sprint(v))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocateRefEnd will perform a complete lookup for a $ref node. This function searches the entire index for
|
||||||
|
// the reference being supplied. If there is a match found, the reference *yaml.Node is returned.
|
||||||
|
// the function operates recursively and will keep iterating through references until it finds a non-reference
|
||||||
|
// node.
|
||||||
func LocateRefEnd(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, depth int) (*yaml.Node, *index.SpecIndex, error, context.Context) {
|
func LocateRefEnd(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, depth int) (*yaml.Node, *index.SpecIndex, error, context.Context) {
|
||||||
depth++
|
depth++
|
||||||
if depth > 100 {
|
if depth > 100 {
|
||||||
@@ -862,17 +859,9 @@ func LocateRefEnd(ctx context.Context, root *yaml.Node, idx *index.SpecIndex, de
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ref, fIdx, err, nCtx
|
return ref, fIdx, err, nCtx
|
||||||
}
|
}
|
||||||
if ref != nil {
|
if rf, _, _ := utils.IsNodeRefValue(ref); rf {
|
||||||
if rf, _, _ := utils.IsNodeRefValue(ref); rf {
|
return LocateRefEnd(nCtx, ref, fIdx, depth)
|
||||||
return LocateRefEnd(nCtx, ref, fIdx, depth)
|
|
||||||
} else {
|
|
||||||
return ref, fIdx, err, nCtx
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if root.Content[1].Value == "" {
|
return ref, fIdx, err, nCtx
|
||||||
return nil, nil, fmt.Errorf("reference at line %d, column %d is empty, it cannot be resolved",
|
|
||||||
root.Content[1].Line, root.Content[1].Column), ctx
|
|
||||||
}
|
|
||||||
return nil, nil, fmt.Errorf("reference cannot be found: %s", root.Content[1].Value), ctx
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -1983,3 +1984,121 @@ func TestLocateRefNode_DoARealLookup(t *testing.T) {
|
|||||||
assert.Nil(t, e)
|
assert.Nil(t, e)
|
||||||
assert.NotNil(t, c)
|
assert.NotNil(t, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocateRefEndNoRef_NoName(t *testing.T) {
|
||||||
|
|
||||||
|
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: ""}}}
|
||||||
|
n, i, e, c := LocateRefEnd(nil, r, nil, 0)
|
||||||
|
assert.Nil(t, n)
|
||||||
|
assert.Nil(t, i)
|
||||||
|
assert.Error(t, e)
|
||||||
|
assert.Nil(t, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocateRefEndNoRef(t *testing.T) {
|
||||||
|
|
||||||
|
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: "cake"}}}
|
||||||
|
n, i, e, c := LocateRefEnd(context.Background(), r, index.NewSpecIndexWithConfig(r, index.CreateClosedAPIIndexConfig()), 0)
|
||||||
|
assert.Nil(t, n)
|
||||||
|
assert.NotNil(t, i)
|
||||||
|
assert.Error(t, e)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocateRefEnd_TooDeep(t *testing.T) {
|
||||||
|
r := &yaml.Node{Content: []*yaml.Node{{Kind: yaml.ScalarNode, Value: "$ref"}, {Kind: yaml.ScalarNode, Value: ""}}}
|
||||||
|
n, i, e, c := LocateRefEnd(nil, r, nil, 100)
|
||||||
|
assert.Nil(t, n)
|
||||||
|
assert.Nil(t, i)
|
||||||
|
assert.Error(t, e)
|
||||||
|
assert.Nil(t, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocateRefEnd_Loop(t *testing.T) {
|
||||||
|
|
||||||
|
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
||||||
|
var bsn yaml.Node
|
||||||
|
_ = yaml.Unmarshal(yml, &bsn)
|
||||||
|
|
||||||
|
cf := index.CreateOpenAPIIndexConfig()
|
||||||
|
cf.BasePath = "../../test_specs"
|
||||||
|
|
||||||
|
localFSConfig := &index.LocalFSConfig{
|
||||||
|
BaseDirectory: cf.BasePath,
|
||||||
|
FileFilters: []string{"first.yaml", "second.yaml", "third.yaml", "fourth.yaml"},
|
||||||
|
DirFS: os.DirFS(cf.BasePath),
|
||||||
|
}
|
||||||
|
localFs, _ := index.NewLocalFSWithConfig(localFSConfig)
|
||||||
|
rolo := index.NewRolodex(cf)
|
||||||
|
rolo.AddLocalFS(cf.BasePath, localFs)
|
||||||
|
rolo.SetRootNode(&bsn)
|
||||||
|
rolo.IndexTheRolodex()
|
||||||
|
idx := rolo.GetRootIndex()
|
||||||
|
loop := yaml.Node{
|
||||||
|
Kind: yaml.MappingNode,
|
||||||
|
Content: []*yaml.Node{
|
||||||
|
{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: "$ref",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: "third.yaml#/properties/property/properties/statistics",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
cp, _ := filepath.Abs(filepath.Join(wd, "../../test_specs/first.yaml"))
|
||||||
|
ctx := context.WithValue(context.Background(), index.CurrentPathKey, cp)
|
||||||
|
n, i, e, c := LocateRefEnd(ctx, &loop, idx, 0)
|
||||||
|
assert.NotNil(t, n)
|
||||||
|
assert.NotNil(t, i)
|
||||||
|
assert.Nil(t, e)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocateRefEnd_Empty(t *testing.T) {
|
||||||
|
|
||||||
|
yml, _ := os.ReadFile("../../test_specs/first.yaml")
|
||||||
|
var bsn yaml.Node
|
||||||
|
_ = yaml.Unmarshal(yml, &bsn)
|
||||||
|
|
||||||
|
cf := index.CreateOpenAPIIndexConfig()
|
||||||
|
cf.BasePath = "../../test_specs"
|
||||||
|
|
||||||
|
localFSConfig := &index.LocalFSConfig{
|
||||||
|
BaseDirectory: cf.BasePath,
|
||||||
|
FileFilters: []string{"first.yaml", "second.yaml", "third.yaml", "fourth.yaml"},
|
||||||
|
DirFS: os.DirFS(cf.BasePath),
|
||||||
|
}
|
||||||
|
localFs, _ := index.NewLocalFSWithConfig(localFSConfig)
|
||||||
|
rolo := index.NewRolodex(cf)
|
||||||
|
rolo.AddLocalFS(cf.BasePath, localFs)
|
||||||
|
rolo.SetRootNode(&bsn)
|
||||||
|
rolo.IndexTheRolodex()
|
||||||
|
idx := rolo.GetRootIndex()
|
||||||
|
loop := yaml.Node{
|
||||||
|
Kind: yaml.MappingNode,
|
||||||
|
Content: []*yaml.Node{
|
||||||
|
{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: "$ref",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Value: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
cp, _ := filepath.Abs(filepath.Join(wd, "../../test_specs/first.yaml"))
|
||||||
|
ctx := context.WithValue(context.Background(), index.CurrentPathKey, cp)
|
||||||
|
n, i, e, c := LocateRefEnd(ctx, &loop, idx, 0)
|
||||||
|
assert.Nil(t, n)
|
||||||
|
assert.Nil(t, i)
|
||||||
|
assert.Error(t, e)
|
||||||
|
assert.Equal(t, "reference at line 0, column 0 is empty, it cannot be resolved", e.Error())
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
}
|
||||||
|
|||||||
@@ -266,7 +266,6 @@ type SpecIndex struct {
|
|||||||
circularReferences []*CircularReferenceResult // only available when the resolver has been used.
|
circularReferences []*CircularReferenceResult // only available when the resolver has been used.
|
||||||
allowCircularReferences bool // decide if you want to error out, or allow circular references, default is false.
|
allowCircularReferences bool // decide if you want to error out, or allow circular references, default is false.
|
||||||
config *SpecIndexConfig // configuration for the index
|
config *SpecIndexConfig // configuration for the index
|
||||||
httpClient *http.Client
|
|
||||||
componentIndexChan chan bool
|
componentIndexChan chan bool
|
||||||
polyComponentIndexChan chan bool
|
polyComponentIndexChan chan bool
|
||||||
resolver *Resolver
|
resolver *Resolver
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ package index
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func isHttpMethod(val string) bool {
|
func isHttpMethod(val string) bool {
|
||||||
@@ -68,7 +66,6 @@ func boostrapIndexCollections(rootNode *yaml.Node, index *SpecIndex) {
|
|||||||
index.polymorphicRefs = make(map[string]*Reference)
|
index.polymorphicRefs = make(map[string]*Reference)
|
||||||
index.refsWithSiblings = make(map[string]Reference)
|
index.refsWithSiblings = make(map[string]Reference)
|
||||||
index.opServersRefs = make(map[string]map[string][]*Reference)
|
index.opServersRefs = make(map[string]map[string][]*Reference)
|
||||||
index.httpClient = &http.Client{Timeout: time.Duration(5) * time.Second}
|
|
||||||
index.componentIndexChan = make(chan bool)
|
index.componentIndexChan = make(chan bool)
|
||||||
index.polyComponentIndexChan = make(chan bool)
|
index.polyComponentIndexChan = make(chan bool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HasIndex interface {
|
// CanBeIndexed is an interface that allows a file to be indexed.
|
||||||
GetIndex() *SpecIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
type CanBeIndexed interface {
|
type CanBeIndexed interface {
|
||||||
Index(config *SpecIndexConfig) (*SpecIndex, error)
|
Index(config *SpecIndexConfig) (*SpecIndex, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RolodexFile is an interface that represents a file in the rolodex. It combines multiple `fs` interfaces
|
||||||
|
// like `fs.FileInfo` and `fs.File` into one interface, so the same struct can be used for everything.
|
||||||
type RolodexFile interface {
|
type RolodexFile interface {
|
||||||
GetContent() string
|
GetContent() string
|
||||||
GetFileExtension() FileExtension
|
GetFileExtension() FileExtension
|
||||||
@@ -40,6 +39,8 @@ type RolodexFile interface {
|
|||||||
Mode() os.FileMode
|
Mode() os.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RolodexFS is an interface that represents a RolodexFS, is the same interface as `fs.FS`, except it
|
||||||
|
// also exposes a GetFiles() signature, to extract all files in the FS.
|
||||||
type RolodexFS interface {
|
type RolodexFS interface {
|
||||||
Open(name string) (fs.File, error)
|
Open(name string) (fs.File, error)
|
||||||
GetFiles() map[string]RolodexFile
|
GetFiles() map[string]RolodexFile
|
||||||
@@ -226,7 +227,6 @@ 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.
|
||||||
r.indexes = indexBuildQueue
|
r.indexes = indexBuildQueue
|
||||||
//if !r.indexConfig.AvoidBuildIndex {
|
|
||||||
|
|
||||||
sort.Slice(indexBuildQueue, func(i, j int) bool {
|
sort.Slice(indexBuildQueue, func(i, j int) bool {
|
||||||
return indexBuildQueue[i].specAbsolutePath < indexBuildQueue[j].specAbsolutePath
|
return indexBuildQueue[i].specAbsolutePath < indexBuildQueue[j].specAbsolutePath
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
|||||||
if len(remoteFile.data) > 0 {
|
if len(remoteFile.data) > 0 {
|
||||||
i.logger.Debug("successfully loaded file", "file", absolutePath)
|
i.logger.Debug("successfully loaded file", "file", absolutePath)
|
||||||
}
|
}
|
||||||
//i.seekRelatives(remoteFile)
|
|
||||||
// remove from processing
|
// remove from processing
|
||||||
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
i.Files.Store(absolutePath, remoteFile)
|
i.Files.Store(absolutePath, remoteFile)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ func (index *SpecIndex) SearchIndexForReferenceWithContext(ctx context.Context,
|
|||||||
func (index *SpecIndex) SearchIndexForReferenceByReferenceWithContext(ctx context.Context, searchRef *Reference) (*Reference, *SpecIndex, context.Context) {
|
func (index *SpecIndex) SearchIndexForReferenceByReferenceWithContext(ctx context.Context, searchRef *Reference) (*Reference, *SpecIndex, context.Context) {
|
||||||
|
|
||||||
if v, ok := index.cache.Load(searchRef.FullDefinition); ok {
|
if v, ok := index.cache.Load(searchRef.FullDefinition); ok {
|
||||||
//return v.(*Reference), index, context.WithValue(ctx, CurrentPathKey, v.(*Reference).RemoteLocation)
|
|
||||||
return v.(*Reference), v.(*Reference).Index, context.WithValue(ctx, CurrentPathKey, v.(*Reference).RemoteLocation)
|
return v.(*Reference), v.(*Reference).Index, context.WithValue(ctx, CurrentPathKey, v.(*Reference).RemoteLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user