mirror of
https://github.com/beego/bee.git
synced 2024-11-21 23:50:54 +00:00
fix annotator and test formatter
This commit is contained in:
parent
a829cb9846
commit
2422bf63e6
2
go.mod
2
go.mod
@ -7,8 +7,10 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-delve/delve v1.5.0
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/lib/pq v1.7.0
|
||||
github.com/pelletier/go-toml v1.8.1
|
||||
|
3
go.sum
3
go.sum
@ -78,6 +78,7 @@ github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915/go.mod h1:fB4mx6dzqF
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
|
||||
@ -94,6 +95,8 @@ github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRf
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
@ -1,6 +1,8 @@
|
||||
package beeParser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -9,6 +11,8 @@ type Annotator interface {
|
||||
}
|
||||
|
||||
type Annotation struct {
|
||||
Key, Description string
|
||||
Default interface{}
|
||||
}
|
||||
|
||||
func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\r' }
|
||||
@ -30,16 +34,27 @@ func handleTailWhitespace(s string) string {
|
||||
}
|
||||
|
||||
//handle value to remove head and tail space.
|
||||
func handleWhitespaceValues(values []string) []string {
|
||||
res := make([]string, 0)
|
||||
func handleWhitespaceValues(values []string) []interface{} {
|
||||
res := make([]interface{}, 0)
|
||||
for _, v := range values {
|
||||
v = handleHeadWhitespace(v)
|
||||
v = handleTailWhitespace(v)
|
||||
res = append(res, v)
|
||||
res = append(res, transferType(v))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
//try to transfer string to original type
|
||||
func transferType(str string) interface{} {
|
||||
if res, err := strconv.Atoi(str); err == nil {
|
||||
return res
|
||||
}
|
||||
if res, err := strconv.ParseBool(str); err == nil {
|
||||
return res
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
//parse annotation to generate array with key and values
|
||||
//start with "@" as a key-value pair,key and values are separated by a space,wrap to distinguish values.
|
||||
func (a *Annotation) Annotate(annotation string) map[string]interface{} {
|
||||
@ -51,7 +66,26 @@ func (a *Annotation) Annotate(annotation string) map[string]interface{} {
|
||||
kvs := strings.Split(line, " ")
|
||||
key := kvs[0]
|
||||
values := strings.Split(strings.TrimSpace(line[len(kvs[0]):]), "\n")
|
||||
results[key] = handleWhitespaceValues(values)
|
||||
if len(values) == 1 {
|
||||
results[key] = handleWhitespaceValues(values)[0]
|
||||
} else {
|
||||
results[key] = handleWhitespaceValues(values)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func NewAnnotation(annotation string) *Annotation {
|
||||
a := &Annotation{}
|
||||
kvs := a.Annotate(annotation)
|
||||
if v, ok := kvs["Key"]; ok {
|
||||
a.Key = fmt.Sprintf("%v", v)
|
||||
}
|
||||
if v, ok := kvs["Description"]; ok {
|
||||
a.Description = fmt.Sprintf("%v", v)
|
||||
}
|
||||
if v, ok := kvs["Default"]; ok {
|
||||
a.Default = v
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
@ -32,14 +32,14 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func TestAnnotate(t *testing.T) {
|
||||
expect1 := map[string]interface{}{
|
||||
"Name": []string{"Field1"},
|
||||
"Type": []string{"string"},
|
||||
"Path": []string{"https://github.com/beego/bee", "https://github.com/beego"},
|
||||
"Name": "Field1",
|
||||
"Type": "string",
|
||||
"Path": []interface{}{"https://github.com/beego/bee", "https://github.com/beego"},
|
||||
}
|
||||
|
||||
expect2 := map[string]interface{}{
|
||||
"Number": []string{"2"},
|
||||
"Projects": []string{"https://github.com/beego/bee", "", "https://github.com/beego"},
|
||||
"Number": 2,
|
||||
"Projects": []interface{}{"https://github.com/beego/bee", "", "https://github.com/beego"},
|
||||
}
|
||||
|
||||
actual := BeeAnnotator.Annotate(Annotation1)
|
||||
@ -55,13 +55,17 @@ func TestHandleWhitespaceValues(t *testing.T) {
|
||||
"",
|
||||
" bee ",
|
||||
" bee beego ",
|
||||
" 1 ",
|
||||
" false ",
|
||||
}
|
||||
|
||||
expect := []string{
|
||||
expect := []interface{}{
|
||||
"beego",
|
||||
"",
|
||||
"bee",
|
||||
"bee beego",
|
||||
1,
|
||||
false,
|
||||
}
|
||||
|
||||
actual := handleWhitespaceValues(src)
|
||||
|
@ -1,20 +1,97 @@
|
||||
package beeParser
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
|
||||
type AnnotationFormatter struct {
|
||||
Annotation Annotator
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type JsonFormatter struct {
|
||||
}
|
||||
|
||||
func (f *AnnotationFormatter) Format(field *StructField) string {
|
||||
if field.Comment == "" && field.Doc == "" {
|
||||
return ""
|
||||
func (f *JsonFormatter) FieldFormatFunc(field *StructField) ([]byte, error) {
|
||||
annotation := NewAnnotation(field.Doc + field.Comment)
|
||||
res := map[string]interface{}{}
|
||||
if field.NestedType != nil {
|
||||
res[annotation.Key] = field.NestedType
|
||||
} else {
|
||||
res[annotation.Key] = annotation.Default
|
||||
}
|
||||
kvs := f.Annotation.Annotate(field.Doc + field.Comment)
|
||||
res, _ := json.Marshal(kvs)
|
||||
return string(res)
|
||||
return json.Marshal(res)
|
||||
}
|
||||
|
||||
func NewAnnotationFormatter() *AnnotationFormatter {
|
||||
return &AnnotationFormatter{Annotation: &Annotation{}}
|
||||
func (f *JsonFormatter) StructFormatFunc(node *StructNode) ([]byte, error) {
|
||||
return json.Marshal(node.Fields)
|
||||
}
|
||||
|
||||
func (f *JsonFormatter) Marshal(node *StructNode) ([]byte, error) {
|
||||
return json.MarshalIndent(node, "", " ")
|
||||
}
|
||||
|
||||
type YamlFormatter struct {
|
||||
}
|
||||
|
||||
func (f *YamlFormatter) FieldFormatFunc(field *StructField) ([]byte, error) {
|
||||
annotation := NewAnnotation(field.Doc + field.Comment)
|
||||
res := map[string]interface{}{}
|
||||
if field.NestedType != nil {
|
||||
res[annotation.Key] = field.NestedType
|
||||
} else {
|
||||
res[annotation.Key] = annotation.Default
|
||||
}
|
||||
return yaml.Marshal(res)
|
||||
}
|
||||
|
||||
func (f *YamlFormatter) StructFormatFunc(node *StructNode) ([]byte, error) {
|
||||
return yaml.Marshal(node.Fields)
|
||||
}
|
||||
|
||||
func (f *YamlFormatter) Marshal(node *StructNode) ([]byte, error) {
|
||||
return yaml.Marshal(node)
|
||||
}
|
||||
|
||||
type XmlFormatter struct {
|
||||
}
|
||||
|
||||
func (f *XmlFormatter) FieldFormatFunc(field *StructField) ([]byte, error) {
|
||||
annotation := NewAnnotation(field.Doc + field.Comment)
|
||||
if field.NestedType != nil {
|
||||
type xmlStruct struct {
|
||||
XMLName xml.Name
|
||||
Default interface{} `xml:",innerxml"`
|
||||
Description string `xml:",comment"`
|
||||
}
|
||||
b, _ := field.NestedType.FormatFunc(field.NestedType)
|
||||
return xml.Marshal(&xmlStruct{
|
||||
XMLName: xml.Name{Local: annotation.Key},
|
||||
Description: annotation.Description,
|
||||
Default: b,
|
||||
})
|
||||
} else {
|
||||
type xmlStruct struct {
|
||||
XMLName xml.Name
|
||||
Default interface{} `xml:",chardata"`
|
||||
Description string `xml:",comment"`
|
||||
}
|
||||
return xml.Marshal(&xmlStruct{
|
||||
XMLName: xml.Name{Local: annotation.Key},
|
||||
Description: annotation.Description,
|
||||
Default: annotation.Default,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *XmlFormatter) StructFormatFunc(node *StructNode) ([]byte, error) {
|
||||
res := make([]byte, 0)
|
||||
for _, f := range node.Fields {
|
||||
b, _ := f.FormatFunc(f)
|
||||
res = append(res, b...)
|
||||
res = append(res, '\n')
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (f *XmlFormatter) Marshal(node *StructNode) ([]byte, error) {
|
||||
return node.FormatFunc(node)
|
||||
}
|
||||
|
@ -1,33 +1,126 @@
|
||||
package beeParser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func TestFormat(t *testing.T) {
|
||||
except := `{
|
||||
"Name": [
|
||||
"Field1"
|
||||
],
|
||||
"Path":[
|
||||
"https://github.com/beego/bee",
|
||||
"https://github.com/beego"
|
||||
],
|
||||
"test":[
|
||||
"test comment"
|
||||
]
|
||||
}`
|
||||
const src = `
|
||||
package p
|
||||
|
||||
field := &StructField{
|
||||
Comment: "@test test comment",
|
||||
Doc: `@Name Field1
|
||||
@Path https://github.com/beego/bee
|
||||
https://github.com/beego`,
|
||||
type StructA struct {
|
||||
// @Key Field1
|
||||
// @Default test
|
||||
// @Description ddddddd
|
||||
Field1 string
|
||||
// @Key Field2
|
||||
Field2 struct{
|
||||
// @Key a
|
||||
// @Default https://github.com/beego/bee
|
||||
// https://github.com/beego
|
||||
a string
|
||||
// @Key b
|
||||
// @Default https://github.com/beego/bee https://github.com/beego
|
||||
b string
|
||||
}
|
||||
// @Key Field3
|
||||
// @Default 1
|
||||
Field3 int
|
||||
// @Key Field4
|
||||
// @Default false
|
||||
Field4 bool
|
||||
}
|
||||
`
|
||||
|
||||
func ExampleJsonFormatter() {
|
||||
sp, err := NewStructParser("src.go", src, "StructA", &JsonFormatter{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
actual := NewAnnotationFormatter().Format(field)
|
||||
b, err := sp.Marshal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
assert.JSONEq(t, except, actual)
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
//[
|
||||
// {
|
||||
// "Field1": "test"
|
||||
// },
|
||||
// {
|
||||
// "Field2": [
|
||||
// {
|
||||
// "a": [
|
||||
// "https://github.com/beego/bee",
|
||||
// "https://github.com/beego"
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "b": "https://github.com/beego/bee https://github.com/beego"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "Field3": 1
|
||||
// },
|
||||
// {
|
||||
// "Field4": false
|
||||
// }
|
||||
//]
|
||||
}
|
||||
|
||||
func ExampleYamlFormatter() {
|
||||
sp, err := NewStructParser("src.go", src, "StructA", &YamlFormatter{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
b, err := sp.Marshal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
//|
|
||||
// - |
|
||||
// Field1: test
|
||||
// - |
|
||||
// Field2: |
|
||||
// - |
|
||||
// a:
|
||||
// - https://github.com/beego/bee
|
||||
// - https://github.com/beego
|
||||
// - |
|
||||
// b: https://github.com/beego/bee https://github.com/beego
|
||||
// - |
|
||||
// Field3: 1
|
||||
// - |
|
||||
// Field4: false
|
||||
}
|
||||
|
||||
func ExampleXmlFormatter() {
|
||||
sp, err := NewStructParser("src.go", src, "StructA", &XmlFormatter{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
b, err := sp.Marshal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(b))
|
||||
|
||||
// Output:
|
||||
//<Field1>test<!--ddddddd--></Field1>
|
||||
//<Field2><a></a>
|
||||
//<b>https://github.com/beego/bee https://github.com/beego</b>
|
||||
//</Field2>
|
||||
//<Field3>1</Field3>
|
||||
//<Field4>false</Field4>
|
||||
}
|
||||
|
@ -34,6 +34,13 @@ func (sf *StructField) MarshalText() ([]byte, error) {
|
||||
return sf.FormatFunc(sf)
|
||||
}
|
||||
|
||||
func (sf *StructField) MarshalJSON() ([]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
|
||||
@ -49,6 +56,14 @@ func (sn *StructNode) MarshalText() ([]byte, error) {
|
||||
return sn.FormatFunc(sn)
|
||||
}
|
||||
|
||||
func (sn *StructNode) MarshalJSON() ([]byte, error) {
|
||||
if sn.FormatFunc == nil {
|
||||
return nil, errors.New("format func is missing")
|
||||
}
|
||||
|
||||
return sn.FormatFunc(sn)
|
||||
}
|
||||
|
||||
// StructParser parses structs in given file or string
|
||||
type StructParser struct {
|
||||
MainStruct *StructNode
|
||||
|
@ -1,41 +0,0 @@
|
||||
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