templates.go

  1//go:generate go run ./inliner/inliner.go
  2
  3package templates
  4
  5import (
  6	"bytes"
  7	"fmt"
  8	"sort"
  9	"strconv"
 10	"strings"
 11	"text/template"
 12	"unicode"
 13)
 14
 15func Run(name string, tpldata interface{}) (*bytes.Buffer, error) {
 16	t := template.New("").Funcs(template.FuncMap{
 17		"ucFirst":     ucFirst,
 18		"lcFirst":     lcFirst,
 19		"quote":       strconv.Quote,
 20		"rawQuote":    rawQuote,
 21		"toCamel":     ToCamel,
 22		"dump":        dump,
 23		"prefixLines": prefixLines,
 24	})
 25
 26	for filename, data := range data {
 27		_, err := t.New(filename).Parse(data)
 28		if err != nil {
 29			panic(err)
 30		}
 31	}
 32
 33	buf := &bytes.Buffer{}
 34	err := t.Lookup(name).Execute(buf, tpldata)
 35	if err != nil {
 36		return nil, err
 37	}
 38
 39	return buf, nil
 40}
 41
 42func ucFirst(s string) string {
 43	if s == "" {
 44		return ""
 45	}
 46	r := []rune(s)
 47	r[0] = unicode.ToUpper(r[0])
 48	return string(r)
 49}
 50
 51func lcFirst(s string) string {
 52	if s == "" {
 53		return ""
 54	}
 55
 56	r := []rune(s)
 57	r[0] = unicode.ToLower(r[0])
 58	return string(r)
 59}
 60
 61func isDelimiter(c rune) bool {
 62	return c == '-' || c == '_' || unicode.IsSpace(c)
 63}
 64
 65func ToCamel(s string) string {
 66	buffer := make([]rune, 0, len(s))
 67	upper := true
 68	lastWasUpper := false
 69
 70	for _, c := range s {
 71		if isDelimiter(c) {
 72			upper = true
 73			continue
 74		}
 75		if !lastWasUpper && unicode.IsUpper(c) {
 76			upper = true
 77		}
 78
 79		if upper {
 80			buffer = append(buffer, unicode.ToUpper(c))
 81		} else {
 82			buffer = append(buffer, unicode.ToLower(c))
 83		}
 84		upper = false
 85		lastWasUpper = unicode.IsUpper(c)
 86	}
 87
 88	return string(buffer)
 89}
 90
 91func rawQuote(s string) string {
 92	return "`" + strings.Replace(s, "`", "`+\"`\"+`", -1) + "`"
 93}
 94
 95func dump(val interface{}) string {
 96	switch val := val.(type) {
 97	case int:
 98		return strconv.Itoa(val)
 99	case float64:
100		return fmt.Sprintf("%f", val)
101	case string:
102		return strconv.Quote(val)
103	case bool:
104		return strconv.FormatBool(val)
105	case nil:
106		return "nil"
107	case []interface{}:
108		var parts []string
109		for _, part := range val {
110			parts = append(parts, dump(part))
111		}
112		return "[]interface{}{" + strings.Join(parts, ",") + "}"
113	case map[string]interface{}:
114		buf := bytes.Buffer{}
115		buf.WriteString("map[string]interface{}{")
116		var keys []string
117		for key := range val {
118			keys = append(keys, key)
119		}
120		sort.Strings(keys)
121
122		for _, key := range keys {
123			data := val[key]
124
125			buf.WriteString(strconv.Quote(key))
126			buf.WriteString(":")
127			buf.WriteString(dump(data))
128			buf.WriteString(",")
129		}
130		buf.WriteString("}")
131		return buf.String()
132	default:
133		panic(fmt.Errorf("unsupported type %T", val))
134	}
135}
136
137func prefixLines(prefix, s string) string {
138	return prefix + strings.Replace(s, "\n", "\n"+prefix, -1)
139}