-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
95 lines (82 loc) · 2.24 KB
/
main.go
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path"
"strings"
"unicode"
"github.com/pkg/errors"
)
func CamelToSnakeCase(str string) string {
runes := []rune(str)
isUpperOrNumber := make([]bool, 0, len(runes))
for _, char := range runes {
isUpperOrNumber = append(isUpperOrNumber, unicode.IsUpper(char) || unicode.IsNumber(char))
}
var snakeCase strings.Builder
for i := 0; i < len(runes); i++ {
if isUpperOrNumber[i] && (i > 0 && unicode.IsLower(runes[i-1]) ||
i > 1 && i < len(runes)-1 && isUpperOrNumber[i-1] && !isUpperOrNumber[i+1]) {
snakeCase.WriteRune('_')
}
snakeCase.WriteRune(unicode.ToLower(runes[i]))
}
return snakeCase.String()
}
type InputFile struct {
Name string
Target string
File *ast.File
FileSet *token.FileSet
}
func (file InputFile) OutputName() string {
dir := path.Dir(file.Name)
if !strings.HasSuffix(dir, "/") {
dir += "/"
}
return dir + CamelToSnakeCase(file.Target) + "_builder.go"
}
func loadFiles(inputs []string) ([]InputFile, error) {
files := make([]InputFile, 0, len(inputs))
fileSet := token.NewFileSet()
for _, input := range inputs {
parts := strings.SplitN(input, ":", 2)
if len(parts) != 2 {
return nil, errors.Errorf("'%s' is not in the format FILE:TARGET_STRUCT", input)
}
file, err := parser.ParseFile(fileSet, parts[0], nil, parser.SkipObjectResolution)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse file '%s'", parts[0])
}
files = append(files, InputFile{
Name: parts[0],
Target: parts[1],
File: file,
FileSet: fileSet,
})
}
return files, nil
}
func exitWithError(err error) {
fmt.Printf("ERROR %v\n", err)
os.Exit(1)
}
func main() {
files, err := loadFiles(os.Args[1:])
if err != nil {
exitWithError(errors.Wrap(err, "failed to load files"))
}
for _, file := range files {
generatedCode, err := generate(file.Target, &file)
if err != nil {
exitWithError(errors.Wrapf(err, "failed to generate builder code for '%s:%s'", file.Name, file.Target))
}
fmt.Printf("Generating '%s'...\n", file.OutputName())
if err := os.WriteFile(file.OutputName(), generatedCode, 0666); err != nil {
exitWithError(errors.Wrapf(err, "failed to write builder code to '%s'", file.OutputName()))
}
}
}