// Copyright 2020-2026 Project Capsule Authors // SPDX-License-Identifier: Apache-2.0 package template import ( "bytes" "encoding/json" "maps" "strings" "text/template" "github.com/BurntSushi/toml" "github.com/go-sprout/sprout/sprigin" "sigs.k8s.io/yaml" ) // TxtFuncMap returns an aggregated template function map. Currently (custom functions + sprig). func ExtraFuncMap() template.FuncMap { funcMap := sprigin.FuncMap() extraFuncs := template.FuncMap{ "toToml": toTOML, "fromToml": fromTOML, "toYaml": toYAML, "fromYaml": fromYAML, "fromYamlArray": fromYAMLArray, "toJson": toJSON, "fromJson": fromJSON, "fromJsonArray": fromJSONArray, } maps.Copy(funcMap, extraFuncs) return funcMap } // toYAML takes an interface, marshals it to yaml, and returns a string. It will // always return a string, even on marshal error (empty string). // // This is designed to be called from a template. func toYAML(v any) string { data, err := yaml.Marshal(v) if err != nil { // Swallow errors inside of a template. return "" } return strings.TrimSuffix(string(data), "\n") } // fromYAML converts a YAML document into a map[string]interface{}. // // This is not a general-purpose YAML parser, and will not parse all valid // YAML documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string into // m["Error"] in the returned map. func fromYAML(str string) map[string]any { m := map[string]any{} if err := yaml.Unmarshal([]byte(str), &m); err != nil { m["Error"] = err.Error() } return m } // fromYAMLArray converts a YAML array into a []interface{}. // // This is not a general-purpose YAML parser, and will not parse all valid // YAML documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string as // the first and only item in the returned array. func fromYAMLArray(str string) []any { a := []any{} if err := yaml.Unmarshal([]byte(str), &a); err != nil { a = []any{err.Error()} } return a } // toTOML takes an interface, marshals it to toml, and returns a string. It will // always return a string, even on marshal error (empty string). // // This is designed to be called from a template. func toTOML(v any) string { b := bytes.NewBuffer(nil) e := toml.NewEncoder(b) err := e.Encode(v) if err != nil { return err.Error() } return b.String() } // fromTOML converts a TOML document into a map[string]interface{}. // // This is not a general-purpose TOML parser, and will not parse all valid // TOML documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string into // m["Error"] in the returned map. func fromTOML(str string) map[string]any { m := make(map[string]any) if err := toml.Unmarshal([]byte(str), &m); err != nil { m["Error"] = err.Error() } return m } // toJSON takes an interface, marshals it to json, and returns a string. It will // always return a string, even on marshal error (empty string). // // This is designed to be called from a template. func toJSON(v any) string { data, err := json.Marshal(v) if err != nil { // Swallow errors inside of a template. return "" } return string(data) } // fromJSON converts a JSON document into a map[string]interface{}. // // This is not a general-purpose JSON parser, and will not parse all valid // JSON documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string into // m["Error"] in the returned map. func fromJSON(str string) map[string]any { m := make(map[string]any) if err := json.Unmarshal([]byte(str), &m); err != nil { m["Error"] = err.Error() } return m } // fromJSONArray converts a JSON array into a []interface{}. // // This is not a general-purpose JSON parser, and will not parse all valid // JSON documents. Additionally, because its intended use is within templates // it tolerates errors. It will insert the returned error message string as // the first and only item in the returned array. func fromJSONArray(str string) []any { a := []any{} if err := json.Unmarshal([]byte(str), &a); err != nil { a = []any{err.Error()} } return a }