Skip to content

Commit 4976053

Browse files
author
mayank
committed
Initial commit
Signed-off-by: mayank <mayank.patel@mayadata.io>
0 parents  commit 4976053

File tree

2 files changed

+293
-0
lines changed

2 files changed

+293
-0
lines changed

main.go

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"go/ast"
8+
"go/parser"
9+
"go/token"
10+
"io"
11+
"log"
12+
"os"
13+
"strings"
14+
)
15+
16+
var builder = []string{BuildTemplate, BuildVarTemplate}
17+
var predicate = []string{PredicateTemplate, PredicateVarTemplate}
18+
var utils = []string{SetVarTemplate, GetVarTemplate}
19+
20+
const (
21+
Builder = iota
22+
Predicate
23+
Utils
24+
All
25+
)
26+
27+
type generator struct {
28+
file *string
29+
genType int
30+
dir *string
31+
headerFile *string
32+
}
33+
34+
func newGenerator(file, dir, headerFile *string, gentype int) *generator {
35+
return &generator{
36+
file: file,
37+
genType: gentype,
38+
dir: dir,
39+
headerFile: headerFile,
40+
}
41+
}
42+
43+
func (g *generator) newParser() *ast.File {
44+
fs := token.NewFileSet()
45+
f, err := parser.ParseFile(fs, *g.file, nil, parser.ParseComments)
46+
if err != nil {
47+
log.Fatal(err)
48+
return nil
49+
}
50+
return f
51+
}
52+
53+
func (g *generator) copyHeaderText(df *os.File) {
54+
sf, err := os.Open(*g.headerFile)
55+
if err != nil {
56+
log.Fatalf("Failed to open header file : %v", err)
57+
}
58+
59+
if _, err := io.Copy(df, sf); err != nil {
60+
log.Fatalf("Failed to copy header file : %v", err)
61+
}
62+
sf.Close()
63+
}
64+
65+
func (g *generator) generatePackage(template []string, file string) {
66+
fs := g.newParser()
67+
if fs == nil {
68+
log.Fatalf("Error occurred creating a new parser")
69+
}
70+
71+
f, err := os.Create(*g.dir + "/" + file)
72+
if err != nil {
73+
log.Fatalf("Failed to create new file : %v", err)
74+
}
75+
76+
g.copyHeaderText(f)
77+
78+
for _, t := range template {
79+
if err := parseTemplate(t, fs, bufio.NewWriter(f)); err != nil {
80+
log.Fatalf("Failed to parse template : %v", err)
81+
}
82+
}
83+
err = f.Close()
84+
if err != nil {
85+
log.Fatalf("Failed to close a file : %v", err)
86+
}
87+
return
88+
}
89+
90+
func (g *generator) generateBuilder() {
91+
g.generatePackage(builder, "builder.go")
92+
}
93+
94+
func (g *generator) generatePredicate() {
95+
g.generatePackage(predicate, "predicate.go")
96+
}
97+
98+
func (g *generator) generateUtils() {
99+
g.generatePackage(utils, "utils.go")
100+
}
101+
102+
func (g *generator) Execute() {
103+
switch g.genType {
104+
case Builder:
105+
g.generateBuilder()
106+
case Predicate:
107+
g.generatePredicate()
108+
case Utils:
109+
g.generateUtils()
110+
case All:
111+
for i := Builder; i < All; i++ {
112+
g.genType = i
113+
g.Execute()
114+
}
115+
}
116+
}
117+
118+
func main() {
119+
dir, _ := os.Getwd()
120+
121+
filename := flag.String("file", "", "file name")
122+
outputpath := flag.String("dir", dir, "output directory name")
123+
bfile := flag.String("boilerplate", "", "boilerplate file path")
124+
125+
flag.Parse()
126+
127+
if len(*filename) == 0 || len(*bfile) == 0 {
128+
log.Fatalf("File name is missing")
129+
}
130+
generator := newGenerator(filename, outputpath, bfile, All)
131+
132+
generator.Execute()
133+
return
134+
}
135+
136+
func parseTemplate(template string, fs *ast.File, w *bufio.Writer) error {
137+
var objname string
138+
shouldParseVar := true
139+
predicateGenertor := false
140+
141+
if template == BuildTemplate || template == PredicateTemplate {
142+
shouldParseVar = false
143+
}
144+
if template == PredicateVarTemplate {
145+
predicateGenertor = true
146+
}
147+
148+
// fs is a parsed, type-checked *ast.File.
149+
ast.Inspect(fs, func(n ast.Node) bool {
150+
switch b := n.(type) {
151+
case *ast.GenDecl:
152+
if b.Tok != token.TYPE {
153+
break
154+
}
155+
objname = b.Specs[0].(*ast.TypeSpec).Name.Name
156+
}
157+
return true
158+
})
159+
160+
// copy strcture if it is builder template
161+
if template == BuildTemplate {
162+
copyStructFile(fs, w)
163+
}
164+
165+
template = strings.Replace(template, "$NewObj", objname, -1)
166+
template = strings.Replace(template, "$newobj", objname, -1)
167+
template = strings.Replace(template, "$obj", string(strings.ToLower(objname)[0]), -1)
168+
template = strings.Replace(template, "$Struct", objname, -1)
169+
170+
// fs is a parsed, type-checked *ast.File.
171+
ast.Inspect(fs, func(n ast.Node) bool {
172+
if expr, ok := n.(*ast.StructType); ok && shouldParseVar {
173+
for _, field := range expr.Fields.List {
174+
template := strings.Replace(template, "$Var", field.Names[0].Name, -1)
175+
template = strings.Replace(template, "$var", field.Names[0].Name, -1)
176+
ntype := fmt.Sprintf("%s", field.Type)
177+
template = strings.Replace(template, "$iType", ntype, -1)
178+
if predicateGenertor {
179+
cond := ""
180+
switch ntype {
181+
case "string":
182+
cond = fmt.Sprintf("len(%s) == 0", field.Names[0].Name)
183+
case "bool":
184+
cond = fmt.Sprintf("%s == true", field.Names[0].Name)
185+
case "int":
186+
cond = fmt.Sprintf("%s == 0", field.Names[0].Name)
187+
}
188+
template = strings.Replace(template, "$cond", cond, -1)
189+
}
190+
_, err := w.WriteString(template)
191+
if err != nil {
192+
log.Fatalf("Failed to write modified template : %v", err)
193+
}
194+
}
195+
}
196+
return true
197+
})
198+
199+
if !shouldParseVar {
200+
_, err := w.WriteString(template)
201+
if err != nil {
202+
log.Fatalf("Failed to write modified template : %v", err)
203+
}
204+
}
205+
if err := w.Flush(); err != nil {
206+
log.Fatalf("Failed to flush data to file : %v", err)
207+
}
208+
return nil
209+
}
210+
211+
func copyStructFile(fs *ast.File, w *bufio.Writer) {
212+
213+
// fs is a parsed, type-checked *ast.File.
214+
ast.Inspect(fs, func(n ast.Node) bool {
215+
switch b := n.(type) {
216+
case *ast.GenDecl:
217+
if b.Tok != token.TYPE {
218+
break
219+
}
220+
_, err := fmt.Fprintf(w, "type %s struct {\n", b.Specs[0].(*ast.TypeSpec).Name.Name)
221+
if err != nil {
222+
log.Fatalf("Failed to write struct : %v", err)
223+
}
224+
}
225+
return true
226+
})
227+
228+
// fs is a parsed, type-checked *ast.File.
229+
ast.Inspect(fs, func(n ast.Node) bool {
230+
if expr, ok := n.(*ast.StructType); ok {
231+
for _, field := range expr.Fields.List {
232+
_, err := fmt.Fprintf(w, "\t%s\n", field.Comment.List[0].Text)
233+
if err != nil {
234+
log.Fatalf("Failed to write struct : %v", err)
235+
}
236+
_, err = fmt.Fprintf(w, "\t%s %s\n", field.Names[0].Name, field.Type)
237+
if err != nil {
238+
log.Fatalf("Failed to write struct : %v", err)
239+
}
240+
}
241+
}
242+
return true
243+
})
244+
245+
_, err := fmt.Fprintf(w, "}\n")
246+
if err != nil {
247+
log.Fatalf("Failed to write struct : %v", err)
248+
}
249+
if err := w.Flush(); err != nil {
250+
log.Fatalf("Failed to flush data to file : %v", err)
251+
}
252+
}

