diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 4e9bbbbd..f2ad1069 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -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 { diff --git a/pkg/yqlib/operator_collect.go b/pkg/yqlib/operator_collect.go index 2a114592..b153952c 100644 --- a/pkg/yqlib/operator_collect.go +++ b/pkg/yqlib/operator_collect.go @@ -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()) diff --git a/pkg/yqlib/operator_column.go b/pkg/yqlib/operator_column.go index 38e374e1..e4e92ba2 100644 --- a/pkg/yqlib/operator_column.go +++ b/pkg/yqlib/operator_column.go @@ -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) } diff --git a/pkg/yqlib/operator_comments.go b/pkg/yqlib/operator_comments.go index 3cef3a0c..80e07264 100644 --- a/pkg/yqlib/operator_comments.go +++ b/pkg/yqlib/operator_comments.go @@ -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 diff --git a/pkg/yqlib/operator_datetime.go b/pkg/yqlib/operator_datetime.go index 25bafa9e..da56f186 100644 --- a/pkg/yqlib/operator_datetime.go +++ b/pkg/yqlib/operator_datetime.go @@ -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 diff --git a/pkg/yqlib/operator_error.go b/pkg/yqlib/operator_error.go index 8b0e3a9f..ba66a8a3 100644 --- a/pkg/yqlib/operator_error.go +++ b/pkg/yqlib/operator_error.go @@ -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) } diff --git a/pkg/yqlib/operator_flatten.go b/pkg/yqlib/operator_flatten.go index e7ccf99c..a768da63 100644 --- a/pkg/yqlib/operator_flatten.go +++ b/pkg/yqlib/operator_flatten.go @@ -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") } diff --git a/pkg/yqlib/operator_group_by.go b/pkg/yqlib/operator_group_by.go index 3bb70b50..20e45507 100644 --- a/pkg/yqlib/operator_group_by.go +++ b/pkg/yqlib/operator_group_by.go @@ -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) } diff --git a/pkg/yqlib/operator_has.go b/pkg/yqlib/operator_has.go index 01d7a1fe..a41703fe 100644 --- a/pkg/yqlib/operator_has.go +++ b/pkg/yqlib/operator_has.go @@ -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) diff --git a/pkg/yqlib/operator_length.go b/pkg/yqlib/operator_length.go index e809607d..d39af847 100644 --- a/pkg/yqlib/operator_length.go +++ b/pkg/yqlib/operator_length.go @@ -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) } diff --git a/pkg/yqlib/operator_line.go b/pkg/yqlib/operator_line.go index cbf2208e..cb19f221 100644 --- a/pkg/yqlib/operator_line.go +++ b/pkg/yqlib/operator_line.go @@ -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) } diff --git a/pkg/yqlib/operator_shuffle.go b/pkg/yqlib/operator_shuffle.go index 73a76965..32b2eb97 100644 --- a/pkg/yqlib/operator_shuffle.go +++ b/pkg/yqlib/operator_shuffle.go @@ -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 } diff --git a/pkg/yqlib/operator_sort_keys.go b/pkg/yqlib/operator_sort_keys.go index 0ab1a3cb..86f9dd00 100644 --- a/pkg/yqlib/operator_sort_keys.go +++ b/pkg/yqlib/operator_sort_keys.go @@ -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] diff --git a/pkg/yqlib/operator_unique.go b/pkg/yqlib/operator_unique.go index a1c5216c..1a821538 100644 --- a/pkg/yqlib/operator_unique.go +++ b/pkg/yqlib/operator_unique.go @@ -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