Add NilToZero option

This commit is contained in:
Elara 2024-03-20 14:31:43 -07:00
parent e20fedbafc
commit bb9b6c8128
2 changed files with 29 additions and 1 deletions

View File

@ -20,6 +20,9 @@ type Namespace struct {
// WriteOnSuccess indicates whether the output should only be written if generation fully succeeds. // WriteOnSuccess indicates whether the output should only be written if generation fully succeeds.
// This option buffers the output of the template, so it will use more memory. (default: false) // This option buffers the output of the template, so it will use more memory. (default: false)
WriteOnSuccess bool WriteOnSuccess bool
// NilToZero indictes whether nil pointer values should be converted to zero values of their underlying
// types.
NilToZero bool
escapeHTML *bool escapeHTML *bool
} }
@ -86,6 +89,14 @@ func (n *Namespace) WithWhitespaceMutations(b bool) *Namespace {
return n return n
} }
// WithNilToZero enables or disables conversion of nil values to zero values for the namespace
func (n *Namespace) WithNilToZero(b bool) *Namespace {
n.mu.Lock()
defer n.mu.Unlock()
n.NilToZero = true
return n
}
// GetTemplate tries to get a template from the namespace's template map. // GetTemplate tries to get a template from the namespace's template map.
// If it finds the template, it returns the template and true. If it // If it finds the template, it returns the template and true. If it
// doesn't find it, it returns nil and false. // doesn't find it, it returns nil and false.

View File

@ -26,6 +26,7 @@ type Template struct {
// WriteOnSuccess indicates whether the output should only be written if generation fully succeeds. // WriteOnSuccess indicates whether the output should only be written if generation fully succeeds.
// This option buffers the output of the template, so it will use more memory. (default: false) // This option buffers the output of the template, so it will use more memory. (default: false)
WriteOnSuccess bool WriteOnSuccess bool
NilToZero bool
tags map[string]Tag tags map[string]Tag
vars map[string]any vars map[string]any
@ -66,6 +67,12 @@ func (t Template) WithWriteOnSuccess(b bool) Template {
return t return t
} }
// WithNilToZero enables or disables conversion of nil values to zero values.
func (t Template) WithNilToZero(b bool) Template {
t.NilToZero = true
return t
}
// Execute executes a parsed template and writes // Execute executes a parsed template and writes
// the result to w. // the result to w.
func (t Template) Execute(w io.Writer) error { func (t Template) Execute(w io.Writer) error {
@ -147,6 +154,10 @@ func (t *Template) getEscapeHTML() bool {
} }
} }
func (t *Template) getNilToZero() bool {
return t.NilToZero || t.ns.NilToZero
}
func (t *Template) toString(v any) string { func (t *Template) toString(v any) string {
if h, ok := v.(HTML); ok { if h, ok := v.(HTML); ok {
return string(h) return string(h)
@ -334,14 +345,20 @@ func (t *Template) unwrapASTValue(node ast.Value, local map[string]any) (any, er
return nil, err return nil, err
} }
if node.Not {
rval := reflect.ValueOf(v) rval := reflect.ValueOf(v)
if node.Not {
if rval.Kind() != reflect.Bool { if rval.Kind() != reflect.Bool {
return nil, ast.PosError(node, "%s: the ! operator can only be used on boolean values", valueToString(node)) return nil, ast.PosError(node, "%s: the ! operator can only be used on boolean values", valueToString(node))
} }
return !rval.Bool(), nil return !rval.Bool(), nil
} }
if rval.Kind() == reflect.Pointer && rval.IsNil() && t.getNilToZero() {
rtyp := rval.Type().Elem()
return reflect.New(rtyp).Interface(), nil
}
return v, err return v, err
} }