mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 04:20:11 +00:00
Addressed issue with anchors and merge nodes
Highlighted in https://github.com/daveshanley/vacuum/issues/508 The comment from @Jakousa annoyed me. Rude.
This commit is contained in:
106
utils/utils.go
106
utils/utils.go
@@ -221,18 +221,21 @@ func FindFirstKeyNode(key string, nodes []*yaml.Node, depth int) (keyNode *yaml.
|
||||
if depth > 40 {
|
||||
return nil, nil
|
||||
}
|
||||
if nodes != nil && len(nodes) > 0 && nodes[0].Tag == "!!merge" {
|
||||
nodes = NodeAlias(nodes[1]).Content
|
||||
}
|
||||
for i, v := range nodes {
|
||||
if key != "" && key == v.Value {
|
||||
if i+1 >= len(nodes) {
|
||||
return v, NodeAlias(nodes[i]) // this is the node we need.
|
||||
}
|
||||
return v, NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
return NodeAlias(v), NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
}
|
||||
if len(v.Content) > 0 {
|
||||
depth++
|
||||
x, y := FindFirstKeyNode(key, v.Content, depth)
|
||||
if x != nil && y != nil {
|
||||
return x, y
|
||||
return NodeAlias(x), NodeAlias(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,16 +261,19 @@ type KeyNodeSearch struct {
|
||||
// FindKeyNodeTop is a non-recursive search of top level nodes for a key, will not look at content.
|
||||
// Returns the key and value
|
||||
func FindKeyNodeTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode *yaml.Node) {
|
||||
for i, v := range nodes {
|
||||
if nodes != nil && len(nodes) > 0 && nodes[0].Tag == "!!merge" {
|
||||
nodes = NodeAlias(nodes[1]).Content
|
||||
}
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
v := nodes[i]
|
||||
if i%2 != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.EqualFold(key, v.Value) {
|
||||
if i+1 >= len(nodes) {
|
||||
return v, nodes[i]
|
||||
return NodeAlias(v), NodeAlias(nodes[i])
|
||||
}
|
||||
return v, nodes[i+1] // next node is what we need.
|
||||
return NodeAlias(v), NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
@@ -276,25 +282,27 @@ func FindKeyNodeTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNo
|
||||
// FindKeyNode is a non-recursive search of a *yaml.Node Content for a child node with a key.
|
||||
// Returns the key and value
|
||||
func FindKeyNode(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode *yaml.Node) {
|
||||
// numNodes := len(nodes)
|
||||
if nodes != nil && len(nodes) > 0 && nodes[0].Tag == "!!merge" {
|
||||
nodes = NodeAlias(nodes[1]).Content
|
||||
}
|
||||
for i, v := range nodes {
|
||||
if i%2 == 0 && key == v.Value {
|
||||
if len(nodes) <= i+1 {
|
||||
return v, nodes[i]
|
||||
return NodeAlias(v), NodeAlias(nodes[i])
|
||||
}
|
||||
return v, nodes[i+1] // next node is what we need.
|
||||
return NodeAlias(v), NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
}
|
||||
for x, j := range v.Content {
|
||||
if key == j.Value {
|
||||
if IsNodeMap(v) {
|
||||
if x+1 == len(v.Content) {
|
||||
return v, v.Content[x]
|
||||
return NodeAlias(v), NodeAlias(v.Content[x])
|
||||
}
|
||||
return v, v.Content[x+1] // next node is what we need.
|
||||
return NodeAlias(v), NodeAlias(v.Content[x+1]) // next node is what we need.
|
||||
|
||||
}
|
||||
if IsNodeArray(v) {
|
||||
return v, v.Content[x]
|
||||
return NodeAlias(v), NodeAlias(v.Content[x])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,25 +314,37 @@ func FindKeyNode(key string, nodes []*yaml.Node) (keyNode *yaml.Node, valueNode
|
||||
// generally different things are required from different node trees, so depending on what this function is looking at
|
||||
// it will return different things.
|
||||
func FindKeyNodeFull(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelNode *yaml.Node, valueNode *yaml.Node) {
|
||||
for i := range nodes {
|
||||
if nodes != nil && len(nodes) > 0 && nodes[0].Tag == "!!merge" {
|
||||
nodes = NodeAlias(nodes[1]).Content
|
||||
}
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
if i%2 == 0 && key == nodes[i].Value {
|
||||
if i+1 >= len(nodes) {
|
||||
return nodes[i], nodes[i], nodes[i]
|
||||
return NodeAlias(nodes[i]), NodeAlias(nodes[i]), NodeAlias(nodes[i])
|
||||
}
|
||||
return nodes[i], nodes[i], nodes[i+1] // next node is what we need.
|
||||
return NodeAlias(nodes[i]), NodeAlias(nodes[i]), NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
}
|
||||
}
|
||||
for _, v := range nodes {
|
||||
for x := range v.Content {
|
||||
for x := 0; x < len(v.Content); x++ {
|
||||
r := v.Content[x]
|
||||
if x%2 == 0 {
|
||||
if r.Tag == "!!merge" {
|
||||
if len(nodes) > x+1 {
|
||||
v = NodeAlias(nodes[x+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if key == v.Content[x].Value {
|
||||
if IsNodeMap(v) {
|
||||
if x+1 == len(v.Content) {
|
||||
return v, v.Content[x], NodeAlias(v.Content[x])
|
||||
}
|
||||
return v, v.Content[x], NodeAlias(v.Content[x+1])
|
||||
return NodeAlias(v), NodeAlias(v.Content[x]), NodeAlias(v.Content[x+1])
|
||||
}
|
||||
if IsNodeArray(v) {
|
||||
return v, v.Content[x], NodeAlias(v.Content[x])
|
||||
return NodeAlias(v), NodeAlias(v.Content[x]), NodeAlias(v.Content[x])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,12 +355,26 @@ func FindKeyNodeFull(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelN
|
||||
// FindKeyNodeFullTop is an overloaded version of FindKeyNodeFull. This version only looks at the top
|
||||
// level of the node and not the children.
|
||||
func FindKeyNodeFullTop(key string, nodes []*yaml.Node) (keyNode *yaml.Node, labelNode *yaml.Node, valueNode *yaml.Node) {
|
||||
for i := range nodes {
|
||||
if nodes != nil && len(nodes) >= 0 && nodes[0].Tag == "!!merge" {
|
||||
nodes = NodeAlias(nodes[1]).Content
|
||||
}
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
v := nodes[i]
|
||||
if i%2 == 0 {
|
||||
if v.Tag == "!!merge" {
|
||||
if len(nodes) > i+1 {
|
||||
v = NodeAlias(nodes[i+1])
|
||||
if len(v.Content) > 0 {
|
||||
nodes = append(nodes, v.Content...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if i%2 != 0 {
|
||||
continue
|
||||
}
|
||||
if i%2 == 0 && key == nodes[i].Value {
|
||||
return nodes[i], nodes[i], NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
return NodeAlias(nodes[i]), NodeAlias(nodes[i]), NodeAlias(nodes[i+1]) // next node is what we need.
|
||||
}
|
||||
}
|
||||
return nil, nil, nil
|
||||
@@ -417,11 +451,43 @@ func IsNodeAlias(node *yaml.Node) (*yaml.Node, bool) {
|
||||
return node, false
|
||||
}
|
||||
|
||||
func NodeMerge(nodes []*yaml.Node) *yaml.Node {
|
||||
for i, v := range nodes {
|
||||
if v.Tag == "!!merge" {
|
||||
if i+1 < len(nodes) {
|
||||
return NodeAlias(nodes[i+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(nodes) > 0 {
|
||||
return NodeAlias(nodes[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeAlias checks if the node is an alias, and lifts out the anchor
|
||||
func NodeAlias(node *yaml.Node) *yaml.Node {
|
||||
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
content := node.Content
|
||||
if node.Kind == yaml.AliasNode {
|
||||
content = node.Alias.Content
|
||||
}
|
||||
|
||||
for i, n := range content {
|
||||
if i%2 == 0 {
|
||||
if n.Tag == "!!merge" {
|
||||
g := NodeMerge(content[i+1:])
|
||||
if g != nil {
|
||||
node = g
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if node.Kind == yaml.AliasNode {
|
||||
node = node.Alias
|
||||
return node
|
||||
|
||||
@@ -1002,19 +1002,143 @@ func TestDetermineJSONWhitespaceLength_None(t *testing.T) {
|
||||
assert.Equal(t, 0, DetermineWhitespaceLength(string(someBytes)))
|
||||
}
|
||||
|
||||
func TestTimeoutFind(t *testing.T) {
|
||||
a := &yaml.Node{
|
||||
Value: "chicken",
|
||||
}
|
||||
b := &yaml.Node{
|
||||
Value: "nuggets",
|
||||
}
|
||||
func TestFindFirstKeyNode_DoubleMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
|
||||
// loopy loop.
|
||||
a.Content = append(a.Content, b)
|
||||
b.Content = append(b.Content, a)
|
||||
t-k: &anchorB
|
||||
important-field: a nice string
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
_ = yaml.Unmarshal(yml, &rootNode)
|
||||
|
||||
k, v := FindFirstKeyNode("important-field", rootNode.Content[0].Content[7].Content, 0)
|
||||
assert.NotNil(t, k)
|
||||
assert.NotNil(t, v)
|
||||
assert.Equal(t, "a nice string", v.Value)
|
||||
|
||||
nodes, err := FindNodesWithoutDeserializing(a, "$..nuggets")
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, nodes)
|
||||
}
|
||||
|
||||
func TestFindKeyNodeTop_DoubleMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
|
||||
t-k: &anchorB
|
||||
important-field: a nice string
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
_ = yaml.Unmarshal(yml, &rootNode)
|
||||
|
||||
k, v := FindKeyNodeTop("important-field", rootNode.Content[0].Content[7].Content)
|
||||
assert.NotNil(t, k)
|
||||
assert.NotNil(t, v)
|
||||
assert.Equal(t, "a nice string", v.Value)
|
||||
|
||||
}
|
||||
|
||||
func TestFindKeyNode_DoubleMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
|
||||
t-k: &anchorB
|
||||
important-field: a nice string
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
_ = yaml.Unmarshal(yml, &rootNode)
|
||||
|
||||
k, v := FindKeyNode("important-field", rootNode.Content[0].Content[7].Content)
|
||||
assert.NotNil(t, k)
|
||||
assert.NotNil(t, v)
|
||||
assert.Equal(t, "a nice string", v.Value)
|
||||
|
||||
}
|
||||
|
||||
func TestFindKeyNodeFull_DoubleMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
any-thing: &anchorH
|
||||
important-field: a nice string
|
||||
t-k: &anchorB
|
||||
panda:
|
||||
<<: *anchorH
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
ee := yaml.Unmarshal(yml, &rootNode)
|
||||
assert.NoError(t, ee)
|
||||
|
||||
k, l, v := FindKeyNodeFull("important-field", rootNode.Content[0].Content[9].Content)
|
||||
assert.NotNil(t, l)
|
||||
assert.NotNil(t, k)
|
||||
assert.NotNil(t, v)
|
||||
assert.Equal(t, "a nice string", v.Value)
|
||||
|
||||
}
|
||||
|
||||
func TestFindKeyNodeFullTop_DoubleMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
any-thing: &anchorH
|
||||
important-field: a nice string
|
||||
t-k: &anchorB
|
||||
<<: *anchorH
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
ee := yaml.Unmarshal(yml, &rootNode)
|
||||
assert.NoError(t, ee)
|
||||
|
||||
k, l, v := FindKeyNodeFullTop("important-field", rootNode.Content[0].Content[9].Content)
|
||||
assert.NotNil(t, l)
|
||||
assert.NotNil(t, k)
|
||||
assert.NotNil(t, v)
|
||||
assert.Equal(t, "a nice string", v.Value)
|
||||
|
||||
}
|
||||
|
||||
func TestNodeMerge(t *testing.T) {
|
||||
yml := []byte(`openapi: 3.0.3
|
||||
any-thing: &anchorH
|
||||
important-field: a nice string
|
||||
t-k: &anchorB
|
||||
<<: *anchorH
|
||||
x-a: &anchorA
|
||||
<<: *anchorB
|
||||
x-b:
|
||||
<<: *anchorA
|
||||
|
||||
`)
|
||||
|
||||
var rootNode yaml.Node
|
||||
ee := yaml.Unmarshal(yml, &rootNode)
|
||||
assert.NoError(t, ee)
|
||||
|
||||
n := NodeMerge(rootNode.Content[0].Content[9].Content)
|
||||
assert.NotNil(t, n)
|
||||
assert.Equal(t, "a nice string", n.Content[1].Value)
|
||||
}
|
||||
|
||||
func TestNodeMerge_NoNodes(t *testing.T) {
|
||||
n := NodeMerge(nil)
|
||||
assert.Nil(t, n)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user