mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
140 lines
3.8 KiB
Go
140 lines
3.8 KiB
Go
package yqlib
|
|
|
|
import (
|
|
"container/list"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
yaml "gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TraverseArrayOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
|
// lhs is an expression that will yield a bunch of arrays
|
|
// rhs is a collect expression that will yield indexes to retreive of the arrays
|
|
|
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var indicesToTraverse = rhs.Front().Value.(*CandidateNode).Node.Content
|
|
|
|
var matchingNodeMap = list.New()
|
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
|
candidate := el.Value.(*CandidateNode)
|
|
node := UnwrapDoc(candidate.Node)
|
|
if node.Tag == "!!null" {
|
|
log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array")
|
|
// auto vivification, make it into an empty array
|
|
node.Tag = ""
|
|
node.Kind = yaml.SequenceNode
|
|
} else if node.Kind == yaml.AliasNode {
|
|
candidate.Node = node.Alias
|
|
node = node.Alias
|
|
}
|
|
|
|
if node.Kind == yaml.SequenceNode {
|
|
newNodes, err := traverseArrayWithIndices(candidate, indicesToTraverse)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
matchingNodeMap.PushBackList(newNodes)
|
|
} else if node.Kind == yaml.MappingNode && len(indicesToTraverse) == 0 {
|
|
// splat the map
|
|
newNodes, err := traverseMapWithIndices(candidate, indicesToTraverse)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
matchingNodeMap.PushBackList(newNodes)
|
|
} else {
|
|
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", candidate, node.Tag)
|
|
}
|
|
}
|
|
|
|
return matchingNodeMap, nil
|
|
}
|
|
|
|
func traverseMapWithIndices(candidate *CandidateNode, indices []*yaml.Node) (*list.List, error) {
|
|
//REWRITE TO USE TRAVERSE MAP
|
|
|
|
node := UnwrapDoc(candidate.Node)
|
|
var contents = node.Content
|
|
var matchingNodeMap = list.New()
|
|
if len(indices) == 0 {
|
|
for index := 0; index < len(contents); index = index + 2 {
|
|
key := contents[index]
|
|
value := contents[index+1]
|
|
matchingNodeMap.PushBack(&CandidateNode{
|
|
Node: value,
|
|
Path: candidate.CreateChildPath(key.Value),
|
|
Document: candidate.Document,
|
|
})
|
|
}
|
|
return matchingNodeMap, nil
|
|
}
|
|
|
|
for index := 0; index < len(contents); index = index + 2 {
|
|
key := contents[index]
|
|
value := contents[index+1]
|
|
for _, indexNode := range indices {
|
|
if key.Value == indexNode.Value {
|
|
matchingNodeMap.PushBack(&CandidateNode{
|
|
Node: value,
|
|
Path: candidate.CreateChildPath(key.Value),
|
|
Document: candidate.Document,
|
|
})
|
|
}
|
|
}
|
|
|
|
}
|
|
return matchingNodeMap, nil
|
|
}
|
|
|
|
func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node) (*list.List, error) {
|
|
log.Debug("traverseArrayWithIndices")
|
|
var newMatches = list.New()
|
|
node := UnwrapDoc(candidate.Node)
|
|
|
|
if len(indices) == 0 {
|
|
var index int64
|
|
for index = 0; index < int64(len(node.Content)); index = index + 1 {
|
|
|
|
newMatches.PushBack(&CandidateNode{
|
|
Document: candidate.Document,
|
|
Path: candidate.CreateChildPath(index),
|
|
Node: node.Content[index],
|
|
})
|
|
}
|
|
return newMatches, nil
|
|
|
|
}
|
|
|
|
for _, indexNode := range indices {
|
|
index, err := strconv.ParseInt(indexNode.Value, 10, 64)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
indexToUse := index
|
|
contentLength := int64(len(node.Content))
|
|
for contentLength <= index {
|
|
node.Content = append(node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
|
|
contentLength = int64(len(node.Content))
|
|
}
|
|
|
|
if indexToUse < 0 {
|
|
indexToUse = contentLength + indexToUse
|
|
}
|
|
|
|
if indexToUse < 0 {
|
|
return nil, fmt.Errorf("Index [%v] out of range, array size is %v", index, contentLength)
|
|
}
|
|
|
|
newMatches.PushBack(&CandidateNode{
|
|
Node: node.Content[indexToUse],
|
|
Document: candidate.Document,
|
|
Path: candidate.CreateChildPath(index),
|
|
})
|
|
}
|
|
return newMatches, nil
|
|
}
|