This commit is contained in:
binwiederhier
2025-07-13 12:45:00 +02:00
parent 3ac3e2ec7c
commit 2a468493f9
16 changed files with 174 additions and 216 deletions

View File

@@ -10,19 +10,19 @@ import (
// Date can be a `time.Time` or an `int, int32, int64`.
// In the later case, it is treated as seconds since UNIX
// epoch.
func date(fmt string, date interface{}) string {
func date(fmt string, date any) string {
return dateInZone(fmt, date, "Local")
}
func htmlDate(date interface{}) string {
func htmlDate(date any) string {
return dateInZone("2006-01-02", date, "Local")
}
func htmlDateInZone(date interface{}, zone string) string {
func htmlDateInZone(date any, zone string) string {
return dateInZone("2006-01-02", date, zone)
}
func dateInZone(fmt string, date interface{}, zone string) string {
func dateInZone(fmt string, date any, zone string) string {
var t time.Time
switch date := date.(type) {
default:
@@ -63,7 +63,7 @@ func mustDateModify(fmt string, date time.Time) (time.Time, error) {
return date.Add(d), nil
}
func dateAgo(date interface{}) string {
func dateAgo(date any) string {
var t time.Time
switch date := date.(type) {
@@ -81,7 +81,7 @@ func dateAgo(date interface{}) string {
return duration.String()
}
func duration(sec interface{}) string {
func duration(sec any) string {
var n int64
switch value := sec.(type) {
default:
@@ -94,7 +94,7 @@ func duration(sec interface{}) string {
return (time.Duration(n) * time.Second).String()
}
func durationRound(duration interface{}) string {
func durationRound(duration any) string {
var d time.Duration
switch duration := duration.(type) {
default:

View File

@@ -15,15 +15,15 @@ func TestHtmlDate(t *testing.T) {
func TestAgo(t *testing.T) {
tpl := "{{ ago .Time }}"
if err := runtv(tpl, "2m5s", map[string]interface{}{"Time": time.Now().Add(-125 * time.Second)}); err != nil {
if err := runtv(tpl, "2m5s", map[string]any{"Time": time.Now().Add(-125 * time.Second)}); err != nil {
t.Error(err)
}
if err := runtv(tpl, "2h34m17s", map[string]interface{}{"Time": time.Now().Add(-(2*3600 + 34*60 + 17) * time.Second)}); err != nil {
if err := runtv(tpl, "2h34m17s", map[string]any{"Time": time.Now().Add(-(2*3600 + 34*60 + 17) * time.Second)}); err != nil {
t.Error(err)
}
if err := runtv(tpl, "-5s", map[string]interface{}{"Time": time.Now().Add(5 * time.Second)}); err != nil {
if err := runtv(tpl, "-5s", map[string]any{"Time": time.Now().Add(5 * time.Second)}); err != nil {
t.Error(err)
}
}
@@ -42,7 +42,7 @@ func TestUnixEpoch(t *testing.T) {
}
tpl := `{{unixEpoch .Time}}`
if err = runtv(tpl, "1560458379", map[string]interface{}{"Time": tm}); err != nil {
if err = runtv(tpl, "1560458379", map[string]any{"Time": tm}); err != nil {
t.Error(err)
}
}
@@ -55,66 +55,66 @@ func TestDateInZone(t *testing.T) {
tpl := `{{ date_in_zone "02 Jan 06 15:04 -0700" .Time "UTC" }}`
// Test time.Time input
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": tm}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": tm}); err != nil {
t.Error(err)
}
// Test pointer to time.Time input
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": &tm}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": &tm}); err != nil {
t.Error(err)
}
// Test no time input. This should be close enough to time.Now() we can test
loc, _ := time.LoadLocation("UTC")
if err = runtv(tpl, time.Now().In(loc).Format("02 Jan 06 15:04 -0700"), map[string]interface{}{"Time": ""}); err != nil {
if err = runtv(tpl, time.Now().In(loc).Format("02 Jan 06 15:04 -0700"), map[string]any{"Time": ""}); err != nil {
t.Error(err)
}
// Test unix timestamp as int64
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": int64(1560458379)}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": int64(1560458379)}); err != nil {
t.Error(err)
}
// Test unix timestamp as int32
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": int32(1560458379)}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": int32(1560458379)}); err != nil {
t.Error(err)
}
// Test unix timestamp as int
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": int(1560458379)}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": int(1560458379)}); err != nil {
t.Error(err)
}
// Test case of invalid timezone
tpl = `{{ date_in_zone "02 Jan 06 15:04 -0700" .Time "foobar" }}`
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]interface{}{"Time": tm}); err != nil {
if err = runtv(tpl, "13 Jun 19 20:39 +0000", map[string]any{"Time": tm}); err != nil {
t.Error(err)
}
}
func TestDuration(t *testing.T) {
tpl := "{{ duration .Secs }}"
if err := runtv(tpl, "1m1s", map[string]interface{}{"Secs": "61"}); err != nil {
if err := runtv(tpl, "1m1s", map[string]any{"Secs": "61"}); err != nil {
t.Error(err)
}
if err := runtv(tpl, "1h0m0s", map[string]interface{}{"Secs": "3600"}); err != nil {
if err := runtv(tpl, "1h0m0s", map[string]any{"Secs": "3600"}); err != nil {
t.Error(err)
}
// 1d2h3m4s but go is opinionated
if err := runtv(tpl, "26h3m4s", map[string]interface{}{"Secs": "93784"}); err != nil {
if err := runtv(tpl, "26h3m4s", map[string]any{"Secs": "93784"}); err != nil {
t.Error(err)
}
}
func TestDurationRound(t *testing.T) {
tpl := "{{ durationRound .Time }}"
if err := runtv(tpl, "2h", map[string]interface{}{"Time": "2h5s"}); err != nil {
if err := runtv(tpl, "2h", map[string]any{"Time": "2h5s"}); err != nil {
t.Error(err)
}
if err := runtv(tpl, "1d", map[string]interface{}{"Time": "24h5s"}); err != nil {
if err := runtv(tpl, "1d", map[string]any{"Time": "24h5s"}); err != nil {
t.Error(err)
}
if err := runtv(tpl, "3mo", map[string]interface{}{"Time": "2400h5s"}); err != nil {
if err := runtv(tpl, "3mo", map[string]any{"Time": "2400h5s"}); err != nil {
t.Error(err)
}
}

View File

@@ -17,7 +17,7 @@ import (
// Structs are never considered unset.
//
// For everything else, including pointers, a nil value is unset.
func dfault(d interface{}, given ...interface{}) interface{} {
func dfault(d any, given ...any) any {
if empty(given) || empty(given[0]) {
return d
@@ -26,7 +26,7 @@ func dfault(d interface{}, given ...interface{}) interface{} {
}
// empty returns true if the given value has the zero value for its type.
func empty(given interface{}) bool {
func empty(given any) bool {
g := reflect.ValueOf(given)
if !g.IsValid() {
return true
@@ -54,7 +54,7 @@ func empty(given interface{}) bool {
}
// coalesce returns the first non-empty value.
func coalesce(v ...interface{}) interface{} {
func coalesce(v ...any) any {
for _, val := range v {
if !empty(val) {
return val
@@ -65,7 +65,7 @@ func coalesce(v ...interface{}) interface{} {
// all returns true if empty(x) is false for all values x in the list.
// If the list is empty, return true.
func all(v ...interface{}) bool {
func all(v ...any) bool {
for _, val := range v {
if empty(val) {
return false
@@ -74,9 +74,9 @@ func all(v ...interface{}) bool {
return true
}
// any returns true if empty(x) is false for any x in the list.
// anyNonEmpty returns true if empty(x) is false for anyNonEmpty x in the list.
// If the list is empty, return false.
func any(v ...interface{}) bool {
func anyNonEmpty(v ...any) bool {
for _, val := range v {
if !empty(val) {
return true
@@ -86,25 +86,25 @@ func any(v ...interface{}) bool {
}
// fromJSON decodes JSON into a structured value, ignoring errors.
func fromJSON(v string) interface{} {
func fromJSON(v string) any {
output, _ := mustFromJSON(v)
return output
}
// mustFromJSON decodes JSON into a structured value, returning errors.
func mustFromJSON(v string) (interface{}, error) {
var output interface{}
func mustFromJSON(v string) (any, error) {
var output any
err := json.Unmarshal([]byte(v), &output)
return output, err
}
// toJSON encodes an item into a JSON string
func toJSON(v interface{}) string {
func toJSON(v any) string {
output, _ := json.Marshal(v)
return string(output)
}
func mustToJSON(v interface{}) (string, error) {
func mustToJSON(v any) (string, error) {
output, err := json.Marshal(v)
if err != nil {
return "", err
@@ -113,12 +113,12 @@ func mustToJSON(v interface{}) (string, error) {
}
// toPrettyJSON encodes an item into a pretty (indented) JSON string
func toPrettyJSON(v interface{}) string {
func toPrettyJSON(v any) string {
output, _ := json.MarshalIndent(v, "", " ")
return string(output)
}
func mustToPrettyJSON(v interface{}) (string, error) {
func mustToPrettyJSON(v any) (string, error) {
output, err := json.MarshalIndent(v, "", " ")
if err != nil {
return "", err
@@ -127,7 +127,7 @@ func mustToPrettyJSON(v interface{}) (string, error) {
}
// toRawJSON encodes an item into a JSON string with no escaping of HTML characters.
func toRawJSON(v interface{}) string {
func toRawJSON(v any) string {
output, err := mustToRawJSON(v)
if err != nil {
panic(err)
@@ -136,7 +136,7 @@ func toRawJSON(v interface{}) string {
}
// mustToRawJSON encodes an item into a JSON string with no escaping of HTML characters.
func mustToRawJSON(v interface{}) (string, error) {
func mustToRawJSON(v any) (string, error) {
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
@@ -148,10 +148,9 @@ func mustToRawJSON(v interface{}) (string, error) {
}
// ternary returns the first value if the last value is true, otherwise returns the second value.
func ternary(vt interface{}, vf interface{}, v bool) interface{} {
func ternary(vt any, vf any, v bool) any {
if v {
return vt
}
return vf
}

View File

@@ -53,7 +53,7 @@ func TestEmpty(t *testing.T) {
t.Error(err)
}
dict := map[string]interface{}{"top": map[string]interface{}{}}
dict := map[string]any{"top": map[string]any{}}
tpl = `{{if empty .top.NoSuchThing}}1{{else}}0{{end}}`
if err := runtv(tpl, "1", dict); err != nil {
t.Error(err)
@@ -77,7 +77,7 @@ func TestCoalesce(t *testing.T) {
assert.NoError(t, runt(tpl, expect))
}
dict := map[string]interface{}{"top": map[string]interface{}{}}
dict := map[string]any{"top": map[string]any{}}
tpl := `{{ coalesce .top.NoSuchThing .bottom .bottom.dollar "airplane"}}`
if err := runtv(tpl, "airplane", dict); err != nil {
t.Error(err)
@@ -97,7 +97,7 @@ func TestAll(t *testing.T) {
assert.NoError(t, runt(tpl, expect))
}
dict := map[string]interface{}{"top": map[string]interface{}{}}
dict := map[string]any{"top": map[string]any{}}
tpl := `{{ all .top.NoSuchThing .bottom .bottom.dollar "airplane"}}`
if err := runtv(tpl, "false", dict); err != nil {
t.Error(err)
@@ -117,7 +117,7 @@ func TestAny(t *testing.T) {
assert.NoError(t, runt(tpl, expect))
}
dict := map[string]interface{}{"top": map[string]interface{}{}}
dict := map[string]any{"top": map[string]any{}}
tpl := `{{ any .top.NoSuchThing .bottom .bottom.dollar "airplane"}}`
if err := runtv(tpl, "true", dict); err != nil {
t.Error(err)
@@ -125,7 +125,7 @@ func TestAny(t *testing.T) {
}
func TestFromJSON(t *testing.T) {
dict := map[string]interface{}{"Input": `{"foo": 55}`}
dict := map[string]any{"Input": `{"foo": 55}`}
tpl := `{{.Input | fromJSON}}`
expected := `map[foo:55]`
@@ -141,7 +141,7 @@ func TestFromJSON(t *testing.T) {
}
func TestToJSON(t *testing.T) {
dict := map[string]interface{}{"Top": map[string]interface{}{"bool": true, "string": "test", "number": 42}}
dict := map[string]any{"Top": map[string]any{"bool": true, "string": "test", "number": 42}}
tpl := `{{.Top | toJSON}}`
expected := `{"bool":true,"number":42,"string":"test"}`
@@ -151,7 +151,7 @@ func TestToJSON(t *testing.T) {
}
func TestToPrettyJSON(t *testing.T) {
dict := map[string]interface{}{"Top": map[string]interface{}{"bool": true, "string": "test", "number": 42}}
dict := map[string]any{"Top": map[string]any{"bool": true, "string": "test", "number": 42}}
tpl := `{{.Top | toPrettyJSON}}`
expected := `{
"bool": true,
@@ -164,7 +164,7 @@ func TestToPrettyJSON(t *testing.T) {
}
func TestToRawJSON(t *testing.T) {
dict := map[string]interface{}{"Top": map[string]interface{}{"bool": true, "string": "test", "number": 42, "html": "<HEAD>"}}
dict := map[string]any{"Top": map[string]any{"bool": true, "string": "test", "number": 42, "html": "<HEAD>"}}
tpl := `{{.Top | toRawJSON}}`
expected := `{"bool":true,"html":"<HEAD>","number":42,"string":"test"}`

View File

@@ -1,29 +1,29 @@
package sprig
func get(d map[string]interface{}, key string) interface{} {
func get(d map[string]any, key string) any {
if val, ok := d[key]; ok {
return val
}
return ""
}
func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} {
func set(d map[string]any, key string, value any) map[string]any {
d[key] = value
return d
}
func unset(d map[string]interface{}, key string) map[string]interface{} {
func unset(d map[string]any, key string) map[string]any {
delete(d, key)
return d
}
func hasKey(d map[string]interface{}, key string) bool {
func hasKey(d map[string]any, key string) bool {
_, ok := d[key]
return ok
}
func pluck(key string, d ...map[string]interface{}) []interface{} {
res := []interface{}{}
func pluck(key string, d ...map[string]any) []any {
var res []any
for _, dict := range d {
if val, ok := dict[key]; ok {
res = append(res, val)
@@ -32,7 +32,7 @@ func pluck(key string, d ...map[string]interface{}) []interface{} {
return res
}
func keys(dicts ...map[string]interface{}) []string {
func keys(dicts ...map[string]any) []string {
k := []string{}
for _, dict := range dicts {
for key := range dict {
@@ -42,8 +42,8 @@ func keys(dicts ...map[string]interface{}) []string {
return k
}
func pick(dict map[string]interface{}, keys ...string) map[string]interface{} {
res := map[string]interface{}{}
func pick(dict map[string]any, keys ...string) map[string]any {
res := map[string]any{}
for _, k := range keys {
if v, ok := dict[k]; ok {
res[k] = v
@@ -52,8 +52,8 @@ func pick(dict map[string]interface{}, keys ...string) map[string]interface{} {
return res
}
func omit(dict map[string]interface{}, keys ...string) map[string]interface{} {
res := map[string]interface{}{}
func omit(dict map[string]any, keys ...string) map[string]any {
res := map[string]any{}
omit := make(map[string]bool, len(keys))
for _, k := range keys {
@@ -68,8 +68,8 @@ func omit(dict map[string]interface{}, keys ...string) map[string]interface{} {
return res
}
func dict(v ...interface{}) map[string]interface{} {
dict := map[string]interface{}{}
func dict(v ...any) map[string]any {
dict := map[string]any{}
lenv := len(v)
for i := 0; i < lenv; i += 2 {
key := strval(v[i])
@@ -82,20 +82,19 @@ func dict(v ...interface{}) map[string]interface{} {
return dict
}
func values(dict map[string]interface{}) []interface{} {
values := []interface{}{}
func values(dict map[string]any) []any {
var values []any
for _, value := range dict {
values = append(values, value)
}
return values
}
func dig(ps ...interface{}) (interface{}, error) {
func dig(ps ...any) (any, error) {
if len(ps) < 3 {
panic("dig needs at least three arguments")
}
dict := ps[len(ps)-1].(map[string]interface{})
dict := ps[len(ps)-1].(map[string]any)
def := ps[len(ps)-2]
ks := make([]string, len(ps)-2)
for i := 0; i < len(ks); i++ {
@@ -105,7 +104,7 @@ func dig(ps ...interface{}) (interface{}, error) {
return digFromDict(dict, def, ks)
}
func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (interface{}, error) {
func digFromDict(dict map[string]any, d any, ks []string) (any, error) {
k, ns := ks[0], ks[1:]
step, has := dict[k]
if !has {
@@ -114,5 +113,5 @@ func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (inter
if len(ns) == 0 {
return step, nil
}
return digFromDict(step.(map[string]interface{}), d, ns)
return digFromDict(step.(map[string]any), d, ns)
}

View File

@@ -8,7 +8,7 @@ import (
func Example() {
// Set up variables and template.
vars := map[string]interface{}{"Name": " John Jacob Jingleheimer Schmidt "}
vars := map[string]any{"Name": " John Jacob Jingleheimer Schmidt "}
tpl := `Hello {{.Name | trim | lower}}`
// Get the Sprig function map.

View File

@@ -24,68 +24,26 @@ func FuncMap() template.FuncMap {
return HTMLFuncMap()
}
// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions.
func HermeticTxtFuncMap() ttemplate.FuncMap {
r := TxtFuncMap()
for _, name := range nonhermeticFunctions {
delete(r, name)
}
return r
}
// HermeticHTMLFuncMap returns an 'html/template'.Funcmap with only repeatable functions.
func HermeticHTMLFuncMap() template.FuncMap {
r := HTMLFuncMap()
for _, name := range nonhermeticFunctions {
delete(r, name)
}
return r
}
// TxtFuncMap returns a 'text/template'.FuncMap
func TxtFuncMap() ttemplate.FuncMap {
return ttemplate.FuncMap(GenericFuncMap())
return GenericFuncMap()
}
// HTMLFuncMap returns an 'html/template'.Funcmap
func HTMLFuncMap() template.FuncMap {
return template.FuncMap(GenericFuncMap())
return GenericFuncMap()
}
// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}.
func GenericFuncMap() map[string]interface{} {
gfm := make(map[string]interface{}, len(genericMap))
// GenericFuncMap returns a copy of the basic function map as a map[string]any.
func GenericFuncMap() map[string]any {
gfm := make(map[string]any, len(genericMap))
for k, v := range genericMap {
gfm[k] = v
}
return gfm
}
// These functions are not guaranteed to evaluate to the same result for given input, because they
// refer to the environment or global state.
var nonhermeticFunctions = []string{
// Date functions
"date",
"date_in_zone",
"date_modify",
"now",
"htmlDate",
"htmlDateInZone",
"dateInZone",
"dateModify",
// Strings
"randAlphaNum",
"randAlpha",
"randAscii",
"randNumeric",
"randBytes",
"uuidv4",
}
var genericMap = map[string]interface{}{
"hello": func() string { return "Hello!" },
var genericMap = map[string]any{
// Date functions
"ago": dateAgo,
"date": date,
@@ -157,18 +115,18 @@ var genericMap = map[string]interface{}{
"untilStep": untilStep,
// VERY basic arithmetic.
"add1": func(i interface{}) int64 { return toInt64(i) + 1 },
"add": func(i ...interface{}) int64 {
"add1": func(i any) int64 { return toInt64(i) + 1 },
"add": func(i ...any) int64 {
var a int64 = 0
for _, b := range i {
a += toInt64(b)
}
return a
},
"sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) },
"div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) },
"mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) },
"mul": func(a interface{}, v ...interface{}) int64 {
"sub": func(a, b any) int64 { return toInt64(a) - toInt64(b) },
"div": func(a, b any) int64 { return toInt64(a) / toInt64(b) },
"mod": func(a, b any) int64 { return toInt64(a) % toInt64(b) },
"mul": func(a any, v ...any) int64 {
val := toInt64(a)
for _, b := range v {
val = val * toInt64(b)
@@ -195,7 +153,7 @@ var genericMap = map[string]interface{}{
"empty": empty,
"coalesce": coalesce,
"all": all,
"any": any,
"any": anyNonEmpty,
"compact": compact,
"mustCompact": mustCompact,
"fromJSON": fromJSON,
@@ -250,8 +208,10 @@ var genericMap = map[string]interface{}{
"omit": omit,
"values": values,
"append": push, "push": push,
"mustAppend": mustPush, "mustPush": mustPush,
"append": push,
"push": push,
"mustAppend": mustPush,
"mustPush": mustPush,
"prepend": prepend,
"mustPrepend": mustPrepend,
"first": first,

View File

@@ -43,7 +43,7 @@ func runt(tpl, expect string) error {
// runtv takes a template, and expected return, and values for substitution.
//
// It runs the template and verifies that the output is an exact match.
func runtv(tpl, expect string, vars interface{}) error {
func runtv(tpl, expect string, vars any) error {
fmap := TxtFuncMap()
t := template.Must(template.New("test").Funcs(fmap).Parse(tpl))
var b bytes.Buffer
@@ -58,7 +58,7 @@ func runtv(tpl, expect string, vars interface{}) error {
}
// runRaw runs a template with the given variables and returns the result.
func runRaw(tpl string, vars interface{}) (string, error) {
func runRaw(tpl string, vars any) (string, error) {
fmap := TxtFuncMap()
t := template.Must(template.New("test").Funcs(fmap).Parse(tpl))
var b bytes.Buffer

View File

@@ -8,14 +8,14 @@ import (
)
// Reflection is used in these functions so that slices and arrays of strings,
// ints, and other types not implementing []interface{} can be worked with.
// ints, and other types not implementing []any can be worked with.
// For example, this is useful if you need to work on the output of regexs.
func list(v ...interface{}) []interface{} {
func list(v ...any) []any {
return v
}
func push(list interface{}, v interface{}) []interface{} {
func push(list any, v any) []any {
l, err := mustPush(list, v)
if err != nil {
panic(err)
@@ -24,14 +24,14 @@ func push(list interface{}, v interface{}) []interface{} {
return l
}
func mustPush(list interface{}, v interface{}) ([]interface{}, error) {
func mustPush(list any, v any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
l2 := reflect.ValueOf(list)
l := l2.Len()
nl := make([]interface{}, l)
nl := make([]any, l)
for i := 0; i < l; i++ {
nl[i] = l2.Index(i).Interface()
}
@@ -43,7 +43,7 @@ func mustPush(list interface{}, v interface{}) ([]interface{}, error) {
}
}
func prepend(list interface{}, v interface{}) []interface{} {
func prepend(list any, v any) []any {
l, err := mustPrepend(list, v)
if err != nil {
panic(err)
@@ -52,8 +52,8 @@ func prepend(list interface{}, v interface{}) []interface{} {
return l
}
func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) {
//return append([]interface{}{v}, list...)
func mustPrepend(list any, v any) ([]any, error) {
//return append([]any{v}, list...)
tp := reflect.TypeOf(list).Kind()
switch tp {
@@ -61,19 +61,19 @@ func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) {
l2 := reflect.ValueOf(list)
l := l2.Len()
nl := make([]interface{}, l)
nl := make([]any, l)
for i := 0; i < l; i++ {
nl[i] = l2.Index(i).Interface()
}
return append([]interface{}{v}, nl...), nil
return append([]any{v}, nl...), nil
default:
return nil, fmt.Errorf("cannot prepend on type %s", tp)
}
}
func chunk(size int, list interface{}) [][]interface{} {
func chunk(size int, list any) [][]any {
l, err := mustChunk(size, list)
if err != nil {
panic(err)
@@ -82,7 +82,7 @@ func chunk(size int, list interface{}) [][]interface{} {
return l
}
func mustChunk(size int, list interface{}) ([][]interface{}, error) {
func mustChunk(size int, list any) ([][]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -91,7 +91,7 @@ func mustChunk(size int, list interface{}) ([][]interface{}, error) {
l := l2.Len()
cs := int(math.Floor(float64(l-1)/float64(size)) + 1)
nl := make([][]interface{}, cs)
nl := make([][]any, cs)
for i := 0; i < cs; i++ {
clen := size
@@ -102,7 +102,7 @@ func mustChunk(size int, list interface{}) ([][]interface{}, error) {
}
}
nl[i] = make([]interface{}, clen)
nl[i] = make([]any, clen)
for j := 0; j < clen; j++ {
ix := i*size + j
@@ -117,7 +117,7 @@ func mustChunk(size int, list interface{}) ([][]interface{}, error) {
}
}
func last(list interface{}) interface{} {
func last(list any) any {
l, err := mustLast(list)
if err != nil {
panic(err)
@@ -126,7 +126,7 @@ func last(list interface{}) interface{} {
return l
}
func mustLast(list interface{}) (interface{}, error) {
func mustLast(list any) (any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -143,7 +143,7 @@ func mustLast(list interface{}) (interface{}, error) {
}
}
func first(list interface{}) interface{} {
func first(list any) any {
l, err := mustFirst(list)
if err != nil {
panic(err)
@@ -152,7 +152,7 @@ func first(list interface{}) interface{} {
return l
}
func mustFirst(list interface{}) (interface{}, error) {
func mustFirst(list any) (any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -169,7 +169,7 @@ func mustFirst(list interface{}) (interface{}, error) {
}
}
func rest(list interface{}) []interface{} {
func rest(list any) []any {
l, err := mustRest(list)
if err != nil {
panic(err)
@@ -178,7 +178,7 @@ func rest(list interface{}) []interface{} {
return l
}
func mustRest(list interface{}) ([]interface{}, error) {
func mustRest(list any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -189,7 +189,7 @@ func mustRest(list interface{}) ([]interface{}, error) {
return nil, nil
}
nl := make([]interface{}, l-1)
nl := make([]any, l-1)
for i := 1; i < l; i++ {
nl[i-1] = l2.Index(i).Interface()
}
@@ -200,7 +200,7 @@ func mustRest(list interface{}) ([]interface{}, error) {
}
}
func initial(list interface{}) []interface{} {
func initial(list any) []any {
l, err := mustInitial(list)
if err != nil {
panic(err)
@@ -209,7 +209,7 @@ func initial(list interface{}) []interface{} {
return l
}
func mustInitial(list interface{}) ([]interface{}, error) {
func mustInitial(list any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -220,7 +220,7 @@ func mustInitial(list interface{}) ([]interface{}, error) {
return nil, nil
}
nl := make([]interface{}, l-1)
nl := make([]any, l-1)
for i := 0; i < l-1; i++ {
nl[i] = l2.Index(i).Interface()
}
@@ -231,7 +231,7 @@ func mustInitial(list interface{}) ([]interface{}, error) {
}
}
func sortAlpha(list interface{}) []string {
func sortAlpha(list any) []string {
k := reflect.Indirect(reflect.ValueOf(list)).Kind()
switch k {
case reflect.Slice, reflect.Array:
@@ -243,7 +243,7 @@ func sortAlpha(list interface{}) []string {
return []string{strval(list)}
}
func reverse(v interface{}) []interface{} {
func reverse(v any) []any {
l, err := mustReverse(v)
if err != nil {
panic(err)
@@ -252,7 +252,7 @@ func reverse(v interface{}) []interface{} {
return l
}
func mustReverse(v interface{}) ([]interface{}, error) {
func mustReverse(v any) ([]any, error) {
tp := reflect.TypeOf(v).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -260,7 +260,7 @@ func mustReverse(v interface{}) ([]interface{}, error) {
l := l2.Len()
// We do not sort in place because the incoming array should not be altered.
nl := make([]interface{}, l)
nl := make([]any, l)
for i := 0; i < l; i++ {
nl[l-i-1] = l2.Index(i).Interface()
}
@@ -271,7 +271,7 @@ func mustReverse(v interface{}) ([]interface{}, error) {
}
}
func compact(list interface{}) []interface{} {
func compact(list any) []any {
l, err := mustCompact(list)
if err != nil {
panic(err)
@@ -280,15 +280,15 @@ func compact(list interface{}) []interface{} {
return l
}
func mustCompact(list interface{}) ([]interface{}, error) {
func mustCompact(list any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
l2 := reflect.ValueOf(list)
l := l2.Len()
nl := []interface{}{}
var item interface{}
nl := []any{}
var item any
for i := 0; i < l; i++ {
item = l2.Index(i).Interface()
if !empty(item) {
@@ -302,7 +302,7 @@ func mustCompact(list interface{}) ([]interface{}, error) {
}
}
func uniq(list interface{}) []interface{} {
func uniq(list any) []any {
l, err := mustUniq(list)
if err != nil {
panic(err)
@@ -311,15 +311,15 @@ func uniq(list interface{}) []interface{} {
return l
}
func mustUniq(list interface{}) ([]interface{}, error) {
func mustUniq(list any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
l2 := reflect.ValueOf(list)
l := l2.Len()
dest := []interface{}{}
var item interface{}
dest := []any{}
var item any
for i := 0; i < l; i++ {
item = l2.Index(i).Interface()
if !inList(dest, item) {
@@ -333,7 +333,7 @@ func mustUniq(list interface{}) ([]interface{}, error) {
}
}
func inList(haystack []interface{}, needle interface{}) bool {
func inList(haystack []any, needle any) bool {
for _, h := range haystack {
if reflect.DeepEqual(needle, h) {
return true
@@ -342,7 +342,7 @@ func inList(haystack []interface{}, needle interface{}) bool {
return false
}
func without(list interface{}, omit ...interface{}) []interface{} {
func without(list any, omit ...any) []any {
l, err := mustWithout(list, omit...)
if err != nil {
panic(err)
@@ -351,15 +351,15 @@ func without(list interface{}, omit ...interface{}) []interface{} {
return l
}
func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) {
func mustWithout(list any, omit ...any) ([]any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
l2 := reflect.ValueOf(list)
l := l2.Len()
res := []interface{}{}
var item interface{}
res := []any{}
var item any
for i := 0; i < l; i++ {
item = l2.Index(i).Interface()
if !inList(omit, item) {
@@ -373,7 +373,7 @@ func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) {
}
}
func has(needle interface{}, haystack interface{}) bool {
func has(needle any, haystack any) bool {
l, err := mustHas(needle, haystack)
if err != nil {
panic(err)
@@ -382,7 +382,7 @@ func has(needle interface{}, haystack interface{}) bool {
return l
}
func mustHas(needle interface{}, haystack interface{}) (bool, error) {
func mustHas(needle any, haystack any) (bool, error) {
if haystack == nil {
return false, nil
}
@@ -390,7 +390,7 @@ func mustHas(needle interface{}, haystack interface{}) (bool, error) {
switch tp {
case reflect.Slice, reflect.Array:
l2 := reflect.ValueOf(haystack)
var item interface{}
var item any
l := l2.Len()
for i := 0; i < l; i++ {
item = l2.Index(i).Interface()
@@ -410,7 +410,7 @@ func mustHas(needle interface{}, haystack interface{}) (bool, error) {
// slice $list 0 3 -> list[0:3] = list[:3]
// slice $list 3 5 -> list[3:5]
// slice $list 3 -> list[3:5] = list[3:]
func slice(list interface{}, indices ...interface{}) interface{} {
func slice(list any, indices ...any) any {
l, err := mustSlice(list, indices...)
if err != nil {
panic(err)
@@ -419,7 +419,7 @@ func slice(list interface{}, indices ...interface{}) interface{} {
return l
}
func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) {
func mustSlice(list any, indices ...any) (any, error) {
tp := reflect.TypeOf(list).Kind()
switch tp {
case reflect.Slice, reflect.Array:
@@ -446,8 +446,8 @@ func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) {
}
}
func concat(lists ...interface{}) interface{} {
var res []interface{}
func concat(lists ...any) any {
var res []any
for _, list := range lists {
tp := reflect.TypeOf(list).Kind()
switch tp {

View File

@@ -9,7 +9,7 @@ import (
)
// toFloat64 converts 64-bit floats
func toFloat64(v interface{}) float64 {
func toFloat64(v any) float64 {
if str, ok := v.(string); ok {
iv, err := strconv.ParseFloat(str, 64)
if err != nil {
@@ -38,13 +38,13 @@ func toFloat64(v interface{}) float64 {
}
}
func toInt(v interface{}) int {
func toInt(v any) int {
// It's not optimal. But I don't want duplicate toInt64 code.
return int(toInt64(v))
}
// toInt64 converts integer types to 64-bit integers
func toInt64(v interface{}) int64 {
func toInt64(v any) int64 {
if str, ok := v.(string); ok {
iv, err := strconv.ParseInt(str, 10, 64)
if err != nil {
@@ -78,7 +78,7 @@ func toInt64(v interface{}) int64 {
}
}
func max(a interface{}, i ...interface{}) int64 {
func max(a any, i ...any) int64 {
aa := toInt64(a)
for _, b := range i {
bb := toInt64(b)
@@ -89,7 +89,7 @@ func max(a interface{}, i ...interface{}) int64 {
return aa
}
func maxf(a interface{}, i ...interface{}) float64 {
func maxf(a any, i ...any) float64 {
aa := toFloat64(a)
for _, b := range i {
bb := toFloat64(b)
@@ -98,7 +98,7 @@ func maxf(a interface{}, i ...interface{}) float64 {
return aa
}
func min(a interface{}, i ...interface{}) int64 {
func min(a any, i ...any) int64 {
aa := toInt64(a)
for _, b := range i {
bb := toInt64(b)
@@ -109,7 +109,7 @@ func min(a interface{}, i ...interface{}) int64 {
return aa
}
func minf(a interface{}, i ...interface{}) float64 {
func minf(a any, i ...any) float64 {
aa := toFloat64(a)
for _, b := range i {
bb := toFloat64(b)
@@ -148,17 +148,17 @@ func untilStep(start, stop, step int) []int {
return v
}
func floor(a interface{}) float64 {
func floor(a any) float64 {
aa := toFloat64(a)
return math.Floor(aa)
}
func ceil(a interface{}) float64 {
func ceil(a any) float64 {
aa := toFloat64(a)
return math.Ceil(aa)
}
func round(a interface{}, p int, rOpt ...float64) float64 {
func round(a any, p int, rOpt ...float64) float64 {
roundOn := .5
if len(rOpt) > 0 {
roundOn = rOpt[0]
@@ -179,7 +179,7 @@ func round(a interface{}, p int, rOpt ...float64) float64 {
}
// converts unix octal to decimal
func toDecimal(v interface{}) int64 {
func toDecimal(v any) int64 {
result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64)
if err != nil {
return 0

View File

@@ -192,7 +192,7 @@ func TestToInt(t *testing.T) {
}
func TestToDecimal(t *testing.T) {
tests := map[interface{}]int64{
tests := map[any]int64{
"777": 511,
777: 511,
770: 504,

View File

@@ -6,23 +6,23 @@ import (
)
// typeIs returns true if the src is the type named in target.
func typeIs(target string, src interface{}) bool {
func typeIs(target string, src any) bool {
return target == typeOf(src)
}
func typeIsLike(target string, src interface{}) bool {
func typeIsLike(target string, src any) bool {
t := typeOf(src)
return target == t || "*"+target == t
}
func typeOf(src interface{}) string {
func typeOf(src any) string {
return fmt.Sprintf("%T", src)
}
func kindIs(target string, src interface{}) bool {
func kindIs(target string, src any) bool {
return target == kindOf(src)
}
func kindOf(src interface{}) string {
func kindOf(src any) string {
return reflect.ValueOf(src).Kind().String()
}

View File

@@ -33,7 +33,7 @@ func base32decode(v string) string {
return string(data)
}
func quote(str ...interface{}) string {
func quote(str ...any) string {
out := make([]string, 0, len(str))
for _, s := range str {
if s != nil {
@@ -43,7 +43,7 @@ func quote(str ...interface{}) string {
return strings.Join(out, " ")
}
func squote(str ...interface{}) string {
func squote(str ...any) string {
out := make([]string, 0, len(str))
for _, s := range str {
if s != nil {
@@ -53,7 +53,7 @@ func squote(str ...interface{}) string {
return strings.Join(out, " ")
}
func cat(v ...interface{}) string {
func cat(v ...any) string {
v = removeNilElements(v)
r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
return fmt.Sprintf(r, v...)
@@ -79,11 +79,11 @@ func plural(one, many string, count int) string {
return many
}
func strslice(v interface{}) []string {
func strslice(v any) []string {
switch v := v.(type) {
case []string:
return v
case []interface{}:
case []any:
b := make([]string, 0, len(v))
for _, s := range v {
if s != nil {
@@ -114,8 +114,8 @@ func strslice(v interface{}) []string {
}
}
func removeNilElements(v []interface{}) []interface{} {
newSlice := make([]interface{}, 0, len(v))
func removeNilElements(v []any) []any {
newSlice := make([]any, 0, len(v))
for _, i := range v {
if i != nil {
newSlice = append(newSlice, i)
@@ -124,7 +124,7 @@ func removeNilElements(v []interface{}) []interface{} {
return newSlice
}
func strval(v interface{}) string {
func strval(v any) string {
switch v := v.(type) {
case string:
return v
@@ -149,7 +149,7 @@ func trunc(c int, s string) string {
return s
}
func join(sep string, v interface{}) string {
func join(sep string, v any) string {
return strings.Join(strslice(v), sep)
}

View File

@@ -56,7 +56,7 @@ func TestQuote(t *testing.T) {
t.Error(err)
}
tpl = `{{ .value | quote }}`
values := map[string]interface{}{"value": nil}
values := map[string]any{"value": nil}
if err := runtv(tpl, ``, values); err != nil {
t.Error(err)
}
@@ -71,7 +71,7 @@ func TestSquote(t *testing.T) {
t.Error(err)
}
tpl = `{{ .value | squote }}`
values := map[string]interface{}{"value": nil}
values := map[string]any{"value": nil}
if err := runtv(tpl, ``, values); err != nil {
t.Error(err)
}
@@ -128,7 +128,7 @@ func TestToStrings(t *testing.T) {
tpl := `{{ $s := list 1 2 3 | toStrings }}{{ index $s 1 | kindOf }}`
assert.NoError(t, runt(tpl, "string"))
tpl = `{{ list 1 .value 2 | toStrings }}`
values := map[string]interface{}{"value": nil}
values := map[string]any{"value": nil}
if err := runtv(tpl, `[1 2]`, values); err != nil {
t.Error(err)
}
@@ -137,10 +137,10 @@ func TestToStrings(t *testing.T) {
func TestJoin(t *testing.T) {
assert.NoError(t, runt(`{{ tuple "a" "b" "c" | join "-" }}`, "a-b-c"))
assert.NoError(t, runt(`{{ tuple 1 2 3 | join "-" }}`, "1-2-3"))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "a-b-c", map[string]interface{}{"V": []string{"a", "b", "c"}}))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "abc", map[string]interface{}{"V": "abc"}))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "1-2-3", map[string]interface{}{"V": []int{1, 2, 3}}))
assert.NoError(t, runtv(`{{ join "-" .value }}`, "1-2", map[string]interface{}{"value": []interface{}{"1", nil, "2"}}))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "a-b-c", map[string]any{"V": []string{"a", "b", "c"}}))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "abc", map[string]any{"V": "abc"}))
assert.NoError(t, runtv(`{{ join "-" .V }}`, "1-2-3", map[string]any{"V": []int{1, 2, 3}}))
assert.NoError(t, runtv(`{{ join "-" .value }}`, "1-2", map[string]any{"value": []any{"1", nil, "2"}}))
}
func TestSortAlpha(t *testing.T) {
@@ -194,7 +194,7 @@ func TestCat(t *testing.T) {
t.Error(err)
}
tpl = `{{ .value | cat "a" "b"}}`
values := map[string]interface{}{"value": nil}
values := map[string]any{"value": nil}
if err := runtv(tpl, "a b", values); err != nil {
t.Error(err)
}

View File

@@ -6,7 +6,7 @@ import (
"reflect"
)
func dictGetOrEmpty(dict map[string]interface{}, key string) string {
func dictGetOrEmpty(dict map[string]any, key string) string {
value, ok := dict[key]
if !ok {
return ""
@@ -19,8 +19,8 @@ func dictGetOrEmpty(dict map[string]interface{}, key string) string {
}
// parses given URL to return dict object
func urlParse(v string) map[string]interface{} {
dict := map[string]interface{}{}
func urlParse(v string) map[string]any {
dict := map[string]any{}
parsedURL, err := url.Parse(v)
if err != nil {
panic(fmt.Sprintf("unable to parse url: %s", err))
@@ -42,7 +42,7 @@ func urlParse(v string) map[string]interface{} {
}
// join given dict to URL string
func urlJoin(d map[string]interface{}) string {
func urlJoin(d map[string]any) string {
resURL := url.URL{
Scheme: dictGetOrEmpty(d, "scheme"),
Host: dictGetOrEmpty(d, "host"),

View File

@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
)
var urlTests = map[string]map[string]interface{}{
var urlTests = map[string]map[string]any{
"proto://auth@host:80/path?query#fragment": {
"fragment": "fragment",
"host": "host:80",