forked from switchupcb/copygen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
matcher.go
103 lines (87 loc) · 3.02 KB
/
matcher.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
100
101
102
103
// Package matcher matches fields.
package matcher
import (
"strings"
"github.com/reedom/copygen/cli/models"
)
// Match matches the fields of a parsed generator.
func Match(gen *models.Generator) error {
for _, function := range gen.Functions {
for _, toType := range function.To {
for _, fromType := range function.From {
// top-level types can be pointed (i.e domain.Account).
toFields := toType.Field.AllFields(nil, nil)
fromFields := fromType.Field.AllFields(nil, nil)
// each toField is compared to every fromField.
for i := 0; i < len(toFields); i++ {
for j := 0; j < len(fromFields); j++ {
match(function, toFields[i], fromFields[j])
if toFields[i].From != nil {
break
}
}
}
}
}
}
RemoveUnpointedFields(gen)
return nil
}
// match determines which matcher to use for two fields, then matches them.
func match(function models.Function, toField *models.Field, fromField *models.Field) {
if function.Options.Manual {
switch {
case toField.Options.Map != "" || fromField.Options.Map != "":
mapmatch(toField, fromField)
case toField.Options.Tag != "":
tagmatch(toField, fromField)
case toField.Options.Automatch || fromField.Options.Automatch:
automatch(toField, fromField, function.Options.NoCase)
}
} else {
automatch(toField, fromField, function.Options.NoCase)
}
}
// automatch automatically matches the fields of a fromType to a toType by name and definition.
// automatch is used when no `map` or `tag` options apply to a field.
func automatch(toField, fromField *models.Field, noCase bool) {
fromFieldName := fromField.Name
toFieldName := toField.Name
if noCase {
fromFieldName = strings.ToLower(fromFieldName)
toFieldName = strings.ToLower(toFieldName)
}
if toFieldName == fromFieldName &&
((toField.FullDefinition() == fromField.FullDefinition() ||
toField.FullDefinition()[1:] == fromField.FullDefinition() ||
toField.FullDefinition() == fromField.FullDefinition()[1:]) ||
!fromField.Options.Convert.IsEmpty()) {
fromField.To = toField
toField.From = fromField
// prevent parallel matching.
fromField.Fields = make([]*models.Field, 0)
toField.Fields = make([]*models.Field, 0)
}
}
// mapmatch manually maps a from-field to a to-field.
// mapmatch is used when a map option is specified.
func mapmatch(toField, fromField *models.Field) {
if fromField.Options.Map != "" && toField.FullNameWithoutPointer("") == fromField.Options.Map {
fromField.To = toField
toField.From = fromField
// prevent parallel matching.
fromField.Fields = make([]*models.Field, 0)
toField.Fields = make([]*models.Field, 0)
}
}
// tagmatch manually maps a from-field to a to-field using tags.
// tagmatch is used when a tag option is specified.
func tagmatch(toField, fromField *models.Field) {
if toField.Options.Tag != "" && toField.Options.Tag == fromField.Options.Tag {
fromField.To = toField
toField.From = fromField
// prevent parallel matching.
fromField.Fields = make([]*models.Field, 0)
toField.Fields = make([]*models.Field, 0)
}
}