1
0
mirror of https://github.com/beego/bee.git synced 2024-11-24 18:30:53 +00:00

Merge pull request #788 from y4h2/parse-config

Parse config | update structFiled and structNode to utilize built-in marshal
This commit is contained in:
Ming Deng 2021-06-17 23:10:15 +08:00 committed by GitHub
commit a829cb9846
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 56 deletions

View File

@ -1,7 +1,6 @@
package beeParser package beeParser
import ( import (
"encoding/json"
"errors" "errors"
"go/ast" "go/ast"
"go/importer" "go/importer"
@ -11,8 +10,10 @@ import (
) )
// FieldFormatter transfers the field value to expected format // FieldFormatter transfers the field value to expected format
type FieldFormatter interface { type Formatter interface {
Format(field *StructField) string FieldFormatFunc(field *StructField) ([]byte, error)
StructFormatFunc(node *StructNode) ([]byte, error)
Marshal(root *StructNode) ([]byte, error)
} }
// StructField defines struct field // StructField defines struct field
@ -23,51 +24,43 @@ type StructField struct {
Comment string Comment string
Doc string Doc string
Tag string Tag string
FormatFunc func(field *StructField) string FormatFunc func(field *StructField) ([]byte, error)
} }
// Key returns the key of the field func (sf *StructField) MarshalText() ([]byte, error) {
func (sf *StructField) Key() string { if sf.FormatFunc == nil {
return sf.Name return nil, errors.New("format func is missing")
}
// Value returns the value of the field
// if the field contains nested struct, it will return a nested result
func (sf *StructField) Value() interface{} {
if sf.NestedType != nil {
return sf.NestedType.ToKV()
} }
return sf.FormatFunc(sf) return sf.FormatFunc(sf)
} }
// StructNode defines struct node // StructNode defines struct node
type StructNode struct { type StructNode struct {
Name string Name string
Fields []*StructField Fields []*StructField
FormatFunc func(node *StructNode) ([]byte, error)
} }
// ToKV transfers struct to key value pair func (sn *StructNode) MarshalText() ([]byte, error) {
func (sn *StructNode) ToKV() map[string]interface{} { if sn.FormatFunc == nil {
value := map[string]interface{}{} return nil, errors.New("format func is missing")
for _, field := range sn.Fields {
value[field.Key()] = field.Value()
} }
return value
return sn.FormatFunc(sn)
} }
// StructParser parses structs in given file or string // StructParser parses structs in given file or string
type StructParser struct { type StructParser struct {
MainStruct *StructNode MainStruct *StructNode
Info types.Info Info types.Info
FieldFormatter FieldFormatter Formatter Formatter
} }
// NewStructParser is the constructor of StructParser // NewStructParser is the constructor of StructParser
// filePath and src follow the same rule with go/parser.ParseFile // 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. // 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 // rootStruct is the root struct we want to use
func NewStructParser(filePath string, src interface{}, rootStruct string, formatter FieldFormatter) (*StructParser, error) { func NewStructParser(filePath string, src interface{}, rootStruct string, formatter Formatter) (*StructParser, error) {
fset := token.NewFileSet() fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filePath, src, parser.ParseComments) f, err := parser.ParseFile(fset, filePath, src, parser.ParseComments)
if err != nil { if err != nil {
@ -88,8 +81,8 @@ func NewStructParser(filePath string, src interface{}, rootStruct string, format
} }
sp := &StructParser{ sp := &StructParser{
FieldFormatter: formatter, Formatter: formatter,
Info: info, Info: info,
} }
ast.Inspect(f, func(n ast.Node) bool { ast.Inspect(f, func(n ast.Node) bool {
@ -120,11 +113,6 @@ func NewStructParser(filePath string, src interface{}, rootStruct string, format
return sp, nil return sp, nil
} }
func (sp *StructParser) ToJSON() ([]byte, error) {
value := sp.MainStruct.ToKV()
return json.MarshalIndent(value, "", " ")
}
// ParseField parses struct field in nested way // ParseField parses struct field in nested way
func (sp *StructParser) ParseField(field *ast.Field) *StructField { func (sp *StructParser) ParseField(field *ast.Field) *StructField {
// ast.Print(nil, field) // ast.Print(nil, field)
@ -173,7 +161,7 @@ func (sp *StructParser) ParseField(field *ast.Field) *StructField {
Comment: fieldComment, Comment: fieldComment,
Doc: fieldDoc, Doc: fieldDoc,
NestedType: nestedStruct, NestedType: nestedStruct,
FormatFunc: sp.FieldFormatter.Format, FormatFunc: sp.Formatter.FieldFormatFunc,
} }
} }
@ -188,7 +176,12 @@ func (sp *StructParser) ParseStruct(structName string, s *ast.StructType) *Struc
} }
return &StructNode{ return &StructNode{
Name: structName, Name: structName,
Fields: fields, Fields: fields,
FormatFunc: sp.Formatter.StructFormatFunc,
} }
} }
func (sp *StructParser) Marshal() ([]byte, error) {
return sp.Formatter.Marshal(sp.MainStruct)
}

