diff --git a/pkg/yqlib/candidate_node.go b/pkg/yqlib/candidate_node.go index 71a398ad..4e9bbbbd 100644 --- a/pkg/yqlib/candidate_node.go +++ b/pkg/yqlib/candidate_node.go @@ -218,6 +218,19 @@ func (n *CandidateNode) CopyChildren() []*CandidateNode { } func (n *CandidateNode) Copy() *CandidateNode { + return n.doCopy(true) +} + +func (n *CandidateNode) CopyWithoutContent() *CandidateNode { + return n.doCopy(false) +} + +func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode { + var content []*CandidateNode + if cloneContent { + content = n.CopyChildren() + } + return &CandidateNode{ Kind: n.Kind, Style: n.Style, @@ -229,7 +242,7 @@ func (n *CandidateNode) Copy() *CandidateNode { // ok not to clone this, // as its a reference to somewhere else. Alias: n.Alias, - Content: n.CopyChildren(), + Content: content, HeadComment: n.HeadComment, LineComment: n.LineComment, diff --git a/pkg/yqlib/operator_column.go b/pkg/yqlib/operator_column.go index ac7d339c..38e374e1 100644 --- a/pkg/yqlib/operator_column.go +++ b/pkg/yqlib/operator_column.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func columnOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -14,8 +12,11 @@ func columnOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Column), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement() + result.Kind = ScalarNode + result.Value = fmt.Sprintf("%v", candidate.Column) + result.Tag = "!!int" + results.PushBack(result) } diff --git a/pkg/yqlib/operator_comments.go b/pkg/yqlib/operator_comments.go index de602bec..3cef3a0c 100644 --- a/pkg/yqlib/operator_comments.go +++ b/pkg/yqlib/operator_comments.go @@ -5,8 +5,6 @@ import ( "bytes" "container/list" "regexp" - - yaml "gopkg.in/yaml.v3" ) type commentOpPreferences struct { @@ -35,7 +33,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod } if rhs.MatchingNodes.Front() != nil { - comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } @@ -49,25 +47,25 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod } if rhs.MatchingNodes.Front() != nil { - comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Node.Value + comment = rhs.MatchingNodes.Front().Value.(*CandidateNode).Value } } log.Debugf("Setting comment of : %v", candidate.GetKey()) if preferences.LineComment { - candidate.Node.LineComment = comment + candidate.LineComment = comment } if preferences.HeadComment { - candidate.Node.HeadComment = comment + candidate.HeadComment = comment candidate.LeadingContent = "" // clobber the leading content, if there was any. } - if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode && comment != "" { + if preferences.FootComment && candidate.Kind == DocumentNode && comment != "" { candidate.TrailingContent = "# " + comment - } else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode { + } else if preferences.FootComment && candidate.Kind == DocumentNode { candidate.TrailingContent = comment - } else if preferences.FootComment && candidate.Node.Kind != yaml.DocumentNode { - candidate.Node.FootComment = comment + } else if preferences.FootComment && candidate.Kind != DocumentNode { + candidate.FootComment = comment candidate.TrailingContent = "" } @@ -91,7 +89,7 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode * candidate := el.Value.(*CandidateNode) comment := "" if preferences.LineComment { - comment = candidate.Node.LineComment + comment = candidate.LineComment } else if preferences.HeadComment && candidate.LeadingContent != "" { var chompRegexp = regexp.MustCompile(`\n$`) var output bytes.Buffer @@ -106,11 +104,11 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode * comment = output.String() comment = chompRegexp.ReplaceAllString(comment, "") } else if preferences.HeadComment { - comment = candidate.Node.HeadComment - } else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode && candidate.TrailingContent != "" { + comment = candidate.HeadComment + } else if preferences.FootComment && candidate.Kind == DocumentNode && candidate.TrailingContent != "" { comment = candidate.TrailingContent } else if preferences.FootComment { - comment = candidate.Node.FootComment + comment = candidate.FootComment } comment = startCommentCharaterRegExp.ReplaceAllString(comment, "") comment = subsequentCommentCharaterRegExp.ReplaceAllString(comment, "\n") diff --git a/pkg/yqlib/operator_create_map.go b/pkg/yqlib/operator_create_map.go index 84582c9e..775451b1 100644 --- a/pkg/yqlib/operator_create_map.go +++ b/pkg/yqlib/operator_create_map.go @@ -2,8 +2,6 @@ package yqlib import ( "container/list" - - "gopkg.in/yaml.v3" ) func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -36,7 +34,11 @@ func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *Ex sequences.PushBack(sequenceNode) } - return context.SingleChildContext(&CandidateNode{Node: listToNodeSeq(sequences), Document: document, Path: path}), nil + node := listToNodeSeq(sequences) + node.Document = document + node.Path = path + + return context.SingleChildContext(node), nil } @@ -53,33 +55,37 @@ func sequenceFor(d *dataTreeNavigator, context Context, matchingNode *CandidateN mapPairs, err := crossFunction(d, context.ChildContext(matches), expressionNode, func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { - node := yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + node := CandidateNode{Kind: MappingNode, Tag: "!!map"} log.Debugf("LHS:", NodeToString(lhs)) log.Debugf("RHS:", NodeToString(rhs)) - node.Content = []*yaml.Node{ - unwrapDoc(lhs.Node), - unwrapDoc(rhs.Node), + node.Content = []*CandidateNode{ + lhs.unwrapDocument(), + rhs.unwrapDocument(), } + node.Document = document + node.Path = path - return &CandidateNode{Node: &node, Document: document, Path: path}, nil + return &node, nil }, false) if err != nil { return nil, err } innerList := listToNodeSeq(mapPairs.MatchingNodes) - innerList.Style = yaml.FlowStyle - return &CandidateNode{Node: innerList, Document: document, Path: path}, nil + innerList.Style = FlowStyle + innerList.Document = document + innerList.Path = path + return innerList, nil } // NOTE: here the document index gets dropped so we // no longer know where the node originates from. -func listToNodeSeq(list *list.List) *yaml.Node { - node := yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} +func listToNodeSeq(list *list.List) *CandidateNode { + node := CandidateNode{Kind: SequenceNode, Tag: "!!seq"} for entry := list.Front(); entry != nil; entry = entry.Next() { entryCandidate := entry.Value.(*CandidateNode) log.Debugf("Collecting %v into sequence", NodeToString(entryCandidate)) - node.Content = append(node.Content, entryCandidate.Node) + node.Content = append(node.Content, entryCandidate) } return &node } diff --git a/pkg/yqlib/operator_eval.go b/pkg/yqlib/operator_eval.go index 78037e97..2bba51d2 100644 --- a/pkg/yqlib/operator_eval.go +++ b/pkg/yqlib/operator_eval.go @@ -17,7 +17,7 @@ func evalOperator(d *dataTreeNavigator, context Context, expressionNode *Express for pathExpStrEntry := pathExpStrResults.MatchingNodes.Front(); pathExpStrEntry != nil; pathExpStrEntry = pathExpStrEntry.Next() { expressionStrCandidate := pathExpStrEntry.Value.(*CandidateNode) - expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Node.Value) + expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Value) if err != nil { return Context{}, err } diff --git a/pkg/yqlib/operator_filter.go b/pkg/yqlib/operator_filter.go index 8cf28303..05bbf1d8 100644 --- a/pkg/yqlib/operator_filter.go +++ b/pkg/yqlib/operator_filter.go @@ -25,7 +25,7 @@ func filterOperator(d *dataTreeNavigator, context Context, expressionNode *Expre if err != nil { return Context{}, err } - collected.Node.Style = unwrapDoc(candidate.Node).Style + collected.Style = candidate.unwrapDocument().Style results.PushBack(collected) } return context.ChildContext(results), nil diff --git a/pkg/yqlib/operator_length.go b/pkg/yqlib/operator_length.go index 46f1c8c8..e809607d 100644 --- a/pkg/yqlib/operator_length.go +++ b/pkg/yqlib/operator_length.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -13,25 +11,27 @@ func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *Expre for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - targetNode := unwrapDoc(candidate.Node) + targetNode := candidate.unwrapDocument() var length int switch targetNode.Kind { - case yaml.ScalarNode: + case ScalarNode: if targetNode.Tag == "!!null" { length = 0 } else { length = len(targetNode.Value) } - case yaml.MappingNode: + case MappingNode: length = len(targetNode.Content) / 2 - case yaml.SequenceNode: + case SequenceNode: length = len(targetNode.Content) default: length = 0 } - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement() + result.Kind = ScalarNode + result.Value = fmt.Sprintf("%v", length) + result.Tag = "!!int" results.PushBack(result) } diff --git a/pkg/yqlib/operator_line.go b/pkg/yqlib/operator_line.go index 1535e059..cbf2208e 100644 --- a/pkg/yqlib/operator_line.go +++ b/pkg/yqlib/operator_line.go @@ -3,8 +3,6 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) func lineOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { @@ -14,8 +12,10 @@ func lineOperator(d *dataTreeNavigator, context Context, expressionNode *Express for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Line), Tag: "!!int"} - result := candidate.CreateReplacement(node) + result := candidate.CreateReplacement() + result.Kind = ScalarNode + result.Value = fmt.Sprintf("%v", candidate.Line) + result.Tag = "!!int" results.PushBack(result) } diff --git a/pkg/yqlib/operator_map.go b/pkg/yqlib/operator_map.go index ec1a5ed0..17322311 100644 --- a/pkg/yqlib/operator_map.go +++ b/pkg/yqlib/operator_map.go @@ -54,7 +54,7 @@ func mapOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi if err != nil { return Context{}, err } - collected.Node.Style = unwrapDoc(candidate.Node).Style + collected.Style = candidate.unwrapDocument().Style results.PushBack(collected) diff --git a/pkg/yqlib/operator_pick.go b/pkg/yqlib/operator_pick.go index 416d947d..6fc5dda3 100644 --- a/pkg/yqlib/operator_pick.go +++ b/pkg/yqlib/operator_pick.go @@ -3,33 +3,31 @@ package yqlib import ( "container/list" "fmt" - - yaml "gopkg.in/yaml.v3" ) -func pickMap(original *yaml.Node, indices *yaml.Node) *yaml.Node { +func pickMap(original *CandidateNode, indices *CandidateNode) *CandidateNode { - filteredContent := make([]*yaml.Node, 0) + filteredContent := make([]*CandidateNode, 0) for index := 0; index < len(indices.Content); index = index + 1 { keyToFind := indices.Content[index] indexInMap := findKeyInMap(original, keyToFind) if indexInMap > -1 { - clonedKey := deepClone(original.Content[indexInMap]) - clonedValue := deepClone(original.Content[indexInMap+1]) + clonedKey := original.Content[indexInMap].Copy() + clonedValue := original.Content[indexInMap+1].Copy() filteredContent = append(filteredContent, clonedKey, clonedValue) } } - newNode := deepCloneNoContent(original) + newNode := original.CopyWithoutContent() newNode.Content = filteredContent return newNode } -func pickSequence(original *yaml.Node, indices *yaml.Node) (*yaml.Node, error) { +func pickSequence(original *CandidateNode, indices *CandidateNode) (*CandidateNode, error) { - filteredContent := make([]*yaml.Node, 0) + filteredContent := make([]*CandidateNode, 0) for index := 0; index < len(indices.Content); index = index + 1 { indexInArray, err := parseInt(indices.Content[index].Value) if err != nil { @@ -37,11 +35,11 @@ func pickSequence(original *yaml.Node, indices *yaml.Node) (*yaml.Node, error) { } if indexInArray > -1 && indexInArray < len(original.Content) { - filteredContent = append(filteredContent, deepClone(original.Content[indexInArray])) + filteredContent = append(filteredContent, original.Content[indexInArray].Copy()) } } - newNode := deepCloneNoContent(original) + newNode := original.CopyWithoutContent() newNode.Content = filteredContent return newNode, nil @@ -55,21 +53,21 @@ func pickOperator(d *dataTreeNavigator, context Context, expressionNode *Express if err != nil { return Context{}, err } - indicesToPick := &yaml.Node{} + indicesToPick := &CandidateNode{} if contextIndicesToPick.MatchingNodes.Len() > 0 { - indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode).Node + indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode) } var results = list.New() for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { candidate := el.Value.(*CandidateNode) - node := unwrapDoc(candidate.Node) + node := candidate.unwrapDocument() - var replacement *yaml.Node - if node.Kind == yaml.MappingNode { + var replacement *CandidateNode + if node.Kind == MappingNode { replacement = pickMap(node, indicesToPick) - } else if node.Kind == yaml.SequenceNode { + } else if node.Kind == SequenceNode { replacement, err = pickSequence(node, indicesToPick) if err != nil { return Context{}, err @@ -79,7 +77,9 @@ func pickOperator(d *dataTreeNavigator, context Context, expressionNode *Express return Context{}, fmt.Errorf("cannot pick indicies from type %v (%v)", node.Tag, candidate.GetNicePath()) } - results.PushBack(candidate.CreateReplacementWithDocWrappers(replacement)) + replacement.LeadingContent = candidate.LeadingContent + replacement.TrailingContent = candidate.TrailingContent + results.PushBack(replacement) } return context.ChildContext(results), nil