github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/jsonformat/computed/renderers/map.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package renderers
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"sort"
    10  
    11  	"github.com/terramate-io/tf/command/jsonformat/computed"
    12  
    13  	"github.com/terramate-io/tf/plans"
    14  )
    15  
    16  var _ computed.DiffRenderer = (*mapRenderer)(nil)
    17  
    18  func Map(elements map[string]computed.Diff) computed.DiffRenderer {
    19  	return &mapRenderer{
    20  		elements:  elements,
    21  		alignKeys: true,
    22  	}
    23  }
    24  
    25  func NestedMap(elements map[string]computed.Diff) computed.DiffRenderer {
    26  	return &mapRenderer{
    27  		elements:                  elements,
    28  		overrideNullSuffix:        true,
    29  		overrideForcesReplacement: true,
    30  	}
    31  }
    32  
    33  type mapRenderer struct {
    34  	NoWarningsRenderer
    35  
    36  	elements map[string]computed.Diff
    37  
    38  	overrideNullSuffix        bool
    39  	overrideForcesReplacement bool
    40  	alignKeys                 bool
    41  }
    42  
    43  func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
    44  	forcesReplacementSelf := diff.Replace && !renderer.overrideForcesReplacement
    45  	forcesReplacementChildren := diff.Replace && renderer.overrideForcesReplacement
    46  
    47  	if len(renderer.elements) == 0 {
    48  		return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(forcesReplacementSelf, opts))
    49  	}
    50  
    51  	// Sort the map elements by key, so we have a deterministic ordering in
    52  	// the output.
    53  	var keys []string
    54  
    55  	// We need to make sure the keys are capable of rendering properly.
    56  	escapedKeys := make(map[string]string)
    57  
    58  	maximumKeyLen := 0
    59  	for key := range renderer.elements {
    60  		keys = append(keys, key)
    61  
    62  		escapedKey := hclEscapeString(key)
    63  		escapedKeys[key] = escapedKey
    64  		if maximumKeyLen < len(escapedKey) {
    65  			maximumKeyLen = len(escapedKey)
    66  		}
    67  	}
    68  	sort.Strings(keys)
    69  
    70  	unchangedElements := 0
    71  
    72  	elementOpts := opts.Clone()
    73  	elementOpts.OverrideNullSuffix = diff.Action == plans.Delete || renderer.overrideNullSuffix
    74  	elementOpts.OverrideForcesReplacement = forcesReplacementChildren
    75  
    76  	var buf bytes.Buffer
    77  	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(forcesReplacementSelf, opts)))
    78  	for _, key := range keys {
    79  		element := renderer.elements[key]
    80  
    81  		if element.Action == plans.NoOp && !opts.ShowUnchangedChildren {
    82  			// Don't render NoOp operations when we are compact display.
    83  			unchangedElements++
    84  			continue
    85  		}
    86  
    87  		for _, warning := range element.WarningsHuman(indent+1, opts) {
    88  			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
    89  		}
    90  		// Only show commas between elements for objects.
    91  		comma := ""
    92  		if _, ok := element.Renderer.(*objectRenderer); ok {
    93  			comma = ","
    94  		}
    95  
    96  		if renderer.alignKeys {
    97  			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s%s\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, elementOpts), maximumKeyLen, escapedKeys[key], element.RenderHuman(indent+1, elementOpts), comma))
    98  		} else {
    99  			buf.WriteString(fmt.Sprintf("%s%s%s = %s%s\n", formatIndent(indent+1), writeDiffActionSymbol(element.Action, elementOpts), escapedKeys[key], element.RenderHuman(indent+1, elementOpts), comma))
   100  		}
   101  
   102  	}
   103  
   104  	if unchangedElements > 0 {
   105  		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("element", unchangedElements, opts)))
   106  	}
   107  
   108  	buf.WriteString(fmt.Sprintf("%s%s}%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
   109  	return buf.String()
   110  }