| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- package sprig
- import (
- "encoding/base32"
- "encoding/base64"
- "fmt"
- "golang.org/x/text/cases"
- "golang.org/x/text/language"
- "reflect"
- "strconv"
- "strings"
- )
- // base64encode encodes a string to base64 using standard encoding.
- //
- // Parameters:
- // - v: The string to encode
- //
- // Returns:
- // - string: The base64 encoded string
- func base64encode(v string) string {
- return base64.StdEncoding.EncodeToString([]byte(v))
- }
- // base64decode decodes a base64 encoded string.
- // If the input is not valid base64, it returns the error message as a string.
- //
- // Parameters:
- // - v: The base64 encoded string to decode
- //
- // Returns:
- // - string: The decoded string, or an error message if decoding fails
- func base64decode(v string) string {
- data, err := base64.StdEncoding.DecodeString(v)
- if err != nil {
- return err.Error()
- }
- return string(data)
- }
- // base32encode encodes a string to base32 using standard encoding.
- //
- // Parameters:
- // - v: The string to encode
- //
- // Returns:
- // - string: The base32 encoded string
- func base32encode(v string) string {
- return base32.StdEncoding.EncodeToString([]byte(v))
- }
- // base32decode decodes a base32 encoded string.
- // If the input is not valid base32, it returns the error message as a string.
- //
- // Parameters:
- // - v: The base32 encoded string to decode
- //
- // Returns:
- // - string: The decoded string, or an error message if decoding fails
- func base32decode(v string) string {
- data, err := base32.StdEncoding.DecodeString(v)
- if err != nil {
- return err.Error()
- }
- return string(data)
- }
- // quote adds double quotes around each non-nil string in the input and joins them with spaces.
- // This uses Go's %q formatter which handles escaping special characters.
- //
- // Parameters:
- // - str: A variadic list of values to quote
- //
- // Returns:
- // - string: The quoted strings joined with spaces
- func quote(str ...any) string {
- out := make([]string, 0, len(str))
- for _, s := range str {
- if s != nil {
- out = append(out, fmt.Sprintf("%q", strval(s)))
- }
- }
- return strings.Join(out, " ")
- }
- // squote adds single quotes around each non-nil value in the input and joins them with spaces.
- // Unlike quote, this doesn't escape special characters.
- //
- // Parameters:
- // - str: A variadic list of values to quote
- //
- // Returns:
- // - string: The single-quoted values joined with spaces
- func squote(str ...any) string {
- out := make([]string, 0, len(str))
- for _, s := range str {
- if s != nil {
- out = append(out, fmt.Sprintf("'%v'", s))
- }
- }
- return strings.Join(out, " ")
- }
- // cat concatenates all non-nil values into a single string.
- // Nil values are removed before concatenation.
- //
- // Parameters:
- // - v: A variadic list of values to concatenate
- //
- // Returns:
- // - string: The concatenated string
- func cat(v ...any) string {
- v = removeNilElements(v)
- r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
- return fmt.Sprintf(r, v...)
- }
- // indent adds a specified number of spaces at the beginning of each line in a string.
- //
- // Parameters:
- // - spaces: The number of spaces to add
- // - v: The string to indent
- //
- // Returns:
- // - string: The indented string
- func indent(spaces int, v string) string {
- pad := strings.Repeat(" ", spaces)
- return pad + strings.Replace(v, "\n", "\n"+pad, -1)
- }
- // nindent adds a newline followed by an indented string.
- // It's a shorthand for "\n" + indent(spaces, v).
- //
- // Parameters:
- // - spaces: The number of spaces to add
- // - v: The string to indent
- //
- // Returns:
- // - string: A newline followed by the indented string
- func nindent(spaces int, v string) string {
- return "\n" + indent(spaces, v)
- }
- // replace replaces all occurrences of a substring with another substring.
- //
- // Parameters:
- // - old: The substring to replace
- // - new: The replacement substring
- // - src: The source string
- //
- // Returns:
- // - string: The resulting string after all replacements
- func replace(old, new, src string) string {
- return strings.Replace(src, old, new, -1)
- }
- // plural returns the singular or plural form of a word based on the count.
- // If count is 1, it returns the singular form, otherwise it returns the plural form.
- //
- // Parameters:
- // - one: The singular form of the word
- // - many: The plural form of the word
- // - count: The count to determine which form to use
- //
- // Returns:
- // - string: Either the singular or plural form based on the count
- func plural(one, many string, count int) string {
- if count == 1 {
- return one
- }
- return many
- }
- // strslice converts a value to a slice of strings.
- // It handles various input types:
- // - []string: returned as is
- // - []any: converted to []string, skipping nil values
- // - arrays and slices: converted to []string, skipping nil values
- // - nil: returns an empty slice
- // - anything else: returns a single-element slice with the string representation
- //
- // Parameters:
- // - v: The value to convert to a string slice
- //
- // Returns:
- // - []string: A slice of strings
- func strslice(v any) []string {
- switch v := v.(type) {
- case []string:
- return v
- case []any:
- b := make([]string, 0, len(v))
- for _, s := range v {
- if s != nil {
- b = append(b, strval(s))
- }
- }
- return b
- default:
- val := reflect.ValueOf(v)
- switch val.Kind() {
- case reflect.Array, reflect.Slice:
- l := val.Len()
- b := make([]string, 0, l)
- for i := 0; i < l; i++ {
- value := val.Index(i).Interface()
- if value != nil {
- b = append(b, strval(value))
- }
- }
- return b
- default:
- if v == nil {
- return []string{}
- }
- return []string{strval(v)}
- }
- }
- }
- // removeNilElements creates a new slice with all nil elements removed.
- // This is a helper function used by other functions like cat.
- //
- // Parameters:
- // - v: The slice to process
- //
- // Returns:
- // - []any: A new slice with all nil elements removed
- func removeNilElements(v []any) []any {
- newSlice := make([]any, 0, len(v))
- for _, i := range v {
- if i != nil {
- newSlice = append(newSlice, i)
- }
- }
- return newSlice
- }
- // strval converts any value to a string.
- // It handles various types:
- // - string: returned as is
- // - []byte: converted to string
- // - error: returns the error message
- // - fmt.Stringer: calls the String() method
- // - anything else: uses fmt.Sprintf("%v", v)
- //
- // Parameters:
- // - v: The value to convert to a string
- //
- // Returns:
- // - string: The string representation of the value
- func strval(v any) string {
- switch v := v.(type) {
- case string:
- return v
- case []byte:
- return string(v)
- case error:
- return v.Error()
- case fmt.Stringer:
- return v.String()
- default:
- return fmt.Sprintf("%v", v)
- }
- }
- // trunc truncates a string to a specified length.
- // If c is positive, it returns the first c characters.
- // If c is negative, it returns the last |c| characters.
- // If the string is shorter than the requested length, it returns the original string.
- //
- // Parameters:
- // - c: The number of characters to keep (positive from start, negative from end)
- // - s: The string to truncate
- //
- // Returns:
- // - string: The truncated string
- func trunc(c int, s string) string {
- if c < 0 && len(s)+c > 0 {
- return s[len(s)+c:]
- }
- if c >= 0 && len(s) > c {
- return s[:c]
- }
- return s
- }
- // title converts a string to title case.
- // This uses the English language rules for capitalization.
- //
- // Parameters:
- // - s: The string to convert
- //
- // Returns:
- // - string: The string in title case
- func title(s string) string {
- return cases.Title(language.English).String(s)
- }
- // join concatenates the elements of a slice with a separator.
- // The input is first converted to a string slice using strslice.
- //
- // Parameters:
- // - sep: The separator to use between elements
- // - v: The value to join (will be converted to a string slice)
- //
- // Returns:
- // - string: The joined string
- func join(sep string, v any) string {
- return strings.Join(strslice(v), sep)
- }
- // split splits a string by a separator and returns a map.
- // The keys in the map are "_0", "_1", etc., corresponding to the position of each part.
- //
- // Parameters:
- // - sep: The separator to split on
- // - orig: The string to split
- //
- // Returns:
- // - map[string]string: A map with keys "_0", "_1", etc. and values being the split parts
- func split(sep, orig string) map[string]string {
- parts := strings.Split(orig, sep)
- res := make(map[string]string, len(parts))
- for i, v := range parts {
- res["_"+strconv.Itoa(i)] = v
- }
- return res
- }
- // splitList splits a string by a separator and returns a slice.
- // This is a simple wrapper around strings.Split.
- //
- // Parameters:
- // - sep: The separator to split on
- // - orig: The string to split
- //
- // Returns:
- // - []string: A slice containing the split parts
- func splitList(sep, orig string) []string {
- return strings.Split(orig, sep)
- }
- // splitn splits a string by a separator with a limit and returns a map.
- // The keys in the map are "_0", "_1", etc., corresponding to the position of each part.
- // It will split the string into at most n parts.
- //
- // Parameters:
- // - sep: The separator to split on
- // - n: The maximum number of parts to return
- // - orig: The string to split
- //
- // Returns:
- // - map[string]string: A map with keys "_0", "_1", etc. and values being the split parts
- func splitn(sep string, n int, orig string) map[string]string {
- parts := strings.SplitN(orig, sep, n)
- res := make(map[string]string, len(parts))
- for i, v := range parts {
- res["_"+strconv.Itoa(i)] = v
- }
- return res
- }
- // substring creates a substring of the given string.
- // It extracts a portion of a string based on start and end indices.
- //
- // Parameters:
- // - start: The starting index (inclusive)
- // - end: The ending index (exclusive)
- // - s: The source string
- //
- // Behavior:
- // - If start < 0, returns s[:end]
- // - If start >= 0 and end < 0 or end > len(s), returns s[start:]
- // - Otherwise, returns s[start:end]
- //
- // Returns:
- // - string: The extracted substring
- func substring(start, end int, s string) string {
- if start < 0 {
- return s[:end]
- }
- if end < 0 || end > len(s) {
- return s[start:]
- }
- return s[start:end]
- }
- // repeat creates a new string by repeating the input string a specified number of times.
- // It has safety limits to prevent excessive memory usage or infinite loops.
- //
- // Parameters:
- // - count: The number of times to repeat the string
- // - str: The string to repeat
- //
- // Returns:
- // - string: The repeated string
- //
- // Panics:
- // - If count exceeds loopExecutionLimit
- // - If the resulting string length would exceed stringLengthLimit
- func repeat(count int, str string) string {
- if count > loopExecutionLimit {
- panic(fmt.Sprintf("repeat count %d exceeds limit of %d", count, loopExecutionLimit))
- } else if count*len(str) >= stringLengthLimit {
- panic(fmt.Sprintf("repeat count %d with string length %d exceeds limit of %d", count, len(str), stringLengthLimit))
- }
- return strings.Repeat(str, count)
- }
- // trimAll removes all leading and trailing characters contained in the cutset.
- // Note that the parameter order is reversed from the standard strings.Trim function.
- //
- // Parameters:
- // - a: The cutset of characters to remove
- // - b: The string to trim
- //
- // Returns:
- // - string: The trimmed string
- func trimAll(a, b string) string {
- return strings.Trim(b, a)
- }
- // trimPrefix removes the specified prefix from a string.
- // If the string doesn't start with the prefix, it returns the original string.
- // Note that the parameter order is reversed from the standard strings.TrimPrefix function.
- //
- // Parameters:
- // - a: The prefix to remove
- // - b: The string to trim
- //
- // Returns:
- // - string: The string with the prefix removed, or the original string if it doesn't start with the prefix
- func trimPrefix(a, b string) string {
- return strings.TrimPrefix(b, a)
- }
- // trimSuffix removes the specified suffix from a string.
- // If the string doesn't end with the suffix, it returns the original string.
- // Note that the parameter order is reversed from the standard strings.TrimSuffix function.
- //
- // Parameters:
- // - a: The suffix to remove
- // - b: The string to trim
- //
- // Returns:
- // - string: The string with the suffix removed, or the original string if it doesn't end with the suffix
- func trimSuffix(a, b string) string {
- return strings.TrimSuffix(b, a)
- }
- // contains checks if a string contains a substring.
- //
- // Parameters:
- // - substr: The substring to search for
- // - str: The string to search in
- //
- // Returns:
- // - bool: True if str contains substr, false otherwise
- func contains(substr string, str string) bool {
- return strings.Contains(str, substr)
- }
- // hasPrefix checks if a string starts with a specified prefix.
- //
- // Parameters:
- // - substr: The prefix to check for
- // - str: The string to check
- //
- // Returns:
- // - bool: True if str starts with substr, false otherwise
- func hasPrefix(substr string, str string) bool {
- return strings.HasPrefix(str, substr)
- }
- // hasSuffix checks if a string ends with a specified suffix.
- //
- // Parameters:
- // - substr: The suffix to check for
- // - str: The string to check
- //
- // Returns:
- // - bool: True if str ends with substr, false otherwise
- func hasSuffix(substr string, str string) bool {
- return strings.HasSuffix(str, substr)
- }
|