View File

@ -1,18 +1,44 @@
package beeParser package beeParser
import ( import (
"encoding/json"
"fmt" "fmt"
"log" "log"
) )
type sampleFormatter struct { type sampleFormatter struct {
Annotation Annotation
} }
func (f *sampleFormatter) Format(field *StructField) string { func (f *sampleFormatter) FieldFormatFunc(field *StructField) ([]byte, error) {
return "" // @todo update annotationResult by parsing with annotation struct
annotationResult := field.Comment + field.Doc
return json.Marshal(&struct {
Key string
Annotation string
NestedType *StructNode `json:"NestedType,omitempty"`
}{
Key: field.Name,
Annotation: annotationResult,
NestedType: field.NestedType,
})
} }
func ExampleStructParser() { func (f *sampleFormatter) StructFormatFunc(node *StructNode) ([]byte, error) {
return json.Marshal(&struct {
Key string
Fields []*StructField `json:"Fields,omitempty"`
}{
Key: node.Name,
Fields: node.Fields,
})
}
func (f *sampleFormatter) Marshal(node *StructNode) ([]byte, error) {
return json.Marshal(node)
}
func ExamplesampleFormatter() {
const src = ` const src = `
package p package p
@ -24,7 +50,11 @@ type StructB struct {
Field1 string Field1 string
} }
type StructA struct { type StructA struct {
Field1 string // doc
Field1 string //comment
// @Name Field1
// @Path https://github.com/beego/bee
// https://github.com/beego
Field2 struct{ Field2 struct{
a string a string
b string b string
@ -43,7 +73,7 @@ type StructA struct {
log.Fatal(err) log.Fatal(err)
} }
b, err := sp.ToJSON() b, err := sp.Marshal()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -51,18 +81,5 @@ type StructA struct {
fmt.Println(string(b)) fmt.Println(string(b))
// Output: // Output:
// { // "{\"Key\":\"StructA\",\"Fields\":[\"{\\\"Key\\\":\\\"Field1\\\",\\\"Annotation\\\":\\\"comment\\\\ndoc\\\\n\\\"}\",\"{\\\"Key\\\":\\\"Field2\\\",\\\"Annotation\\\":\\\"@Name Field1\\\\n@Path https://github.com/beego/bee\\\\n\\\\t\\\\t https://github.com/beego\\\\n\\\",\\\"NestedType\\\":\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"\\\\\\\",\\\\\\\"Fields\\\\\\\":[\\\\\\\"{\\\\\\\\\\\\\\\"Key\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"a\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"Annotation\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\",\\\\\\\"{\\\\\\\\\\\\\\\"Key\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"b\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"Annotation\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\"]}\\\"}\",\"{\\\"Key\\\":\\\"Field3\\\",\\\"Annotation\\\":\\\"\\\"}\",\"{\\\"Key\\\":\\\"Field4\\\",\\\"Annotation\\\":\\\"\\\"}\",\"{\\\"Key\\\":\\\"Field5\\\",\\\"Annotation\\\":\\\"\\\"}\",\"{\\\"Key\\\":\\\"Field6\\\",\\\"Annotation\\\":\\\"\\\"}\",\"{\\\"Key\\\":\\\"Field7\\\",\\\"Annotation\\\":\\\"\\\",\\\"NestedType\\\":\\\"{\\\\\\\"Key\\\\\\\":\\\\\\\"StructB\\\\\\\",\\\\\\\"Fields\\\\\\\":[\\\\\\\"{\\\\\\\\\\\\\\\"Key\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"Field1\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"Annotation\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\"]}\\\"}\"]}"
// "Field1": "",
// "Field2": {
// "a": "",
// "b": ""
// },
// "Field3": "",
// "Field4": "",
// "Field5": "",
// "Field6": "",
// "Field7": {
// "Field1": ""
// }
// }
} }

View File

@ -0,0 +1,41 @@
package beeParser
import "encoding/json"
type AnnotationJSONFormatter struct {
Annotation Annotator
}
func (f *AnnotationJSONFormatter) Format(field *StructField) string {
if field.Comment == "" && field.Doc == "" {
return ""
}
kvs := f.Annotation.Annotate(field.Doc + field.Comment)
res, _ := json.Marshal(kvs)
return string(res)
}
func NewAnnotationJSONFormatter() *AnnotationJSONFormatter {
return &AnnotationJSONFormatter{Annotation: &Annotation{}}
}
type AnnotationYAMLFormatter struct {
Annotation Annotator
}
func (f *AnnotationYAMLFormatter) Format(field *StructField) string {
if field.Comment == "" && field.Doc == "" {
return ""
}
kvs := f.Annotation.Annotate(field.Doc + field.Comment)
res, _ := json.Marshal(kvs)
return string(res)
}
func NewAnnotationYAMLFormatter() *AnnotationYAMLFormatter {
return &AnnotationYAMLFormatter{Annotation: &Annotation{}}
}
type AnnotationTextFromatter struct {
Annotation Annotator
}