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