diff --git a/parser/parser.go b/parser/parser.go index 2b93e3a..15d0fe6 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -10,6 +10,11 @@ import ( "go/types" ) +// FieldFormatter transfers the field value to expected format +type FieldFormatter interface { + Format(field *StructField) string +} + // StructField defines struct field type StructField struct { Name string @@ -18,6 +23,7 @@ type StructField struct { Comment string Doc string Tag string + FormatFunc func(field *StructField) string } // Key returns the key of the field @@ -32,7 +38,7 @@ func (sf *StructField) Value() interface{} { return sf.NestedType.ToKV() } - return "" + return sf.FormatFunc(sf) } // StructNode defines struct node @@ -52,15 +58,16 @@ func (sn *StructNode) ToKV() map[string]interface{} { // StructParser parses structs in given file or string type StructParser struct { - MainStruct *StructNode - Info types.Info + MainStruct *StructNode + Info types.Info + FieldFormatter FieldFormatter } // NewStructParser is the constructor of StructParser // filePath and src follow the same rule with go/parser.ParseFile // If src != nil, ParseFile parses the source from src and the filename is only used when recording position information. The type of the argument for the src parameter must be string, []byte, or io.Reader. If src == nil, ParseFile parses the file specified by filename. // rootStruct is the root struct we want to use -func NewStructParser(filePath string, src interface{}, rootStruct string) (*StructParser, error) { +func NewStructParser(filePath string, src interface{}, rootStruct string, formatter FieldFormatter) (*StructParser, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, filePath, src, parser.ParseComments) if err != nil { @@ -80,8 +87,9 @@ func NewStructParser(filePath string, src interface{}, rootStruct string) (*Stru return nil, err } - cg := &StructParser{ - Info: info, + sp := &StructParser{ + FieldFormatter: formatter, + Info: info, } ast.Inspect(f, func(n ast.Node) bool { @@ -101,27 +109,27 @@ func NewStructParser(filePath string, src interface{}, rootStruct string) (*Stru return true } - cg.MainStruct = cg.ParseStruct(structName, s) + sp.MainStruct = sp.ParseStruct(structName, s) return false }) - if cg.MainStruct == nil { + if sp.MainStruct == nil { return nil, errors.New("non-exist root struct") } - return cg, nil + return sp, nil } -func (cg *StructParser) ToJSON() ([]byte, error) { - value := cg.MainStruct.ToKV() +func (sp *StructParser) ToJSON() ([]byte, error) { + value := sp.MainStruct.ToKV() return json.MarshalIndent(value, "", " ") } // ParseField parses struct field in nested way -func (cg *StructParser) ParseField(field *ast.Field) *StructField { +func (sp *StructParser) ParseField(field *ast.Field) *StructField { // ast.Print(nil, field) fieldName := field.Names[0].Name - fieldType := cg.Info.TypeOf(field.Type) + fieldType := sp.Info.TypeOf(field.Type) fieldTag := "" if field.Tag != nil { @@ -138,7 +146,7 @@ func (cg *StructParser) ParseField(field *ast.Field) *StructField { var nestedStruct *StructNode if s, isInlineStruct := field.Type.(*ast.StructType); isInlineStruct { - nestedStruct = cg.ParseStruct("", s) + nestedStruct = sp.ParseStruct("", s) } if _, isNamedStructorBasic := field.Type.(*ast.Ident); isNamedStructorBasic && field.Type.(*ast.Ident).Obj != nil { @@ -151,7 +159,7 @@ func (cg *StructParser) ParseField(field *ast.Field) *StructField { if !ok { return nil } - nestedStruct = cg.ParseStruct(ts.Name.Name, s) + nestedStruct = sp.ParseStruct(ts.Name.Name, s) } // fieldType.(*types.Basic) // basic type // *ast.ArrayType: @@ -165,14 +173,15 @@ func (cg *StructParser) ParseField(field *ast.Field) *StructField { Comment: fieldComment, Doc: fieldDoc, NestedType: nestedStruct, + FormatFunc: sp.FieldFormatter.Format, } } // ParseStruct parses struct in nested way -func (cg *StructParser) ParseStruct(structName string, s *ast.StructType) *StructNode { +func (sp *StructParser) ParseStruct(structName string, s *ast.StructType) *StructNode { fields := []*StructField{} for _, field := range s.Fields.List { - parsedField := cg.ParseField(field) + parsedField := sp.ParseField(field) if parsedField != nil { fields = append(fields, parsedField) } diff --git a/parser/parser_test.go b/parser/parser_test.go index 4ba578a..9413765 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -5,6 +5,13 @@ import ( "log" ) +type sampleFormatter struct { +} + +func (f *sampleFormatter) Format(field *StructField) string { + return "" +} + func ExampleStructParser() { const src = ` package p @@ -28,14 +35,15 @@ type StructA struct { Field6 func(int) Field7 StructB } - ` - cg, err := NewStructParser("src.go", src, "StructA") + formatter := &sampleFormatter{} + + sp, err := NewStructParser("src.go", src, "StructA", formatter) if err != nil { log.Fatal(err) } - b, err := cg.ToJSON() + b, err := sp.ToJSON() if err != nil { log.Fatal(err) }