mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
cleaned up path handling a little
Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
@@ -450,6 +450,7 @@ func (n *NodeBuilder) AddYAMLNode(parent *yaml.Node, entry *nodes.NodeEntry) *ya
|
|||||||
} else {
|
} else {
|
||||||
// try an inline render if we can, otherwise there is no option but to default to the
|
// try an inline render if we can, otherwise there is no option but to default to the
|
||||||
// full render.
|
// full render.
|
||||||
|
|
||||||
if _, ko := r.(RenderableInline); ko {
|
if _, ko := r.(RenderableInline); ko {
|
||||||
rawRender, _ = r.(RenderableInline).MarshalYAMLInline()
|
rawRender, _ = r.(RenderableInline).MarshalYAMLInline()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -840,7 +840,7 @@ func TestCreateDocument_YamlAnchor(t *testing.T) {
|
|||||||
assert.NotNil(t, postParams)
|
assert.NotNil(t, postParams)
|
||||||
assert.Equal(t, 1, len(getParams))
|
assert.Equal(t, 1, len(getParams))
|
||||||
assert.Equal(t, 1, len(postParams))
|
assert.Equal(t, 1, len(postParams))
|
||||||
assert.Equal(t, getParams, postParams)
|
assert.Equal(t, getParams[0].ValueNode, postParams[0].ValueNode)
|
||||||
|
|
||||||
// check post request body
|
// check post request body
|
||||||
responses := examplePath.GetValue().Get.GetValue().GetResponses().Value.(*Responses)
|
responses := examplePath.GetValue().Get.GetValue().GetResponses().Value.(*Responses)
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
package v3
|
package v3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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/orderedmap"
|
"github.com/pb33f/libopenapi/orderedmap"
|
||||||
"github.com/pb33f/libopenapi/utils"
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Link represents a low-level OpenAPI 3+ Link object.
|
// Link represents a low-level OpenAPI 3+ Link object.
|
||||||
@@ -28,71 +28,71 @@ import (
|
|||||||
// in an operation and using them as parameters while invoking the linked operation.
|
// in an operation and using them as parameters while invoking the linked operation.
|
||||||
// - https://spec.openapis.org/oas/v3.1.0#link-object
|
// - https://spec.openapis.org/oas/v3.1.0#link-object
|
||||||
type Link struct {
|
type Link struct {
|
||||||
OperationRef low.NodeReference[string]
|
OperationRef low.NodeReference[string]
|
||||||
OperationId low.NodeReference[string]
|
OperationId low.NodeReference[string]
|
||||||
Parameters low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
Parameters low.NodeReference[*orderedmap.Map[low.KeyReference[string], low.ValueReference[string]]]
|
||||||
RequestBody low.NodeReference[string]
|
RequestBody low.NodeReference[string]
|
||||||
Description low.NodeReference[string]
|
Description low.NodeReference[string]
|
||||||
Server low.NodeReference[*Server]
|
Server low.NodeReference[*Server]
|
||||||
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
|
||||||
KeyNode *yaml.Node
|
KeyNode *yaml.Node
|
||||||
RootNode *yaml.Node
|
RootNode *yaml.Node
|
||||||
*low.Reference
|
*low.Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface.
|
// GetExtensions returns all Link extensions and satisfies the low.HasExtensions interface.
|
||||||
func (l *Link) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
func (l *Link) GetExtensions() *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]] {
|
||||||
return l.Extensions
|
return l.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindParameter will attempt to locate a parameter string value, using a parameter name input.
|
// FindParameter will attempt to locate a parameter string value, using a parameter name input.
|
||||||
func (l *Link) FindParameter(pName string) *low.ValueReference[string] {
|
func (l *Link) FindParameter(pName string) *low.ValueReference[string] {
|
||||||
return low.FindItemInOrderedMap[string](pName, l.Parameters.Value)
|
return low.FindItemInOrderedMap[string](pName, l.Parameters.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindExtension will attempt to locate an extension with a specific key
|
// FindExtension will attempt to locate an extension with a specific key
|
||||||
func (l *Link) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
func (l *Link) FindExtension(ext string) *low.ValueReference[*yaml.Node] {
|
||||||
return low.FindItemInOrderedMap(ext, l.Extensions)
|
return low.FindItemInOrderedMap(ext, l.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build will extract extensions and servers from the node.
|
// Build will extract extensions and servers from the node.
|
||||||
func (l *Link) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
|
func (l *Link) Build(ctx context.Context, keyNode, root *yaml.Node, idx *index.SpecIndex) error {
|
||||||
l.KeyNode = keyNode
|
l.KeyNode = keyNode
|
||||||
root = utils.NodeAlias(root)
|
root = utils.NodeAlias(root)
|
||||||
|
|
||||||
utils.CheckForMergeNodes(root)
|
utils.CheckForMergeNodes(root)
|
||||||
l.Reference = new(low.Reference)
|
l.Reference = new(low.Reference)
|
||||||
l.Extensions = low.ExtractExtensions(root)
|
l.Extensions = low.ExtractExtensions(root)
|
||||||
// extract server.
|
// extract server.
|
||||||
ser, sErr := low.ExtractObject[*Server](ctx, ServerLabel, root, idx)
|
ser, sErr := low.ExtractObject[*Server](ctx, ServerLabel, root, idx)
|
||||||
if sErr != nil {
|
if sErr != nil {
|
||||||
return sErr
|
return sErr
|
||||||
}
|
}
|
||||||
l.Server = ser
|
l.Server = ser
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash will return a consistent SHA256 Hash of the Link object
|
// Hash will return a consistent SHA256 Hash of the Link object
|
||||||
func (l *Link) Hash() [32]byte {
|
func (l *Link) Hash() [32]byte {
|
||||||
var f []string
|
var f []string
|
||||||
if l.Description.Value != "" {
|
if l.Description.Value != "" {
|
||||||
f = append(f, l.Description.Value)
|
f = append(f, l.Description.Value)
|
||||||
}
|
}
|
||||||
if l.OperationRef.Value != "" {
|
if l.OperationRef.Value != "" {
|
||||||
f = append(f, l.OperationRef.Value)
|
f = append(f, l.OperationRef.Value)
|
||||||
}
|
}
|
||||||
if l.OperationId.Value != "" {
|
if l.OperationId.Value != "" {
|
||||||
f = append(f, l.OperationId.Value)
|
f = append(f, l.OperationId.Value)
|
||||||
}
|
}
|
||||||
if l.RequestBody.Value != "" {
|
if l.RequestBody.Value != "" {
|
||||||
f = append(f, l.RequestBody.Value)
|
f = append(f, l.RequestBody.Value)
|
||||||
}
|
}
|
||||||
if l.Server.Value != nil {
|
if l.Server.Value != nil {
|
||||||
f = append(f, low.GenerateHashString(l.Server.Value))
|
f = append(f, low.GenerateHashString(l.Server.Value))
|
||||||
}
|
}
|
||||||
for pair := orderedmap.First(orderedmap.SortAlpha(l.Parameters.Value)); pair != nil; pair = pair.Next() {
|
for pair := orderedmap.First(orderedmap.SortAlpha(l.Parameters.Value)); pair != nil; pair = pair.Next() {
|
||||||
f = append(f, pair.Value().Value)
|
f = append(f, pair.Value().Value)
|
||||||
}
|
}
|
||||||
f = append(f, low.HashExtensions(l.Extensions)...)
|
f = append(f, low.HashExtensions(l.Extensions)...)
|
||||||
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
return sha256.Sum256([]byte(strings.Join(f, "|")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -529,8 +529,8 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
seenPath = append(seenPath, strings.ReplaceAll(n.Value, "/", "~1"))
|
//seenPath = append(seenPath, strings.ReplaceAll(n.Value, "/", "~1"))
|
||||||
//seenPath = append(seenPath, n.Value)
|
seenPath = append(seenPath, n.Value)
|
||||||
prev = n.Value
|
prev = n.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -971,7 +971,7 @@ func (index *SpecIndex) GetOperationCount() int {
|
|||||||
Definition: m.Value,
|
Definition: m.Value,
|
||||||
Name: m.Value,
|
Name: m.Value,
|
||||||
Node: method.Content[y+1],
|
Node: method.Content[y+1],
|
||||||
Path: fmt.Sprintf("$.paths.%s.%s", p.Value, m.Value),
|
Path: fmt.Sprintf("$.paths['%s'].%s", p.Value, m.Value),
|
||||||
ParentNode: m,
|
ParentNode: m,
|
||||||
}
|
}
|
||||||
if locatedPathRefs[p.Value] == nil {
|
if locatedPathRefs[p.Value] == nil {
|
||||||
@@ -1039,7 +1039,7 @@ func (index *SpecIndex) GetOperationsParameterCount() int {
|
|||||||
Name: serverRef.Value,
|
Name: serverRef.Value,
|
||||||
Node: serverRef,
|
Node: serverRef,
|
||||||
ParentNode: prop,
|
ParentNode: prop,
|
||||||
Path: fmt.Sprintf("$.paths.%s.servers[%d]", pathItemNode.Value, i),
|
Path: fmt.Sprintf("$.paths['%s'].servers[%d]", pathItemNode.Value, i),
|
||||||
}
|
}
|
||||||
serverRefs = append(serverRefs, ref)
|
serverRefs = append(serverRefs, ref)
|
||||||
}
|
}
|
||||||
@@ -1123,7 +1123,7 @@ func (index *SpecIndex) GetOperationsParameterCount() int {
|
|||||||
Name: "servers",
|
Name: "servers",
|
||||||
Node: serverRef,
|
Node: serverRef,
|
||||||
ParentNode: httpMethodProp,
|
ParentNode: httpMethodProp,
|
||||||
Path: fmt.Sprintf("$.paths.%s.%s.servers[%d]", pathItemNode.Value, prop.Value, i),
|
Path: fmt.Sprintf("$.paths['%s'].%s.servers[%d]", pathItemNode.Value, prop.Value, i),
|
||||||
}
|
}
|
||||||
serverRefs = append(serverRefs, ref)
|
serverRefs = append(serverRefs, ref)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,7 +1214,7 @@ components:
|
|||||||
assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
||||||
}
|
}
|
||||||
if assert.Contains(t, params["/"]["get"], "test") {
|
if assert.Contains(t, params["/"]["get"], "test") {
|
||||||
assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"][0].Path)
|
assert.Equal(t, "$.paths['/'].get.parameters[2]", params["/"]["get"]["test"][0].Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1255,7 +1255,7 @@ paths:
|
|||||||
opPath = ""
|
opPath = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, fmt.Sprintf("$.paths.%s%s.servers[%d]", path, opPath, i), server.Path)
|
assert.Equal(t, fmt.Sprintf("$.paths['%s']%s.servers[%d]", path, opPath, i), server.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1278,7 +1278,7 @@ func TestSpecIndex_schemaComponentsHaveParentsAndPaths(t *testing.T) {
|
|||||||
|
|
||||||
for _, schema := range schemas {
|
for _, schema := range schemas {
|
||||||
assert.NotNil(t, schema.ParentNode)
|
assert.NotNil(t, schema.ParentNode)
|
||||||
assert.Equal(t, fmt.Sprintf("$.components.schemas.%s", schema.Name), schema.Path)
|
assert.Equal(t, fmt.Sprintf("$.components.schemas['%s']", schema.Name), schema.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,12 +1497,12 @@ paths:
|
|||||||
|
|
||||||
paths := idx.GetAllPaths()
|
paths := idx.GetAllPaths()
|
||||||
|
|
||||||
assert.Equal(t, "$.paths./test.get", paths["/test"]["get"].Path)
|
assert.Equal(t, "$.paths['/test'].get", paths["/test"]["get"].Path)
|
||||||
assert.Equal(t, 9, paths["/test"]["get"].ParentNode.Line)
|
assert.Equal(t, 9, paths["/test"]["get"].ParentNode.Line)
|
||||||
assert.Equal(t, "$.paths./test.post", paths["/test"]["post"].Path)
|
assert.Equal(t, "$.paths['/test'].post", paths["/test"]["post"].Path)
|
||||||
assert.Equal(t, 13, paths["/test"]["post"].ParentNode.Line)
|
assert.Equal(t, 13, paths["/test"]["post"].ParentNode.Line)
|
||||||
assert.Equal(t, "$.paths./test2.delete", paths["/test2"]["delete"].Path)
|
assert.Equal(t, "$.paths['/test2'].delete", paths["/test2"]["delete"].Path)
|
||||||
assert.Equal(t, 18, paths["/test2"]["delete"].ParentNode.Line)
|
assert.Equal(t, 18, paths["/test2"]["delete"].ParentNode.Line)
|
||||||
assert.Equal(t, "$.paths./test2.put", paths["/test2"]["put"].Path)
|
assert.Equal(t, "$.paths['/test2'].put", paths["/test2"]["put"].Path)
|
||||||
assert.Equal(t, 22, paths["/test2"]["put"].ParentNode.Line)
|
assert.Equal(t, 22, paths["/test2"]["put"].ParentNode.Line)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func (index *SpecIndex) extractDefinitionsAndSchemas(schemasNode *yaml.Node, pat
|
|||||||
Definition: def,
|
Definition: def,
|
||||||
Name: name,
|
Name: name,
|
||||||
Node: schema,
|
Node: schema,
|
||||||
Path: fmt.Sprintf("$.components.schemas.%s", name),
|
Path: fmt.Sprintf("$.components.schemas['%s']", name),
|
||||||
ParentNode: schemasNode,
|
ParentNode: schemasNode,
|
||||||
RequiredRefProperties: extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}, fullDef, index),
|
RequiredRefProperties: extractDefinitionRequiredRefProperties(schemasNode, map[string][]string{}, fullDef, index),
|
||||||
}
|
}
|
||||||
@@ -384,9 +384,9 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
|
|
||||||
// if this is a duplicate, add an error and ignore it
|
// if this is a duplicate, add an error and ignore it
|
||||||
if index.paramOpRefs[pathItemNode.Value][method][paramRefName] != nil {
|
if index.paramOpRefs[pathItemNode.Value][method][paramRefName] != nil {
|
||||||
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
|
path := fmt.Sprintf("$.paths['%s'].%s.parameters[%d]", pathItemNode.Value, method, i)
|
||||||
if method == "top" {
|
if method == "top" {
|
||||||
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
|
path = fmt.Sprintf("$.paths['%s'].parameters[%d]", pathItemNode.Value, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
||||||
@@ -408,9 +408,9 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
// param is inline.
|
// param is inline.
|
||||||
_, vn := utils.FindKeyNode("name", param.Content)
|
_, vn := utils.FindKeyNode("name", param.Content)
|
||||||
|
|
||||||
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
|
path := fmt.Sprintf("$.paths['%s'].%s.parameters[%d]", pathItemNode.Value, method, i)
|
||||||
if method == "top" {
|
if method == "top" {
|
||||||
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
|
path = fmt.Sprintf("$.paths['%s'].parameters[%d]", pathItemNode.Value, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if vn == nil {
|
if vn == nil {
|
||||||
@@ -452,9 +452,9 @@ func (index *SpecIndex) scanOperationParams(params []*yaml.Node, pathItemNode *y
|
|||||||
|
|
||||||
if currentIn != nil && checkIn != nil && currentIn.Value == checkIn.Value {
|
if currentIn != nil && checkIn != nil && currentIn.Value == checkIn.Value {
|
||||||
|
|
||||||
path := fmt.Sprintf("$.paths.%s.%s.parameters[%d]", pathItemNode.Value, method, i)
|
path := fmt.Sprintf("$.paths['%s'].%s.parameters[%d]", pathItemNode.Value, method, i)
|
||||||
if method == "top" {
|
if method == "top" {
|
||||||
path = fmt.Sprintf("$.paths.%s.parameters[%d]", pathItemNode.Value, i)
|
path = fmt.Sprintf("$.paths['%s'].parameters[%d]", pathItemNode.Value, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
index.operationParamErrors = append(index.operationParamErrors, &IndexingError{
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Case int8
|
type Case int8
|
||||||
@@ -106,11 +107,34 @@ func FindNodesWithoutDeserializing(node *yaml.Node, jsonPath string) ([]*yaml.No
|
|||||||
jsonPath = FixContext(jsonPath)
|
jsonPath = FixContext(jsonPath)
|
||||||
|
|
||||||
path, err := yamlpath.NewPath(jsonPath)
|
path, err := yamlpath.NewPath(jsonPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
results, _ := path.Find(node)
|
|
||||||
return results, nil
|
// this can spin out, to lets gatekeep it.
|
||||||
|
done := make(chan bool)
|
||||||
|
eChan := make(chan error)
|
||||||
|
var results []*yaml.Node
|
||||||
|
timeout, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
go func(d chan bool, e chan error) {
|
||||||
|
var er error
|
||||||
|
results, er = path.Find(node)
|
||||||
|
if er != nil {
|
||||||
|
e <- er
|
||||||
|
}
|
||||||
|
done <- true
|
||||||
|
}(done, eChan)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return results, nil
|
||||||
|
case er := <-eChan:
|
||||||
|
return nil, er
|
||||||
|
case <-timeout.Done():
|
||||||
|
return nil, fmt.Errorf("node lookup timeout exceeded")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertInterfaceIntoStringMap will convert an unknown input into a string map.
|
// ConvertInterfaceIntoStringMap will convert an unknown input into a string map.
|
||||||
|
|||||||
Reference in New Issue
Block a user