github.com/hartzell/terraform@v0.8.6-0.20180503104400-0cc9e050ecd4/config/configschema/decoder_spec.go (about)

     1  package configschema
     2  
     3  import (
     4  	"github.com/hashicorp/hcl2/hcldec"
     5  	"github.com/zclconf/go-cty/cty"
     6  )
     7  
     8  var mapLabelNames = []string{"key"}
     9  
    10  // DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body
    11  // using the facilities in the hcldec package.
    12  //
    13  // The returned specification is guaranteed to return a value of the same type
    14  // returned by method ImpliedType, but it may contain null or unknown values if
    15  // any of the block attributes are defined as optional and/or computed
    16  // respectively.
    17  func (b *Block) DecoderSpec() hcldec.Spec {
    18  	ret := hcldec.ObjectSpec{}
    19  	if b == nil {
    20  		return ret
    21  	}
    22  
    23  	for name, attrS := range b.Attributes {
    24  		switch {
    25  		case attrS.Computed && attrS.Optional:
    26  			// In this special case we use an unknown value as a default
    27  			// to get the intended behavior that the result is computed
    28  			// unless it has been explicitly set in config.
    29  			ret[name] = &hcldec.DefaultSpec{
    30  				Primary: &hcldec.AttrSpec{
    31  					Name: name,
    32  					Type: attrS.Type,
    33  				},
    34  				Default: &hcldec.LiteralSpec{
    35  					Value: cty.UnknownVal(attrS.Type),
    36  				},
    37  			}
    38  		case attrS.Computed:
    39  			ret[name] = &hcldec.LiteralSpec{
    40  				Value: cty.UnknownVal(attrS.Type),
    41  			}
    42  		default:
    43  			ret[name] = &hcldec.AttrSpec{
    44  				Name:     name,
    45  				Type:     attrS.Type,
    46  				Required: attrS.Required,
    47  			}
    48  		}
    49  	}
    50  
    51  	for name, blockS := range b.BlockTypes {
    52  		if _, exists := ret[name]; exists {
    53  			// This indicates an invalid schema, since it's not valid to
    54  			// define both an attribute and a block type of the same name.
    55  			// However, we don't raise this here since it's checked by
    56  			// InternalValidate.
    57  			continue
    58  		}
    59  
    60  		childSpec := blockS.Block.DecoderSpec()
    61  
    62  		switch blockS.Nesting {
    63  		case NestingSingle:
    64  			ret[name] = &hcldec.BlockSpec{
    65  				TypeName: name,
    66  				Nested:   childSpec,
    67  				Required: blockS.MinItems == 1 && blockS.MaxItems >= 1,
    68  			}
    69  		case NestingList:
    70  			ret[name] = &hcldec.BlockListSpec{
    71  				TypeName: name,
    72  				Nested:   childSpec,
    73  				MinItems: blockS.MinItems,
    74  				MaxItems: blockS.MaxItems,
    75  			}
    76  		case NestingSet:
    77  			ret[name] = &hcldec.BlockSetSpec{
    78  				TypeName: name,
    79  				Nested:   childSpec,
    80  				MinItems: blockS.MinItems,
    81  				MaxItems: blockS.MaxItems,
    82  			}
    83  		case NestingMap:
    84  			ret[name] = &hcldec.BlockMapSpec{
    85  				TypeName:   name,
    86  				Nested:     childSpec,
    87  				LabelNames: mapLabelNames,
    88  			}
    89  		default:
    90  			// Invalid nesting type is just ignored. It's checked by
    91  			// InternalValidate.
    92  			continue
    93  		}
    94  	}
    95  
    96  	return ret
    97  }