github.com/mineiros-io/terradoc@v0.0.9-0.20220711062319-018bd4ae81f5/internal/parsers/hclparser/hclattribute.go (about) 1 package hclparser 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/hcl/v2" 9 "github.com/hashicorp/hcl/v2/hclwrite" 10 "github.com/mineiros-io/terradoc/internal/entities" 11 "github.com/zclconf/go-cty/cty" 12 "github.com/zclconf/go-cty/cty/convert" 13 ctyjson "github.com/zclconf/go-cty/cty/json" 14 ) 15 16 type HCLAttribute struct { 17 *hcl.Attribute 18 } 19 20 func (a *HCLAttribute) String() (string, error) { 21 if a == nil { 22 return "", nil 23 } 24 25 val, diags := a.Expr.Value(nil) 26 if diags.HasErrors() { 27 return "", fmt.Errorf("getting string value for %q: %v", a.Name, diags.Errs()) 28 } 29 30 // use cty's convert pkg to prevent panic if value is not a string 31 strVal, err := convert.Convert(val, cty.String) 32 if err != nil { 33 return "", fmt.Errorf("could not convert %q to string: %v", a.Name, err) 34 } 35 36 return strings.TrimSpace(strVal.AsString()), nil 37 } 38 39 func (a *HCLAttribute) Bool() (bool, error) { 40 if a == nil { 41 return false, nil 42 } 43 44 val, diags := a.Expr.Value(nil) 45 if diags.HasErrors() { 46 return false, fmt.Errorf("fetching bool value for %q: %v", a.Name, diags.Errs()) 47 } 48 49 // use cty's convert pkg to prevent panic if value is not a bool 50 boolVal, err := convert.Convert(val, cty.Bool) 51 if err != nil { 52 return false, fmt.Errorf("could not convert %q to bool: %s", a.Name, err) 53 } 54 55 return boolVal.True(), nil 56 } 57 58 func (a *HCLAttribute) Keyword() string { 59 return hcl.ExprAsKeyword(a.Expr) 60 } 61 62 func (a *HCLAttribute) RawJSON() (json.RawMessage, error) { 63 if a == nil { 64 return nil, nil 65 } 66 67 if len(a.Expr.Variables()) > 0 { 68 return getRawVariables(a.Expr), nil 69 } 70 71 val, diags := a.Expr.Value(nil) 72 if diags.HasErrors() { 73 return nil, fmt.Errorf("could not fetch JSON value for %q: %v", a.Name, diags.Errs()) 74 } 75 76 // convert cty.Value to SimpleJSONValue to get the correct decoding of its internal value 77 jsonVal := ctyjson.SimpleJSONValue{Value: val} 78 79 src, err := jsonVal.MarshalJSON() 80 if err != nil { 81 return nil, err 82 } 83 84 return json.RawMessage(src), nil 85 } 86 87 func (a *HCLAttribute) VarType() (entities.Type, error) { 88 if a == nil { 89 return entities.Type{}, nil 90 } 91 92 return GetVarTypeFromExpression(a.Expr) 93 } 94 95 func (a *HCLAttribute) VarTypeFromString() (entities.Type, error) { 96 if a == nil { 97 return entities.Type{}, nil 98 } 99 100 val, diags := a.Expr.Value(nil) 101 if diags.HasErrors() { 102 return entities.Type{}, fmt.Errorf("could not fetch type string value for %q: %v", a.Name, diags.Errs()) 103 } 104 105 return getVarTypeFromString(val.AsString(), a.Range.Start) 106 } 107 108 func getRawVariables(expr hcl.Expression) json.RawMessage { 109 var varValue []byte 110 111 for _, exprVar := range expr.Variables() { 112 tk := hclwrite.TokensForTraversal(exprVar) 113 114 varValue = append(varValue, tk.Bytes()...) 115 } 116 117 return varValue 118 } 119 120 func (a *HCLAttribute) OutputType() (entities.Type, error) { 121 if a == nil { 122 return entities.Type{}, nil 123 } 124 125 return GetOutputTypeFromExpression(a.Expr) 126 }