mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-10 04:20:24 +00:00
(enhancement): Improved resolving/lookup code for #45
This commit is contained in:
@@ -362,7 +362,7 @@ func TestStripeAsDoc(t *testing.T) {
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
var err []error
|
||||
lowDoc, err = lowv3.CreateDocument(info)
|
||||
assert.Len(t, err, 21)
|
||||
assert.Len(t, err, 23)
|
||||
d := NewDocument(lowDoc)
|
||||
fmt.Println(d)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestCreateDocumentStripe(t *testing.T) {
|
||||
data, _ := ioutil.ReadFile("../../../test_specs/stripe.yaml")
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
d, err := CreateDocument(info)
|
||||
assert.Len(t, err, 21)
|
||||
assert.Len(t, err, 23)
|
||||
|
||||
assert.Equal(t, "3.0.0", d.Version.Value)
|
||||
assert.Equal(t, "Stripe API", d.Info.Value.Title.Value)
|
||||
|
||||
@@ -243,6 +243,16 @@ func NewSpecIndex(rootNode *yaml.Node) *SpecIndex {
|
||||
|
||||
// pull out references
|
||||
index.ExtractComponentsFromRefs(results)
|
||||
|
||||
// map poly refs
|
||||
poly := make([]*Reference, len(index.polymorphicRefs))
|
||||
z := 0
|
||||
for i := range index.polymorphicRefs {
|
||||
poly[z] = index.polymorphicRefs[i]
|
||||
z++
|
||||
}
|
||||
index.ExtractComponentsFromRefs(poly)
|
||||
|
||||
index.ExtractExternalDocuments(index.root)
|
||||
index.GetPathCount()
|
||||
|
||||
@@ -593,14 +603,15 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
||||
|
||||
segs := strings.Split(value, "/")
|
||||
name := segs[len(segs)-1]
|
||||
// name := strings.ReplaceAll(segs[len(segs)-1], "~1", "/")
|
||||
//name := strings.ReplaceAll(segs[len(segs)-1], "~1", "/")
|
||||
_, p := utils.ConvertComponentIdIntoFriendlyPathSearch(value)
|
||||
ref := &Reference{
|
||||
Definition: value,
|
||||
Name: name,
|
||||
Node: node,
|
||||
Path: fmt.Sprintf("$.%s", strings.Join(seenPath, ".")),
|
||||
Path: p,
|
||||
}
|
||||
|
||||
//utils.ConvertComponentIdIntoFriendlyPathSearch(ref.Definition)
|
||||
// add to raw sequenced refs
|
||||
index.rawSequencedRefs = append(index.rawSequencedRefs, ref)
|
||||
|
||||
@@ -623,7 +634,7 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
||||
Definition: ref.Definition,
|
||||
Name: ref.Name,
|
||||
Node: &copiedNode,
|
||||
Path: ref.Path,
|
||||
Path: p,
|
||||
}
|
||||
// protect this data using a copy, prevent the resolver from destroying things.
|
||||
index.refsWithSiblings[value] = copied
|
||||
@@ -1527,12 +1538,14 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc
|
||||
|
||||
located := index.FindComponent(ref.Definition, ref.Node)
|
||||
if located != nil {
|
||||
if index.allMappedRefs[ref.Definition] == nil {
|
||||
found = append(found, located)
|
||||
index.allMappedRefs[ref.Definition] = located
|
||||
index.allMappedRefsSequenced = append(index.allMappedRefsSequenced, &ReferenceMapped{
|
||||
Reference: located,
|
||||
Definition: ref.Definition,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
||||
_, path := utils.ConvertComponentIdIntoFriendlyPathSearch(ref.Definition)
|
||||
@@ -1816,7 +1829,6 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
|
||||
func (index *SpecIndex) FindComponentInRoot(componentId string) *Reference {
|
||||
if index.root != nil {
|
||||
name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId)
|
||||
friendlySearch = strings.ReplaceAll(friendlySearch, "~1", "/")
|
||||
path, err := yamlpath.NewPath(friendlySearch)
|
||||
if path == nil || err != nil {
|
||||
return nil // no component found
|
||||
|
||||
@@ -21,8 +21,7 @@ func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
|
||||
index := NewSpecIndex(&rootNode)
|
||||
|
||||
assert.Len(t, index.allRefs, 385)
|
||||
assert.Len(t, index.allMappedRefs, 385)
|
||||
|
||||
assert.Equal(t, 537, len(index.allMappedRefs))
|
||||
combined := index.GetAllCombinedReferences()
|
||||
assert.Equal(t, 537, len(combined))
|
||||
|
||||
@@ -68,7 +67,7 @@ func TestSpecIndex_Asana(t *testing.T) {
|
||||
index := NewSpecIndex(&rootNode)
|
||||
|
||||
assert.Len(t, index.allRefs, 152)
|
||||
assert.Len(t, index.allMappedRefs, 152)
|
||||
assert.Len(t, index.allMappedRefs, 171)
|
||||
combined := index.GetAllCombinedReferences()
|
||||
assert.Equal(t, 171, len(combined))
|
||||
assert.Equal(t, 118, index.pathCount)
|
||||
@@ -90,7 +89,7 @@ func TestSpecIndex_k8s(t *testing.T) {
|
||||
index := NewSpecIndex(&rootNode)
|
||||
|
||||
assert.Len(t, index.allRefs, 558)
|
||||
assert.Len(t, index.allMappedRefs, 558)
|
||||
assert.Equal(t, 563, len(index.allMappedRefs))
|
||||
combined := index.GetAllCombinedReferences()
|
||||
assert.Equal(t, 563, len(combined))
|
||||
assert.Equal(t, 436, index.pathCount)
|
||||
|
||||
@@ -239,6 +239,7 @@ func (resolver *Resolver) extractRelatives(node *yaml.Node,
|
||||
}
|
||||
|
||||
value := node.Content[i+1].Value
|
||||
|
||||
ref := resolver.specIndex.GetMappedReferences()[value]
|
||||
|
||||
if ref == nil {
|
||||
|
||||
@@ -86,10 +86,10 @@ func TestResolver_ResolveComponents_Stripe(t *testing.T) {
|
||||
assert.NotNil(t, resolver)
|
||||
|
||||
circ := resolver.Resolve()
|
||||
assert.Len(t, circ, 21)
|
||||
assert.Len(t, circ, 23)
|
||||
|
||||
assert.Len(t, resolver.GetNonPolymorphicCircularErrors(), 2)
|
||||
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 19)
|
||||
assert.Len(t, resolver.GetNonPolymorphicCircularErrors(), 3)
|
||||
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 20)
|
||||
|
||||
}
|
||||
|
||||
@@ -202,6 +202,6 @@ func ExampleNewResolver() {
|
||||
//
|
||||
fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not",
|
||||
len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors()))
|
||||
// Output: There are 21 circular reference errors, 19 of them are polymorphic errors, 2 are not
|
||||
// Output: There are 23 circular reference errors, 20 of them are polymorphic errors, 3 are not
|
||||
|
||||
}
|
||||
@@ -480,44 +480,54 @@ func IsHttpVerb(verb string) bool {
|
||||
|
||||
func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) {
|
||||
segs := strings.Split(id, "/")
|
||||
name := strings.ReplaceAll(segs[len(segs)-1], "~1", "/")
|
||||
name, _ := url.QueryUnescape(strings.ReplaceAll(segs[len(segs)-1], "~1", "/"))
|
||||
var cleaned []string
|
||||
|
||||
// check for strange spaces, chars and if found, wrap them up, clean them and create a new cleaned path.
|
||||
for i := range segs {
|
||||
reg, _ := regexp.MatchString("[%=;~]", segs[i])
|
||||
reg, _ := regexp.MatchString("[%=;~.]", segs[i])
|
||||
if reg {
|
||||
segs[i], _ = url.QueryUnescape(strings.ReplaceAll(segs[i], "~1", "/"))
|
||||
segs[i] = fmt.Sprintf("['%s']", segs[i])
|
||||
h := i
|
||||
if h-1 == len(cleaned) {
|
||||
h--
|
||||
if len(cleaned) > 0 {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i])
|
||||
continue
|
||||
}
|
||||
cleaned[h-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i])
|
||||
cleaned = append(cleaned, fmt.Sprintf("%s%s", segs[i], segs[i]))
|
||||
continue
|
||||
} else {
|
||||
intVal, err := strconv.ParseInt(segs[i], 10, 32)
|
||||
if err == nil && intVal <= 99 {
|
||||
segs[i] = fmt.Sprintf("[%d]", intVal)
|
||||
if i < len(cleaned) {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i])
|
||||
} else {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i])
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil && intVal > 99 {
|
||||
segs[i] = fmt.Sprintf("['%d']", intVal)
|
||||
if i < len(cleaned) {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i])
|
||||
} else {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i])
|
||||
}
|
||||
continue
|
||||
}
|
||||
cleaned = append(cleaned, segs[i])
|
||||
}
|
||||
}
|
||||
|
||||
nameIntVal, err := strconv.ParseInt(name, 10, 32)
|
||||
_, err := strconv.ParseInt(name, 10, 32)
|
||||
var replaced string
|
||||
if err != nil {
|
||||
if len(cleaned) > 2 {
|
||||
replaced = strings.ReplaceAll(fmt.Sprintf("%s['%s']",
|
||||
strings.Join(cleaned[:len(cleaned)-1], "."), name), "#", "$")
|
||||
replaced = strings.ReplaceAll(fmt.Sprintf("%s",
|
||||
strings.Join(cleaned, ".")), "#", "$")
|
||||
} else {
|
||||
replaced = strings.ReplaceAll(fmt.Sprintf("%s",
|
||||
strings.Join(cleaned, ".")), "#", "$")
|
||||
}
|
||||
} else {
|
||||
if nameIntVal <= 99 { // codes start at 100
|
||||
replaced = strings.ReplaceAll(fmt.Sprintf("%s[%d]",
|
||||
strings.Join(cleaned[:len(cleaned)-1], "."), nameIntVal), "#", "$")
|
||||
} else {
|
||||
replaced = strings.ReplaceAll(fmt.Sprintf("%s.%d",
|
||||
strings.Join(cleaned[:len(cleaned)-1], "."), nameIntVal), "#", "$")
|
||||
}
|
||||
}
|
||||
|
||||
if len(replaced) > 0 {
|
||||
if replaced[0] != '$' {
|
||||
|
||||
@@ -603,27 +603,47 @@ func TestIsHttpVerb(t *testing.T) {
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/chicken/chips/pizza/cake")
|
||||
assert.Equal(t, "$.chicken.chips.pizza['cake']", path)
|
||||
assert.Equal(t, "$.chicken.chips.pizza.cake", path)
|
||||
assert.Equal(t, "cake", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_WithRootSymbol(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("/chicken/chips/pizza/cake")
|
||||
assert.Equal(t, "$.chicken.chips.pizza['cake']", path)
|
||||
assert.Equal(t, "cake", segment)
|
||||
|
||||
segment, path = ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema")
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses.404.content['application/xml; charset=utf-8']['schema']", path)
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_SuperCrazy(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema")
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses['404'].content['application/xml; charset=utf-8'].schema", path)
|
||||
assert.Equal(t, "schema", segment)
|
||||
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Crazy(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/example/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas.gpg-key.properties.subkeys.example[0].expires_at", path)
|
||||
assert.Equal(t, "expires_at", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Simple(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#//~1fresh~1pizza/get")
|
||||
assert.Equal(t, "$.['/fresh/pizza'].get", path)
|
||||
assert.Equal(t, "get", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Crazy_Github(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema")
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses.404.content['application/xml; charset=utf-8']['schema']", path)
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses['404'].content['application/xml; charset=utf-8'].schema", path)
|
||||
assert.Equal(t, "schema", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Crazy_DigitalOcean(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1v2~1customers~1my~1invoices~1%7Binvoice_uuid%7D/get/parameters/0")
|
||||
assert.Equal(t, "$.paths['/v2/customers/my/invoices/{invoice_uuid}'].get.parameters[0]", path)
|
||||
assert.Equal(t, "0", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Crazy_DigitalOcean_More(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1v2~1certificates/post/responses/201/content/application~1json/examples/Custom%20Certificate")
|
||||
assert.Equal(t, "$.paths['/v2/certificates'].post.responses['201'].content['application/json'].examples['Custom Certificate']", path)
|
||||
assert.Equal(t, "Custom Certificate", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_CrazyShort(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1crazy~1ass~1references")
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references']", path)
|
||||
@@ -638,7 +658,7 @@ func TestConvertComponentIdIntoFriendlyPathSearch_Array(t *testing.T) {
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_HTTPCode(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/paths/~1crazy~1ass~1references/get/responses/404")
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses.404", path)
|
||||
assert.Equal(t, "$.paths['/crazy/ass/references'].get.responses['404']", path)
|
||||
assert.Equal(t, "404", segment)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user