44 "errors"
55 "fmt"
66 "go/types"
7+ "regexp"
78
89 "github.com/fatih/structtag"
910 "github.com/iancoleman/strcase"
@@ -17,6 +18,16 @@ type field struct {
1718 Depth int
1819}
1920
21+ type parseFieldsParams struct {
22+ format string
23+ tag string
24+ tagRegex string
25+ tagFormat string
26+ tagStrict bool
27+ embedded bool
28+ excluded []string
29+ }
30+
2031func parseType (path , name string ) (string , types.Type , error ) {
2132 cfg := & packages.Config {
2233 Mode : packages .NeedTypes | packages .NeedImports | packages .NeedModule ,
@@ -40,14 +51,7 @@ func parseType(path, name string) (string, types.Type, error) {
4051 return obj .Pkg ().Name (), obj .Type (), nil
4152}
4253
43- func parseFields (
44- typ types.Type ,
45- useTag string ,
46- useEmbedded bool ,
47- excluded []string ,
48- format string ,
49- depth int ,
50- ) ([]field , error ) {
54+ func parseFields (typ types.Type , params parseFieldsParams , depth int ) ([]field , error ) {
5155 strct , ok := typ .Underlying ().(* types.Struct )
5256 if ! ok {
5357 return nil , fmt .Errorf ("type %s is not a struct" , typ )
@@ -62,42 +66,70 @@ func parseFields(
6266 continue
6367 }
6468
65- isExcluded := lo .Contains (excluded , strct .Field (i ).Name ())
69+ isExcluded := lo .Contains (params . excluded , strct .Field (i ).Name ())
6670 if isExcluded {
6771 continue
6872 }
6973
7074 if strct .Field (i ).Embedded () {
71- if ! useEmbedded {
75+ if ! params . embedded {
7276 continue
7377 }
7478
75- embeddedFields , err := parseFields (strct .Field (i ).Type (), useTag , useEmbedded , excluded , format , depth )
79+ embeddedFields , err := parseFields (strct .Field (i ).Type (), params , depth )
7680 if err != nil {
7781 return nil , err
7882 }
7983
8084 fields = append (fields , embeddedFields ... )
8185 } else {
8286 alias := strct .Field (i ).Name ()
83- if useTag != "" {
87+ format := params .format
88+
89+ if params .tag != "" {
8490 tags , err := structtag .Parse (strct .Tag (i ))
8591 if err != nil {
8692 return nil , err
8793 }
8894
89- found := false
95+ var matchedTag * structtag. Tag
9096 for _ , t := range tags .Tags () {
91- if t .Key == useTag {
92- alias = t .Name
93- found = true
97+ if t .Key == params .tag {
98+ matchedTag = t
9499
95100 break
96101 }
97102 }
98103
99- if ! found {
100- return nil , fmt .Errorf ("tag %s not found for field %s" , useTag , strct .Field (i ).Name ())
104+ if matchedTag != nil {
105+ if params .tagRegex == "" {
106+ alias = matchedTag .Name
107+ format = params .tagFormat
108+ } else {
109+ regex , err := regexp .Compile (params .tagRegex )
110+ if err != nil {
111+ return nil , err
112+ }
113+
114+ matches := regex .FindStringSubmatch (matchedTag .Value ())
115+ if len (matches ) < 2 {
116+ if params .tagStrict {
117+ return nil , fmt .Errorf (
118+ "tag %s of field %s does not match regex %s" ,
119+ matchedTag .Value (),
120+ strct .Field (i ).Name (),
121+ params .tagRegex ,
122+ )
123+ }
124+ } else {
125+ format = params .tagFormat
126+ alias = matches [1 ]
127+ }
128+ }
129+ } else {
130+ if params .tagStrict {
131+ return nil , fmt .Errorf ("tag %s not found for field %s" , params .tag , strct .Field (i ).Name ())
132+ }
101133 }
102134 }
103135
@@ -110,7 +142,7 @@ func parseFields(
110142 case formatPascalCase :
111143 alias = strcase .ToCamel (alias )
112144 default :
113- return nil , fmt .Errorf ("invalid format %s" , format )
145+ return nil , fmt .Errorf ("invalid format %s" , params . format )
114146 }
115147
116148 fields = append (fields , field {
0 commit comments