1/*
2Copyright 2021 The terraform-docs Authors.
3Licensed under the MIT license (the "License"); you may not
4use this file except in compliance with the License.
5
6You may obtain a copy of the License at the LICENSE file in
7the root directory of this source tree.
8*/
9
10package format
11
12import (
13	_ "embed" //nolint
14	"fmt"
15	"reflect"
16	"strings"
17	gotemplate "text/template"
18
19	"github.com/terraform-docs/terraform-docs/internal/types"
20	"github.com/terraform-docs/terraform-docs/print"
21	"github.com/terraform-docs/terraform-docs/template"
22	"github.com/terraform-docs/terraform-docs/terraform"
23)
24
25//go:embed templates/tfvars_hcl.tmpl
26var tfvarsHCLTpl []byte
27
28// tfvarsHCL represents Terraform tfvars HCL format.
29type tfvarsHCL struct {
30	*generator
31
32	config   *print.Config
33	template *template.Template
34}
35
36var padding []int
37
38// NewTfvarsHCL returns new instance of TfvarsHCL.
39func NewTfvarsHCL(config *print.Config) Type {
40	tt := template.New(config, &template.Item{
41		Name: "tfvars",
42		Text: string(tfvarsHCLTpl),
43	})
44	tt.CustomFunc(gotemplate.FuncMap{
45		"align": func(s string, i int) string {
46			return fmt.Sprintf("%-*s", padding[i], s)
47		},
48		"value": func(s string) string {
49			if s == "" || s == "null" {
50				return "\"\""
51			}
52			return s
53		},
54		"convertToComment": func(s types.String) string {
55			return "\n# " + strings.ReplaceAll(string(s), "\n", "\n# ")
56		},
57		"showDescription": func() bool {
58			return config.Settings.Description
59		},
60	})
61
62	return &tfvarsHCL{
63		generator: newGenerator(config, false),
64		config:    config,
65		template:  tt,
66	}
67}
68
69// Generate a Terraform module as Terraform tfvars HCL.
70func (h *tfvarsHCL) Generate(module *terraform.Module) error {
71	alignments(module.Inputs, h.config)
72
73	rendered, err := h.template.Render("tfvars", module)
74	if err != nil {
75		return err
76	}
77
78	h.generator.funcs(withContent(strings.TrimSuffix(sanitize(rendered), "\n")))
79
80	return nil
81}
82
83func isMultilineFormat(input *terraform.Input) bool {
84	isList := input.Type == "list" || reflect.TypeOf(input.Default).Name() == "List"
85	isMap := input.Type == "map" || reflect.TypeOf(input.Default).Name() == "Map"
86	return (isList || isMap) && input.Default.Length() > 0
87}
88
89func alignments(inputs []*terraform.Input, config *print.Config) {
90	padding = make([]int, len(inputs))
91	maxlen := 0
92	index := 0
93	for i, input := range inputs {
94		isDescribed := config.Settings.Description && input.Description.Length() > 0
95		l := len(input.Name)
96		if isMultilineFormat(input) || isDescribed {
97			for j := index; j < i; j++ {
98				padding[j] = maxlen
99			}
100			padding[i] = l
101			maxlen = 0
102			index = i + 1
103		} else if l > maxlen {
104			maxlen = l
105		}
106	}
107	for i := index; i < len(inputs); i++ {
108		padding[i] = maxlen
109	}
110}
111
112func init() {
113	register(map[string]initializerFn{
114		"tfvars hcl": NewTfvarsHCL,
115	})
116}
117