1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package lazytemplate is a thin wrapper over text/template, allowing the use
6// of global template variables without forcing them to be parsed at init.
7package lazytemplate
8
9import (
10	"io"
11	"os"
12	"strings"
13	"sync"
14	"text/template"
15)
16
17// Template is a wrapper around text/template.Template, where the underlying
18// template will be parsed the first time it is needed.
19type Template struct {
20	name, text string
21
22	once sync.Once
23	tmpl *template.Template
24}
25
26func (r *Template) tp() *template.Template {
27	r.once.Do(r.build)
28	return r.tmpl
29}
30
31func (r *Template) build() {
32	r.tmpl = template.Must(template.New(r.name).Parse(r.text))
33	r.name, r.text = "", ""
34}
35
36func (r *Template) Execute(w io.Writer, data any) error {
37	return r.tp().Execute(w, data)
38}
39
40var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
41
42// New creates a new lazy template, delaying the parsing work until it is first
43// needed. If the code is being run as part of tests, the template parsing will
44// happen immediately.
45func New(name, text string) *Template {
46	lt := &Template{name: name, text: text}
47	if inTest {
48		// In tests, always parse the templates early.
49		lt.tp()
50	}
51	return lt
52}
53