Merge pull request #412 from hashicorp/mitchellh/body
"body" struct tag to capture entire body for a block decode
This commit is contained in:
commit
3de61ecba2
@ -65,6 +65,19 @@ func decodeBodyToStruct(body hcl.Body, ctx *hcl.EvalContext, val reflect.Value)
|
||||
|
||||
tags := getFieldTags(val.Type())
|
||||
|
||||
if tags.Body != nil {
|
||||
fieldIdx := *tags.Body
|
||||
field := val.Type().Field(fieldIdx)
|
||||
fieldV := val.Field(fieldIdx)
|
||||
switch {
|
||||
case bodyType.AssignableTo(field.Type):
|
||||
fieldV.Set(reflect.ValueOf(body))
|
||||
|
||||
default:
|
||||
diags = append(diags, decodeBodyToValue(body, ctx, fieldV)...)
|
||||
}
|
||||
}
|
||||
|
||||
if tags.Remain != nil {
|
||||
fieldIdx := *tags.Remain
|
||||
field := val.Type().Field(fieldIdx)
|
||||
|
@ -217,6 +217,30 @@ func TestDecodeBody(t *testing.T) {
|
||||
}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"name": "Ermintrude",
|
||||
"age": 50,
|
||||
},
|
||||
makeInstantiateType(struct {
|
||||
Name string `hcl:"name"`
|
||||
Body hcl.Body `hcl:",body"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
}{}),
|
||||
func(gotI interface{}) bool {
|
||||
got := gotI.(struct {
|
||||
Name string `hcl:"name"`
|
||||
Body hcl.Body `hcl:",body"`
|
||||
Remain hcl.Body `hcl:",remain"`
|
||||
})
|
||||
|
||||
attrs, _ := got.Body.JustAttributes()
|
||||
|
||||
return got.Name == "Ermintrude" && len(attrs) == 2 &&
|
||||
attrs["name"] != nil && attrs["age"] != nil
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"noodle": map[string]interface{}{},
|
||||
|
@ -30,6 +30,13 @@
|
||||
// in which case multiple blocks of the corresponding type are decoded into
|
||||
// the slice.
|
||||
//
|
||||
// "body" can be placed on a single field of type hcl.Body to capture
|
||||
// the full hcl.Body that was decoded for a block. This does not allow leftover
|
||||
// values like "remain", so a decoding error will still be returned if leftover
|
||||
// fields are given. If you want to capture the decoding body PLUS leftover
|
||||
// fields, you must specify a "remain" field as well to prevent errors. The
|
||||
// body field and the remain field will both contain the leftover fields.
|
||||
//
|
||||
// "label" fields are considered only in a struct used as the type of a field
|
||||
// marked as "block", and are used sequentially to capture the labels of
|
||||
// the blocks being decoded. In this case, the name token is used only as
|
||||
|
@ -113,6 +113,7 @@ type fieldTags struct {
|
||||
Blocks map[string]int
|
||||
Labels []labelField
|
||||
Remain *int
|
||||
Body *int
|
||||
Optional map[string]bool
|
||||
}
|
||||
|
||||
@ -162,6 +163,12 @@ func getFieldTags(ty reflect.Type) *fieldTags {
|
||||
}
|
||||
idx := i // copy, because this loop will continue assigning to i
|
||||
ret.Remain = &idx
|
||||
case "body":
|
||||
if ret.Body != nil {
|
||||
panic("only one 'body' tag is permitted")
|
||||
}
|
||||
idx := i // copy, because this loop will continue assigning to i
|
||||
ret.Body = &idx
|
||||
case "optional":
|
||||
ret.Attributes[name] = i
|
||||
ret.Optional[name] = true
|
||||
|
Loading…
Reference in New Issue
Block a user