github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/configs/configschema/implied_type.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package configschema
     5  
     6  import (
     7  	"github.com/hashicorp/hcl/v2/hcldec"
     8  	"github.com/zclconf/go-cty/cty"
     9  )
    10  
    11  // ImpliedType returns the cty.Type that would result from decoding a
    12  // configuration block using the receiving block schema.
    13  //
    14  // The type returned from Block.ImpliedType differs from the type returned by
    15  // hcldec.ImpliedType in that there will be no objects with optional
    16  // attributes, since this value is not to be used for the decoding of
    17  // configuration.
    18  //
    19  // ImpliedType always returns a result, even if the given schema is
    20  // inconsistent. Code that creates configschema.Block objects should be
    21  // tested using the InternalValidate method to detect any inconsistencies
    22  // that would cause this method to fall back on defaults and assumptions.
    23  func (b *Block) ImpliedType() cty.Type {
    24  	return b.specType().WithoutOptionalAttributesDeep()
    25  }
    26  
    27  // specType returns the cty.Type used for decoding a configuration
    28  // block using the receiving block schema. This is the type used internally by
    29  // hcldec to decode configuration.
    30  func (b *Block) specType() cty.Type {
    31  	if b == nil {
    32  		return cty.EmptyObject
    33  	}
    34  
    35  	return hcldec.ImpliedType(b.DecoderSpec())
    36  }
    37  
    38  // ContainsSensitive returns true if any of the attributes of the receiving
    39  // block or any of its descendent blocks are marked as sensitive.
    40  //
    41  // Blocks themselves cannot be sensitive as a whole -- sensitivity is a
    42  // per-attribute idea -- but sometimes we want to include a whole object
    43  // decoded from a block in some UI output, and that is safe to do only if
    44  // none of the contained attributes are sensitive.
    45  func (b *Block) ContainsSensitive() bool {
    46  	for _, attrS := range b.Attributes {
    47  		if attrS.Sensitive {
    48  			return true
    49  		}
    50  		if attrS.NestedType != nil && attrS.NestedType.ContainsSensitive() {
    51  			return true
    52  		}
    53  	}
    54  	for _, blockS := range b.BlockTypes {
    55  		if blockS.ContainsSensitive() {
    56  			return true
    57  		}
    58  	}
    59  	return false
    60  }
    61  
    62  // ImpliedType returns the cty.Type that would result from decoding a Block's
    63  // ImpliedType and getting the resulting AttributeType.
    64  //
    65  // ImpliedType always returns a result, even if the given schema is
    66  // inconsistent. Code that creates configschema.Object objects should be tested
    67  // using the InternalValidate method to detect any inconsistencies that would
    68  // cause this method to fall back on defaults and assumptions.
    69  func (a *Attribute) ImpliedType() cty.Type {
    70  	if a.NestedType != nil {
    71  		return a.NestedType.specType().WithoutOptionalAttributesDeep()
    72  	}
    73  	return a.Type
    74  }
    75  
    76  // ImpliedType returns the cty.Type that would result from decoding a
    77  // NestedType Attribute using the receiving block schema.
    78  //
    79  // ImpliedType always returns a result, even if the given schema is
    80  // inconsistent. Code that creates configschema.Object objects should be tested
    81  // using the InternalValidate method to detect any inconsistencies that would
    82  // cause this method to fall back on defaults and assumptions.
    83  func (o *Object) ImpliedType() cty.Type {
    84  	return o.specType().WithoutOptionalAttributesDeep()
    85  }
    86  
    87  // specType returns the cty.Type used for decoding a NestedType Attribute using
    88  // the receiving block schema.
    89  func (o *Object) specType() cty.Type {
    90  	if o == nil {
    91  		return cty.EmptyObject
    92  	}
    93  
    94  	attrTys := make(map[string]cty.Type, len(o.Attributes))
    95  	for name, attrS := range o.Attributes {
    96  		if attrS.NestedType != nil {
    97  			attrTys[name] = attrS.NestedType.specType()
    98  		} else {
    99  			attrTys[name] = attrS.Type
   100  		}
   101  	}
   102  	optAttrs := listOptionalAttrsFromObject(o)
   103  
   104  	var ret cty.Type
   105  	if len(optAttrs) > 0 {
   106  		ret = cty.ObjectWithOptionalAttrs(attrTys, optAttrs)
   107  	} else {
   108  		ret = cty.Object(attrTys)
   109  	}
   110  	switch o.Nesting {
   111  	case NestingSingle:
   112  		return ret
   113  	case NestingList:
   114  		return cty.List(ret)
   115  	case NestingMap:
   116  		return cty.Map(ret)
   117  	case NestingSet:
   118  		return cty.Set(ret)
   119  	default: // Should never happen
   120  		return cty.EmptyObject
   121  	}
   122  }
   123  
   124  // ContainsSensitive returns true if any of the attributes of the receiving
   125  // Object are marked as sensitive.
   126  func (o *Object) ContainsSensitive() bool {
   127  	for _, attrS := range o.Attributes {
   128  		if attrS.Sensitive {
   129  			return true
   130  		}
   131  		if attrS.NestedType != nil && attrS.NestedType.ContainsSensitive() {
   132  			return true
   133  		}
   134  	}
   135  	return false
   136  }