template.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
var BuildVarTemplate = `
4+
// With$Var method fills the $Var field of $NewObj object.
5+
func ($obj *$newobj) With$Var($var $iType) *$NewObj {
6+
$obj.$var = $var
7+
return $obj
8+
}
9+
`
10+
var BuildTemplate = `
11+
// New$Struct returns new instance of object $Struct
12+
func New$Struct() *$NewObj {
13+
return &$Struct{}
14+
}
15+
`
16+
17+
var SetVarTemplate = `
18+
// Set$Var method set the $Var field of $NewObj object.
19+
func ($obj *$newobj) Set$Var($var $iType) {
20+
$obj.$var = $var
21+
}
22+
`
23+
var GetVarTemplate = `
24+
// Get$Var method get the $Var field of $NewObj object.
25+
func ($obj *$newobj) Get$Var() $iType {
26+
return $obj.$var
27+
}
28+
`
29+
var PredicateVarTemplate = `
30+
// IsSet$Var method check if the $Var field of $NewObj object is set.
31+
func Is$VarSet() PredicateFunc {
32+
return func(c *$newobj) bool {
33+
return $cond
34+
}
35+
}
36+
`
37+
var PredicateTemplate = `
38+
// PredicateFunc defines data-type for validation function
39+
type PredicateFunc func(*$newobj) bool
40+
41+
`

0 commit comments

Comments
 (0)