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}