hashicorp / hcl2

Former temporary home for experimental new version of HCL

Home Page:https://github.com/hashicorp/hcl

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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!