add anonymous annotation (#134)

* rebase upstream

* rebase

* trim no need line

* trim no need line

* trim no need line

* update doc

* remove update

* remove no need

* remove no need

* goctl add jwt support

* goctl add jwt support

* goctl add jwt support

* goctl support import

* goctl support import

* support return ()

* revert

* refactor and rename folder to group

* remove no need

* add anonymous annotation

* optimized

* rename

* rename

* update test

* optimized new command

Co-authored-by: kingxt <dream4kingxt@163.com>
master
kingxt 4 years ago committed by GitHub
parent 7e83895c6e
commit 1d9c4a4c4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -65,7 +65,7 @@ func ApiFormat(path string, printToConsole bool) error {
return m return m
}) })
apiStruct, err := parser.MatchStruct(r) apiStruct, err := parser.ParseApi(r)
if err != nil { if err != nil {
return err return err
} }

@ -20,9 +20,7 @@ type Response struct {
} }
service {{.name}}-api { service {{.name}}-api {
@server( @handler GreetHandler
handler: GreetHandler
)
get /greet/from/:name(Request) returns (Response); get /greet/from/:name(Request) returns (Response);
} }
` `

@ -84,6 +84,18 @@ memberLoop:
if builder.Len() == 0 { if builder.Len() == 0 {
return errors.New("invalid annotation format") return errors.New("invalid annotation format")
} }
if len(annoName) > 0 {
value := builder.String()
if value != string(leftParenthesis) {
builder.Reset()
annos = append(annos, spec.Annotation{
Name: annoName,
Value: value,
})
annoName = ""
break annotationLoop
}
}
case next == leftParenthesis: case next == leftParenthesis:
if builder.Len() == 0 { if builder.Len() == 0 {
return errors.New("invalid annotation format") return errors.New("invalid annotation format")
@ -101,6 +113,7 @@ memberLoop:
Name: annoName, Name: annoName,
Properties: attrs, Properties: attrs,
}) })
annoName = ""
break annotationLoop break annotationLoop
default: default:
builder.WriteRune(next) builder.WriteRune(next)

@ -16,6 +16,7 @@ import (
type Parser struct { type Parser struct {
r *bufio.Reader r *bufio.Reader
typeDef string typeDef string
api *ApiStruct
} }
func NewParser(filename string) (*Parser, error) { func NewParser(filename string) (*Parser, error) {
@ -29,7 +30,7 @@ func NewParser(filename string) (*Parser, error) {
return nil, err return nil, err
} }
apiStruct, err := MatchStruct(string(api)) apiStruct, err := ParseApi(string(api))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -55,6 +56,7 @@ func NewParser(filename string) (*Parser, error) {
return &Parser{ return &Parser{
r: bufio.NewReader(buffer), r: bufio.NewReader(buffer),
typeDef: apiStruct.StructBody, typeDef: apiStruct.StructBody,
api: apiStruct,
}, nil }, nil
} }
@ -66,7 +68,7 @@ func (p *Parser) Parse() (api *spec.ApiSpec, err error) {
return nil, err return nil, err
} }
api.Types = types api.Types = types
var lineNumber = 1 var lineNumber = p.api.serviceBeginLine
st := newRootState(p.r, &lineNumber) st := newRootState(p.r, &lineNumber)
for { for {
st, err = st.process(api) st, err = st.process(api)

@ -104,6 +104,21 @@ service A-api
} }
` `
const anonymousAnnotation = `
type Request struct {
Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
}
type Response struct {
Message string ` + "`" + `json:"message"` + "`" + `
}
service A-api {
@handler GreetHandler
get /greet/from/:name(Request) returns (Response)
}
`
func TestParser(t *testing.T) { func TestParser(t *testing.T) {
filename := "greet.api" filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm) err := ioutil.WriteFile(filename, []byte(testApiTemplate), os.ModePerm)
@ -161,6 +176,25 @@ func TestInvalidApiFile(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
defer os.Remove(filename) defer os.Remove(filename)
_, err = NewParser(filename) parser, err := NewParser(filename)
assert.Nil(t, err)
_, err = parser.Parse()
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestAnonymousAnnotation(t *testing.T) {
filename := "greet.api"
err := ioutil.WriteFile(filename, []byte(anonymousAnnotation), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(filename)
parser, err := NewParser(filename)
assert.Nil(t, err)
api, err := parser.Parse()
assert.Nil(t, err)
assert.Equal(t, len(api.Service.Routes), 1)
assert.Equal(t, api.Service.Routes[0].Annotations[0].Value, "GreetHandler")
}

@ -11,10 +11,11 @@ import (
var emptyType spec.Type var emptyType spec.Type
type ApiStruct struct { type ApiStruct struct {
Info string Info string
StructBody string StructBody string
Service string Service string
Imports string Imports string
serviceBeginLine int
} }
func GetType(api *spec.ApiSpec, t string) spec.Type { func GetType(api *spec.ApiSpec, t string) spec.Type {
@ -69,7 +70,7 @@ func unread(r *bufio.Reader) error {
return r.UnreadRune() return r.UnreadRune()
} }
func MatchStruct(api string) (*ApiStruct, error) { func ParseApi(api string) (*ApiStruct, error) {
var result ApiStruct var result ApiStruct
scanner := bufio.NewScanner(strings.NewReader(api)) scanner := bufio.NewScanner(strings.NewReader(api))
var parseInfo = false var parseInfo = false
@ -104,13 +105,13 @@ func MatchStruct(api string) (*ApiStruct, error) {
parseType = true parseType = true
} }
if isServiceBeginLine(line) { if isServiceBeginLine(line) {
parseService = true
if parseType { if parseType {
parseType = false parseType = false
result.StructBody = segment result.StructBody = segment
segment = line + "\n" segment = line + "\n"
continue continue
} }
parseService = true
} }
segment += scanner.Text() + "\n" segment += scanner.Text() + "\n"
} }
@ -119,6 +120,7 @@ func MatchStruct(api string) (*ApiStruct, error) {
return nil, errors.New("no service defined") return nil, errors.New("no service defined")
} }
result.Service = segment result.Service = segment
result.serviceBeginLine = lineBeginOfService(api)
return &result, nil return &result, nil
} }
@ -133,3 +135,16 @@ func isTypeBeginLine(line string) bool {
func isServiceBeginLine(line string) bool { func isServiceBeginLine(line string) bool {
return strings.HasPrefix(line, "@server(") || (strings.HasPrefix(line, "service") && strings.HasSuffix(line, "{")) return strings.HasPrefix(line, "@server(") || (strings.HasPrefix(line, "service") && strings.HasSuffix(line, "{"))
} }
func lineBeginOfService(api string) int {
scanner := bufio.NewScanner(strings.NewReader(api))
var number = 0
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if isServiceBeginLine(line) {
break
}
number++
}
return number
}

@ -4,6 +4,7 @@ type (
Annotation struct { Annotation struct {
Name string Name string
Properties map[string]string Properties map[string]string
Value string
} }
ApiSpec struct { ApiSpec struct {

@ -8,6 +8,9 @@ import (
func GetAnnotationValue(annos []spec.Annotation, key, field string) (string, bool) { func GetAnnotationValue(annos []spec.Annotation, key, field string) (string, bool) {
for _, anno := range annos { for _, anno := range annos {
if anno.Name == field && len(anno.Value) > 0 {
return anno.Value, true
}
if anno.Name == key { if anno.Name == key {
value, ok := anno.Properties[field] value, ok := anno.Properties[field]
return strings.TrimSpace(value), ok return strings.TrimSpace(value), ok

Loading…
Cancel
Save