yq/pkg/yqlib/operator_array_traverse.go
2020-12-27 09:55:21 +11:00

92 lines
2.4 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
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
if err != nil {
return nil, err
}
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 := lhs.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
if candidate.Node.Kind == yaml.SequenceNode {
newNodes, err := traverseArrayWithIndices(candidate, indicesToTraverse)
if err != nil {
return nil, err
}
matchingNodeMap.PushBackList(newNodes)
} else {
log.Debugf("OperatorArray Traverse skipping %v as its a %v", candidate, candidate.Node.Tag)
}
}
return matchingNodeMap, nil
}
func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node) (*list.List, error) {
log.Debug("traverseArrayWithIndices")
var newMatches = list.New()
if len(indices) == 0 {
var contents = candidate.Node.Content
var index int64
for index = 0; index < int64(len(contents)); index = index + 1 {
newMatches.PushBack(&CandidateNode{
Document: candidate.Document,
Path: candidate.CreateChildPath(index),
Node: contents[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(candidate.Node.Content))
for contentLength <= index {
candidate.Node.Content = append(candidate.Node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
contentLength = int64(len(candidate.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: candidate.Node.Content[indexToUse],
Document: candidate.Document,
Path: candidate.CreateChildPath(index),
})
}
return newMatches, nil
}