| package configschema |
| |
| import ( |
| "github.com/hashicorp/hcl2/hcldec" |
| "github.com/zclconf/go-cty/cty" |
| ) |
| |
| var mapLabelNames = []string{"key"} |
| |
| // 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 or unknown values if |
| // any of the block attributes are defined as optional and/or computed |
| // respectively. |
| func (b *Block) DecoderSpec() hcldec.Spec { |
| ret := hcldec.ObjectSpec{} |
| if b == nil { |
| return ret |
| } |
| |
| for name, attrS := range b.Attributes { |
| switch { |
| case attrS.Computed && attrS.Optional: |
| // In this special case we use an unknown value as a default |
| // to get the intended behavior that the result is computed |
| // unless it has been explicitly set in config. |
| ret[name] = &hcldec.DefaultSpec{ |
| Primary: &hcldec.AttrSpec{ |
| Name: name, |
| Type: attrS.Type, |
| }, |
| Default: &hcldec.LiteralSpec{ |
| Value: cty.UnknownVal(attrS.Type), |
| }, |
| } |
| case attrS.Computed: |
| ret[name] = &hcldec.LiteralSpec{ |
| Value: cty.UnknownVal(attrS.Type), |
| } |
| default: |
| ret[name] = &hcldec.AttrSpec{ |
| Name: name, |
| Type: attrS.Type, |
| Required: attrS.Required, |
| } |
| } |
| } |
| |
| for name, blockS := range b.BlockTypes { |
| if _, exists := ret[name]; exists { |
| // This indicates an invalid schema, since it's not valid to |
| // define both an attribute and a block type of the same name. |
| // However, we don't raise this here since it's checked by |
| // InternalValidate. |
| continue |
| } |
| |
| childSpec := blockS.Block.DecoderSpec() |
| |
| switch blockS.Nesting { |
| case NestingSingle: |
| ret[name] = &hcldec.BlockSpec{ |
| TypeName: name, |
| Nested: childSpec, |
| Required: blockS.MinItems == 1 && blockS.MaxItems >= 1, |
| } |
| case NestingList: |
| ret[name] = &hcldec.BlockListSpec{ |
| TypeName: name, |
| Nested: childSpec, |
| MinItems: blockS.MinItems, |
| MaxItems: blockS.MaxItems, |
| } |
| case NestingSet: |
| ret[name] = &hcldec.BlockSetSpec{ |
| TypeName: name, |
| Nested: childSpec, |
| MinItems: blockS.MinItems, |
| MaxItems: blockS.MaxItems, |
| } |
| case NestingMap: |
| ret[name] = &hcldec.BlockMapSpec{ |
| TypeName: name, |
| Nested: childSpec, |
| LabelNames: mapLabelNames, |
| } |
| default: |
| // Invalid nesting type is just ignored. It's checked by |
| // InternalValidate. |
| continue |
| } |
| } |
| |
| return ret |
| } |