template.go 1.14 KB
Newer Older
Michael Yang's avatar
Michael Yang committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package templates

import (
	"bytes"
	"embed"
	"encoding/json"
	"errors"
	"io"
	"math"
	"sync"

	"github.com/agnivade/levenshtein"
)

//go:embed index.json
var indexBytes []byte

//go:embed *.gotmpl
var templatesFS embed.FS

var templatesOnce = sync.OnceValues(func() ([]*Template, error) {
	var templates []*Template
	if err := json.Unmarshal(indexBytes, &templates); err != nil {
		return nil, err
	}

	for _, t := range templates {
		bts, err := templatesFS.ReadFile(t.Name + ".gotmpl")
		if err != nil {
			return nil, err
		}

		t.Bytes = bts
	}

	return templates, nil
})

type Template struct {
	Name     string `json:"name"`
	Template string `json:"template"`
	Bytes []byte
}

func (t Template) Reader() io.Reader {
	return bytes.NewReader(t.Bytes)
}

func NamedTemplate(s string) (*Template, error) {
	templates, err := templatesOnce()
	if err != nil {
		return nil, err
	}

	var template *Template
	score := math.MaxInt
	for _, t := range templates {
		if s := levenshtein.ComputeDistance(s, t.Template); s < score {
			score = s
			template = t
		}
	}

	if score < 100 {
		return template, nil
	}

	return nil, errors.New("no matching template found")
}