Skip to content

Commit

Permalink
Allow multiple merge keys
Browse files Browse the repository at this point in the history
  • Loading branch information
moskyb committed Jul 21, 2023
1 parent 3514762 commit e93e6ae
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
13 changes: 9 additions & 4 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
nerrs := len(d.terrors)
for i := 0; i < l; i += 2 {
ni := n.Content[i]
if isMerge(ni) {
// Merge keys ("<<") are discarded during processing, so don't need to be unique.
continue
}

for j := i + 2; j < l; j += 2 {
nj := n.Content[j]
if ni.Kind == nj.Kind && ni.Value == nj.Value {
Expand Down Expand Up @@ -816,7 +821,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
mergedFields := d.mergedFields
d.mergedFields = nil

var mergeNode *Node
mergeNodes := []*Node{}

mapIsNew := false
if out.IsNil() {
Expand All @@ -825,7 +830,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
for i := 0; i < l; i += 2 {
if isMerge(n.Content[i]) {
mergeNode = n.Content[i+1]
mergeNodes = append(mergeNodes, n.Content[i+1])
continue
}
k := reflect.New(kt).Elem()
Expand All @@ -852,8 +857,8 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}

d.mergedFields = mergedFields
if mergeNode != nil {
d.merge(n, mergeNode, out)
for _, node := range mergeNodes {
d.merge(n, node, out)
}

d.stringMapType = stringMapType
Expand Down
25 changes: 25 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,31 @@ func (s *S) TestMergeNestedStruct(c *C) {
c.Assert(testm["outer"], DeepEquals, wantm)
}

const doubleMerge = `
one: &one
a: 1
b: 2
two: &two
b: 3
c: 4
merged:
<<: *one
<<: *two
`

func (s *S) TestDoubleMerge(c *C) {
var m map[string]interface{}
err := yaml.Unmarshal([]byte(doubleMerge), &m)
c.Assert(err, IsNil)
c.Assert(m["merged"], DeepEquals, map[string]interface{}{
"a": 1,
"b": 3,
"c": 4,
})
}

var unmarshalNullTests = []struct {
input string
pristine, expected func() interface{}
Expand Down

0 comments on commit e93e6ae

Please sign in to comment.