DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body using the facilities in the hcldec package. The returned specification is guaranteed to return a value of the same type returned by method ImpliedType, but it may contain null values if any of the block attributes are defined a
()
| 82 | // returned by method ImpliedType, but it may contain null values if any of the |
| 83 | // block attributes are defined as optional and/or computed respectively. |
| 84 | func (b *Block) DecoderSpec() hcldec.Spec { |
| 85 | ret := hcldec.ObjectSpec{} |
| 86 | if b == nil { |
| 87 | return ret |
| 88 | } |
| 89 | |
| 90 | if spec := decoderSpecCache.get(b); spec != nil { |
| 91 | return spec |
| 92 | } |
| 93 | |
| 94 | for name, attrS := range b.Attributes { |
| 95 | ret[name] = attrS.decoderSpec(name) |
| 96 | } |
| 97 | |
| 98 | for name, blockS := range b.BlockTypes { |
| 99 | if _, exists := ret[name]; exists { |
| 100 | // This indicates an invalid schema, since it's not valid to define |
| 101 | // both an attribute and a block type of the same name. We assume |
| 102 | // that the provider has already used something like |
| 103 | // InternalValidate to validate their schema. |
| 104 | continue |
| 105 | } |
| 106 | |
| 107 | childSpec := blockS.Block.DecoderSpec() |
| 108 | |
| 109 | switch blockS.Nesting { |
| 110 | case NestingSingle, NestingGroup: |
| 111 | ret[name] = &hcldec.BlockSpec{ |
| 112 | TypeName: name, |
| 113 | Nested: childSpec, |
| 114 | Required: blockS.MinItems == 1, |
| 115 | } |
| 116 | if blockS.Nesting == NestingGroup { |
| 117 | ret[name] = &hcldec.DefaultSpec{ |
| 118 | Primary: ret[name], |
| 119 | Default: &hcldec.LiteralSpec{ |
| 120 | Value: blockS.EmptyValue(), |
| 121 | }, |
| 122 | } |
| 123 | } |
| 124 | case NestingList: |
| 125 | // We prefer to use a list where possible, since it makes our |
| 126 | // implied type more complete, but if there are any |
| 127 | // dynamically-typed attributes inside we must use a tuple |
| 128 | // instead, at the expense of our type then not being predictable. |
| 129 | if blockS.Block.specType().HasDynamicTypes() { |
| 130 | ret[name] = &hcldec.BlockTupleSpec{ |
| 131 | TypeName: name, |
| 132 | Nested: childSpec, |
| 133 | MinItems: blockS.MinItems, |
| 134 | MaxItems: blockS.MaxItems, |
| 135 | } |
| 136 | } else { |
| 137 | ret[name] = &hcldec.BlockListSpec{ |
| 138 | TypeName: name, |
| 139 | Nested: childSpec, |
| 140 | MinItems: blockS.MinItems, |
| 141 | MaxItems: blockS.MaxItems, |