github.com/blend/go-sdk@v1.20220411.3/template/template.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package template 9 10 import ( 11 "bytes" 12 "io" 13 "os" 14 texttemplate "text/template" 15 16 "github.com/blend/go-sdk/env" 17 "github.com/blend/go-sdk/ex" 18 ) 19 20 // New creates a new template. 21 func New() *Template { 22 temp := &Template{ 23 Viewmodel: Viewmodel{ 24 vars: Vars{}, 25 env: env.Env(), 26 }, 27 } 28 temp.funcs = texttemplate.FuncMap(ViewFuncs{}.FuncMap()) 29 return temp 30 } 31 32 // NewFromFile creates a new template from a file. 33 func NewFromFile(filepath string) (*Template, error) { 34 contents, err := os.ReadFile(filepath) 35 if err != nil { 36 return nil, ex.New(err) 37 } 38 39 return New().WithName(filepath).WithBody(string(contents)), nil 40 } 41 42 // Template is a wrapper for html.Template. 43 type Template struct { 44 Viewmodel 45 name string 46 body string 47 includes []string 48 funcs texttemplate.FuncMap 49 leftDelim string 50 rightDelim string 51 } 52 53 // WithName sets the template name. 54 func (t *Template) WithName(name string) *Template { 55 t.name = name 56 return t 57 } 58 59 // Name returns the template name if set, or if not set, just "template" as a constant. 60 func (t *Template) Name() string { 61 if len(t.name) > 0 { 62 return t.name 63 } 64 return "template" 65 } 66 67 // WithDelims sets the template action delimiters, treating empty string as default delimiter. 68 func (t *Template) WithDelims(left, right string) *Template { 69 t.leftDelim = left 70 t.rightDelim = right 71 return t 72 } 73 74 // WithBody sets the template body and returns a reference to the template object. 75 func (t *Template) WithBody(body string) *Template { 76 t.body = body 77 return t 78 } 79 80 // WithInclude includes a (sub) template into the rendering assets. 81 func (t *Template) WithInclude(body string) *Template { 82 t.includes = append(t.includes, body) 83 return t 84 } 85 86 // Body returns the template body. 87 func (t *Template) Body() string { 88 return t.body 89 } 90 91 // WithVar sets a variable and returns a reference to the template object. 92 func (t *Template) WithVar(key string, value interface{}) *Template { 93 t.SetVar(key, value) 94 return t 95 } 96 97 // SetVar sets a var in the template. 98 func (t *Template) SetVar(key string, value interface{}) { 99 t.vars[key] = value 100 } 101 102 // WithVars reads a map of variables into the template. 103 func (t *Template) WithVars(vars Vars) *Template { 104 t.vars = MergeVars(t.vars, vars) 105 return t 106 } 107 108 // WithEnvVars sets the environment variables. 109 func (t *Template) WithEnvVars(envVars env.Vars) *Template { 110 t.Viewmodel.env = env.Merge(t.Viewmodel.env, envVars) 111 return t 112 } 113 114 // SetVarsFromFile reads vars from a file and merges them 115 // with the current variables set. 116 func (t *Template) SetVarsFromFile(path string) error { 117 fileVars, err := NewVarsFromPath(path) 118 if err != nil { 119 return err 120 } 121 122 t.vars = MergeVars(t.vars, fileVars) 123 return nil 124 } 125 126 // Process processes the template. 127 func (t *Template) Process(dst io.Writer) error { 128 base := texttemplate.New(t.Name()).Funcs(t.ViewFuncs()).Delims(t.leftDelim, t.rightDelim) 129 130 var err error 131 for _, include := range t.includes { 132 _, err = base.New(t.Name()).Parse(include) 133 if err != nil { 134 return err 135 } 136 } 137 138 final, err := base.New(t.Name()).Parse(t.body) 139 if err != nil { 140 return err 141 } 142 return final.Execute(dst, t.Viewmodel) 143 } 144 145 // ProcessString is a helper to process the template as a string. 146 func (t *Template) ProcessString() (string, error) { 147 buffer := new(bytes.Buffer) 148 err := t.Process(buffer) 149 if err != nil { 150 return "", err 151 } 152 return buffer.String(), nil 153 } 154 155 // MustProcessString is a helper to process a template as a string 156 // and panic on error. 157 func (t *Template) MustProcessString() string { 158 output, err := t.ProcessString() 159 if err != nil { 160 panic(err) 161 } 162 return output 163 } 164 165 // ViewFuncs returns the view funcs. 166 func (t *Template) ViewFuncs() texttemplate.FuncMap { 167 return t.funcs 168 }