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 }