-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
title: '## Change Log' | ||
# style allow: simple, markdown(mkdown), ghr(gh-release) | ||
style: gh-release | ||
# group names | ||
names: [Refactor, Fixed, Feature, Update, Other] | ||
# if empty will auto fetch by git remote | ||
#repo_url: https://github.com/gookit/goutil | ||
|
||
filters: | ||
# message length should >= 12 | ||
- name: msg_len | ||
min_len: 12 | ||
# message words should >= 3 | ||
- name: words_len | ||
min_len: 3 | ||
- name: keyword | ||
keyword: format code | ||
exclude: true | ||
- name: keywords | ||
keywords: format code, action test | ||
exclude: true | ||
|
||
# group match rules | ||
# not matched will use 'Other' group. | ||
rules: | ||
- name: Refactor | ||
start_withs: [refactor, break] | ||
contains: ['refactor:'] | ||
- name: Fixed | ||
start_withs: [fix] | ||
contains: ['fix:'] | ||
- name: Feature | ||
start_withs: [feat, new] | ||
contains: [feature, 'feat:'] | ||
- name: Update | ||
start_withs: [up] | ||
contains: ['update:', 'up:'] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package easytpl | ||
|
||
type ExtendsTpl struct { | ||
Renderer | ||
} | ||
|
||
// NewExtends create a new extends template instance | ||
func NewExtends() *ExtendsTpl { | ||
return &ExtendsTpl{} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package litetpl | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"reflect" | ||
"regexp" | ||
"strings" | ||
"text/template" | ||
|
||
"github.com/gookit/goutil/basefn" | ||
"github.com/gookit/goutil/fsutil" | ||
"github.com/gookit/goutil/strutil" | ||
"github.com/gookit/goutil/strutil/textutil" | ||
) | ||
|
||
// StrTemplate implement a simple string template | ||
// | ||
// - support replace vars | ||
// - support pipeline filter handle | ||
// - support default value | ||
// - support custom func | ||
type StrTemplate struct { | ||
textutil.VarReplacer | ||
// Funcs template funcs. refer the text/template.Funcs | ||
Funcs map[string]func(string) string | ||
} | ||
|
||
// NewStrTemplate instance | ||
func NewStrTemplate(opFns ...func(st *StrTemplate)) *StrTemplate { | ||
st := &StrTemplate{} | ||
// st.WithFormat(defaultVarFormat) | ||
st.RenderFn = st.renderVars | ||
Check failure on line 35 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 35 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
|
||
for _, fn := range opFns { | ||
fn(st) | ||
} | ||
return st | ||
} | ||
|
||
// Init StrTemplate | ||
func (t *StrTemplate) Init() { | ||
if t.init { | ||
Check failure on line 45 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 45 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
return | ||
} | ||
|
||
basefn.PanicIf(t.Right == "", "var format Right chars is required") | ||
Check failure on line 49 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 49 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
|
||
t.lLen, t.rLen = len(t.Left), len(t.Right) | ||
Check failure on line 51 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 51 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 51 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
Check failure on line 51 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
Check failure on line 51 in litetpl/template.go GitHub Actions / Test on go 1.20 and ubuntu-latest
|
||
t.varReg = regexp.MustCompile(regexp.QuoteMeta(t.Left) + `(.+)` + regexp.QuoteMeta(t.Right)) | ||
Check failure on line 52 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 52 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
} | ||
|
||
func (t *StrTemplate) renderVars(s string, varMap map[string]string) string { | ||
return t.varReg.ReplaceAllStringFunc(s, func(sub string) string { | ||
Check failure on line 56 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 56 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
name := strings.TrimSpace(sub[t.lLen : len(sub)-t.rLen]) | ||
Check failure on line 57 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 57 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 57 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
Check failure on line 57 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
Check failure on line 57 in litetpl/template.go GitHub Actions / Test on go 1.20 and ubuntu-latest
|
||
|
||
var defVal string | ||
if t.parseDef && strings.ContainsRune(name, '|') { | ||
Check failure on line 60 in litetpl/template.go GitHub Actions / Test on go 1.18 and ubuntu-latest
Check failure on line 60 in litetpl/template.go GitHub Actions / Test on go 1.19 and ubuntu-latest
|
||
name, defVal = strutil.TrimCut(name, "|") | ||
} | ||
|
||
if val, ok := varMap[name]; ok { | ||
return val | ||
} | ||
|
||
if t.NotFound != nil { | ||
if val, ok := t.NotFound(name); ok { | ||
return val | ||
} | ||
} | ||
|
||
if len(defVal) > 0 { | ||
return defVal | ||
} | ||
t.missVars = append(t.missVars, name) | ||
return sub | ||
}) | ||
} | ||
|
||
// ErrFuncNotFound error | ||
var ErrFuncNotFound = errors.New("template func not found") | ||
|
||
func (t *StrTemplate) applyFilters(val string, filters []string) (string, error) { | ||
// filters like: "trim|upper|substr:1,2" => ["trim", "upper", "substr:1,2"] | ||
for _, filter := range filters { | ||
if fn, ok := t.Funcs[filter]; ok { | ||
val = fn(val) | ||
} else { | ||
return "", ErrFuncNotFound | ||
} | ||
} | ||
|
||
return val, nil | ||
} | ||
|
||
var builtInFuncs = template.FuncMap{ | ||
// don't escape content | ||
"raw": func(s string) string { | ||
return s | ||
}, | ||
"trim": func(s string) string { | ||
return strings.TrimSpace(s) | ||
}, | ||
// join strings | ||
"join": func(ss []string, sep string) string { | ||
return strings.Join(ss, sep) | ||
}, | ||
// lower first char | ||
"lcFirst": func(s string) string { | ||
return strutil.LowerFirst(s) | ||
}, | ||
// upper first char | ||
"upFirst": func(s string) string { | ||
return strutil.UpperFirst(s) | ||
}, | ||
} | ||
|
||
var ( | ||
errorType = reflect.TypeOf((*error)(nil)).Elem() | ||
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() | ||
reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem() | ||
) | ||
|
||
// goodFunc reports whether the function or method has the right result signature. | ||
func goodFunc(typ reflect.Type) bool { | ||
// We allow functions with 1 result or 2 results where the second is an error. | ||
switch { | ||
case typ.NumOut() == 1: | ||
return true | ||
case typ.NumOut() == 2 && typ.Out(1) == errorType: | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// TextRenderOpt render text template options | ||
type TextRenderOpt struct { | ||
// Output use custom output writer | ||
Output io.Writer | ||
// Funcs add custom template functions | ||
Funcs template.FuncMap | ||
} | ||
|
||
// RenderOptFn render option func | ||
type RenderOptFn func(opt *TextRenderOpt) | ||
|
||
// NewRenderOpt create a new render options | ||
func NewRenderOpt(optFns []RenderOptFn) *TextRenderOpt { | ||
opt := &TextRenderOpt{} | ||
for _, fn := range optFns { | ||
fn(opt) | ||
} | ||
return opt | ||
} | ||
|
||
// RenderTpl render go template string or file. | ||
func RenderTpl(input string, data any, optFns ...RenderOptFn) string { | ||
return RenderGoTpl(input, data, optFns...) | ||
} | ||
|
||
// RenderGoTpl render input text or template file. | ||
func RenderGoTpl(input string, data any, optFns ...RenderOptFn) string { | ||
opt := NewRenderOpt(optFns) | ||
|
||
t := template.New("text-renderer") | ||
t.Funcs(builtInFuncs) | ||
if len(opt.Funcs) > 0 { | ||
t.Funcs(opt.Funcs) | ||
} | ||
|
||
if !strings.Contains(input, "{{") && fsutil.IsFile(input) { | ||
template.Must(t.ParseFiles(input)) | ||
} else { | ||
template.Must(t.Parse(input)) | ||
} | ||
|
||
// use custom output writer | ||
if opt.Output != nil { | ||
basefn.MustOK(t.Execute(opt.Output, data)) | ||
return "" // return empty string | ||
} | ||
|
||
// use buffer receive rendered content | ||
buf := new(bytes.Buffer) | ||
basefn.MustOK(t.Execute(buf, data)) | ||
return buf.String() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Package tplfunc provides a default FuncMap for use with text/template and html/template. | ||
// | ||
// - string functions: join, trim, trimLeft, trimRight, trimPrefix, trimSuffix, trimSpace, repeat, replace, replaceAll, toUpper, toLower, title, toTitle, toCamel, toSnake, toKebab, toLowerCamel, toLowerSnake, toLowerKebab, toCamelLower, toSnakeLower, toKebabLower, toLowerCamelLower, toLowerSnakeLower, toLowerKebabLower, toCamelUpper, toSnakeUpper, toKebabUpper, toLowerCamelUpper, toLowerSnakeUpper, toLowerKebabUpper, toCamelTitle, toSnakeTitle, toKebabTitle | ||
// - math functions: add, max, mul, min, sub, div, mod, ceil, floor, round, roundEven, trunc, sqrt, pow, rand, randInt, randIntRange, randFloat, randFloatRange, randPerm, randShuffle, randChoice, randChoices, randSample, randSamples, randString, randStrings, randBytes, randByte, randRune, randRunes, randTime, randDate, randDateTime, randTimeDuration, randDateDuration, randDateTimeDuration, randTimeUnix, randDateUnix, randDateTimeUnix | ||
// - list functions: list, first, last, len, reverse, sort, shuffle, unique, contains, in, has, keys, values, chunk, chunkBy, chunkByNum, chunkBySize | ||
// - encoding functions: b64enc, b64dec, b32enc, b32dec | ||
// - path functions: base, dir, ext, clean, isAbs, osBase, osDir, osExt, osClean, osIsAbs | ||
// - hash functions: uuid, md5, sha1, sha256, sha512, crc32, crc64 | ||
// - other functions: default, empty, coalesce, fromJson, toJson, toPrettyJson, toRawJson, dump | ||
// | ||
// Example: | ||
// | ||
// import ( | ||
// "github.com/gookit/easytpl/tplfunc" | ||
// "html/template" | ||
// ) | ||
// | ||
// // This example illustrates that the FuncMap *must* be set before the | ||
// // templates themselves are loaded. | ||
// tpl := template.Must( | ||
// template.New("base").Funcs(tplfunc.FuncMap()).ParseGlob("path/to/*.tpl") | ||
// ) | ||
// | ||
// refer: https://github.com/Masterminds/sprig | ||
package tplfunc | ||
|
||
import ( | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
"text/template" | ||
) | ||
|
||
// FuncMap returns the default FuncMap. | ||
func FuncMap() template.FuncMap { | ||
return stdFuncMap | ||
} | ||
|
||
var stdFuncMap = map[string]any{ | ||
// String | ||
"join": strings.Join, | ||
"trim": strings.TrimSpace, | ||
"upper": strings.ToUpper, | ||
"lower": strings.ToLower, | ||
|
||
// OS: | ||
"env": os.Getenv, | ||
"expandenv": os.ExpandEnv, | ||
|
||
// Paths: | ||
"base": path.Base, | ||
"dir": path.Dir, | ||
"clean": path.Clean, | ||
"ext": path.Ext, | ||
"isAbs": path.IsAbs, | ||
|
||
// File paths: | ||
"osBase": filepath.Base, | ||
"osClean": filepath.Clean, | ||
"osDir": filepath.Dir, | ||
"osExt": filepath.Ext, | ||
"osIsAbs": filepath.IsAbs, | ||
} |