github.com/wabain/gqlgen@v0.7.2/codegen/templates/templates.go (about) 1 //go:generate go run ./inliner/inliner.go 2 3 package templates 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "sort" 12 "strconv" 13 "strings" 14 "text/template" 15 "unicode" 16 17 "github.com/99designs/gqlgen/internal/imports" 18 19 "github.com/pkg/errors" 20 ) 21 22 // this is done with a global because subtemplates currently get called in functions. Lets aim to remove this eventually. 23 var CurrentImports *Imports 24 25 func Run(name string, tpldata interface{}) (*bytes.Buffer, error) { 26 t := template.New("").Funcs(template.FuncMap{ 27 "ucFirst": ucFirst, 28 "lcFirst": lcFirst, 29 "quote": strconv.Quote, 30 "rawQuote": rawQuote, 31 "toCamel": ToCamel, 32 "dump": dump, 33 "prefixLines": prefixLines, 34 "reserveImport": CurrentImports.Reserve, 35 "lookupImport": CurrentImports.Lookup, 36 }) 37 38 for filename, data := range data { 39 _, err := t.New(filename).Parse(data) 40 if err != nil { 41 panic(err) 42 } 43 } 44 45 buf := &bytes.Buffer{} 46 err := t.Lookup(name).Execute(buf, tpldata) 47 if err != nil { 48 return nil, err 49 } 50 51 return buf, nil 52 } 53 54 func ucFirst(s string) string { 55 if s == "" { 56 return "" 57 } 58 r := []rune(s) 59 r[0] = unicode.ToUpper(r[0]) 60 return string(r) 61 } 62 63 func lcFirst(s string) string { 64 if s == "" { 65 return "" 66 } 67 68 r := []rune(s) 69 r[0] = unicode.ToLower(r[0]) 70 return string(r) 71 } 72 73 func isDelimiter(c rune) bool { 74 return c == '-' || c == '_' || unicode.IsSpace(c) 75 } 76 77 func ToCamel(s string) string { 78 buffer := make([]rune, 0, len(s)) 79 upper := true 80 lastWasUpper := false 81 82 for _, c := range s { 83 if isDelimiter(c) { 84 upper = true 85 continue 86 } 87 if !lastWasUpper && unicode.IsUpper(c) { 88 upper = true 89 } 90 91 if upper { 92 buffer = append(buffer, unicode.ToUpper(c)) 93 } else { 94 buffer = append(buffer, unicode.ToLower(c)) 95 } 96 upper = false 97 lastWasUpper = unicode.IsUpper(c) 98 } 99 100 return string(buffer) 101 } 102 103 func rawQuote(s string) string { 104 return "`" + strings.Replace(s, "`", "`+\"`\"+`", -1) + "`" 105 } 106 107 func dump(val interface{}) string { 108 switch val := val.(type) { 109 case int: 110 return strconv.Itoa(val) 111 case int64: 112 return fmt.Sprintf("%d", val) 113 case float64: 114 return fmt.Sprintf("%f", val) 115 case string: 116 return strconv.Quote(val) 117 case bool: 118 return strconv.FormatBool(val) 119 case nil: 120 return "nil" 121 case []interface{}: 122 var parts []string 123 for _, part := range val { 124 parts = append(parts, dump(part)) 125 } 126 return "[]interface{}{" + strings.Join(parts, ",") + "}" 127 case map[string]interface{}: 128 buf := bytes.Buffer{} 129 buf.WriteString("map[string]interface{}{") 130 var keys []string 131 for key := range val { 132 keys = append(keys, key) 133 } 134 sort.Strings(keys) 135 136 for _, key := range keys { 137 data := val[key] 138 139 buf.WriteString(strconv.Quote(key)) 140 buf.WriteString(":") 141 buf.WriteString(dump(data)) 142 buf.WriteString(",") 143 } 144 buf.WriteString("}") 145 return buf.String() 146 default: 147 panic(fmt.Errorf("unsupported type %T", val)) 148 } 149 } 150 151 func prefixLines(prefix, s string) string { 152 return prefix + strings.Replace(s, "\n", "\n"+prefix, -1) 153 } 154 155 func RenderToFile(tpl string, filename string, data interface{}) error { 156 if CurrentImports != nil { 157 panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected")) 158 } 159 CurrentImports = &Imports{destDir: filepath.Dir(filename)} 160 161 var buf *bytes.Buffer 162 buf, err := Run(tpl, data) 163 if err != nil { 164 return errors.Wrap(err, filename+" generation failed") 165 } 166 167 b := bytes.Replace(buf.Bytes(), []byte("%%%IMPORTS%%%"), []byte(CurrentImports.String()), -1) 168 CurrentImports = nil 169 170 return write(filename, b) 171 } 172 173 func write(filename string, b []byte) error { 174 err := os.MkdirAll(filepath.Dir(filename), 0755) 175 if err != nil { 176 return errors.Wrap(err, "failed to create directory") 177 } 178 179 formatted, err := imports.Prune(filename, b) 180 if err != nil { 181 fmt.Fprintf(os.Stderr, "gofmt failed on %s: %s\n", filepath.Base(filename), err.Error()) 182 formatted = b 183 } 184 185 err = ioutil.WriteFile(filename, formatted, 0644) 186 if err != nil { 187 return errors.Wrapf(err, "failed to write %s", filename) 188 } 189 190 return nil 191 }