Skip to content

Commit

Permalink
hcldec: New function ChildBlockTypes
Browse files Browse the repository at this point in the history
This function returns a map describing all of the child block types
declared inside a spec. This can be used for recursive decoding of bodies
using the low-level HCL API, though in most cases callers should just use
Decode which does recursive decoding of an entire nested structure in
a single call.
  • Loading branch information
apparentlymart committed Jan 27, 2018
1 parent 45c6cc8 commit 130b3c5
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 11 deletions.
25 changes: 25 additions & 0 deletions hcldec/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,28 @@ func ImpliedType(spec Spec) cty.Type {
func SourceRange(body hcl.Body, spec Spec) hcl.Range {
return sourceRange(body, nil, spec)
}

// ChildBlockTypes returns a map of all of the child block types declared
// by the given spec, with block type names as keys and the associated
// nested body specs as values.
func ChildBlockTypes(spec Spec) map[string]Spec {
ret := map[string]Spec{}

// visitSameBodyChildren walks through the spec structure, calling
// the given callback for each descendent spec encountered. We are
// interested in the specs that reference attributes and blocks.
var visit visitFunc
visit = func(s Spec) {
if bs, ok := s.(blockSpec); ok {
for _, blockS := range bs.blockHeaderSchemata() {
ret[blockS.Type] = bs.nestedSpec()
}
}

s.visitSameBodyChildren(visit)
}

visit(spec)

return ret
}
21 changes: 21 additions & 0 deletions hcldec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type attrSpec interface {
// blockSpec is implemented by specs that require blocks from the body.
type blockSpec interface {
blockHeaderSchemata() []hcl.BlockHeaderSchema
nestedSpec() Spec
}

// specNeedingVariables is implemented by specs that can use variables
Expand Down Expand Up @@ -298,6 +299,11 @@ func (s *BlockSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
}
}

// blockSpec implementation
func (s *BlockSpec) nestedSpec() Spec {
return s.Nested
}

// specNeedingVariables implementation
func (s *BlockSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
var childBlock *hcl.Block
Expand Down Expand Up @@ -409,6 +415,11 @@ func (s *BlockListSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
}
}

// blockSpec implementation
func (s *BlockListSpec) nestedSpec() Spec {
return s.Nested
}

// specNeedingVariables implementation
func (s *BlockListSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
var ret []hcl.Traversal
Expand Down Expand Up @@ -519,6 +530,11 @@ func (s *BlockSetSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
}
}

// blockSpec implementation
func (s *BlockSetSpec) nestedSpec() Spec {
return s.Nested
}

// specNeedingVariables implementation
func (s *BlockSetSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
var ret []hcl.Traversal
Expand Down Expand Up @@ -631,6 +647,11 @@ func (s *BlockMapSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
}
}

// blockSpec implementation
func (s *BlockMapSpec) nestedSpec() Spec {
return s.Nested
}

// specNeedingVariables implementation
func (s *BlockMapSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
var ret []hcl.Traversal
Expand Down
29 changes: 18 additions & 11 deletions hcldec/spec_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package hcldec

// Verify that all of our spec types implement the necessary interfaces
var objectSpecAsSpec Spec = ObjectSpec(nil)
var tupleSpecAsSpec Spec = TupleSpec(nil)
var attrSpecAsSpec Spec = (*AttrSpec)(nil)
var literalSpecAsSpec Spec = (*LiteralSpec)(nil)
var exprSpecAsSpec Spec = (*ExprSpec)(nil)
var blockSpecAsSpec Spec = (*BlockSpec)(nil)
var blockListSpecAsSpec Spec = (*BlockListSpec)(nil)
var blockSetSpecAsSpec Spec = (*BlockSetSpec)(nil)
var blockMapSpecAsSpec Spec = (*BlockMapSpec)(nil)
var blockLabelSpecAsSpec Spec = (*BlockLabelSpec)(nil)
var defaultSpecAsSpec Spec = (*DefaultSpec)(nil)
var _ Spec = ObjectSpec(nil)
var _ Spec = TupleSpec(nil)
var _ Spec = (*AttrSpec)(nil)
var _ Spec = (*LiteralSpec)(nil)
var _ Spec = (*ExprSpec)(nil)
var _ Spec = (*BlockSpec)(nil)
var _ Spec = (*BlockListSpec)(nil)
var _ Spec = (*BlockSetSpec)(nil)
var _ Spec = (*BlockMapSpec)(nil)
var _ Spec = (*BlockLabelSpec)(nil)
var _ Spec = (*DefaultSpec)(nil)

var _ attrSpec = (*AttrSpec)(nil)

var _ blockSpec = (*BlockSpec)(nil)
var _ blockSpec = (*BlockListSpec)(nil)
var _ blockSpec = (*BlockSetSpec)(nil)
var _ blockSpec = (*BlockMapSpec)(nil)

0 comments on commit 130b3c5

Please sign in to comment.