diff --git a/go.mod b/go.mod index fa39702..cae35ee 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/talos-systems/talos/pkg/machinery v0.0.0-20210625144407-2060ceaa0b16 golang.org/x/mod v0.4.2 // indirect + golang.org/x/text v0.3.6 golang.org/x/tools v0.1.3 gopkg.in/yaml.v2 v2.4.0 honnef.co/go/tools v0.1.4 // indirect diff --git a/parser/annotator.go b/parser/annotator.go index 2109185..03babe1 100644 --- a/parser/annotator.go +++ b/parser/annotator.go @@ -2,6 +2,7 @@ package beeParser import ( "fmt" + "go/types" "strconv" "strings" ) @@ -33,7 +34,7 @@ func handleTailWhitespace(s string) string { return s[0:i] } -//handle value to remove head and tail space. +// Handle value to remove head and tail space. func handleWhitespaceValues(values []string) []interface{} { res := make([]interface{}, 0) for _, v := range values { @@ -44,7 +45,7 @@ func handleWhitespaceValues(values []string) []interface{} { return res } -//try to transfer string to original type +// Transfer string to original type func transferType(str string) interface{} { if res, err := strconv.Atoi(str); err == nil { return res @@ -55,8 +56,8 @@ func transferType(str string) interface{} { 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. +// 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{} { results := make(map[string]interface{}) //split annotation with '@' @@ -75,20 +76,54 @@ func (a *Annotation) Annotate(annotation string) map[string]interface{} { return results } -//create new annotation -//parse "Key","Default","Description" by annotation -//the type of "Key" and "Description" is string, "Default" is interface{} -func NewAnnotation(annotation string) *Annotation { +// Create new annotation,parse "Key","Default","Description" by annotation. +// If key and default value is empty by annotaion, set default key and value +// by params, default value according defaultType to generate +func NewAnnotation(annotation, defaultKey string, defaultType types.Type) *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 ss, ok := v.([]interface{}); ok { + for i, s := range ss { + if i == 0 { + a.Description += s.(string) + continue + } + a.Description += "\n" + s.(string) + } + } else { + a.Description = fmt.Sprintf("%v", v) + } } if v, ok := kvs["Default"]; ok { a.Default = v } + if a.Key == "" { + //if key by parse is empty, set a default key + a.Key = defaultKey + } + if a.Default == nil { + //if default value is nil, set the default value according to the defaultType + a.Default = getDefaultValue(defaultType) + } return a } + +// Get the default value according to the t, process bool/string/int +func getDefaultValue(t types.Type) interface{} { + switch tys := t.(type) { + case *types.Basic: + switch tys.Kind() { + case types.Bool: + return false + case types.Int, types.Int16, types.Int8, types.Int32, types.Int64, types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr, types.Float32, types.Float64: + return 0 + case types.String: + return "" + } + } + return nil +} diff --git a/parser/formatter.go b/parser/formatter.go index 2dbdbf9..e9a847a 100644 --- a/parser/formatter.go +++ b/parser/formatter.go @@ -2,6 +2,8 @@ package beeParser import ( "encoding/json" + "io/ioutil" + "strings" "github.com/talos-systems/talos/pkg/machinery/config/encoder" ) @@ -10,10 +12,7 @@ type JsonFormatter struct { } func (f *JsonFormatter) FieldFormatFunc(field *StructField) ([]byte, error) { - annotation := NewAnnotation(field.Doc + field.Comment) - if annotation.Key == "" { - annotation.Key = field.Name - } + annotation := NewAnnotation(field.Doc+field.Comment, field.Name, field.Type) res := map[string]interface{}{} if field.NestedType != nil { res[annotation.Key] = field.NestedType @@ -41,24 +40,34 @@ type Result map[string]interface{} func (c Result) Doc() *encoder.Doc { return &result } + func (f *YamlFormatter) FieldFormatFunc(field *StructField) ([]byte, error) { - annotation := NewAnnotation(field.Doc + field.Comment) - if annotation.Key == "" { - annotation.Key = field.Name - } + annotation := NewAnnotation(field.Doc+field.Comment, field.Name, field.Type) res := Result{} // add head comment for this field res.Doc().Comments[encoder.HeadComment] = annotation.Description if field.NestedType != nil { - b, _ := field.NestedType.FormatFunc(field.NestedType) + // nestedType format result as this field value + b, err := field.NestedType.FormatFunc(field.NestedType) + if err != nil { + return nil, err + } res[annotation.Key] = string(b) } else { res[annotation.Key] = annotation.Default } + encoder := encoder.NewEncoder(&res, []encoder.Option{ encoder.WithComments(encoder.CommentsAll), }...) - return encoder.Encode() + encodeByte, err := encoder.Encode() + if err != nil { + return nil, err + } + // when field.NestedType != nil, the key and nested value strings are encoded with "|" + // remove "|" by string replace + encodeByte = []byte(strings.Replace(string(encodeByte), annotation.Key+": |", annotation.Key+":", 1)) + return encodeByte, nil } func (f *YamlFormatter) StructFormatFunc(node *StructNode) ([]byte, error) { @@ -71,5 +80,10 @@ func (f *YamlFormatter) StructFormatFunc(node *StructNode) ([]byte, error) { } func (f *YamlFormatter) Marshal(node *StructNode) ([]byte, error) { - return node.FormatFunc(node) + res, err := node.FormatFunc(node) + if err != nil { + return nil, err + } + ioutil.WriteFile(node.Name+".yaml", res, 0667) + return res, nil } diff --git a/parser/formatter_test.go b/parser/formatter_test.go index 1cd6f67..5842381 100644 --- a/parser/formatter_test.go +++ b/parser/formatter_test.go @@ -25,6 +25,7 @@ type StructA struct { // @Default https://github.com/beego/bee // https://github.com/beego // @Description comment of a of field2 + // ssssss a string // @Key b // @Default https://github.com/beego/bee https://github.com/beego @@ -38,6 +39,11 @@ type StructA struct { // @Key NestField // @Description comment of NestField NestField StructB + Field5 float32 + Field6 bool + Field7 string + Field8 interface{} + Field9 *StructB } ` @@ -105,16 +111,22 @@ func ExampleYamlFormatter() { // # comment of field1 // Field1: test // # comment of b of field2 - // Field2: | + // Field2: // # comment of a of field2 + // # ssssss // a: // - https://github.com/beego/bee // - https://github.com/beego // # comment of b of field2 // b: https://github.com/beego/bee https://github.com/beego // # comment of field3 - // Field3: null + // Field3: 0 // Field4: false - // NestField: | + // NestField: // FieldB1: null + // Field5: 0 + // Field6: false + // Field7: "" + // Field8: null + // Field9: null }