Skip to content

Commit

Permalink
Merge pull request #21 from RussellLuo/minor-syntax-improvements
Browse files Browse the repository at this point in the history
Minor syntax improvements
  • Loading branch information
RussellLuo authored Nov 18, 2021
2 parents 1a89e07 + 901a92a commit 1bf1b93
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 311 deletions.
584 changes: 337 additions & 247 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/usersvc/endpoint.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/usersvc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
type User struct {
Name string
Age int
IP net.IP `kok:"in=header name=X-Forwarded-For; in=request name=RemoteAddr"`
IP net.IP `kok:"in=header name=X-Forwarded-For, in=request name=RemoteAddr"`
}

type Service interface {
Expand Down
6 changes: 4 additions & 2 deletions gen/http/parser/annotation/annotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,13 @@ func ParseMethodAnnotation(method *ifacetool.Method) (*MethodAnnotation, error)
anno.Op = op

case "param":
param, err := ParseParam(value)
params, err := ParseParams(value)
if err != nil {
return nil, err
}
anno.Params[param.ArgName] = param
for _, p := range params {
anno.Params[p.ArgName] = p
}

case "body":
if anno.Body != nil {
Expand Down
2 changes: 1 addition & 1 deletion gen/http/parser/annotation/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func ParseBody(s string) (*Body, error) {
break
}

param, err := ParseParam(text)
param, err := parseParam(text)
if err != nil {
return nil, err
}
Expand Down
44 changes: 30 additions & 14 deletions gen/http/parser/annotation/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,48 +17,64 @@ type Param struct {
Params []*spec.Parameter
}

// ParseParam parses s per the format as below:
// ParseParams parses s per the format as below:
//
// <argName> [<parameter> [; <parameter2> [; ...]]]
// <argName> [<parameter> [, <parameter2> [, ...]]]
//
// The format of `<parameter>`:
//
// in=<in> name=<name> required=<required> type=<type> descr=<descr>
//
func ParseParam(s string) (*Param, error) {
// Multiple bindings can be specified in a single semicolon-separated comment.
//
func ParseParams(s string) ([]*Param, error) {
s = strings.TrimSpace(s)
if s == "" {
return nil, fmt.Errorf("empty //kok:param")
}

var list []*Param

for _, text := range strings.Split(s, ";") {
p, err := parseParam(text)
if err != nil {
return nil, err
}
list = append(list, p)
}

return list, nil
}

func parseParam(s string) (*Param, error) {
s = strings.TrimSpace(s)

r := reKokParam.FindStringSubmatch(s)
if len(r) != 3 {
return nil, fmt.Errorf("invalid directive arguments: %s", s)
}
argName, remaining := r[1], r[2]
argName, remaining := r[1], strings.TrimSpace(r[2])

p := &Param{
ArgName: argName,
}
p := &Param{ArgName: argName}

if len(remaining) == 0 {
if remaining == "" {
// No remaining parameter definitions after the argument name.
return p, nil
}

params, err := ParseParamParameters(argName, remaining)
opts, err := ParseParamOptions(argName, remaining)
if err != nil {
return nil, err
}
p.Params = append(p.Params, params...)
p.Params = append(p.Params, opts...)

return p, nil
}

func ParseParamParameters(argName, s string) ([]*spec.Parameter, error) {
func ParseParamOptions(argName, s string) ([]*spec.Parameter, error) {
var params []*spec.Parameter
for _, text := range strings.Split(s, ";") {
param, err := parseParamParameter(argName, strings.TrimSpace(text))
for _, text := range strings.Split(s, ",") {
param, err := parseOption(argName, strings.TrimSpace(text))
if err != nil {
return nil, err
}
Expand All @@ -67,7 +83,7 @@ func ParseParamParameters(argName, s string) ([]*spec.Parameter, error) {
return params, nil
}

func parseParamParameter(argName, s string) (*spec.Parameter, error) {
func parseOption(argName, s string) (*spec.Parameter, error) {
s = strings.TrimSpace(s)
p := new(spec.Parameter)

Expand Down
114 changes: 76 additions & 38 deletions gen/http/parser/annotation/param_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,100 @@ import (
"github.com/RussellLuo/kok/gen/http/spec"
)

func TestParseParam(t *testing.T) {
func TestParseParams(t *testing.T) {
tests := []struct {
name string
in string
wantOut *annotation.Param
wantOut []*annotation.Param
wantErrStr string
}{
{
name: "simple argument",
name: "one binding one sub-parameter",
in: "name in=header name=X-User-Name required=true type=string descr=user-name",
wantOut: &annotation.Param{
ArgName: "name",
Params: []*spec.Parameter{
{
In: spec.InHeader,
Name: "X-User-Name",
Required: true,
Type: "string",
Description: "user-name",
wantOut: []*annotation.Param{
{
ArgName: "name",
Params: []*spec.Parameter{
{
In: spec.InHeader,
Name: "X-User-Name",
Required: true,
Type: "string",
Description: "user-name",
},
},
},
},
},
{
name: "argument aggregation",
in: "ip in=header name=X-Forwarded-For; in=request name=RemoteAddr",
wantOut: &annotation.Param{
ArgName: "ip",
Params: []*spec.Parameter{
{
In: spec.InHeader,
Name: "X-Forwarded-For",
},
{
In: spec.InRequest,
Name: "RemoteAddr",
name: "one binding no sub-parameter",
in: "name",
wantOut: []*annotation.Param{
{
ArgName: "name",
},
},
},
{
name: "one binding multiple sub-parameters",
in: "ip in=header name=X-Forwarded-For, in=request name=RemoteAddr",
wantOut: []*annotation.Param{
{
ArgName: "ip",
Params: []*spec.Parameter{
{
In: spec.InHeader,
Name: "X-Forwarded-For",
},
{
In: spec.InRequest,
Name: "RemoteAddr",
},
},
},
},
},
{
name: "no parameters",
in: "name",
wantOut: &annotation.Param{
ArgName: "name",
name: "multiple bindings",
in: "name; age in=query; ip in=header name=X-Forwarded-For, in=request name=RemoteAddr",
wantOut: []*annotation.Param{
{
ArgName: "name",
},
{
ArgName: "age",
Params: []*spec.Parameter{
{
In: spec.InQuery,
},
},
},
{
ArgName: "ip",
Params: []*spec.Parameter{
{
In: spec.InHeader,
Name: "X-Forwarded-For",
},
{
In: spec.InRequest,
Name: "RemoteAddr",
},
},
},
},
},
{
name: "in query by default",
name: "defaults in query",
in: "name required=true",
wantOut: &annotation.Param{
ArgName: "name",
Params: []*spec.Parameter{
{
In: spec.InQuery,
Required: true,
wantOut: []*annotation.Param{
{
ArgName: "name",
Params: []*spec.Parameter{
{
In: spec.InQuery,
Required: true,
},
},
},
},
Expand All @@ -82,12 +120,12 @@ func TestParseParam(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
param, err := annotation.ParseParam(tt.in)
list, err := annotation.ParseParams(tt.in)
if err != nil && err.Error() != tt.wantErrStr {
t.Fatalf("ErrStr: got (%#v), want (%#v)", err.Error(), tt.wantErrStr)
}
if !reflect.DeepEqual(param, tt.wantOut) {
t.Fatalf("Out: got (%#v), want (%#v)", param.Params[0], tt.wantOut.Params[0])
if !reflect.DeepEqual(list, tt.wantOut) {
t.Fatalf("Out: got (%#v), want (%#v)", list, tt.wantOut)
}
})
}
Expand Down
4 changes: 3 additions & 1 deletion gen/http/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func Parse(data *ifacetool.Data, snakeCase bool) (*spec.Specification, []docutil

for _, m := range data.Methods {
doc := docutil.Doc(m.Doc).JoinComments()
m.Doc = doc // Replace the original doc with joined doc.

transport := doc.Transport()
if transport == 0 {
// Empty transport indicates that there are no kok annotations.
Expand Down Expand Up @@ -395,7 +397,7 @@ type StructField struct {
}

func (f *StructField) Parse() error {
params, err := annotation.ParseParamParameters(f.Name, f.Tag.Get(tagName))
params, err := annotation.ParseParamOptions(f.Name, f.Tag.Get(tagName))
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion gen/util/docutil/docutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ func (d Doc) JoinComments() (joined Doc) {
continue
}

c := incompleteComment + strings.TrimSpace(comment)
noPrefix := strings.TrimPrefix(comment, "//")
c := incompleteComment + strings.TrimSpace(noPrefix)

if HasContinuationLine(c) {
incompleteComment = strings.TrimSuffix(c, `\`)
} else {
Expand Down
10 changes: 5 additions & 5 deletions gen/util/docutil/docutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ func TestDoc_JoinLines(t *testing.T) {
name: "no backslash",
in: []string{
"//kok:op POST /logs",
"//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr",
"//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr",
},
want: []string{
"//kok:op POST /logs",
"//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr",
"//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr",
},
},
{
name: "has backslash",
in: []string{
"//kok:op POST /logs",
`//kok:param ip in=header name=X-Forwarded-For; \`,
" in=request name=RemoteAddr",
`//kok:param ip in=header name=X-Forwarded-For, \`,
"// in=request name=RemoteAddr",
},
want: []string{
"//kok:op POST /logs",
"//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr",
"//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr",
},
},
}
Expand Down

0 comments on commit 1bf1b93

Please sign in to comment.