This commit is contained in:
Mike Farah 2023-04-08 20:17:13 +10:00
parent 66ab916c6b
commit 6e3f1d959e
10 changed files with 83 additions and 65 deletions

View File

@ -218,6 +218,19 @@ func (n *CandidateNode) CopyChildren() []*CandidateNode {
} }
func (n *CandidateNode) Copy() *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{ return &CandidateNode{
Kind: n.Kind, Kind: n.Kind,
Style: n.Style, Style: n.Style,
@ -229,7 +242,7 @@ func (n *CandidateNode) Copy() *CandidateNode {
// ok not to clone this, // ok not to clone this,
// as its a reference to somewhere else. // as its a reference to somewhere else.
Alias: n.Alias, Alias: n.Alias,
Content: n.CopyChildren(), Content: content,
HeadComment: n.HeadComment, HeadComment: n.HeadComment,
LineComment: n.LineComment, LineComment: n.LineComment,

View File

@ -3,8 +3,6 @@ package yqlib
import ( import (
"container/list" "container/list"
"fmt" "fmt"
yaml "gopkg.in/yaml.v3"
) )
func columnOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { 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() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Column), Tag: "!!int"} result := candidate.CreateReplacement()
result := candidate.CreateReplacement(node) result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", candidate.Column)
result.Tag = "!!int"
results.PushBack(result) results.PushBack(result)
} }

View File

@ -5,8 +5,6 @@ import (
"bytes" "bytes"
"container/list" "container/list"
"regexp" "regexp"
yaml "gopkg.in/yaml.v3"
) )
type commentOpPreferences struct { type commentOpPreferences struct {
@ -35,7 +33,7 @@ func assignCommentsOperator(d *dataTreeNavigator, context Context, expressionNod
} }
if rhs.MatchingNodes.Front() != nil { 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 { 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()) log.Debugf("Setting comment of : %v", candidate.GetKey())
if preferences.LineComment { if preferences.LineComment {
candidate.Node.LineComment = comment candidate.LineComment = comment
} }
if preferences.HeadComment { if preferences.HeadComment {
candidate.Node.HeadComment = comment candidate.HeadComment = comment
candidate.LeadingContent = "" // clobber the leading content, if there was any. 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 candidate.TrailingContent = "# " + comment
} else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode { } else if preferences.FootComment && candidate.Kind == DocumentNode {
candidate.TrailingContent = comment candidate.TrailingContent = comment
} else if preferences.FootComment && candidate.Node.Kind != yaml.DocumentNode { } else if preferences.FootComment && candidate.Kind != DocumentNode {
candidate.Node.FootComment = comment candidate.FootComment = comment
candidate.TrailingContent = "" candidate.TrailingContent = ""
} }
@ -91,7 +89,7 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode *
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
comment := "" comment := ""
if preferences.LineComment { if preferences.LineComment {
comment = candidate.Node.LineComment comment = candidate.LineComment
} else if preferences.HeadComment && candidate.LeadingContent != "" { } else if preferences.HeadComment && candidate.LeadingContent != "" {
var chompRegexp = regexp.MustCompile(`\n$`) var chompRegexp = regexp.MustCompile(`\n$`)
var output bytes.Buffer var output bytes.Buffer
@ -106,11 +104,11 @@ func getCommentsOperator(d *dataTreeNavigator, context Context, expressionNode *
comment = output.String() comment = output.String()
comment = chompRegexp.ReplaceAllString(comment, "") comment = chompRegexp.ReplaceAllString(comment, "")
} else if preferences.HeadComment { } else if preferences.HeadComment {
comment = candidate.Node.HeadComment comment = candidate.HeadComment
} else if preferences.FootComment && candidate.Node.Kind == yaml.DocumentNode && candidate.TrailingContent != "" { } else if preferences.FootComment && candidate.Kind == DocumentNode && candidate.TrailingContent != "" {
comment = candidate.TrailingContent comment = candidate.TrailingContent
} else if preferences.FootComment { } else if preferences.FootComment {
comment = candidate.Node.FootComment comment = candidate.FootComment
} }
comment = startCommentCharaterRegExp.ReplaceAllString(comment, "") comment = startCommentCharaterRegExp.ReplaceAllString(comment, "")
comment = subsequentCommentCharaterRegExp.ReplaceAllString(comment, "\n") comment = subsequentCommentCharaterRegExp.ReplaceAllString(comment, "\n")

View File

@ -2,8 +2,6 @@ package yqlib
import ( import (
"container/list" "container/list"
"gopkg.in/yaml.v3"
) )
func createMapOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { 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) 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, mapPairs, err := crossFunction(d, context.ChildContext(matches), expressionNode,
func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) { 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("LHS:", NodeToString(lhs))
log.Debugf("RHS:", NodeToString(rhs)) log.Debugf("RHS:", NodeToString(rhs))
node.Content = []*yaml.Node{ node.Content = []*CandidateNode{
unwrapDoc(lhs.Node), lhs.unwrapDocument(),
unwrapDoc(rhs.Node), rhs.unwrapDocument(),
} }
node.Document = document
node.Path = path
return &CandidateNode{Node: &node, Document: document, Path: path}, nil return &node, nil
}, false) }, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
innerList := listToNodeSeq(mapPairs.MatchingNodes) innerList := listToNodeSeq(mapPairs.MatchingNodes)
innerList.Style = yaml.FlowStyle innerList.Style = FlowStyle
return &CandidateNode{Node: innerList, Document: document, Path: path}, nil innerList.Document = document
innerList.Path = path
return innerList, nil
} }
// NOTE: here the document index gets dropped so we // NOTE: here the document index gets dropped so we
// no longer know where the node originates from. // no longer know where the node originates from.
func listToNodeSeq(list *list.List) *yaml.Node { func listToNodeSeq(list *list.List) *CandidateNode {
node := yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} node := CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
for entry := list.Front(); entry != nil; entry = entry.Next() { for entry := list.Front(); entry != nil; entry = entry.Next() {
entryCandidate := entry.Value.(*CandidateNode) entryCandidate := entry.Value.(*CandidateNode)
log.Debugf("Collecting %v into sequence", NodeToString(entryCandidate)) log.Debugf("Collecting %v into sequence", NodeToString(entryCandidate))
node.Content = append(node.Content, entryCandidate.Node) node.Content = append(node.Content, entryCandidate)
} }
return &node return &node
} }

