diff --git a/file/file_test.go b/file/file_test.go index 44b5e2e..d3e079c 100644 --- a/file/file_test.go +++ b/file/file_test.go @@ -307,6 +307,45 @@ meta: } } +func TestDecodeContent_YAML_typedSliceRecursive(t *testing.T) { + content := ` +foo: + - foo + - bar +bar: + foo: + - foo + - bar + baz: + foo: + - foo + - bar + boz: + foo: + - 42 + - 42 +` + + element := map[string]interface{}{} + + err := DecodeContent(content, ".yaml", &element) + require.NoError(t, err) + + expected := map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "bar": map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "baz": map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "boz": map[string]interface{}{ + "foo": []interface{}{int64(42), int64(42)}, + }, + }, + }, + } + assert.Equal(t, expected, element) +} + func TestDecodeContent_JSON(t *testing.T) { content := ` { diff --git a/parser/element_fill.go b/parser/element_fill.go index 1fb39a4..0afe048 100644 --- a/parser/element_fill.go +++ b/parser/element_fill.go @@ -420,6 +420,12 @@ func (f filler) fillRawValue(field reflect.Value, node *Node, subMap bool) error return nil } + // In the case of sub-map, fill raw typed slices recursively. + _, err := f.fillRawMapWithTypedSlice(m) + if err != nil { + return err + } + p := map[string]interface{}{node.Name: m} node.RawValue = p @@ -428,6 +434,34 @@ func (f filler) fillRawValue(field reflect.Value, node *Node, subMap bool) error return nil } +func (f filler) fillRawMapWithTypedSlice(elt interface{}) (reflect.Value, error) { + eltValue := reflect.ValueOf(elt) + + switch eltValue.Kind() { + case reflect.String: + if strings.HasPrefix(elt.(string), f.RawSliceSeparator) { + sliceValue, err := f.fillRawTypedSlice(elt.(string)) + if err != nil { + return eltValue, err + } + + return sliceValue, nil + } + + case reflect.Map: + for k, v := range elt.(map[string]interface{}) { + value, err := f.fillRawMapWithTypedSlice(v) + if err != nil { + return eltValue, err + } + + eltValue.SetMapIndex(reflect.ValueOf(k), value) + } + } + + return eltValue, nil +} + func (f filler) fillRawTypedSlice(s string) (reflect.Value, error) { raw := strings.Split(s, f.RawSliceSeparator) diff --git a/parser/element_fill_test.go b/parser/element_fill_test.go index 28d3e77..b9d54a6 100644 --- a/parser/element_fill_test.go +++ b/parser/element_fill_test.go @@ -1556,6 +1556,48 @@ func TestFill(t *testing.T) { }, }}, }, + { + desc: "recursive slices", + rawSliceSeparator: "║", + node: &Node{ + Name: "traefik", + Kind: reflect.Pointer, + Children: []*Node{ + { + Name: "bar", + RawValue: map[string]interface{}{ + "baz": map[string]interface{}{ + "boz": map[string]interface{}{ + "foo": "║2║42║42", + }, + "foo": "║24║foo║bar", + }, + "foo": "║24║foo║bar", + }, + }, + { + Name: "foo", + Value: "║24║foo║bar", + RawValue: map[string]interface{}{ + "foo": "║24║foo║bar", + }, + }, + }, + }, + element: &map[string]interface{}{}, + expected: expected{element: &map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "bar": map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "baz": map[string]interface{}{ + "foo": []interface{}{"foo", "bar"}, + "boz": map[string]interface{}{ + "foo": []interface{}{int64(42), int64(42)}, + }, + }, + }, + }}, + }, } for _, test := range testCases {