From 57fa164af7715948265afda6a2dcc323c2700157 Mon Sep 17 00:00:00 2001 From: Tristan Cartledge Date: Fri, 13 Jan 2023 10:06:18 +0000 Subject: [PATCH] feat: support filesystem features --- engine.go | 63 +++++++++++++++++++++++++++++++++++++-------------- templating.go | 18 +++++++-------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/engine.go b/engine.go index 83854d4..d264202 100644 --- a/engine.go +++ b/engine.go @@ -2,6 +2,7 @@ package easytemplate import ( "fmt" + "io/fs" "os" "path" "text/template" @@ -10,17 +11,25 @@ import ( _ "github.com/robertkrimen/otto/underscore" ) +type WriteFunc func(string, []byte) error + type Opt func(*Engine) -func WithTemplateDir(templateDir string) Opt { +func WithBaseDir(baseDir string) Opt { + return func(e *Engine) { + e.baseDir = baseDir + } +} + +func WithReadFileSystem(fs fs.FS) Opt { return func(e *Engine) { - e.templateDir = templateDir + e.readFS = fs } } -func WithScriptDir(scriptDir string) Opt { +func WithWriteFunc(writeFunc WriteFunc) Opt { return func(e *Engine) { - e.scriptDir = scriptDir + e.writeFunc = writeFunc } } @@ -49,8 +58,9 @@ func WithJSFuncs(funcs map[string]func(call otto.FunctionCall) otto.Value) Opt { } type Engine struct { - templateDir string - scriptDir string + baseDir string + readFS fs.FS + writeFunc WriteFunc ran bool tmplFuncs template.FuncMap jsFuncs map[string]func(call otto.FunctionCall) otto.Value @@ -88,7 +98,12 @@ func (e *Engine) RunScript(scriptFile string, data any) error { return err } - s, err := vm.Compile(scriptFile, nil) + script, err := e.ReadFile(scriptFile) + if err != nil { + return fmt.Errorf("failed to read script file: %w", err) + } + + s, err := vm.Compile("", script) if err != nil { return fmt.Errorf("failed to compile script: %w", err) } @@ -106,16 +121,16 @@ func (e *Engine) RunTemplate(templateFile string, outFile string, data any) erro return err } - templated, err := e.tmpl(vm, templateFile, data) - if err != nil { - return fmt.Errorf("failed to template file: %w", err) - } + return e.templateFile(vm, templateFile, outFile, data) +} - if err := os.WriteFile(outFile, []byte(templated), 0o644); err != nil { - return fmt.Errorf("failed to write file: %w", err) +func (e *Engine) RunTemplateString(templateString string, data any) (string, error) { + vm, err := e.init(data) + if err != nil { + return "", err } - return nil + return e.tmpl(vm, templateString, data) } func (e *Engine) init(data any) (*otto.Otto, error) { @@ -170,11 +185,12 @@ func (e *Engine) require(call otto.FunctionCall) otto.Value { scriptPath := call.Argument(0).String() - if e.scriptDir != "" { - scriptPath = path.Join(e.scriptDir, scriptPath) + script, err := e.ReadFile(scriptPath) + if err != nil { + panic(vm.MakeCustomError("requireScript", err.Error())) } - s, err := vm.Compile(scriptPath, nil) + s, err := vm.Compile("", script) if err != nil { panic(vm.MakeCustomError("requireScript", err.Error())) } @@ -212,3 +228,16 @@ func (e *Engine) registerTemplateFunc(call otto.FunctionCall) otto.Value { return otto.Value{} } + +func (e *Engine) ReadFile(file string) ([]byte, error) { + filePath := file + if e.baseDir != "" { + filePath = path.Join(e.baseDir, filePath) + } + + if e.readFS != nil { + return fs.ReadFile(e.readFS, filePath) + } else { + return os.ReadFile(filePath) + } +} diff --git a/templating.go b/templating.go index c658384..15f8274 100644 --- a/templating.go +++ b/templating.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "os" - "path" "regexp" "strings" "text/template" @@ -38,8 +37,14 @@ func (e *Engine) templateFile(vm *otto.Otto, templateFile, outFile string, input return err } - if err := os.WriteFile(outFile, []byte(output), 0o644); err != nil { - return err + if e.writeFunc != nil { + err = e.writeFunc(outFile, []byte(output)) + } else { + err = os.WriteFile(outFile, []byte(output), 0o644) + } + + if err != nil { + return fmt.Errorf("failed to write file %s: %w", outFile, err) } return nil @@ -101,12 +106,7 @@ func (e *Engine) tmpl(vm *otto.Otto, templatePath string, inputData any) (out st return "", fmt.Errorf("failed to set context: %w", err) } - tp := templatePath - if e.templateDir != "" { - tp = path.Join(e.templateDir, templatePath) - } - - data, err := os.ReadFile(tp) + data, err := e.ReadFile(templatePath) if err != nil { return "", fmt.Errorf("failed to read template file: %w", err) }