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  }