mirror of
				https://github.com/beego/bee.git
				synced 2025-10-31 22:43:24 +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:
		| @@ -1,7 +1,6 @@ | ||||
| package beeParser | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"go/ast" | ||||
| 	"go/importer" | ||||
| @@ -11,8 +10,10 @@ import ( | ||||
| ) | ||||
|  | ||||
| // FieldFormatter transfers the field value to expected format | ||||
| type FieldFormatter interface { | ||||
| 	Format(field *StructField) string | ||||
| type Formatter interface { | ||||
| 	FieldFormatFunc(field *StructField) ([]byte, error) | ||||
| 	StructFormatFunc(node *StructNode) ([]byte, error) | ||||
| 	Marshal(root *StructNode) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // StructField defines struct field | ||||
| @@ -23,51 +24,43 @@ type StructField struct { | ||||
| 	Comment    string | ||||
| 	Doc        string | ||||
| 	Tag        string | ||||
| 	FormatFunc func(field *StructField) string | ||||
| 	FormatFunc func(field *StructField) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // Key returns the key of the field | ||||
| func (sf *StructField) Key() string { | ||||
| 	return sf.Name | ||||
| } | ||||
|  | ||||
| // 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() | ||||
| func (sf *StructField) MarshalText() ([]byte, error) { | ||||
| 	if sf.FormatFunc == nil { | ||||
| 		return nil, errors.New("format func is missing") | ||||
| 	} | ||||
|  | ||||
| 	return sf.FormatFunc(sf) | ||||
| } | ||||
|  | ||||
| // StructNode defines struct node | ||||
| type StructNode struct { | ||||
| 	Name   string | ||||
| 	Fields []*StructField | ||||
| 	Name       string | ||||
| 	Fields     []*StructField | ||||
| 	FormatFunc func(node *StructNode) ([]byte, error) | ||||
| } | ||||
|  | ||||
| // ToKV transfers struct to key value pair | ||||
| func (sn *StructNode) ToKV() map[string]interface{} { | ||||
| 	value := map[string]interface{}{} | ||||
| 	for _, field := range sn.Fields { | ||||
| 		value[field.Key()] = field.Value() | ||||
| func (sn *StructNode) MarshalText() ([]byte, error) { | ||||
| 	if sn.FormatFunc == nil { | ||||
| 		return nil, errors.New("format func is missing") | ||||
| 	} | ||||
| 	return value | ||||
|  | ||||
| 	return sn.FormatFunc(sn) | ||||
| } | ||||
|  | ||||
| // StructParser parses structs in given file or string | ||||
| type StructParser struct { | ||||
| 	MainStruct     *StructNode | ||||
| 	Info           types.Info | ||||
| 	FieldFormatter FieldFormatter | ||||
| 	MainStruct *StructNode | ||||
| 	Info       types.Info | ||||
| 	Formatter  Formatter | ||||
| } | ||||
|  | ||||
| // 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, formatter FieldFormatter) (*StructParser, error) { | ||||
| func NewStructParser(filePath string, src interface{}, rootStruct string, formatter Formatter) (*StructParser, error) { | ||||
| 	fset := token.NewFileSet() | ||||
| 	f, err := parser.ParseFile(fset, filePath, src, parser.ParseComments) | ||||
| 	if err != nil { | ||||
| @@ -88,8 +81,8 @@ func NewStructParser(filePath string, src interface{}, rootStruct string, format | ||||
| 	} | ||||
|  | ||||
| 	sp := &StructParser{ | ||||
| 		FieldFormatter: formatter, | ||||
| 		Info:           info, | ||||
| 		Formatter: formatter, | ||||
| 		Info:      info, | ||||
| 	} | ||||
|  | ||||
| 	ast.Inspect(f, func(n ast.Node) bool { | ||||
| @@ -120,11 +113,6 @@ func NewStructParser(filePath string, src interface{}, rootStruct string, format | ||||
| 	return sp, nil | ||||
| } | ||||
|  | ||||
| func (sp *StructParser) ToJSON() ([]byte, error) { | ||||
| 	value := sp.MainStruct.ToKV() | ||||
| 	return json.MarshalIndent(value, "", "  ") | ||||
| } | ||||
|  | ||||
| // ParseField parses struct field in nested way | ||||
| func (sp *StructParser) ParseField(field *ast.Field) *StructField { | ||||
| 	// ast.Print(nil, field) | ||||
| @@ -173,7 +161,7 @@ func (sp *StructParser) ParseField(field *ast.Field) *StructField { | ||||
| 		Comment:    fieldComment, | ||||
| 		Doc:        fieldDoc, | ||||
| 		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{ | ||||
| 		Name:   structName, | ||||
| 		Fields: fields, | ||||
| 		Name:       structName, | ||||
| 		Fields:     fields, | ||||
| 		FormatFunc: sp.Formatter.StructFormatFunc, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (sp *StructParser) Marshal() ([]byte, error) { | ||||
| 	return sp.Formatter.Marshal(sp.MainStruct) | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,44 @@ | ||||
| package beeParser | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| ) | ||||
|  | ||||
| type sampleFormatter struct { | ||||
| 	Annotation Annotation | ||||
| } | ||||
|  | ||||
| func (f *sampleFormatter) Format(field *StructField) string { | ||||
| 	return "" | ||||
| func (f *sampleFormatter) FieldFormatFunc(field *StructField) ([]byte, error) { | ||||
| 	// @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 = ` | ||||
| package p | ||||
|  | ||||
| @@ -24,7 +50,11 @@ type StructB struct { | ||||
| 	Field1 string | ||||
| } | ||||
| type StructA struct { | ||||
| 	Field1 string | ||||
| 	// doc | ||||
| 	Field1 string //comment | ||||
| 	// @Name Field1 | ||||
| 	// @Path https://github.com/beego/bee | ||||
| 	// 		  https://github.com/beego | ||||
| 	Field2 struct{ | ||||
| 		a string | ||||
| 		b string | ||||
| @@ -43,7 +73,7 @@ type StructA struct { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	b, err := sp.ToJSON() | ||||
| 	b, err := sp.Marshal() | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| @@ -51,18 +81,5 @@ type StructA struct { | ||||
| 	fmt.Println(string(b)) | ||||
|  | ||||
| 	// Output: | ||||
| 	// { | ||||
| 	//   "Field1": "", | ||||
| 	//   "Field2": { | ||||
| 	//     "a": "", | ||||
| 	//     "b": "" | ||||
| 	//   }, | ||||
| 	//   "Field3": "", | ||||
| 	//   "Field4": "", | ||||
| 	//   "Field5": "", | ||||
| 	//   "Field6": "", | ||||
| 	//   "Field7": { | ||||
| 	//     "Field1": "" | ||||
| 	//   } | ||||
| 	// } | ||||
| 	// "{\"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\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\"}\\\\\\\"]}\\\"}\"]}" | ||||
| } | ||||
|   | ||||
							
								
								
									
										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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Ming Deng
					Ming Deng