Skip to content

Commit

Permalink
hcldec: BlockLabelSpec decoding
Browse files Browse the repository at this point in the history
A BlockLabelSpec can be placed in the nested spec structure of one of the
block specs to require and obtain labels on that block.

This is a more generic methodology than BlockMapSpec since it allows the
result to be a list or set with the labels inside the values, rather than
forcing all the label tuples to be unique and losing the ordering by
collapsing into a map structure.
  • Loading branch information
apparentlymart committed Oct 3, 2017
1 parent a6dff4e commit 0d6247f
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 63 deletions.
21 changes: 21 additions & 0 deletions hcldec/block_labels.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package hcldec

import (
"github.com/hashicorp/hcl2/hcl"
)

type blockLabel struct {
Value string
Range hcl.Range
}

func labelsForBlock(block *hcl.Block) []blockLabel {
ret := make([]blockLabel, len(block.Labels))
for i := range block.Labels {
ret[i] = blockLabel{
Value: block.Labels[i],
Range: block.LabelRanges[i],
}
}
return ret
}
8 changes: 4 additions & 4 deletions hcldec/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/zclconf/go-cty/cty"
)

func decode(body hcl.Body, block *hcl.Block, ctx *hcl.EvalContext, spec Spec, partial bool) (cty.Value, hcl.Body, hcl.Diagnostics) {
func decode(body hcl.Body, blockLabels []blockLabel, ctx *hcl.EvalContext, spec Spec, partial bool) (cty.Value, hcl.Body, hcl.Diagnostics) {
schema := ImpliedSchema(spec)

var content *hcl.BodyContent
Expand All @@ -18,15 +18,15 @@ func decode(body hcl.Body, block *hcl.Block, ctx *hcl.EvalContext, spec Spec, pa
content, diags = body.Content(schema)
}

val, valDiags := spec.decode(content, block, ctx)
val, valDiags := spec.decode(content, blockLabels, ctx)
diags = append(diags, valDiags...)

return val, leftovers, diags
}

func sourceRange(body hcl.Body, block *hcl.Block, spec Spec) hcl.Range {
func sourceRange(body hcl.Body, blockLabels []blockLabel, spec Spec) hcl.Range {
schema := ImpliedSchema(spec)
content, _, _ := body.PartialContent(schema)

return spec.sourceRange(content, block)
return spec.sourceRange(content, blockLabels)
}
1 change: 1 addition & 0 deletions hcldec/gob.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ func init() {
gob.Register((*BlockListSpec)(nil))
gob.Register((*BlockSetSpec)(nil))
gob.Register((*BlockMapSpec)(nil))
gob.Register((*BlockLabelSpec)(nil))
gob.Register((*DefaultSpec)(nil))
}
125 changes: 125 additions & 0 deletions hcldec/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,54 @@ b {
cty.EmptyObjectVal,
0,
},
{
`
b "baz" {
}
`,
&BlockSpec{
TypeName: "b",
Nested: &BlockLabelSpec{
Index: 0,
Name: "name",
},
},
nil,
cty.StringVal("baz"),
0,
},
{
`
b "baz" {}
b "foo" {}
`,
&BlockSpec{
TypeName: "b",
Nested: &BlockLabelSpec{
Index: 0,
Name: "name",
},
},
nil,
cty.StringVal("baz"),
1, // duplicate "b" block
},
{
`
b {
}
`,
&BlockSpec{
TypeName: "b",
Nested: &BlockLabelSpec{
Index: 0,
Name: "name",
},
},
nil,
cty.NullVal(cty.DynamicPseudoType),
1, // missing name label
},
{
``,
&BlockSpec{
Expand Down Expand Up @@ -218,6 +266,22 @@ b {}
},
{
`
b "foo" {}
b "bar" {}
`,
&BlockListSpec{
TypeName: "b",
Nested: &BlockLabelSpec{
Name: "name",
Index: 0,
},
},
nil,
cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
0,
},
{
`
b {}
b {}
b {}
Expand Down Expand Up @@ -261,6 +325,31 @@ b {}
},
{
`
b "foo" "bar" {}
b "bar" "baz" {}
`,
&BlockSetSpec{
TypeName: "b",
Nested: TupleSpec{
&BlockLabelSpec{
Name: "name",
Index: 1,
},
&BlockLabelSpec{
Name: "type",
Index: 0,
},
},
},
nil,
cty.SetVal([]cty.Value{
cty.TupleVal([]cty.Value{cty.StringVal("bar"), cty.StringVal("foo")}),
cty.TupleVal([]cty.Value{cty.StringVal("baz"), cty.StringVal("bar")}),
}),
0,
},
{
`
b "foo" {}
b "bar" {}
`,
Expand Down Expand Up @@ -388,6 +477,42 @@ b "foo" "bar" {}
cty.MapVal(map[string]cty.Value{"foo": cty.MapVal(map[string]cty.Value{"bar": cty.EmptyObjectVal})}),
1, // duplicate b block
},
{
`
b "foo" "bar" {}
b "bar" "baz" {}
`,
&BlockMapSpec{
TypeName: "b",
LabelNames: []string{"type"},
Nested: &BlockLabelSpec{
Name: "name",
Index: 0,
},
},
nil,
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
"bar": cty.StringVal("baz"),
}),
0,
},
{
`
b "foo" {}
`,
&BlockMapSpec{
TypeName: "b",
LabelNames: []string{"type"},
Nested: &BlockLabelSpec{
Name: "name",
Index: 0,
},
},
nil,
cty.MapValEmpty(cty.DynamicPseudoType),
1, // missing name
},
}

for i, test := range tests {
Expand Down
Loading

0 comments on commit 0d6247f

Please sign in to comment.