View File

@ -17,7 +17,7 @@ func evalOperator(d *dataTreeNavigator, context Context, expressionNode *Express
for pathExpStrEntry := pathExpStrResults.MatchingNodes.Front(); pathExpStrEntry != nil; pathExpStrEntry = pathExpStrEntry.Next() { for pathExpStrEntry := pathExpStrResults.MatchingNodes.Front(); pathExpStrEntry != nil; pathExpStrEntry = pathExpStrEntry.Next() {
expressionStrCandidate := pathExpStrEntry.Value.(*CandidateNode) expressionStrCandidate := pathExpStrEntry.Value.(*CandidateNode)
expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Node.Value) expressions[expIndex], err = ExpressionParser.ParseExpression(expressionStrCandidate.Value)
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }

View File

@ -25,7 +25,7 @@ func filterOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
collected.Node.Style = unwrapDoc(candidate.Node).Style collected.Style = candidate.unwrapDocument().Style
results.PushBack(collected) results.PushBack(collected)
} }
return context.ChildContext(results), nil return context.ChildContext(results), nil

View File

@ -3,8 +3,6 @@ package yqlib
import ( import (
"container/list" "container/list"
"fmt" "fmt"
yaml "gopkg.in/yaml.v3"
) )
func lengthOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { 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() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
targetNode := unwrapDoc(candidate.Node) targetNode := candidate.unwrapDocument()
var length int var length int
switch targetNode.Kind { switch targetNode.Kind {
case yaml.ScalarNode: case ScalarNode:
if targetNode.Tag == "!!null" { if targetNode.Tag == "!!null" {
length = 0 length = 0
} else { } else {
length = len(targetNode.Value) length = len(targetNode.Value)
} }
case yaml.MappingNode: case MappingNode:
length = len(targetNode.Content) / 2 length = len(targetNode.Content) / 2
case yaml.SequenceNode: case SequenceNode:
length = len(targetNode.Content) length = len(targetNode.Content)
default: default:
length = 0 length = 0
} }
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"} result := candidate.CreateReplacement()
result := candidate.CreateReplacement(node) result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", length)
result.Tag = "!!int"
results.PushBack(result) results.PushBack(result)
} }

