diff --git a/environment.go b/environment.go index c3e7d41..cb2e832 100644 --- a/environment.go +++ b/environment.go @@ -9,6 +9,8 @@ import ( "strconv" "sync" "sync/atomic" + + "github.com/gowool/extends-template/internal" ) const ( @@ -55,8 +57,8 @@ func (e *Environment) Delims(left, right string) *Environment { e.left = left e.right = right - e.reExtends = ReExtends(left, right) - e.reTemplate = ReTemplate(left, right) + e.reExtends = internal.ReExtends(left, right) + e.reTemplate = internal.ReTemplate(left, right) e.updateHash() return e @@ -137,10 +139,10 @@ func (e *Environment) updateHash() { buf.WriteString(name) } - e.hash.Store(hash(buf.Bytes())) + e.hash.Store(internal.Hash(buf.Bytes())) e.templates = &sync.Map{} } func (e *Environment) key(name string) string { - return hash(toBytes(fmt.Sprintf("%s:%s", name, e.hash.Load()))) + return internal.Hash(internal.Bytes(fmt.Sprintf("%s:%s", name, e.hash.Load()))) } diff --git a/go.mod b/go.mod index 930fc24..bfa99c8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gowool/extends-template -go 1.21 +go 1.22.0 require github.com/stretchr/testify v1.8.4 diff --git a/common.go b/internal/common.go similarity index 51% rename from common.go rename to internal/common.go index b0bf583..359764a 100644 --- a/common.go +++ b/internal/common.go @@ -1,11 +1,10 @@ -package et +package internal import ( "crypto/sha256" "fmt" "reflect" "regexp" - "unsafe" ) const ( @@ -21,22 +20,7 @@ func ReTemplate(left, right string) *regexp.Regexp { return regexp.MustCompile(fmt.Sprintf(templatePattern, left, right)) } -func merge(left error, right error) error { - switch { - case left == nil: - return right - case right == nil: - return left - } - - return fmt.Errorf("%w; %w", left, right) -} - -func errorf(right error, format string, a ...any) error { - return merge(fmt.Errorf(format, a...), right) -} - -func typeName(i any) string { +func TypeName(i any) string { t := reflect.TypeOf(i) for t.Kind() == reflect.Ptr { @@ -46,14 +30,6 @@ func typeName(i any) string { return t.Name() } -func toBytes(s string) []byte { - return unsafe.Slice(unsafe.StringData(s), len(s)) -} - -func toString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) -} - -func hash(data []byte) string { +func Hash(data []byte) string { return fmt.Sprintf("%x", sha256.Sum256(data)) } diff --git a/internal/unsafe.go b/internal/unsafe.go new file mode 100644 index 0000000..4f8b113 --- /dev/null +++ b/internal/unsafe.go @@ -0,0 +1,11 @@ +package internal + +import "unsafe" + +func Bytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +func String(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} diff --git a/loader_chain.go b/loader_chain.go index 19e5ae4..6a3d3d5 100644 --- a/loader_chain.go +++ b/loader_chain.go @@ -2,8 +2,11 @@ package et import ( "context" + "errors" "fmt" "sync" + + "github.com/gowool/extends-template/internal" ) var _ Loader = (*ChainLoader)(nil) @@ -83,16 +86,16 @@ func (l *ChainLoader) loop(ctx context.Context, name string, fn func(loader Load for _, loader := range l.loaders { if ok, err1 := loader.Exists(ctx, name); !ok { - err = merge(err, err1) + err = errors.Join(err, err1) continue } if r, err1 := fn(loader); err1 == nil { return r, nil } else { - err = merge(err, fmt.Errorf("[%s]: %w", typeName(loader), err1)) + err = errors.Join(err, fmt.Errorf("[%s]: %w", internal.TypeName(loader), err1)) } } - return nil, errorf(err, ErrNotDefinedFormat, name) + return nil, errors.Join(fmt.Errorf(ErrNotDefinedFormat, name), err) } diff --git a/loader_filesystem.go b/loader_filesystem.go index a588ff2..73b1880 100644 --- a/loader_filesystem.go +++ b/loader_filesystem.go @@ -2,6 +2,7 @@ package et import ( "context" + "errors" "fmt" "io/fs" "path/filepath" @@ -101,7 +102,7 @@ func (l *FilesystemLoader) SetPaths(namespace string, paths ...string) error { var err error for _, p := range paths { - err = merge(err, l.add(namespace, p)) + err = errors.Join(err, l.add(namespace, p)) } return err } @@ -199,9 +200,9 @@ func (l *FilesystemLoader) path(p string) (string, error) { p = strings.Trim(l.normalize(p), sep) if stat, err := fs.Stat(l.fsys, p); err != nil { - return p, errorf(err, ErrDirNotExistsFormat, p) + return p, errors.Join(fmt.Errorf(ErrDirNotExistsFormat, p), err) } else if !stat.IsDir() { - return p, errorf(nil, ErrDirNotExistsFormat, p) + return p, fmt.Errorf(ErrDirNotExistsFormat, p) } return p, nil diff --git a/loader_memory.go b/loader_memory.go index 91d3934..56cbc6f 100644 --- a/loader_memory.go +++ b/loader_memory.go @@ -2,6 +2,7 @@ package et import ( "context" + "fmt" "sync" ) @@ -31,7 +32,7 @@ func (l *MemoryLoader) Get(_ context.Context, name string) (*Source, error) { if code, ok := l.templates.Load(name); ok { return &Source{Code: code.([]byte), Name: name}, nil } - return nil, errorf(nil, ErrNotDefinedFormat, name) + return nil, fmt.Errorf(ErrNotDefinedFormat, name) } func (l *MemoryLoader) IsFresh(ctx context.Context, name string, _ int64) (bool, error) { @@ -42,5 +43,5 @@ func (l *MemoryLoader) Exists(_ context.Context, name string) (bool, error) { if _, ok := l.templates.Load(name); ok { return true, nil } - return false, errorf(nil, ErrNotDefinedFormat, name) + return false, fmt.Errorf(ErrNotDefinedFormat, name) } diff --git a/node.go b/node.go index 06d2de1..244677d 100644 --- a/node.go +++ b/node.go @@ -5,6 +5,8 @@ import ( "context" "html/template" "path" + + "github.com/gowool/extends-template/internal" ) type Handler func(ctx context.Context, node *Node, namespace string) error @@ -52,20 +54,20 @@ func (n *Node) Init(ctx context.Context) (err error) { if extends := n.w.reExtends.FindAllSubmatch(n.Source.Code, -1); len(extends) > 0 { n.Source.Code = n.w.reExtends.ReplaceAll(n.Source.Code, []byte{}) - if err = NewNode(toString(extends[0][1]), n.w, n).Init(ctx); err != nil { + if err = NewNode(internal.String(extends[0][1]), n.w, n).Init(ctx); err != nil { return } } if includes := n.w.reTemplates.FindAllSubmatch(n.Source.Code, -1); len(includes) > 0 { for _, tpl := range includes { - include := NewNode(toString(tpl[1]), n.w, nil) + include := NewNode(internal.String(tpl[1]), n.w, nil) if err = include.Init(ctx); err != nil { return } n.Includes = append(n.Includes, include) if n.w.ns != "" && '@' == n.w.ns[0] && '@' != rune(tpl[1][0]) { - n.Source.Code = bytes.Replace(n.Source.Code, tpl[1], append(toBytes(n.w.ns), tpl[1]...), 1) + n.Source.Code = bytes.Replace(n.Source.Code, tpl[1], append(internal.Bytes(n.w.ns), tpl[1]...), 1) } } } @@ -80,7 +82,7 @@ func (n *Node) Init(ctx context.Context) (err error) { } func (n *Node) Parse(t *template.Template) error { - if _, err := t.Parse(toString(n.Source.Code)); err != nil { + if _, err := t.Parse(internal.String(n.Source.Code)); err != nil { return err } diff --git a/template_wrapper_test.go b/template_wrapper_test.go index 4200e3f..6dfb971 100644 --- a/template_wrapper_test.go +++ b/template_wrapper_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" et "github.com/gowool/extends-template" + "github.com/gowool/extends-template/internal" ) const ( @@ -83,8 +84,8 @@ func TestTemplateWrapper_IsFresh(t *testing.T) { template.New(name), wrapLoader{t: s.t}, s.handlers, - et.ReExtends("{{", "}}"), - et.ReTemplate("{{", "}}")) + internal.ReExtends("{{", "}}"), + internal.ReTemplate("{{", "}}")) isFresh := wrapper.IsFresh(context.TODO()) @@ -122,8 +123,8 @@ func TestTemplateWrapper_Parse(t *testing.T) { template.New(name), wrapLoader{}, s.handlers, - et.ReExtends("{{", "}}"), - et.ReTemplate("{{", "}}"), + internal.ReExtends("{{", "}}"), + internal.ReTemplate("{{", "}}"), "@main/global.html", )