github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/jsonformat/computed/renderers/object.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  	"github.com/terramate-io/tf/plans"
    13  )
    14  
    15  var _ computed.DiffRenderer = (*objectRenderer)(nil)
    16  
    17  func Object(attributes map[string]computed.Diff) computed.DiffRenderer {
    18  	return &objectRenderer{
    19  		attributes:         attributes,
    20  		overrideNullSuffix: true,
    21  	}
    22  }
    23  
    24  func NestedObject(attributes map[string]computed.Diff) computed.DiffRenderer {
    25  	return &objectRenderer{
    26  		attributes:         attributes,
    27  		overrideNullSuffix: false,
    28  	}
    29  }
    30  
    31  type objectRenderer struct {
    32  	NoWarningsRenderer
    33  
    34  	attributes         map[string]computed.Diff
    35  	overrideNullSuffix bool
    36  }
    37  
    38  func (renderer objectRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string {
    39  	if len(renderer.attributes) == 0 {
    40  		return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts))
    41  	}
    42  
    43  	attributeOpts := opts.Clone()
    44  	attributeOpts.OverrideNullSuffix = renderer.overrideNullSuffix
    45  
    46  	// We need to keep track of our keys in two ways. The first is the order in
    47  	// which we will display them. The second is a mapping to their safely
    48  	// escaped equivalent.
    49  
    50  	maximumKeyLen := 0
    51  	var keys []string
    52  	escapedKeys := make(map[string]string)
    53  	for key := range renderer.attributes {
    54  		keys = append(keys, key)
    55  		escapedKey := EnsureValidAttributeName(key)
    56  		escapedKeys[key] = escapedKey
    57  		if maximumKeyLen < len(escapedKey) {
    58  			maximumKeyLen = len(escapedKey)
    59  		}
    60  	}
    61  	sort.Strings(keys)
    62  
    63  	unchangedAttributes := 0
    64  	var buf bytes.Buffer
    65  	buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts)))
    66  	for _, key := range keys {
    67  		attribute := renderer.attributes[key]
    68  
    69  		if importantAttribute(key) {
    70  			importantAttributeOpts := attributeOpts.Clone()
    71  			importantAttributeOpts.ShowUnchangedChildren = true
    72  
    73  			for _, warning := range attribute.WarningsHuman(indent+1, importantAttributeOpts) {
    74  				buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
    75  			}
    76  			buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, importantAttributeOpts), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, importantAttributeOpts)))
    77  			continue
    78  		}
    79  
    80  		if attribute.Action == plans.NoOp && !opts.ShowUnchangedChildren {
    81  			// Don't render NoOp operations when we are compact display.
    82  			unchangedAttributes++
    83  			continue
    84  		}
    85  
    86  		for _, warning := range attribute.WarningsHuman(indent+1, opts) {
    87  			buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning))
    88  		}
    89  		buf.WriteString(fmt.Sprintf("%s%s%-*s = %s\n", formatIndent(indent+1), writeDiffActionSymbol(attribute.Action, attributeOpts), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, attributeOpts)))
    90  	}
    91  
    92  	if unchangedAttributes > 0 {
    93  		buf.WriteString(fmt.Sprintf("%s%s%s\n", formatIndent(indent+1), writeDiffActionSymbol(plans.NoOp, opts), unchanged("attribute", unchangedAttributes, opts)))
    94  	}
    95  
    96  	buf.WriteString(fmt.Sprintf("%s%s}%s", formatIndent(indent), writeDiffActionSymbol(plans.NoOp, opts), nullSuffix(diff.Action, opts)))
    97  	return buf.String()
    98  }