json: Implement Body.Content
This is a wrapper around Body.PartialContent that generates additional error diagnostics if any object properties are left over after decoding, helping the config author to catch typos that would otherwise have caused a property to be silently ignored.
This commit is contained in:
parent
17d372677d
commit
45f97bf427
@ -25,9 +25,40 @@ type expression struct {
|
||||
}
|
||||
|
||||
func (b *body) Content(schema *zcl.BodySchema) (*zcl.BodyContent, zcl.Diagnostics) {
|
||||
content, _, diags := b.PartialContent(schema)
|
||||
content, newBody, diags := b.PartialContent(schema)
|
||||
|
||||
// TODO: generate errors for the stuff we didn't use in PartialContent
|
||||
hiddenAttrs := newBody.(*body).hiddenAttrs
|
||||
|
||||
var nameSuggestions []string
|
||||
for _, attrS := range schema.Attributes {
|
||||
if _, ok := hiddenAttrs[attrS.Name]; !ok {
|
||||
// Only suggest an attribute name if we didn't use it already.
|
||||
nameSuggestions = append(nameSuggestions, attrS.Name)
|
||||
}
|
||||
}
|
||||
for _, blockS := range schema.Blocks {
|
||||
// Blocks can appear multiple times, so we'll suggest their type
|
||||
// names regardless of whether they've already been used.
|
||||
nameSuggestions = append(nameSuggestions, blockS.Type)
|
||||
}
|
||||
|
||||
for k, attr := range b.obj.Attrs {
|
||||
if _, ok := hiddenAttrs[k]; !ok {
|
||||
var fixItHint string
|
||||
suggestion := nameSuggestion(k, nameSuggestions)
|
||||
if suggestion != "" {
|
||||
fixItHint = fmt.Sprintf(" Did you mean %q?", suggestion)
|
||||
}
|
||||
|
||||
diags = append(diags, &zcl.Diagnostic{
|
||||
Severity: zcl.DiagError,
|
||||
Summary: "Extraneous JSON object property",
|
||||
Detail: fmt.Sprintf("No attribute or block type is named %q.%s", k, fixItHint),
|
||||
Subject: &attr.NameRange,
|
||||
Context: attr.Range().Ptr(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return content, diags
|
||||
}
|
||||
@ -61,7 +92,6 @@ func (b *body) PartialContent(schema *zcl.BodySchema) (*zcl.BodyContent, zcl.Bod
|
||||
Subject: &obj.OpenRange,
|
||||
})
|
||||
}
|
||||
usedNames[attrS.Name] = struct{}{}
|
||||
continue
|
||||
}
|
||||
content.Attributes[attrS.Name] = &zcl.Attribute{
|
||||
|
@ -527,7 +527,7 @@ func TestBodyPartialContent(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("%02d-%s", i, test.src), func(t *testing.T) {
|
||||
file, diags := Parse([]byte(test.src), "test.json")
|
||||
if len(diags) != 0 {
|
||||
t.Errorf("Parse produced diagnostics: %s", diags)
|
||||
t.Fatalf("Parse produced diagnostics: %s", diags)
|
||||
}
|
||||
got, _, diags := file.Body.PartialContent(test.schema)
|
||||
if len(diags) != test.diagCount {
|
||||
@ -543,3 +543,57 @@ func TestBodyPartialContent(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBodyContent(t *testing.T) {
|
||||
// We test most of the functionality already in TestBodyPartialContent, so
|
||||
// this test focuses on the handling of extraneous attributes.
|
||||
tests := []struct {
|
||||
src string
|
||||
schema *zcl.BodySchema
|
||||
diagCount int
|
||||
}{
|
||||
{
|
||||
`{"unknown": true}`,
|
||||
&zcl.BodySchema{},
|
||||
1,
|
||||
},
|
||||
{
|
||||
`{"unknow": true}`,
|
||||
&zcl.BodySchema{
|
||||
Attributes: []zcl.AttributeSchema{
|
||||
{
|
||||
Name: "unknown",
|
||||
},
|
||||
},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
`{"unknow": true, "unnown": true}`,
|
||||
&zcl.BodySchema{
|
||||
Attributes: []zcl.AttributeSchema{
|
||||
{
|
||||
Name: "unknown",
|
||||
},
|
||||
},
|
||||
},
|
||||
2,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%02d-%s", i, test.src), func(t *testing.T) {
|
||||
file, diags := Parse([]byte(test.src), "test.json")
|
||||
if len(diags) != 0 {
|
||||
t.Fatalf("Parse produced diagnostics: %s", diags)
|
||||
}
|
||||
_, diags = file.Body.Content(test.schema)
|
||||
if len(diags) != test.diagCount {
|
||||
t.Errorf("Wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
|
||||
for _, diag := range diags {
|
||||
t.Logf(" - %s", diag)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user