Files
terraform-docs/format/util.go
Khosrow Moossavi 5727f8b412 Preserve whitespaces of provided content and template
Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com>
2022-01-07 18:14:21 -05:00

160 lines
4.9 KiB
Go

/*
Copyright 2021 The terraform-docs Authors.
Licensed under the MIT license (the "License"); you may not
use this file except in compliance with the License.
You may obtain a copy of the License at the LICENSE file in
the root directory of this source tree.
*/
package format
import (
"embed"
"fmt"
"io/fs"
"regexp"
"strings"
"github.com/terraform-docs/terraform-docs/print"
"github.com/terraform-docs/terraform-docs/template"
"github.com/terraform-docs/terraform-docs/terraform"
)
// sanitize cleans a Markdown document to soothe linters.
func sanitize(markdown string) string {
result := markdown
// Preserve double spaces at the end of the line
result = regexp.MustCompile(` {2}(\r?\n)`).ReplaceAllString(result, "‡‡‡DOUBLESPACES‡‡‡$1")
// Remove trailing spaces from the end of lines
result = regexp.MustCompile(` +(\r?\n)`).ReplaceAllString(result, "$1")
result = regexp.MustCompile(` +$`).ReplaceAllLiteralString(result, "")
// Preserve double spaces at the end of the line
result = regexp.MustCompile(`‡‡‡DOUBLESPACES‡‡‡(\r?\n)`).ReplaceAllString(result, " $1")
// Remove blank line with only double spaces in it
result = regexp.MustCompile(`(\r?\n) (\r?\n)`).ReplaceAllString(result, "$1")
// Remove multiple consecutive blank lines
result = regexp.MustCompile(`(\r?\n){3,}`).ReplaceAllString(result, "$1$1")
result = regexp.MustCompile(`(\r?\n){2,}$`).ReplaceAllString(result, "")
return result
}
// PrintFencedCodeBlock prints codes in fences, it automatically detects if
// the input 'code' contains '\n' it will use multi line fence, otherwise it
// wraps the 'code' inside single-tick block.
// If the fenced is multi-line it also appens an extra '\n` at the end and
// returns true accordingly, otherwise returns false for non-carriage return.
func PrintFencedCodeBlock(code string, language string) (string, bool) {
if strings.Contains(code, "\n") {
return fmt.Sprintf("\n\n```%s\n%s\n```\n", language, code), true
}
return fmt.Sprintf("`%s`", code), false
}
// PrintFencedAsciidocCodeBlock prints codes in fences, it automatically detects if
// the input 'code' contains '\n' it will use multi line fence, otherwise it
// wraps the 'code' inside single-tick block.
// If the fenced is multi-line it also appens an extra '\n` at the end and
// returns true accordingly, otherwise returns false for non-carriage return.
func PrintFencedAsciidocCodeBlock(code string, language string) (string, bool) {
if strings.Contains(code, "\n") {
return fmt.Sprintf("\n[source,%s]\n----\n%s\n----\n", language, code), true
}
return fmt.Sprintf("`%s`", code), false
}
// readTemplateItems reads all static formatter .tmpl files prefixed by specific string
// from an embed file system.
func readTemplateItems(efs embed.FS, prefix string) []*template.Item {
items := make([]*template.Item, 0)
files, err := fs.ReadDir(efs, "templates")
if err != nil {
return items
}
for _, f := range files {
content, err := efs.ReadFile("templates/" + f.Name())
if err != nil {
continue
}
name := f.Name()
name = strings.ReplaceAll(name, prefix, "")
name = strings.ReplaceAll(name, "_", "")
name = strings.ReplaceAll(name, ".tmpl", "")
if name == "" {
name = "all"
}
items = append(items, &template.Item{
Name: name,
Text: string(content),
TrimSpace: true,
})
}
return items
}
// copySections sets the sections that'll be printed
func copySections(config *print.Config, src *terraform.Module) *terraform.Module {
dest := &terraform.Module{
Header: "",
Footer: "",
Inputs: make([]*terraform.Input, 0),
ModuleCalls: make([]*terraform.ModuleCall, 0),
Outputs: make([]*terraform.Output, 0),
Providers: make([]*terraform.Provider, 0),
Requirements: make([]*terraform.Requirement, 0),
Resources: make([]*terraform.Resource, 0),
}
if config.Sections.Header {
dest.Header = src.Header
}
if config.Sections.Footer {
dest.Footer = src.Footer
}
if config.Sections.Inputs {
dest.Inputs = src.Inputs
}
if config.Sections.ModuleCalls {
dest.ModuleCalls = src.ModuleCalls
}
if config.Sections.Outputs {
dest.Outputs = src.Outputs
}
if config.Sections.Providers {
dest.Providers = src.Providers
}
if config.Sections.Requirements {
dest.Requirements = src.Requirements
}
if config.Sections.Resources || config.Sections.DataSources {
dest.Resources = filterResourcesByMode(config, src.Resources)
}
return dest
}
// filterResourcesByMode returns the managed or data resources defined by the show argument
func filterResourcesByMode(config *print.Config, module []*terraform.Resource) []*terraform.Resource {
resources := make([]*terraform.Resource, 0)
for _, r := range module {
if config.Sections.Resources && r.Mode == "managed" {
resources = append(resources, r)
}
if config.Sections.DataSources && r.Mode == "data" {
resources = append(resources, r)
}
}
return resources
}