diff --git a/earlydecoder/decoder_test.go b/earlydecoder/decoder_test.go index 6215c4dc..016160bb 100644 --- a/earlydecoder/decoder_test.go +++ b/earlydecoder/decoder_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/go-version" "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/ext/typeexpr" "github.com/hashicorp/hcl/v2/hclsyntax" tfaddr "github.com/hashicorp/terraform-registry-address" "github.com/hashicorp/terraform-schema/backend" @@ -811,6 +812,42 @@ variable "name" { }, nil, }, + { + "variables with optional type values", + ` +variable "name" { + type = object({ + foo = optional(string, "food") + bar = optional(number) + }) +}`, + &module.Meta{ + Path: path, + ProviderReferences: map[module.ProviderRef]tfaddr.Provider{}, + ProviderRequirements: map[tfaddr.Provider]version.Constraints{}, + Variables: map[string]module.Variable{ + "name": { + Type: cty.Object(map[string]cty.Type{ + "foo": cty.String, + "bar": cty.Number, + }), + TypeDefaults: &typeexpr.Defaults{ + Type: cty.Object(map[string]cty.Type{ + "foo": cty.String, + "bar": cty.Number, + }), + DefaultValues: map[string]cty.Value{ + "foo": cty.StringVal("food"), + }, + }, + }, + }, + Outputs: map[string]module.Output{}, + Filenames: []string{"test.tf"}, + ModuleCalls: map[string]module.DeclaredModuleCall{}, + }, + nil, + }, { "empty output", ` diff --git a/earlydecoder/load_module.go b/earlydecoder/load_module.go index f2e0982e..583c1c8d 100644 --- a/earlydecoder/load_module.go +++ b/earlydecoder/load_module.go @@ -214,8 +214,9 @@ func loadModuleFromFile(file *hcl.File, mod *decodedModule) hcl.Diagnostics { diags = append(diags, valDiags...) } varType := cty.DynamicPseudoType + var defaults *typeexpr.Defaults if attr, defined := content.Attributes["type"]; defined { - varType, valDiags = typeexpr.TypeConstraint(attr.Expr) + varType, defaults, valDiags = typeexpr.TypeConstraintWithDefaults(attr.Expr) diags = append(diags, valDiags...) } if attr, defined := content.Attributes["sensitive"]; defined { @@ -239,6 +240,7 @@ func loadModuleFromFile(file *hcl.File, mod *decodedModule) hcl.Diagnostics { val = cty.DynamicVal } } + defaultValue = val } } @@ -247,6 +249,7 @@ func loadModuleFromFile(file *hcl.File, mod *decodedModule) hcl.Diagnostics { Description: description, IsSensitive: isSensitive, DefaultValue: defaultValue, + TypeDefaults: defaults, } case "output": content, _, contentDiags := block.Body.PartialContent(outputSchema) diff --git a/module/variable.go b/module/variable.go index 856ab370..a996e021 100644 --- a/module/variable.go +++ b/module/variable.go @@ -1,6 +1,7 @@ package module import ( + "github.com/hashicorp/hcl/v2/ext/typeexpr" "github.com/zclconf/go-cty/cty" ) @@ -15,4 +16,11 @@ type Variable struct { // DefaultValue represents default value if one is defined // and is decodable without errors, else cty.NilVal DefaultValue cty.Value + + // TypeDefaults represents any default values for optional object + // attributes assuming Type is of cty.Object and has defaults. + // + // Any relationships between DefaultValue & TypeDefaults are left + // for downstream to deal with using e.g. TypeDefaults.Apply(). + TypeDefaults *typeexpr.Defaults }