protohcl: allow attribute syntax for all map fields (#19108)

This commit is contained in:
Matt Keeler 2023-10-06 19:07:08 -04:00 committed by GitHub
parent a9747dc38c
commit 4713317457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 5 deletions

View File

@ -173,22 +173,22 @@ func (bd bodyDecoder) schema(desc protoreflect.MessageDescriptor) (*hcl.BodySche
f := fields.Get(i) f := fields.Get(i)
kind := f.Kind() kind := f.Kind()
// maps are special and whether they use block or attribute syntax depends // maps are special and whether they can use block syntax depends on the value type
// on the value type
if f.IsMap() { if f.IsMap() {
valueDesc := f.MapValue() valueDesc := f.MapValue()
valueKind := valueDesc.Kind() valueKind := valueDesc.Kind()
wktHint := wellKnownTypeSchemaHint(valueDesc) wktHint := wellKnownTypeSchemaHint(valueDesc)
// Message types should generally be encoded as blocks unless its a special Well Known Type // Maps with values that are Messages can generally be decoded using the block syntax.
// that should use attribute encoding // The exception are some of the Well-Known-Types that appear as scalar values with
// either string or numeric encoding but get parsed into message types. It is still
// fine to also decode these from the attribute syntax.
if valueKind == protoreflect.MessageKind && wktHint != wellKnownAttribute { if valueKind == protoreflect.MessageKind && wktHint != wellKnownAttribute {
schema.Blocks = append(schema.Blocks, hcl.BlockHeaderSchema{ schema.Blocks = append(schema.Blocks, hcl.BlockHeaderSchema{
Type: bd.namer.NameField(f), Type: bd.namer.NameField(f),
LabelNames: []string{"key"}, LabelNames: []string{"key"},
}) })
continue
} }
// non-message types or Well Known Message types that need attribute encoding // non-message types or Well Known Message types that need attribute encoding

View File

@ -109,6 +109,56 @@ func TestNestedAndCollections(t *testing.T) {
require.Equal(t, out.IntList[1], int32(2)) require.Equal(t, out.IntList[1], int32(2))
} }
func TestNestedAndCollections_AttributeSyntax(t *testing.T) {
hcl := `
primitives {
uint32_val = 42
}
primitives_map = {
"foo" = {
uint32_val = 42
}
}
protocol_map = {
"foo" = "PROTOCOL_TCP"
}
primitives_list = [
{
uint32_val = 42
},
{
uint32_val = 56
}
]
int_list = [
1,
2
]
`
var out testproto.NestedAndCollections
err := Unmarshal([]byte(hcl), &out)
require.NoError(t, err)
require.NotNil(t, out.Primitives)
require.Equal(t, out.Primitives.Uint32Val, uint32(42))
require.NotNil(t, out.PrimitivesMap)
require.Equal(t, out.PrimitivesMap["foo"].Uint32Val, uint32(42))
require.NotNil(t, out.ProtocolMap)
require.Equal(t, out.ProtocolMap["foo"], testproto.Protocol_PROTOCOL_TCP)
require.Len(t, out.PrimitivesList, 2)
require.Equal(t, out.PrimitivesList[0].Uint32Val, uint32(42))
require.Equal(t, out.PrimitivesList[1].Uint32Val, uint32(56))
require.Len(t, out.IntList, 2)
require.Equal(t, out.IntList[1], int32(2))
}
func TestPrimitiveWrappers(t *testing.T) { func TestPrimitiveWrappers(t *testing.T) {
hcl := ` hcl := `
double_val = 1.234 double_val = 1.234