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:
commit
a829cb9846
@ -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)
|
||||||
|
}
|
||||||
|
@ -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": ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
41
parser/sample_formatter.go
Normal file
41
parser/sample_formatter.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user