optimized parse tag (#256)

This commit is contained in:
kingxt
2020-12-09 11:16:38 +08:00
committed by GitHub
parent 65ee877236
commit 67804a6bb2
4 changed files with 109 additions and 74 deletions

View File

@@ -2,30 +2,15 @@ package spec
import (
"errors"
"regexp"
"strings"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/util"
)
const (
TagKey = "tag"
NameKey = "name"
OptionKey = "option"
BodyTag = "json"
)
const bodyTagKey = "json"
var (
TagRe = regexp.MustCompile(`(?P<tag>\w+):"(?P<name>[^,"]+)[,]?(?P<option>[^"]*)"`)
TagSubNames = TagRe.SubexpNames()
definedTags = []string{TagKey, NameKey, OptionKey}
)
type Attribute struct {
Key string
value string
}
var definedKeys = []string{"json", "form", "path"}
func (s Service) Routes() []Route {
var result []Route
@@ -35,81 +20,62 @@ func (s Service) Routes() []Route {
return result
}
func (m Member) IsOptional() bool {
var option string
matches := TagRe.FindStringSubmatch(m.Tag)
for i := range matches {
name := TagSubNames[i]
if name == OptionKey {
option = matches[i]
}
func (m Member) Tags() []*Tag {
tags, err := Parse(m.Tag)
if err != nil {
panic(m.Tag + ", " + err.Error())
}
if len(option) == 0 {
return tags.Tags()
}
func (m Member) IsOptional() bool {
if !m.IsBodyMember() {
return false
}
fields := strings.Split(option, ",")
for _, field := range fields {
if field == "optional" || strings.HasPrefix(field, "default=") {
return true
tag := m.Tags()
for _, item := range tag {
if item.Key == bodyTagKey {
if stringx.Contains(item.Options, "optional") {
return true
}
}
}
return false
}
func (m Member) IsOmitempty() bool {
var option string
matches := TagRe.FindStringSubmatch(m.Tag)
for i := range matches {
name := TagSubNames[i]
if name == OptionKey {
option = matches[i]
}
}
if len(option) == 0 {
if !m.IsBodyMember() {
return false
}
fields := strings.Split(option, ",")
for _, field := range fields {
if field == "omitempty" {
return true
tag := m.Tags()
for _, item := range tag {
if item.Key == bodyTagKey {
if stringx.Contains(item.Options, "omitempty") {
return true
}
}
}
return false
}
func (m Member) GetAttributes() []Attribute {
matches := TagRe.FindStringSubmatch(m.Tag)
var result []Attribute
for i := range matches {
name := TagSubNames[i]
if stringx.Contains(definedTags, name) {
result = append(result, Attribute{
Key: name,
value: matches[i],
})
}
}
return result
}
func (m Member) GetPropertyName() (string, error) {
attrs := m.GetAttributes()
for _, attr := range attrs {
if attr.Key == NameKey && len(attr.value) > 0 {
if attr.value == "-" {
tags := m.Tags()
if len(tags) == 0 {
return "", errors.New("json property name not exist, member: " + m.Name)
}
for _, tag := range tags {
if stringx.Contains(definedKeys, tag.Key) {
if tag.Name == "-" {
return util.Untitle(m.Name), nil
}
return attr.value, nil
return tag.Name, nil
}
}
return "", errors.New("json property name not exist, member: " + m.Name)
}
@@ -121,9 +87,10 @@ func (m Member) IsBodyMember() bool {
if m.IsInline {
return true
}
attrs := m.GetAttributes()
for _, attr := range attrs {
if attr.value == BodyTag {
tags := m.Tags()
for _, tag := range tags {
if tag.Key == bodyTagKey {
return true
}
}

View File

@@ -0,0 +1,67 @@
package spec
import (
"errors"
"strings"
"github.com/fatih/structtag"
)
var errTagNotExist = errors.New("tag does not exist")
type (
Tag struct {
// Key is the tag key, such as json, xml, etc..
// i.e: `json:"foo,omitempty". Here key is: "json"
Key string
// Name is a part of the value
// i.e: `json:"foo,omitempty". Here name is: "foo"
Name string
// Options is a part of the value. It contains a slice of tag options i.e:
// `json:"foo,omitempty". Here options is: ["omitempty"]
Options []string
}
Tags struct {
tags []*Tag
}
)
func Parse(tag string) (*Tags, error) {
tag = strings.TrimPrefix(tag, "`")
tag = strings.TrimSuffix(tag, "`")
tags, err := structtag.Parse(tag)
if err != nil {
return nil, err
}
var result Tags
for _, item := range tags.Tags() {
result.tags = append(result.tags, &Tag{Key: item.Key, Name: item.Name, Options: item.Options})
}
return &result, nil
}
func (t *Tags) Get(key string) (*Tag, error) {
for _, tag := range t.tags {
if tag.Key == key {
return tag, nil
}
}
return nil, errTagNotExist
}
func (t *Tags) Keys() []string {
var keys []string
for _, tag := range t.tags {
keys = append(keys, tag.Key)
}
return keys
}
func (t *Tags) Tags() []*Tag {
return t.tags
}