You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
2.4 KiB

package engine
import (
"context"
"errors"
"fmt"
"gitoa.ru/go-4devs/mime"
"gitoa.ru/go-4devs/templating/loader"
"gitoa.ru/go-4devs/templating/render"
)
var _ render.Engine = (*Engine)(nil)
var (
ErrNotSupport = errors.New("not support")
ErrDuplicate = errors.New("duplicate")
ErrNotFound = errors.New("not found")
)
type (
Option func(*Engine)
Parse func(loader.Source) (Template, error)
)
type Cache interface {
Set(ctx context.Context, tpl Template) error
Get(ctx context.Context, name string) (Template, error)
List(_ context.Context) []Template
}
func WithTemplates(tpls ...Template) Option {
ctx := context.Background()
return func(l *Engine) {
for _, tpl := range tpls {
_ = l.tpls.Set(ctx, tpl)
}
}
}
func WithLoader(load loader.Loader) Option {
return func(l *Engine) {
l.load = load
}
}
func WithFormats(formats ...mime.Ext) Option {
return func(e *Engine) {
e.formats = formats
}
}
func New(name string, parse Parse, opts ...Option) *Engine {
engine := Engine{
name: name,
parce: parse,
tpls: NewTemplates(),
load: loader.Empty(),
}
for _, opt := range opts {
opt(&engine)
}
return &engine
}
type Engine struct {
name string
formats []mime.Ext
tpls Cache
load loader.Loader
parce Parse
}
func (l Engine) WithLoader(load loader.Loader) *Engine {
return New(l.name, l.parce, WithTemplates(l.tpls.List(context.Background())...), WithLoader(load))
}
func (l Engine) Add(ctx context.Context, tpls ...Template) error {
for idx, tpl := range tpls {
if err := l.tpls.Set(ctx, tpl); err != nil {
return fmt.Errorf("engine add template[%d] with name %s: %w", idx, tpl.Name(), err)
}
}
return nil
}
func (l Engine) Support(ctx context.Context, tpl render.Reference) bool {
return Support(tpl, l.name, l.formats...)
}
func (l Engine) Load(ctx context.Context, reference render.Reference) (render.Execute, error) {
var (
tpl Template
err error
)
tpl, err = l.tpls.Get(ctx, reference.Name())
if err == nil {
return tpl.Execute, nil
}
if !errors.Is(err, ErrNotFound) {
return nil, fmt.Errorf("load get:%w", err)
}
source, err := l.load.Load(ctx, reference)
if err != nil {
return nil, fmt.Errorf("load source:%w", err)
}
tpl, err = l.parce(source)
if err != nil {
return nil, fmt.Errorf("load parce:%w", err)
}
if err := l.tpls.Set(ctx, tpl); err != nil {
return nil, fmt.Errorf("load set:%w", err)
}
return tpl.Execute, nil
}