mirror of
https://github.com/terraform-docs/terraform-docs.git
synced 2026-03-27 04:48:33 +07:00
160 lines
4.9 KiB
Go
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
|
|
}
|