templates.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
  2. //go:build go1.23
  3. package templates
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "strings"
  8. "text/template"
  9. )
  10. // basicFunctions are the set of initial
  11. // functions provided to every template.
  12. var basicFunctions = template.FuncMap{
  13. "json": func(v any) string {
  14. buf := &bytes.Buffer{}
  15. enc := json.NewEncoder(buf)
  16. enc.SetEscapeHTML(false)
  17. err := enc.Encode(v)
  18. if err != nil {
  19. panic(err)
  20. }
  21. // Remove the trailing new line added by the encoder
  22. return strings.TrimSpace(buf.String())
  23. },
  24. "split": strings.Split,
  25. "join": strings.Join,
  26. "title": strings.Title, //nolint:nolintlint,staticcheck // strings.Title is deprecated, but we only use it for ASCII, so replacing with golang.org/x/text is out of scope
  27. "lower": strings.ToLower,
  28. "upper": strings.ToUpper,
  29. "pad": padWithSpace,
  30. "truncate": truncateWithLength,
  31. }
  32. // HeaderFunctions are used to created headers of a table.
  33. // This is a replacement of basicFunctions for header generation
  34. // because we want the header to remain intact.
  35. // Some functions like `pad` are not overridden (to preserve alignment
  36. // with the columns).
  37. var HeaderFunctions = template.FuncMap{
  38. "json": func(v string) string {
  39. return v
  40. },
  41. "split": func(v string, _ string) string {
  42. // we want the table header to show the name of the column, and not
  43. // split the table header itself. Using a different signature
  44. // here, and return a string instead of []string
  45. return v
  46. },
  47. "join": func(v string, _ string) string {
  48. // table headers are always a string, so use a different signature
  49. // for the "join" function (string instead of []string)
  50. return v
  51. },
  52. "title": func(v string) string {
  53. return v
  54. },
  55. "lower": func(v string) string {
  56. return v
  57. },
  58. "upper": func(v string) string {
  59. return v
  60. },
  61. "truncate": func(v string, _ int) string {
  62. return v
  63. },
  64. }
  65. // Parse creates a new anonymous template with the basic functions
  66. // and parses the given format.
  67. func Parse(format string) (*template.Template, error) {
  68. return NewParse("", format)
  69. }
  70. // New creates a new empty template with the provided tag and built-in
  71. // template functions.
  72. func New(tag string) *template.Template {
  73. return template.New(tag).Funcs(basicFunctions)
  74. }
  75. // NewParse creates a new tagged template with the basic functions
  76. // and parses the given format.
  77. func NewParse(tag, format string) (*template.Template, error) {
  78. return New(tag).Parse(format)
  79. }
  80. // padWithSpace adds whitespace to the input if the input is non-empty
  81. func padWithSpace(source string, prefix, suffix int) string {
  82. if source == "" {
  83. return source
  84. }
  85. return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
  86. }
  87. // truncateWithLength truncates the source string up to the length provided by the input
  88. func truncateWithLength(source string, length int) string {
  89. if len(source) < length {
  90. return source
  91. }
  92. return source[:length]
  93. }