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  }