github.com/terraform-linters/tflint@v0.51.2-0.20240520175844-3750771571b6/terraform/tfhcl/variables_hclext.go (about) 1 package tfhcl 2 3 import ( 4 "github.com/hashicorp/hcl/v2" 5 "github.com/hashicorp/hcl/v2/ext/dynblock" 6 "github.com/terraform-linters/tflint-plugin-sdk/hclext" 7 ) 8 9 // ExpandVariablesHCLExt is a wrapper around dynblock.WalkVariables that 10 // uses the given hclext.BodySchema to automatically drive the recursive 11 // walk through nested blocks in the given body. 12 // 13 // Note that it's a wrapper around ExpandVariables, not WalkExpandVariables. 14 // This package evaluates expressions immediately on expansion, so we always 15 // need all variables to expand. It also implicitly walks count/for_each to 16 // support expansion by meta-arguments. 17 func ExpandVariablesHCLExt(body hcl.Body, schema *hclext.BodySchema) []hcl.Traversal { 18 rootNode := dynblock.WalkVariables(body) 19 return walkVariablesWithHCLExt(rootNode, schema) 20 } 21 22 func walkVariablesWithHCLExt(node dynblock.WalkVariablesNode, schema *hclext.BodySchema) []hcl.Traversal { 23 vars, children := node.Visit(extendSchema(asHCLSchema(schema))) 24 25 if len(children) > 0 { 26 childSchemas := childBlockTypes(schema) 27 for _, child := range children { 28 if childSchema, exists := childSchemas[child.BlockTypeName]; exists { 29 vars = append(vars, walkVariablesWithHCLExt(child.Node, childSchema.Body)...) 30 } 31 } 32 } 33 34 return vars 35 } 36 37 func asHCLSchema(in *hclext.BodySchema) *hcl.BodySchema { 38 out := &hcl.BodySchema{} 39 if in == nil || in.Mode == hclext.SchemaJustAttributesMode { 40 return out 41 } 42 43 out.Attributes = make([]hcl.AttributeSchema, len(in.Attributes)) 44 for idx, attr := range in.Attributes { 45 out.Attributes[idx] = hcl.AttributeSchema{Name: attr.Name, Required: attr.Required} 46 } 47 out.Blocks = make([]hcl.BlockHeaderSchema, len(in.Blocks)) 48 for idx, block := range in.Blocks { 49 out.Blocks[idx] = hcl.BlockHeaderSchema{Type: block.Type, LabelNames: block.LabelNames} 50 } 51 return out 52 } 53 54 func extendSchema(schema *hcl.BodySchema) *hcl.BodySchema { 55 schema.Attributes = append(schema.Attributes, hcl.AttributeSchema{Name: "count"}, hcl.AttributeSchema{Name: "for_each"}) 56 return schema 57 } 58 59 func childBlockTypes(schema *hclext.BodySchema) map[string]hclext.BlockSchema { 60 ret := make(map[string]hclext.BlockSchema) 61 for _, block := range schema.Blocks { 62 ret[block.Type] = block 63 } 64 return ret 65 }