Question: how to decode a custom type and validate it?
schu opened this issue · comments
Hey, given the following example code:
package main
import (
"fmt"
"github.com/hashicorp/hcl2/gohcl"
"github.com/hashicorp/hcl2/hclparse"
)
const configSrc = `
config {
type = "foo"
}
`
type MyType string
const (
Foo MyType = "foo"
Bar = "bar"
)
type Config struct {
Type string `hcl:"type,attr"`
}
type Root struct {
Config Config `hcl:"config,block"`
}
func main() {
parser := hclparse.NewParser()
file, diags := parser.ParseHCL([]byte(configSrc), "demo.hcl")
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("%+v\n", diag)
}
return
}
configBody := file.Body
var root Root
diags = gohcl.DecodeBody(configBody, nil, &root)
if len(diags) != 0 {
for _, diag := range diags {
fmt.Printf("%+v\n", diag)
}
return
}
fmt.Printf("%+v\n", root)
}
If only Foo
or Bar
should be accepted values for Config.Type
, is there a way to enforce that through hcl means (e.g. hcldec.Decode
with an AttrSpec
?) or would I need to validate myself after decoding into string
?
Hi @schu!
Indeed HCL does not provide a general solution for all possible validations; HCL's own functionality is primarily concerned with checking the "shape" of the configuration: correct usage of block structure, correct argument names, etc. Aside from the simple type checking implied by the conversion to Go types, validation of values is the application's responsibility.
One tricky edge right now is that decoding into Go types necessarily loses the source location information (because there's nowhere to store it in the resulting Go values), which makes it a little tricky to report errors with particular attributes in a helpful way. I expect we'll add some new functionality to gohcl
for that in future, but for now a workaround is to use hcldec.SourceRange
with an AttrSpec
to find a reasonable location for that attribute value when returning an error:
rng := hcldec.SourceRange(configBody, &hcldec.Spec{Name: "type", Type: cty.String})
Thanks for conforming and the detailed response!