forked from jmattheis/goverter
/
generate.go
99 lines (85 loc) · 3.19 KB
/
generate.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
96
97
98
99
package generator
import (
"fmt"
"go/types"
"github.com/dave/jennifer/jen"
"github.com/rahimlis/go-converter/builder"
"github.com/rahimlis/go-converter/comments"
"github.com/rahimlis/go-converter/namer"
"github.com/rahimlis/go-converter/xtype"
)
// Config the generate config.
type Config struct {
Name string
PackagePath string
ExtendMethods []string
WorkingDir string
WrapErrors bool
IgnoreUnexportedFields bool
MatchFieldsIgnoreCase bool
}
// BuildSteps that'll used for generation.
var BuildSteps = []builder.Builder{
&builder.BasicTargetPointerRule{},
&builder.Pointer{},
&builder.SourcePointer{},
&builder.TargetPointer{},
&builder.Basic{},
&builder.Struct{},
&builder.List{},
&builder.Map{},
}
// Generate generates a jen.File containing converters.
func Generate(pattern []string, mapping []comments.Converter, config Config) (*jen.File, error) {
file := jen.NewFilePathName(config.PackagePath, config.Name)
file.HeaderComment("// Code generated by github.com/rahimlis/go-converter, DO NOT EDIT.")
for _, converter := range mapping {
obj := converter.Scope.Lookup(converter.Name)
if obj == nil {
return nil, fmt.Errorf("%s: could not find %s", pattern, converter.Name)
}
// create the converter struct
file.Type().Id(converter.Config.Name).Struct()
gen := generator{
namer: namer.New(),
file: file,
name: converter.Config.Name,
lookup: map[xtype.Signature]*methodDefinition{},
extend: map[xtype.Signature]*methodDefinition{},
workingDir: config.WorkingDir,
flags: converter.Config.Flags.Add(builder.ConversionFlags{
builder.FlagWrapErrors: config.WrapErrors,
builder.FlagIgnoreUnexported: config.IgnoreUnexportedFields,
builder.FlagMatchIgnoreCase: config.MatchFieldsIgnoreCase,
}),
}
interf := obj.Type().Underlying().(*types.Interface)
extendMethods := make([]string, 0, len(config.ExtendMethods)+len(converter.Config.ExtendMethods))
// Order is important: converter methods are keyed using their in and out type pairs; newly
// discovered methods override existing ones. To enable fine-tuning per converter, extends
// declared on the converter interface should override extends provided globally.
extendMethods = append(extendMethods, config.ExtendMethods...)
extendMethods = append(extendMethods, converter.Config.ExtendMethods...)
if err := gen.parseExtend(obj.Type(), converter.Scope, extendMethods); err != nil {
return nil, fmt.Errorf("Error while parsing extend in\n %s\n\n%s", obj.Type().String(), err)
}
// we checked in comments, that it is an interface
for i := 0; i < interf.NumMethods(); i++ {
method := interf.Method(i)
converterMethod := comments.Method{}
if m, ok := converter.Methods[method.Name()]; ok {
converterMethod = m
}
if err := gen.registerMethod(obj.Type(), converter.Scope, method, converterMethod); err != nil {
return nil, fmt.Errorf("Error while creating converter method:\n %s\n\n%s", method.String(), err)
}
}
if err := gen.validateMethods(); err != nil {
return nil, err
}
if err := gen.createMethods(); err != nil {
return nil, err
}
}
return file, nil
}