mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-11-29 19:59:59 +01:00
487 lines
13 KiB
Go
487 lines
13 KiB
Go
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)
|
|
}
|