summaryrefslogtreecommitdiff
path: root/hcldec
diff options
context:
space:
mode:
authorMartin Atkins <mart@degeneration.co.uk>2017-10-03 11:57:53 -0700
committerMartin Atkins <mart@degeneration.co.uk>2017-10-03 11:57:53 -0700
commita4ee7188ad9ea5f18d11fe8b5469da7ac7c29de0 (patch)
tree927757ce22059f0df4e97380ff4def2483cdaa77 /hcldec
parentf44382c4fab57666c486c77a8b89c9ea00be08ba (diff)
hcldec: New DefaultSpec specification
This is a wrapper that allows a default value to be applied if a primary spec results in a null value.
Diffstat (limited to 'hcldec')
-rw-r--r--hcldec/public_test.go32
-rw-r--r--hcldec/spec.go30
-rw-r--r--hcldec/spec_test.go1
3 files changed, 62 insertions, 1 deletions
diff --git a/hcldec/public_test.go b/hcldec/public_test.go
index afd483f..79ef710 100644
--- a/hcldec/public_test.go
+++ b/hcldec/public_test.go
@@ -5,8 +5,8 @@ import (
"reflect"
"testing"
- "github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/hashicorp/hcl2/hcl"
+ "github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/zclconf/go-cty/cty"
)
@@ -57,6 +57,36 @@ func TestDecode(t *testing.T) {
0,
},
{
+ "a = 1\n",
+ &DefaultSpec{
+ Primary: &AttrSpec{
+ Name: "a",
+ Type: cty.Number,
+ },
+ Default: &LiteralSpec{
+ Value: cty.NumberIntVal(10),
+ },
+ },
+ nil,
+ cty.NumberIntVal(1),
+ 0,
+ },
+ {
+ "",
+ &DefaultSpec{
+ Primary: &AttrSpec{
+ Name: "a",
+ Type: cty.Number,
+ },
+ Default: &LiteralSpec{
+ Value: cty.NumberIntVal(10),
+ },
+ },
+ nil,
+ cty.NumberIntVal(10),
+ 0,
+ },
+ {
"a = \"1\"\n",
&AttrSpec{
Name: "a",
diff --git a/hcldec/spec.go b/hcldec/spec.go
index b385642..3dc9fdb 100644
--- a/hcldec/spec.go
+++ b/hcldec/spec.go
@@ -566,3 +566,33 @@ func (s *BlockLabelSpec) sourceRange(content *hcl.BodyContent, block *hcl.Block)
return block.LabelRanges[s.Index]
}
+
+// DefaultSpec is a spec that wraps two specs, evaluating the primary first
+// and then evaluating the default if the primary returns a null value.
+type DefaultSpec struct {
+ Primary Spec
+ Default Spec
+}
+
+func (s *DefaultSpec) visitSameBodyChildren(cb visitFunc) {
+ cb(s.Primary)
+ cb(s.Default)
+}
+
+func (s *DefaultSpec) decode(content *hcl.BodyContent, block *hcl.Block, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+ val, diags := s.Primary.decode(content, block, ctx)
+ if val.IsNull() {
+ var moreDiags hcl.Diagnostics
+ val, moreDiags = s.Default.decode(content, block, ctx)
+ diags = append(diags, moreDiags...)
+ }
+ return val, diags
+}
+
+func (s *DefaultSpec) sourceRange(content *hcl.BodyContent, block *hcl.Block) hcl.Range {
+ // We can't tell from here which of the two specs will ultimately be used
+ // in our result, so we'll just assume the first. This is usually the right
+ // choice because the default is often a literal spec that doesn't have a
+ // reasonable source range to return anyway.
+ return s.Primary.sourceRange(content, block)
+}
diff --git a/hcldec/spec_test.go b/hcldec/spec_test.go
index 4982ffe..164bdaa 100644
--- a/hcldec/spec_test.go
+++ b/hcldec/spec_test.go
@@ -11,3 +11,4 @@ var blockListSpecAsSpec Spec = (*BlockListSpec)(nil)
var blockSetSpecAsSpec Spec = (*BlockSetSpec)(nil)
var blockMapSpecAsSpec Spec = (*BlockMapSpec)(nil)
var blockLabelSpecAsSpec Spec = (*BlockLabelSpec)(nil)
+var defaultSepcAsSpec Spec = (*DefaultSpec)(nil)