addressed issue #195

Resolving and indexing has changed, new code is required and this isue highlighted a glitch introduced with the addition of the rolodex when resolving.

Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
quobix
2023-11-08 11:25:31 -05:00
parent 78b50cb909
commit e624efbf84
4 changed files with 86 additions and 8 deletions

View File

@@ -563,9 +563,10 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc
found = append(found, located) found = append(found, located)
index.allMappedRefs[located.FullDefinition] = located index.allMappedRefs[located.FullDefinition] = located
rm := &ReferenceMapped{ rm := &ReferenceMapped{
Reference: located, OriginalReference: ref,
Definition: located.Definition, Reference: located,
FullDefinition: located.FullDefinition, Definition: located.Definition,
FullDefinition: located.FullDefinition,
} }
sequence[refIndex] = rm sequence[refIndex] = rm
} }

View File

@@ -44,9 +44,10 @@ type Reference struct {
// ReferenceMapped is a helper struct for mapped references put into sequence (we lose the key) // ReferenceMapped is a helper struct for mapped references put into sequence (we lose the key)
type ReferenceMapped struct { type ReferenceMapped struct {
Reference *Reference OriginalReference *Reference
Definition string Reference *Reference
FullDefinition string Definition string
FullDefinition string
} }
// SpecIndexConfig is a configuration struct for the SpecIndex introduced in 0.6.0 that provides an expandable // SpecIndexConfig is a configuration struct for the SpecIndex introduced in 0.6.0 that provides an expandable

View File

@@ -258,7 +258,11 @@ func visitIndex(res *Resolver, idx *SpecIndex) {
var journey []*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) n := res.VisitReference(ref.Reference, seenReferences, journey, true)
ref.Reference.Node.Content = n
if !ref.Reference.Circular {
ref.OriginalReference.Node.Content = n
}
} }
} }
@@ -548,7 +552,7 @@ func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.No
if resolve { if resolve {
// if this is a reference also, we want to resolve it. // if this is a reference also, we want to resolve it.
if ok, _, _ := utils.IsNodeRefValue(ref.Node); ok { if ok, _, _ := utils.IsNodeRefValue(ref.Node); ok {
ref.Node = locatedRef.Node ref.Node.Content = locatedRef.Node.Content
ref.Resolved = true ref.Resolved = true
} }
} }

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/pb33f/libopenapi/datamodel" "github.com/pb33f/libopenapi/datamodel"
"github.com/pb33f/libopenapi/utils" "github.com/pb33f/libopenapi/utils"
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@@ -1018,3 +1019,74 @@ func TestLocateRefEnd_WithResolve(t *testing.T) {
isRef, _, _ = utils.IsNodeRefValue(ref.Node) isRef, _, _ = utils.IsNodeRefValue(ref.Node)
assert.False(t, isRef) assert.False(t, isRef)
} }
func TestResolveDoc_Issue195(t *testing.T) {
spec := `openapi: 3.0.1
info:
title: Some Example!
paths:
"/pet/findByStatus":
get:
responses:
default:
content:
application/json:
schema:
"$ref": https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml#/components/schemas/Error`
var rootNode yaml.Node
_ = yaml.Unmarshal([]byte(spec), &rootNode)
// create an index config
config := CreateOpenAPIIndexConfig()
// the rolodex will automatically try and check for circular references, you don't want to do this
// if you're resolving the spec, as the node tree is marked as 'seen' and you won't be able to resolve
// correctly.
config.AvoidCircularReferenceCheck = true
// new in 0.13+ is the ability to add remote and local file systems to the index
// requires a new part, the rolodex. It holds all the indexes and knows where to find
// every reference across local and remote files.
rolodex := NewRolodex(config)
// add a new remote file system.
remoteFS, _ := NewRemoteFSWithConfig(config)
// add the remote file system to the rolodex
rolodex.AddRemoteFS("", remoteFS)
// set the root node of the rolodex, this is your spec.
rolodex.SetRootNode(&rootNode)
// index the rolodex
indexingError := rolodex.IndexTheRolodex()
if indexingError != nil {
panic(indexingError)
}
// resolve the rolodex
rolodex.Resolve()
// there should be no errors at this point
resolvingErrors := rolodex.GetCaughtErrors()
if resolvingErrors != nil {
panic(resolvingErrors)
}
// perform some lookups.
var nodes []*yaml.Node
// pull out schema type
path, _ := yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.type")
nodes, _ = path.Find(&rootNode)
assert.Equal(t, nodes[0].Value, "object")
// pull out required array
path, _ = yamlpath.NewPath("$.paths./pet/findByStatus.get.responses.default.content['application/json'].schema.required")
nodes, _ = path.Find(&rootNode)
assert.Equal(t, nodes[0].Content[0].Value, "code")
assert.Equal(t, nodes[0].Content[1].Value, "message")
}