blob: 2b1b0cacbfe86fd1584ff04b9aa90b9b6841759a [file] [log] [blame]
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
}