From 2453025a1ab19780b8debc4cc3d18ff815d3c98d Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Wed, 9 Jun 2021 17:24:10 -0700 Subject: [PATCH] addrs: Reference.DisplayString method We've ended up implementing something approximately like this in a few places now, so this is a centralized version that we can consolidate on moving forward, gradually removing that duplication. --- internal/addrs/parse_ref.go | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/internal/addrs/parse_ref.go b/internal/addrs/parse_ref.go index bb6842979..bd5bcc7c5 100644 --- a/internal/addrs/parse_ref.go +++ b/internal/addrs/parse_ref.go @@ -2,10 +2,12 @@ package addrs import ( "fmt" + "strings" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/terraform/internal/tfdiags" + "github.com/zclconf/go-cty/cty" ) // Reference describes a reference to an address with source location @@ -16,6 +18,43 @@ type Reference struct { Remaining hcl.Traversal } +// DisplayString returns a string that approximates the subject and remaining +// traversal of the reciever in a way that resembles the Terraform language +// syntax that could've produced it. +// +// It's not guaranteed to actually be a valid Terraform language expression, +// since the intended use here is primarily for UI messages such as +// diagnostics. +func (r *Reference) DisplayString() string { + if len(r.Remaining) == 0 { + // Easy case: we can just return the subject's string. + return r.Subject.String() + } + + var ret strings.Builder + ret.WriteString(r.Subject.String()) + for _, step := range r.Remaining { + switch tStep := step.(type) { + case hcl.TraverseRoot: + ret.WriteString(tStep.Name) + case hcl.TraverseAttr: + ret.WriteByte('.') + ret.WriteString(tStep.Name) + case hcl.TraverseIndex: + ret.WriteByte('[') + switch tStep.Key.Type() { + case cty.String: + ret.WriteString(fmt.Sprintf("%q", tStep.Key.AsString())) + case cty.Number: + bf := tStep.Key.AsBigFloat() + ret.WriteString(bf.Text('g', 10)) + } + ret.WriteByte(']') + } + } + return ret.String() +} + // ParseRef attempts to extract a referencable address from the prefix of the // given traversal, which must be an absolute traversal or this function // will panic.