File: type_string.go

package info (click to toggle)
golang-github-zclconf-go-cty-debug 0.0~git20191215.b22d67c-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 108 kB
  • sloc: makefile: 2
file content (112 lines) | stat: -rw-r--r-- 3,111 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package ctydebug

import (
	"fmt"
	"sort"
	"strings"

	"github.com/zclconf/go-cty/cty"
)

// TypeString returns a string representation of a given type that is
// reminiscent of Go syntax calling into the cty package but is mainly
// intended for easy human inspection of values in tests, debug output, etc.
//
// The resulting string will include newlines and indentation in order to
// increase the readability of complex structures. It always ends with a
// newline, so you can print this result directly to your output.
func TypeString(ty cty.Type) string {
	var b strings.Builder
	writeType(ty, &b, 0)
	b.WriteByte('\n') // always end with a newline for easier printing
	return b.String()
}

func writeType(ty cty.Type, b *strings.Builder, indent int) {
	switch {
	case ty == cty.NilType:
		b.WriteString("cty.NilType")
		return
	case ty.IsObjectType():
		atys := ty.AttributeTypes()
		if len(atys) == 0 {
			b.WriteString("cty.EmptyObject")
			return
		}
		attrNames := make([]string, 0, len(atys))
		for name := range atys {
			attrNames = append(attrNames, name)
		}
		sort.Strings(attrNames)
		b.WriteString("cty.Object(map[string]cty.Type{\n")
		indent++
		for _, name := range attrNames {
			aty := atys[name]
			b.WriteString(indentSpaces(indent))
			fmt.Fprintf(b, "%q: ", name)
			writeType(aty, b, indent)
			b.WriteString(",\n")
		}
		indent--
		b.WriteString(indentSpaces(indent))
		b.WriteString("})")
	case ty.IsTupleType():
		etys := ty.TupleElementTypes()
		if len(etys) == 0 {
			b.WriteString("cty.EmptyTuple")
			return
		}
		b.WriteString("cty.Tuple([]cty.Type{\n")
		indent++
		for _, ety := range etys {
			b.WriteString(indentSpaces(indent))
			writeType(ety, b, indent)
			b.WriteString(",\n")
		}
		indent--
		b.WriteString(indentSpaces(indent))
		b.WriteString("})")
	case ty.IsCollectionType():
		ety := ty.ElementType()
		switch {
		case ty.IsListType():
			b.WriteString("cty.List(")
		case ty.IsMapType():
			b.WriteString("cty.Map(")
		case ty.IsSetType():
			b.WriteString("cty.Set(")
		default:
			// At the time of writing there are no other collection types,
			// but we'll be robust here and just pass through the GoString
			// of anything we don't recognize.
			b.WriteString(ty.GoString())
			return
		}
		// Because object and tuple types render split over multiple
		// lines, a collection type container around them can end up
		// being hard to see when scanning, so we'll generate some extra
		// indentation to make a collection of structural type more visually
		// distinct from the structural type alone.
		complexElem := ety.IsObjectType() || ety.IsTupleType()
		if complexElem {
			indent++
			b.WriteString("\n")
			b.WriteString(indentSpaces(indent))
		}
		writeType(ty.ElementType(), b, indent)
		if complexElem {
			indent--
			b.WriteString(",\n")
			b.WriteString(indentSpaces(indent))
		}
		b.WriteString(")")
	default:
		// For any other type we'll just use its GoString and assume it'll
		// follow the usual GoString conventions.
		b.WriteString(ty.GoString())
	}
}

func indentSpaces(level int) string {
	return strings.Repeat("    ", level)
}