github.com/opentofu/opentofu@v1.7.1/internal/lang/blocktoattr/variables.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package blocktoattr 7 8 import ( 9 "github.com/hashicorp/hcl/v2" 10 "github.com/hashicorp/hcl/v2/ext/dynblock" 11 "github.com/hashicorp/hcl/v2/hcldec" 12 "github.com/opentofu/opentofu/internal/configs/configschema" 13 ) 14 15 // ExpandedVariables finds all of the global variables referenced in the 16 // given body with the given schema while taking into account the possibilities 17 // both of "dynamic" blocks being expanded and the possibility of certain 18 // attributes being written instead as nested blocks as allowed by the 19 // FixUpBlockAttrs function. 20 // 21 // This function exists to allow variables to be analyzed prior to dynamic 22 // block expansion while also dealing with the fact that dynamic block expansion 23 // might in turn produce nested blocks that are subject to FixUpBlockAttrs. 24 // 25 // This is intended as a drop-in replacement for dynblock.VariablesHCLDec, 26 // which is itself a drop-in replacement for hcldec.Variables. 27 func ExpandedVariables(body hcl.Body, schema *configschema.Block) []hcl.Traversal { 28 rootNode := dynblock.WalkVariables(body) 29 return walkVariables(rootNode, body, schema) 30 } 31 32 func walkVariables(node dynblock.WalkVariablesNode, body hcl.Body, schema *configschema.Block) []hcl.Traversal { 33 givenRawSchema := hcldec.ImpliedSchema(schema.DecoderSpec()) 34 ambiguousNames := ambiguousNames(schema) 35 effectiveRawSchema := effectiveSchema(givenRawSchema, body, ambiguousNames, false) 36 vars, children := node.Visit(effectiveRawSchema) 37 38 for _, child := range children { 39 if blockS, exists := schema.BlockTypes[child.BlockTypeName]; exists { 40 vars = append(vars, walkVariables(child.Node, child.Body(), &blockS.Block)...) 41 } else if attrS, exists := schema.Attributes[child.BlockTypeName]; exists && attrS.Type.IsCollectionType() && attrS.Type.ElementType().IsObjectType() { 42 // ☝️Check for collection type before element type, because if this is a mis-placed reference, 43 // a panic here will prevent other useful diags from being elevated to show the user what to fix 44 synthSchema := SchemaForCtyElementType(attrS.Type.ElementType()) 45 vars = append(vars, walkVariables(child.Node, child.Body(), synthSchema)...) 46 } 47 } 48 49 return vars 50 }