Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 41b1516

Browse files
committed
Allow multiple merge keys
1 parent 3514762 commit 41b1516

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

decode.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
770770
nerrs := len(d.terrors)
771771
for i := 0; i < l; i += 2 {
772772
ni := n.Content[i]
773+
if isMerge(ni) {
774+
// Merge keys ("<<") are discarded during processing, so don't need to be unique.
775+
continue
776+
}
777+
773778
for j := i + 2; j < l; j += 2 {
774779
nj := n.Content[j]
775780
if ni.Kind == nj.Kind && ni.Value == nj.Value {
@@ -816,7 +821,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
816821
mergedFields := d.mergedFields
817822
d.mergedFields = nil
818823

819-
var mergeNode *Node
824+
mergeNodes := []*Node{}
820825

821826
mapIsNew := false
822827
if out.IsNil() {
@@ -825,7 +830,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
825830
}
826831
for i := 0; i < l; i += 2 {
827832
if isMerge(n.Content[i]) {
828-
mergeNode = n.Content[i+1]
833+
mergeNodes = append(mergeNodes, n.Content[i+1])
829834
continue
830835
}
831836
k := reflect.New(kt).Elem()
@@ -852,8 +857,8 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
852857
}
853858

854859
d.mergedFields = mergedFields
855-
if mergeNode != nil {
856-
d.merge(n, mergeNode, out)
860+
for _, node := range mergeNodes {
861+
d.merge(n, node, out)
857862
}
858863

859864
d.stringMapType = stringMapType

decode_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,37 @@ func (s *S) TestMergeNestedStruct(c *C) {
15301530
c.Assert(testm["outer"], DeepEquals, wantm)
15311531
}
15321532

1533+
const doubleMerge = `
1534+
one: &one
1535+
a: 1
1536+
b: 2
1537+
d: 5
1538+
1539+
two: &two
1540+
b: 3
1541+
c: 4
1542+
e: 6
1543+
1544+
merged:
1545+
a: 0
1546+
<<: *one
1547+
<<: *two
1548+
e: 7
1549+
`
1550+
1551+
func (s *S) TestDoubleMerge(c *C) {
1552+
var m map[string]interface{}
1553+
err := yaml.Unmarshal([]byte(doubleMerge), &m)
1554+
c.Assert(err, IsNil)
1555+
c.Assert(m["merged"], DeepEquals, map[string]interface{}{
1556+
"a": 0, // The value of the parent is preserved over what's brought in by the merge
1557+
"b": 3,
1558+
"c": 4,
1559+
"d": 5,
1560+
"e": 7,
1561+
})
1562+
}
1563+
15331564
var unmarshalNullTests = []struct {
15341565
input string
15351566
pristine, expected func() interface{}

0 commit comments

Comments
 (0)