View File

@ -3,8 +3,6 @@ package yqlib
import ( import (
"container/list" "container/list"
"fmt" "fmt"
yaml "gopkg.in/yaml.v3"
) )
func lineOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { 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() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", candidate.Node.Line), Tag: "!!int"} result := candidate.CreateReplacement()
result := candidate.CreateReplacement(node) result.Kind = ScalarNode
result.Value = fmt.Sprintf("%v", candidate.Line)
result.Tag = "!!int"
results.PushBack(result) results.PushBack(result)
} }

View File

@ -54,7 +54,7 @@ func mapOperator(d *dataTreeNavigator, context Context, expressionNode *Expressi
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
collected.Node.Style = unwrapDoc(candidate.Node).Style collected.Style = candidate.unwrapDocument().Style
results.PushBack(collected) results.PushBack(collected)

View File

@ -3,33 +3,31 @@ package yqlib
import ( import (
"container/list" "container/list"
"fmt" "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 { for index := 0; index < len(indices.Content); index = index + 1 {
keyToFind := indices.Content[index] keyToFind := indices.Content[index]
indexInMap := findKeyInMap(original, keyToFind) indexInMap := findKeyInMap(original, keyToFind)
if indexInMap > -1 { if indexInMap > -1 {
clonedKey := deepClone(original.Content[indexInMap]) clonedKey := original.Content[indexInMap].Copy()
clonedValue := deepClone(original.Content[indexInMap+1]) clonedValue := original.Content[indexInMap+1].Copy()
filteredContent = append(filteredContent, clonedKey, clonedValue) filteredContent = append(filteredContent, clonedKey, clonedValue)
} }
} }
newNode := deepCloneNoContent(original) newNode := original.CopyWithoutContent()
newNode.Content = filteredContent newNode.Content = filteredContent
return newNode 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 { for index := 0; index < len(indices.Content); index = index + 1 {
indexInArray, err := parseInt(indices.Content[index].Value) indexInArray, err := parseInt(indices.Content[index].Value)
if err != nil { 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) { 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 newNode.Content = filteredContent
return newNode, nil return newNode, nil
@ -55,21 +53,21 @@ func pickOperator(d *dataTreeNavigator, context Context, expressionNode *Express
if err != nil { if err != nil {
return Context{}, err return Context{}, err
} }
indicesToPick := &yaml.Node{} indicesToPick := &CandidateNode{}
if contextIndicesToPick.MatchingNodes.Len() > 0 { if contextIndicesToPick.MatchingNodes.Len() > 0 {
indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode).Node indicesToPick = contextIndicesToPick.MatchingNodes.Front().Value.(*CandidateNode)
} }
var results = list.New() var results = list.New()
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() { for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
candidate := el.Value.(*CandidateNode) candidate := el.Value.(*CandidateNode)
node := unwrapDoc(candidate.Node) node := candidate.unwrapDocument()
var replacement *yaml.Node var replacement *CandidateNode
if node.Kind == yaml.MappingNode { if node.Kind == MappingNode {
replacement = pickMap(node, indicesToPick) replacement = pickMap(node, indicesToPick)
} else if node.Kind == yaml.SequenceNode { } else if node.Kind == SequenceNode {
replacement, err = pickSequence(node, indicesToPick) replacement, err = pickSequence(node, indicesToPick)
if err != nil { if err != nil {
return Context{}, err 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()) 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 return context.ChildContext(results), nil