package engine import ( "bytes" "fmt" "strings" "text/template" ) type Renderer struct{} func NewRenderer() *Renderer { return &Renderer{} } func (r *Renderer) Render(tmplContent string, data map[string]interface{}) (string, error) { tmpl, err := template.New("notify"). Option("missingkey=zero"). Funcs(template.FuncMap{"line": templateLine}). Parse(tmplContent) if err != nil { return "", fmt.Errorf("parse template: %w", err) } var buf bytes.Buffer if err := tmpl.Execute(&buf, data); err != nil { return "", fmt.Errorf("execute template: %w", err) } return buf.String(), nil } // templateLine renders "label:value\n" or empty if value is missing/zero. func templateLine(label string, v any) string { if isEmptyValue(v) { return "" } return label + ":" + fmt.Sprint(v) + "\n" } func isEmptyValue(v any) bool { switch t := v.(type) { case nil: return true case string: return strings.TrimSpace(t) == "" case bool: return !t case int: return t == 0 case int32: return t == 0 case int64: return t == 0 case float32: return t == 0 case float64: return t == 0 default: return false } }