github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/lang/globalref/analyzer_meta_references_shortcuts.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package globalref 5 6 import ( 7 "fmt" 8 9 "github.com/terramate-io/tf/addrs" 10 "github.com/terramate-io/tf/lang" 11 ) 12 13 // ReferencesFromOutputValue returns all of the direct references from the 14 // value expression of the given output value. It doesn't include any indirect 15 // references. 16 func (a *Analyzer) ReferencesFromOutputValue(addr addrs.AbsOutputValue) []Reference { 17 mc := a.ModuleConfig(addr.Module) 18 if mc == nil { 19 return nil 20 } 21 oc := mc.Outputs[addr.OutputValue.Name] 22 if oc == nil { 23 return nil 24 } 25 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, oc.Expr) 26 return absoluteRefs(addr.Module, refs) 27 } 28 29 // ReferencesFromResourceInstance returns all of the direct references from the 30 // definition of the resource instance at the given address. It doesn't include 31 // any indirect references. 32 // 33 // The result doesn't directly include references from a "count" or "for_each" 34 // expression belonging to the associated resource, but it will include any 35 // references to count.index, each.key, or each.value that appear in the 36 // expressions which you can then, if you wish, resolve indirectly using 37 // Analyzer.MetaReferences. Alternatively, you can use 38 // Analyzer.ReferencesFromResourceRepetition to get that same result directly. 39 func (a *Analyzer) ReferencesFromResourceInstance(addr addrs.AbsResourceInstance) []Reference { 40 // Using MetaReferences for this is kinda overkill, since 41 // lang.ReferencesInBlock would be sufficient really, but 42 // this ensures we keep consistent in how we build the 43 // resulting absolute references and otherwise aside from 44 // some extra overhead this call boils down to a call to 45 // lang.ReferencesInBlock anyway. 46 fakeRef := Reference{ 47 ContainerAddr: addr.Module, 48 LocalRef: &addrs.Reference{ 49 Subject: addr.Resource, 50 }, 51 } 52 return a.MetaReferences(fakeRef) 53 } 54 55 // ReferencesFromResourceRepetition returns the references from the given 56 // resource's for_each or count expression, or an empty set if the resource 57 // doesn't use repetition. 58 // 59 // This is a special-case sort of helper for use in situations where an 60 // expression might refer to count.index, each.key, or each.value, and thus 61 // we say that it depends indirectly on the repetition expression. 62 func (a *Analyzer) ReferencesFromResourceRepetition(addr addrs.AbsResource) []Reference { 63 modCfg := a.ModuleConfig(addr.Module) 64 if modCfg == nil { 65 return nil 66 } 67 rc := modCfg.ResourceByAddr(addr.Resource) 68 if rc == nil { 69 return nil 70 } 71 72 // We're assuming here that resources can either have count or for_each, 73 // but never both, because that's a requirement enforced by the language 74 // decoder. But we'll assert it just to make sure we catch it if that 75 // changes for some reason. 76 if rc.ForEach != nil && rc.Count != nil { 77 panic(fmt.Sprintf("%s has both for_each and count", addr)) 78 } 79 80 switch { 81 case rc.ForEach != nil: 82 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, rc.ForEach) 83 return absoluteRefs(addr.Module, refs) 84 case rc.Count != nil: 85 refs, _ := lang.ReferencesInExpr(addrs.ParseRef, rc.Count) 86 return absoluteRefs(addr.Module, refs) 87 default: 88 return nil 89 } 90 }