package main import ( "fmt" "os" "github.com/davecgh/go-spew/spew" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/hcl/v2/hclparse" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" ) func main() { err := realMain() if err != nil { fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) os.Exit(1) } } type MapDetails struct { Width int `cty:"width"` FontSize int `cty:"font_size"` } type NestedMapDetails struct { Size *Size `cty:"size"` } type Size struct { Width int `cty:"width"` FontSize int `cty:"font_size"` } // type NestedMapDetails struct { // Size struct { // Width int `cty:"width"` // FontSize int `cty:"font_size"` // } `cty:"size"` // } func realMain() error { var mapDetailsSpec = &hcldec.ObjectSpec{ "width": &hcldec.AttrSpec{ Name: "width", Required: false, Type: cty.Number, }, "font_size": &hcldec.AttrSpec{ Name: "font_size", Required: false, Type: cty.Number, }, } var data = ` width = 100 font_size = 9 ` val, err := do([]byte(data), "test.hcl", mapDetailsSpec) if err != nil { return err } var mapDetails MapDetails err = gocty.FromCtyValue(val, &mapDetails) if err != nil { return err } spew.Dump(mapDetails) var nestedMapDetailsSpec = &hcldec.ObjectSpec{ "size": &hcldec.BlockListSpec{ TypeName: "size", Nested: &hcldec.ObjectSpec{ "width": &hcldec.AttrSpec{ Name: "width", Required: false, Type: cty.Number, }, "font_size": &hcldec.AttrSpec{ Name: "font_size", Required: false, Type: cty.Number, }, }, }, } data = `size { width = 100 font_size = 9 } ` val, err = do([]byte(data), "test.hcl", nestedMapDetailsSpec) if err != nil { return err } var nestedMapDetails NestedMapDetails err = gocty.FromCtyValue(val, &nestedMapDetails) if err != nil { return err } spew.Dump(nestedMapDetails) return nil } func do(data []byte, filename string, spec *hcldec.ObjectSpec) (cty.Value, error) { parser := hclparse.NewParser() f, diags := parser.ParseHCL([]byte(data), filename) val, moreDiags := hcldec.Decode(f.Body, spec, nil) diags = append(diags, moreDiags...) if diags.HasErrors() { wr := hcl.NewDiagnosticTextWriter( os.Stderr, // writer to send messages to parser.Files(), // the parser's file cache, for source snippets 100, // wrapping width true, // generate colored/highlighted output ) wr.WriteDiagnostics(diags) return val, fmt.Errorf("failure during decoding") } return val, nil }