diff --git a/pkg/yqlib/treeops/candidate_node.go b/pkg/yqlib/treeops/candidate_node.go index 74096f58..61843a99 100644 --- a/pkg/yqlib/treeops/candidate_node.go +++ b/pkg/yqlib/treeops/candidate_node.go @@ -49,9 +49,9 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) { if n.Node.Style == 0 { n.Node.Style = other.Node.Style } - n.Node.FootComment = other.Node.FootComment - n.Node.HeadComment = other.Node.HeadComment - n.Node.LineComment = other.Node.LineComment + n.Node.FootComment = n.Node.FootComment + other.Node.FootComment + n.Node.HeadComment = n.Node.HeadComment + other.Node.HeadComment + n.Node.LineComment = n.Node.LineComment + other.Node.LineComment } func (n *CandidateNode) PathStackToString() string { diff --git a/pkg/yqlib/treeops/lib.go b/pkg/yqlib/treeops/lib.go index 35fbdbc1..4f9e684f 100644 --- a/pkg/yqlib/treeops/lib.go +++ b/pkg/yqlib/treeops/lib.go @@ -18,6 +18,17 @@ type OperationType struct { Handler OperatorHandler } +// operators TODO: +// - stripComments (recursive) +// - mergeAppend (merges and appends arrays) +// - mergeIfEmpty (sets only if the document is empty, do I do that now?) +// - updateStyle +// - updateTag +// - explodeAnchors +// - compare ?? +// - validate ?? +// - exists ?? + var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator} var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator} diff --git a/pkg/yqlib/treeops/operator_multiply_test.go b/pkg/yqlib/treeops/operator_multiply_test.go index 65c5af22..fbcd7f90 100644 --- a/pkg/yqlib/treeops/operator_multiply_test.go +++ b/pkg/yqlib/treeops/operator_multiply_test.go @@ -95,6 +95,13 @@ b: "D0, P[c], (!!map)::{g: thongs, c: frog}\n", }, }, + { + document: mergeDocSample, + expression: `.foobar * .foobarList`, + expected: []string{ + "D0, P[foobar], (!!map)::c: foobarList_c\n<<: [*foo, *bar]\nthing: foobar_thing\nb: foobarList_b\n", + }, + }, } func TestMultiplyOperatorScenarios(t *testing.T) { diff --git a/pkg/yqlib/treeops/operator_recursive_descent_test.go b/pkg/yqlib/treeops/operator_recursive_descent_test.go index 0079efea..7ced6738 100644 --- a/pkg/yqlib/treeops/operator_recursive_descent_test.go +++ b/pkg/yqlib/treeops/operator_recursive_descent_test.go @@ -60,6 +60,28 @@ var recursiveDescentOperatorScenarios = []expressionScenario{ "D0, P[b], (alias)::*cat\n", }, }, + { + document: mergeDocSample, + expression: `.foobar | ..`, + expected: []string{ + "D0, P[foobar], (!!map)::c: foobar_c\n!!merge <<: *foo\nthing: foobar_thing\n", + "D0, P[foobar c], (!!str)::foobar_c\n", + "D0, P[foobar <<], (alias)::*foo\n", + "D0, P[foobar thing], (!!str)::foobar_thing\n", + }, + }, + { + document: mergeDocSample, + expression: `.foobarList | ..`, + expected: []string{ + "D0, P[foobarList], (!!map)::b: foobarList_b\n!!merge <<: [*foo, *bar]\nc: foobarList_c\n", + "D0, P[foobarList b], (!!str)::foobarList_b\n", + "D0, P[foobarList <<], (!!seq)::[*foo, *bar]\n", + "D0, P[foobarList << 0], (alias)::*foo\n", + "D0, P[foobarList << 1], (alias)::*bar\n", + "D0, P[foobarList c], (!!str)::foobarList_c\n", + }, + }, } func TestRecursiveDescentOperatorScenarios(t *testing.T) { diff --git a/pkg/yqlib/treeops/operator_traverse_path.go b/pkg/yqlib/treeops/operator_traverse_path.go index a2bcc1de..3b12e9d3 100644 --- a/pkg/yqlib/treeops/operator_traverse_path.go +++ b/pkg/yqlib/treeops/operator_traverse_path.go @@ -44,12 +44,6 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Oper log.Debug("Traversing %v", NodeToString(matchingNode)) value := matchingNode.Node - followAlias := true - - // if operation.Preferences != nil { - // followAlias = !operation.Preferences.(*TraversePreferences).DontFollowAlias - // } - if value.Tag == "!!null" && operation.Value != "[]" { log.Debugf("Guessing kind") // we must ahve added this automatically, lets guess what it should be now @@ -102,11 +96,8 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Oper case yaml.AliasNode: log.Debug("its an alias!") - if followAlias { - matchingNode.Node = matchingNode.Node.Alias - return traverse(d, matchingNode, operation) - } - return []*CandidateNode{matchingNode}, nil + matchingNode.Node = matchingNode.Node.Alias + return traverse(d, matchingNode, operation) case yaml.DocumentNode: log.Debug("digging into doc node") return traverse(d, &CandidateNode{ @@ -130,6 +121,12 @@ func traverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, op node := candidate.Node + followAlias := true + + if operation.Preferences != nil { + followAlias = !operation.Preferences.(*TraversePreferences).DontFollowAlias + } + var contents = node.Content for index := 0; index < len(contents); index = index + 2 { key := contents[index] @@ -137,7 +134,7 @@ func traverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, op log.Debug("checking %v (%v)", key.Value, key.Tag) //skip the 'merge' tag, find a direct match first - if key.Tag == "!!merge" { + if key.Tag == "!!merge" && followAlias { log.Debug("Merge anchor") traverseMergeAnchor(newMatches, candidate, value, operation) } else if keyMatches(key, operation) {