This commit is contained in:
Mike Farah 2023-04-08 21:27:47 +10:00
parent 6e3f1d959e
commit e4dd94248b
14 changed files with 77 additions and 115 deletions

View File

@ -176,7 +176,7 @@ func (n *CandidateNode) guessTagFromCustomType() string {
// }
// }
func (n *CandidateNode) CreateReplacement() *CandidateNode {
func (n *CandidateNode) CreateReplacement(kind Kind, tag string, value string) *CandidateNode {
return &CandidateNode{
Path: n.createChildPath(nil),
Parent: n.Parent,
@ -185,15 +185,18 @@ func (n *CandidateNode) CreateReplacement() *CandidateNode {
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
Kind: kind,
Tag: tag,
Value: value,
}
}
// func (n *CandidateNode) CreateReplacementWithDocWrappers(node *yaml.Node) *CandidateNode {
// replacement := n.CreateReplacement(node)
// replacement.LeadingContent = n.LeadingContent
// replacement.TrailingContent = n.TrailingContent
// return replacement
// }
func (n *CandidateNode) CreateReplacementWithDocWrappers(kind Kind, tag string, value string) *CandidateNode {
replacement := n.CreateReplacement(kind, tag, value)
replacement.LeadingContent = n.LeadingContent
replacement.TrailingContent = n.TrailingContent
return replacement
}
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
if path == nil {

View File

@ -55,8 +55,7 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
collectedNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
collectCandidate := candidate.CreateReplacement(collectedNode)
collectCandidate := candidate.CreateReplacement(SequenceNode, "!!seq", "")
log.Debugf("collect rhs: %v", expressionNode.RHS.Operation.toString())
@ -68,7 +67,7 @@ func collectOperator(d *dataTreeNavigator, context Context, expressionNode *Expr
for result := collectExpResults.MatchingNodes.Front(); result != nil; result = result.Next() {
resultC := result.Value.(*CandidateNode)
log.Debugf("found this: %v", NodeToString(resultC))
collectedNode.Content = append(collectedNode.Content, unwrapDoc(resultC.Node))
collectCandidate.Content = append(collectCandidate.Content, resultC.unwrapDocument())
}
log.Debugf("done collect rhs: %v", expressionNode.RHS.Operation.toString())

View File

@ -12,11 +12,7 @@ func columnOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
result := candidate.CreateReplacement()
result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", candidate.Column)
result.Tag = "!!int"
result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.Column))
results.PushBack(result)
}

View File

@ -113,10 +113,7 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode *
comment = startCommentCharaterRegExp.ReplaceAllString(comment, "")
comment = subsequentCommentCharaterRegExp.ReplaceAllString(comment, "\n")
result := candidate.CreateReplacement()
result.Kind = ScalarNode
result.Tag = "!!str"
result.LeadingContent = "" // don't include the leading yaml content when retrieving a comment
result := candidate.CreateReplacement(ScalarNode, "!!str", comment)
results.PushBack(result)
}
return context.ChildContext(results), nil

View File

@ -6,8 +6,6 @@ import (
"fmt"
"strconv"
"time"
"gopkg.in/yaml.v3"
)
func getStringParamter(parameterName string, d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (string, error) {
@ -19,7 +17,7 @@ func getStringParamter(parameterName string, d *dataTreeNavigator, context Conte
return "", fmt.Errorf("could not find %v for format_time", parameterName)
}
return result.MatchingNodes.Front().Value.(*CandidateNode).Node.Value, nil
return result.MatchingNodes.Front().Value.(*CandidateNode).Value, nil
}
func withDateTimeFormat(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -41,13 +39,13 @@ var Now = time.Now
func nowOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
node := &yaml.Node{
node := &CandidateNode{
Tag: "!!timestamp",
Kind: yaml.ScalarNode,
Kind: ScalarNode,
Value: Now().Format(time.RFC3339),
}
return context.SingleChildContext(&CandidateNode{Node: node}), nil
return context.SingleChildContext(node), nil
}
@ -74,7 +72,7 @@ func formatDateTime(d *dataTreeNavigator, context Context, expressionNode *Expre
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
parsedTime, err := parseDateTime(layout, candidate.Node.Value)
parsedTime, err := parseDateTime(layout, candidate.Value)
if err != nil {
return Context{}, fmt.Errorf("could not parse datetime of [%v]: %w", candidate.GetNicePath(), err)
}
@ -83,14 +81,16 @@ func formatDateTime(d *dataTreeNavigator, context Context, expressionNode *Expre
node, errorReading := parseSnippet(formattedTimeStr)
if errorReading != nil {
log.Debugf("could not parse %v - lets just leave it as a string: %w", formattedTimeStr, errorReading)
node = &yaml.Node{
Kind: yaml.ScalarNode,
node = &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: formattedTimeStr,
}
}
results.PushBack(candidate.CreateReplacement(node))
node.Document = candidate.Document
node.FileIndex = candidate.FileIndex
node.Path = candidate.Path
results.PushBack(node)
}
return context.ChildContext(results), nil
@ -113,19 +113,13 @@ func tzOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode)
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
parsedTime, err := parseDateTime(layout, candidate.Node.Value)
parsedTime, err := parseDateTime(layout, candidate.Value)
if err != nil {
return Context{}, fmt.Errorf("could not parse datetime of [%v] using layout [%v]: %w", candidate.GetNicePath(), layout, err)
}
tzTime := parsedTime.In(timezone)
node := &yaml.Node{
Kind: yaml.ScalarNode,
Tag: candidate.Node.Tag,
Value: tzTime.Format(layout),
}
results.PushBack(candidate.CreateReplacement(node))
results.PushBack(candidate.CreateReplacement(ScalarNode, candidate.Tag, tzTime.Format(layout)))
}
return context.ChildContext(results), nil
@ -148,24 +142,20 @@ func fromUnixOp(d *dataTreeNavigator, context Context, expressionNode *Expressio
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
actualTag := guessTagFromCustomType(candidate.Node)
actualTag := candidate.guessTagFromCustomType()
if actualTag != "!!int" && guessTagFromCustomType(candidate.Node) != "!!float" {
return Context{}, fmt.Errorf("from_unix only works on numbers, found %v instead", candidate.Node.Tag)
if actualTag != "!!int" && actualTag != "!!float" {
return Context{}, fmt.Errorf("from_unix only works on numbers, found %v instead", candidate.Tag)
}
parsedTime, err := parseUnixTime(candidate.Node.Value)
parsedTime, err := parseUnixTime(candidate.Value)
if err != nil {
return Context{}, err
}
node := &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!timestamp",
Value: parsedTime.Format(time.RFC3339),
}
node := candidate.CreateReplacement(ScalarNode, "!!timestamp", parsedTime.Format(time.RFC3339))
results.PushBack(candidate.CreateReplacement(node))
results.PushBack(node)
}
return context.ChildContext(results), nil
@ -180,18 +170,12 @@ func toUnixOp(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
parsedTime, err := parseDateTime(layout, candidate.Node.Value)
parsedTime, err := parseDateTime(layout, candidate.Value)
if err != nil {
return Context{}, fmt.Errorf("could not parse datetime of [%v] using layout [%v]: %w", candidate.GetNicePath(), layout, err)
}
node := &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!int",
Value: fmt.Sprintf("%v", parsedTime.Unix()),
}
results.PushBack(candidate.CreateReplacement(node))
results.PushBack(candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", parsedTime.Unix())))
}
return context.ChildContext(results), nil

View File

@ -14,7 +14,7 @@ func errorOperator(d *dataTreeNavigator, context Context, expressionNode *Expres
}
errorMessage := "aborted"
if rhs.MatchingNodes.Len() > 0 {
errorMessage = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value
errorMessage = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value
}
return Context{}, fmt.Errorf(errorMessage)
}

View File

@ -2,26 +2,24 @@ package yqlib
import (
"fmt"
yaml "gopkg.in/yaml.v3"
)
type flattenPreferences struct {
depth int
}
func flatten(node *yaml.Node, depth int) {
func flatten(node *CandidateNode, depth int) {
if depth == 0 {
return
}
if node.Kind != yaml.SequenceNode {
if node.Kind != SequenceNode {
return
}
content := node.Content
newSeq := make([]*yaml.Node, 0)
newSeq := make([]*CandidateNode, 0)
for i := 0; i < len(content); i++ {
if content[i].Kind == yaml.SequenceNode {
if content[i].Kind == SequenceNode {
flatten(content[i], depth-1)
for j := 0; j < len(content[i].Content); j++ {
newSeq = append(newSeq, content[i].Content[j])
@ -40,8 +38,8 @@ func flattenOp(d *dataTreeNavigator, context Context, expressionNode *Expression
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
candidateNode := unwrapDoc(candidate.Node)
if candidateNode.Kind != yaml.SequenceNode {
candidateNode := candidate.unwrapDocument()
if candidateNode.Kind != SequenceNode {
return Context{}, fmt.Errorf("Only arrays are supported for flatten")
}

View File

@ -5,13 +5,11 @@ import (
"fmt"
"github.com/elliotchance/orderedmap"
yaml "gopkg.in/yaml.v3"
)
func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *ExpressionNode, node *yaml.Node) (*orderedmap.OrderedMap, error) {
func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *ExpressionNode, node *CandidateNode) (*orderedmap.OrderedMap, error) {
var newMatches = orderedmap.NewOrderedMap()
for _, node := range node.Content {
child := &CandidateNode{Node: node}
for _, child := range node.Content {
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(child), rhsExp)
if err != nil {
@ -23,7 +21,7 @@ func processIntoGroups(d *dataTreeNavigator, context Context, rhsExp *Expression
if rhs.MatchingNodes.Len() > 0 {
first := rhs.MatchingNodes.Front()
keyCandidate := first.Value.(*CandidateNode)
keyValue = keyCandidate.Node.Value
keyValue = keyCandidate.Value
}
groupList, exists := newMatches.Get(keyValue)
@ -44,9 +42,9 @@ func groupBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionNo
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
candidateNode := unwrapDoc(candidate.Node)
candidateNode := candidate.unwrapDocument()
if candidateNode.Kind != yaml.SequenceNode {
if candidateNode.Kind != SequenceNode {
return Context{}, fmt.Errorf("Only arrays are supported for group by")
}
@ -56,18 +54,18 @@ func groupBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionNo
return Context{}, err
}
resultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
resultNode := candidate.CreateReplacement(SequenceNode, "!!seq", "")
for groupEl := newMatches.Front(); groupEl != nil; groupEl = groupEl.Next() {
groupResultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
groupResultNode := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
groupList := groupEl.Value.(*list.List)
for groupItem := groupList.Front(); groupItem != nil; groupItem = groupItem.Next() {
groupResultNode.Content = append(groupResultNode.Content, groupItem.Value.(*yaml.Node))
groupResultNode.Content = append(groupResultNode.Content, groupItem.Value.(*CandidateNode))
}
resultNode.Content = append(resultNode.Content, groupResultNode)
}
results.PushBack(candidate.CreateReplacement(resultNode))
results.PushBack(resultNode)
}

View File

@ -3,8 +3,6 @@ package yqlib
import (
"container/list"
"strconv"
yaml "gopkg.in/yaml.v3"
)
func hasOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -19,9 +17,9 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
}
wantedKey := "null"
wanted := &yaml.Node{Tag: "!!null"}
wanted := &CandidateNode{Tag: "!!null"}
if rhs.MatchingNodes.Len() != 0 {
wanted = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node
wanted = rhs.MatchingNodes.Front().Value.(*CandidateNode)
wantedKey = wanted.Value
}
@ -29,10 +27,10 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
candidate := el.Value.(*CandidateNode)
// grab the first value
candidateNode := unwrapDoc(candidate.Node)
candidateNode := candidate.unwrapDocument()
var contents = candidateNode.Content
switch candidateNode.Kind {
case yaml.MappingNode:
case MappingNode:
candidateHasKey := false
for index := 0; index < len(contents) && !candidateHasKey; index = index + 2 {
key := contents[index]
@ -41,7 +39,7 @@ func hasOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
}
}
results.PushBack(createBooleanCandidate(candidate, candidateHasKey))
case yaml.SequenceNode:
case SequenceNode:
candidateHasKey := false
if wanted.Tag == "!!int" {
var number, errParsingInt = strconv.ParseInt(wantedKey, 10, 64)

View File

@ -28,10 +28,7 @@ func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
length = 0
}
result := candidate.CreateReplacement()
result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", length)
result.Tag = "!!int"
result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", length))
results.PushBack(result)
}

View File

@ -12,10 +12,7 @@ func lineOperator(d *dataTreeNavigator, context Context, expressionNode *Express
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
result := candidate.CreateReplacement()
result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", candidate.Line)
result.Tag = "!!int"
result := candidate.CreateReplacement(ScalarNode, "!!int", fmt.Sprintf("%v", candidate.Line))
results.PushBack(result)
}

View File

@ -4,8 +4,6 @@ import (
"container/list"
"fmt"
"math/rand"
yaml "gopkg.in/yaml.v3"
)
func shuffleOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -20,18 +18,19 @@ func shuffleOperator(d *dataTreeNavigator, context Context, expressionNode *Expr
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
candidateNode := unwrapDoc(candidate.Node)
candidateNode := candidate.unwrapDocument()
if candidateNode.Kind != yaml.SequenceNode {
if candidateNode.Kind != SequenceNode {
return context, fmt.Errorf("node at path [%v] is not an array (it's a %v)", candidate.GetNicePath(), candidate.GetNiceTag())
}
result := deepClone(candidateNode)
result := candidateNode.Copy()
a := result.Content
myRand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
results.PushBack(candidate.CreateReplacement(result))
results.PushBack(result)
}
return context.ChildContext(results), nil
}

View File

@ -2,8 +2,6 @@ package yqlib
import (
"sort"
yaml "gopkg.in/yaml.v3"
)
func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -16,8 +14,8 @@ func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *Exp
}
for childEl := rhs.MatchingNodes.Front(); childEl != nil; childEl = childEl.Next() {
node := unwrapDoc(childEl.Value.(*CandidateNode).Node)
if node.Kind == yaml.MappingNode {
node := childEl.Value.(*CandidateNode).unwrapDocument()
if node.Kind == MappingNode {
sortKeys(node)
}
if err != nil {
@ -29,10 +27,10 @@ func sortKeysOperator(d *dataTreeNavigator, context Context, expressionNode *Exp
return context, nil
}
func sortKeys(node *yaml.Node) {
func sortKeys(node *CandidateNode) {
keys := make([]string, len(node.Content)/2)
keyBucket := map[string]*yaml.Node{}
valueBucket := map[string]*yaml.Node{}
keyBucket := map[string]*CandidateNode{}
valueBucket := map[string]*CandidateNode{}
var contents = node.Content
for index := 0; index < len(contents); index = index + 2 {
key := contents[index]
@ -42,7 +40,7 @@ func sortKeys(node *yaml.Node) {
valueBucket[key.Value] = value
}
sort.Strings(keys)
sortedContent := make([]*yaml.Node, len(node.Content))
sortedContent := make([]*CandidateNode, len(node.Content))
for index := 0; index < len(keys); index = index + 1 {
keyString := keys[index]
sortedContent[index*2] = keyBucket[keyString]

View File

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/elliotchance/orderedmap"
yaml "gopkg.in/yaml.v3"
)
func unique(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
@ -22,15 +21,14 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode)
candidateNode := unwrapDoc(candidate.Node)
candidateNode := candidate.unwrapDocument()
if candidateNode.Kind != yaml.SequenceNode {
if candidateNode.Kind != SequenceNode {
return Context{}, fmt.Errorf("Only arrays are supported for unique")
}
var newMatches = orderedmap.NewOrderedMap()
for _, node := range candidateNode.Content {
child := &CandidateNode{Node: node}
for _, child := range candidateNode.Content {
rhs, err := d.GetMatchingNodes(context.SingleReadonlyChildContext(child), expressionNode.RHS)
if err != nil {
@ -42,21 +40,21 @@ func uniqueBy(d *dataTreeNavigator, context Context, expressionNode *ExpressionN
if rhs.MatchingNodes.Len() > 0 {
first := rhs.MatchingNodes.Front()
keyCandidate := first.Value.(*CandidateNode)
keyValue = keyCandidate.Node.Value
keyValue = keyCandidate.Value
}
_, exists := newMatches.Get(keyValue)
if !exists {
newMatches.Set(keyValue, child.Node)
newMatches.Set(keyValue, child)
}
}
resultNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
resultNode := candidate.CreateReplacementWithDocWrappers(SequenceNode, "!!seq", "")
for el := newMatches.Front(); el != nil; el = el.Next() {
resultNode.Content = append(resultNode.Content, el.Value.(*yaml.Node))
resultNode.Content = append(resultNode.Content, el.Value.(*CandidateNode))
}
results.PushBack(candidate.CreateReplacementWithDocWrappers(resultNode))
results.PushBack(resultNode)
}
return context.ChildContext(results), nil