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 | 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 | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Ming Deng
					Ming Deng