Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pacedotdev/oto
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.7.0
Choose a base ref
...
head repository: pacedotdev/oto
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.8.0
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Jul 23, 2020

  1. Copy the full SHA
    fbb06aa View commit details
  2. Copy the full SHA
    98db51c View commit details
Showing with 75 additions and 82 deletions.
  1. +8 −8 otohttp/templates/client.ts.plush
  2. +1 −1 otohttp/templates/server.go.plush
  3. +50 −50 parser.go
  4. +16 −23 parser_test.go
16 changes: 8 additions & 8 deletions otohttp/templates/client.ts.plush
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ export class Client {
<%= format_comment_text(service.Comment) %>export class <%= service.Name %> {
constructor(readonly client: Client) {}
<%= for (method) in service.Methods { %>
<%= format_comment_text(method.Comment) %> async <%= camelize_down(method.Name) %>(<%= camelize_down(method.InputObject.TypeName) %>: <%= method.InputObject.TypeName %> = null) {
<%= format_comment_text(method.Comment) %> async <%= method.NameLowerCamel %>(<%= camelize_down(method.InputObject.TypeName) %>: <%= method.InputObject.TypeName %> = null) {
if (<%= camelize_down(method.InputObject.TypeName) %> == null) {
<%= camelize_down(method.InputObject.TypeName) %> = new <%= method.InputObject.TypeName %>();
}
@@ -51,23 +51,23 @@ export class Client {
<%= for (field) in object.Fields { %>
<%= if (field.Type.IsObject) { %>
<%= if (field.Type.Multiple) { %>
if (data.<%= camelize_down(field.Name) %>) {
this.<%= camelize_down(field.Name) %> = new Array<<%= field.Type.ObjectName() %>>()
for (let i = 0; i < data.<%= camelize_down(field.Name) %>.length; i++) {
this.<%= camelize_down(field.Name) %>.push(new <%= field.Type.ObjectName() %>(data.<%= camelize_down(field.Name) %>[i]));
if (data.<%= field.NameLowerCamel %>) {
this.<%= field.NameLowerCamel %> = new Array<<%= field.Type.ObjectName() %>>()
for (let i = 0; i < data.<%= field.NameLowerCamel %>.length; i++) {
this.<%= field.NameLowerCamel %>.push(new <%= field.Type.ObjectName() %>(data.<%= field.NameLowerCamel %>[i]));
}
}
<% } else { %>
this.<%= camelize_down(field.Name) %> = new <%= field.Type.ObjectName() %>(data.<%= camelize_down(field.Name) %>);
this.<%= field.NameLowerCamel %> = new <%= field.Type.ObjectName() %>(data.<%= field.NameLowerCamel %>);
<% } %>
<% } else { %>
this.<%= camelize_down(field.Name) %> = data.<%= camelize_down(field.Name) %>;
this.<%= field.NameLowerCamel %> = data.<%= field.NameLowerCamel %>;
<% } %>
<% } %>
}
}
<%= for (field) in object.Fields { %>
<%= format_comment_text(field.Comment) %> <%= camelize_down(field.Name) %>: <%= if (field.Type.IsObject) { %><%= field.Type.TypeName %><% } else { %><%= field.Type.JSType() %><% } %><%= if (field.Type.Multiple) { %>[]<% } %>;
<%= format_comment_text(field.Comment) %> <%= field.NameLowerCamel %>: <%= if (field.Type.IsObject) { %><%= field.Type.TypeName %><% } else { %><%= field.Type.JSType() %><% } %><%= if (field.Type.Multiple) { %>[]<% } %>;
<% } %>
}
<% } %>
2 changes: 1 addition & 1 deletion otohttp/templates/server.go.plush
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ func (s *<%= camelize_down(service.Name) %>Server) handle<%= method.Name %>(w ht

<%= for (object) in def.Objects { %>
<%= format_comment_text(object.Comment) %>type <%= object.Name %> struct {
<%= for (field) in object.Fields { %><%= format_comment_text(field.Comment) %><%= field.Name %> <%= if (field.Type.Multiple == true) { %>[]<% } %><%= field.Type.TypeName %> `json:"<%= camelize_down(field.Name) %><%= if (field.OmitEmpty) { %>,omitempty<% } %>"`
<%= for (field) in object.Fields { %><%= format_comment_text(field.Comment) %><%= field.Name %> <%= if (field.Type.Multiple == true) { %>[]<% } %><%= field.Type.TypeName %> `json:"<%= field.NameLowerCamel %><%= if (field.OmitEmpty) { %>,omitempty<% } %>"`
<% } %>
}
<% } %>
100 changes: 50 additions & 50 deletions parser.go
Original file line number Diff line number Diff line change
@@ -52,10 +52,11 @@ type Service struct {

// Method describes a method that a Service can perform.
type Method struct {
Name string `json:"name"`
InputObject FieldType `json:"inputObject"`
OutputObject FieldType `json:"outputObject"`
Comment string `json:"comment"`
Name string `json:"name"`
NameLowerCamel string `json:"nameLowerCamel"`
InputObject FieldType `json:"inputObject"`
OutputObject FieldType `json:"outputObject"`
Comment string `json:"comment"`
}

// Object describes a data structure that is part of this definition.
@@ -69,13 +70,14 @@ type Object struct {

// Field describes the field inside an Object.
type Field struct {
Name string `json:"name"`
Type FieldType `json:"type"`
OmitEmpty bool `json:"omitEmpty"`
Comment string `json:"comment"`
Tag string `json:"tag"`
ParsedTags map[string]FieldTag `json:"parsedTags"`
Example interface{} `json:"example"`
Name string `json:"name"`
NameLowerCamel string `json:"nameLowerCamel"`
Type FieldType `json:"type"`
OmitEmpty bool `json:"omitEmpty"`
Comment string `json:"comment"`
Tag string `json:"tag"`
ParsedTags map[string]FieldTag `json:"parsedTags"`
Example interface{} `json:"example"`
}

// FieldTag is a parsed tag.
@@ -90,40 +92,14 @@ type FieldTag struct {
// FieldType holds information about the type of data that this
// Field stores.
type FieldType struct {
TypeID string `json:"typeID"`
TypeName string `json:"typeName"`
Multiple bool `json:"multiple"`
Package string `json:"package"`
IsObject bool `json:"isObject"`
}

// JSType gets the JavaScript type for this FieldType.
func (f FieldType) JSType() (string, error) {
if f.IsObject {
return "object", nil
}
switch f.TypeName {
case "interface{}":
return "any", nil
case "map[string]interface{}":
return "object", nil
case "string":
return "string", nil
case "bool":
return "boolean", nil
case "int", "int16", "int32", "int64",
"uint", "uint16", "uint32", "uint64",
"float32", "float64":
return "number", nil
}
return "", errors.Errorf("oto: type not supported: %s", f.TypeName)
}

// ObjectName gets the namespace-free object name of the type.
// For imported packages, the package name is stripped.
func (f FieldType) ObjectName() string {
segs := strings.Split(f.TypeName, ".")
return segs[len(segs)-1]
TypeID string `json:"typeID"`
TypeName string `json:"typeName"`
ObjectName string `json:"objectName"`
ObjectNameLowerCamel string `json:"objectNameLowerCamel"`
Multiple bool `json:"multiple"`
Package string `json:"package"`
IsObject bool `json:"isObject"`
JSType string `json:"jsType"`
}

type parser struct {
@@ -240,6 +216,7 @@ func (p *parser) parseService(pkg *packages.Package, obj types.Object, interface
func (p *parser) parseMethod(pkg *packages.Package, serviceName string, methodType *types.Func) (Method, error) {
var m Method
m.Name = methodType.Name()
m.NameLowerCamel = camelizeDown(m.Name)
m.Comment = p.commentForMethod(serviceName, m.Name)
sig := methodType.Type().(*types.Signature)
inputParams := sig.Params()
@@ -316,6 +293,7 @@ func (p *parser) parseTags(tag string) (map[string]FieldTag, error) {
func (p *parser) parseField(pkg *packages.Package, objectName string, v *types.Var) (Field, error) {
var f Field
f.Name = v.Name()
f.NameLowerCamel = camelizeDown(f.Name)
f.Comment = p.commentForField(objectName, f.Name)
if !v.Exported() {
return f, p.wrapErr(errors.New(f.Name+" must be exported"), pkg, v.Pos())
@@ -361,20 +339,42 @@ func (p *parser) parseFieldType(pkg *packages.Package, obj types.Object) (FieldT
}
}
ftype.TypeName = types.TypeString(typ, resolver)
typeNameWithoutPackage := types.TypeString(typ, func(other *types.Package) string { return "" })
ftype.TypeID = pkgPath + "." + typeNameWithoutPackage
ftype.ObjectName = types.TypeString(typ, func(other *types.Package) string { return "" })
ftype.ObjectNameLowerCamel = camelizeDown(ftype.ObjectName)
ftype.TypeID = pkgPath + "." + ftype.ObjectName
if ftype.IsObject {
ftype.JSType = "object"
} else {
switch ftype.TypeName {
case "interface{}":
ftype.JSType = "any"
case "map[string]interface{}":
ftype.JSType = "object"
case "string":
ftype.JSType = "string"
case "bool":
ftype.JSType = "boolean"
case "int", "int16", "int32", "int64",
"uint", "uint16", "uint32", "uint64",
"float32", "float64":
ftype.JSType = "number"
}
}

return ftype, nil
}

// addOutputFields adds built-in fields to the response objects
// mentioned in p.outputObjects.
func (p *parser) addOutputFields() error {
errorField := Field{
OmitEmpty: true,
Name: "Error",
Comment: "Error is string explaining what went wrong. Empty if everything was fine.",
OmitEmpty: true,
Name: "Error",
NameLowerCamel: "error",
Comment: "Error is string explaining what went wrong. Empty if everything was fine.",
Type: FieldType{
TypeName: "string",
JSType: "string",
},
}
for typeName := range p.outputObjects {
39 changes: 16 additions & 23 deletions parser_test.go
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ func TestParse(t *testing.T) {
You will love it.`)
is.Equal(len(def.Services[0].Methods), 2)
is.Equal(def.Services[0].Methods[0].Name, "GetGreetings")
is.Equal(def.Services[0].Methods[0].NameLowerCamel, "getGreetings")
is.Equal(def.Services[0].Methods[0].Comment, "GetGreetings gets a range of saved Greetings.")
is.Equal(def.Services[0].Methods[0].InputObject.TypeName, "GetGreetingsRequest")
is.Equal(def.Services[0].Methods[0].InputObject.Multiple, false)
@@ -30,6 +31,7 @@ You will love it.`)
is.Equal(def.Services[0].Methods[0].OutputObject.Package, "")

is.Equal(def.Services[0].Methods[1].Name, "Greet")
is.Equal(def.Services[0].Methods[1].NameLowerCamel, "greet")
is.Equal(def.Services[0].Methods[1].Comment, "Greet creates a Greeting for one or more people.")
is.Equal(def.Services[0].Methods[1].InputObject.TypeName, "GreetRequest")
is.Equal(def.Services[0].Methods[1].InputObject.Multiple, false)
@@ -44,9 +46,13 @@ You will love it.`)
is.Equal(greetInputObject.Comment, "GetGreetingsRequest is the request object for GreeterService.GetGreetings.")
is.Equal(len(greetInputObject.Fields), 1)
is.Equal(greetInputObject.Fields[0].Name, "Page")
is.Equal(greetInputObject.Fields[0].NameLowerCamel, "page")
is.Equal(greetInputObject.Fields[0].Comment, "Page describes which page of data to get.")
is.Equal(greetInputObject.Fields[0].OmitEmpty, false)
is.Equal(greetInputObject.Fields[0].Type.TypeName, "services.Page")
is.Equal(greetInputObject.Fields[0].Type.ObjectName, "Page")
is.Equal(greetInputObject.Fields[0].Type.ObjectNameLowerCamel, "page")
is.Equal(greetInputObject.Fields[0].Type.JSType, "object")
is.Equal(greetInputObject.Fields[0].Type.TypeID, "github.com/pacedotdev/oto/testdata/services.Page")
is.Equal(greetInputObject.Fields[0].Type.IsObject, true)
is.Equal(greetInputObject.Fields[0].Type.Multiple, false)
@@ -63,12 +69,14 @@ You will love it.`)
is.Equal(greetOutputObject.Name, "GetGreetingsResponse")
is.Equal(len(greetOutputObject.Fields), 2)
is.Equal(greetOutputObject.Fields[0].Name, "Greetings")
is.Equal(greetOutputObject.Fields[0].NameLowerCamel, "greetings")
is.Equal(greetOutputObject.Fields[0].Type.TypeID, "github.com/pacedotdev/oto/testdata/services/pleasantries.Greeting")
is.Equal(greetOutputObject.Fields[0].OmitEmpty, false)
is.Equal(greetOutputObject.Fields[0].Type.TypeName, "Greeting")
is.Equal(greetOutputObject.Fields[0].Type.Multiple, true)
is.Equal(greetOutputObject.Fields[0].Type.Package, "")
is.Equal(greetOutputObject.Fields[1].Name, "Error")
is.Equal(greetOutputObject.Fields[1].NameLowerCamel, "error")
is.Equal(greetOutputObject.Fields[1].OmitEmpty, true)
is.Equal(greetOutputObject.Fields[1].Type.TypeName, "string")
is.Equal(greetOutputObject.Fields[1].Type.Multiple, false)
@@ -90,33 +98,41 @@ You will love it.`)
is.Equal(len(welcomeInputObject.Fields), 4)

is.Equal(welcomeInputObject.Fields[0].Name, "To")
is.Equal(welcomeInputObject.Fields[0].NameLowerCamel, "to")
is.Equal(welcomeInputObject.Fields[0].OmitEmpty, false)
is.Equal(welcomeInputObject.Fields[0].Type.TypeName, "string")
is.Equal(welcomeInputObject.Fields[0].Type.Multiple, false)
is.Equal(welcomeInputObject.Fields[0].Type.Package, "")
is.Equal(welcomeInputObject.Fields[0].Example, "your@email.com")

is.Equal(welcomeInputObject.Fields[1].Name, "Name")
is.Equal(welcomeInputObject.Fields[1].NameLowerCamel, "name")
is.Equal(welcomeInputObject.Fields[1].OmitEmpty, false)
is.Equal(welcomeInputObject.Fields[1].Type.TypeName, "string")
is.Equal(welcomeInputObject.Fields[1].Type.JSType, "string")
is.Equal(welcomeInputObject.Fields[1].Type.Multiple, false)
is.Equal(welcomeInputObject.Fields[1].Type.Package, "")
is.Equal(welcomeInputObject.Fields[1].Example, "John Smith")

is.Equal(welcomeInputObject.Fields[2].Example, float64(3))
is.Equal(welcomeInputObject.Fields[2].Type.JSType, "number")

is.Equal(welcomeInputObject.Fields[3].Example, true)
is.Equal(welcomeInputObject.Fields[3].Type.JSType, "boolean")

welcomeOutputObject, err := def.Object(def.Services[1].Methods[0].OutputObject.TypeName)
is.NoErr(err)
is.Equal(welcomeOutputObject.Name, "WelcomeResponse")
is.Equal(len(welcomeOutputObject.Fields), 2)
is.Equal(welcomeOutputObject.Fields[0].Name, "Message")
is.Equal(welcomeOutputObject.Fields[0].NameLowerCamel, "message")
is.Equal(welcomeOutputObject.Fields[0].Type.IsObject, false)
is.Equal(welcomeOutputObject.Fields[0].OmitEmpty, false)
is.Equal(welcomeOutputObject.Fields[0].Type.TypeName, "string")
is.Equal(welcomeOutputObject.Fields[0].Type.Multiple, false)
is.Equal(welcomeOutputObject.Fields[0].Type.Package, "")
is.Equal(welcomeOutputObject.Fields[1].Name, "Error")
is.Equal(welcomeOutputObject.Fields[1].NameLowerCamel, "error")
is.Equal(welcomeOutputObject.Fields[1].OmitEmpty, true)
is.Equal(welcomeOutputObject.Fields[1].Type.TypeName, "string")
is.Equal(welcomeOutputObject.Fields[1].Type.Multiple, false)
@@ -140,29 +156,6 @@ You will love it.`)
// log.Println(string(b))
}

func TestFieldJSType(t *testing.T) {
is := is.New(t)
for in, expected := range map[FieldType]string{
{TypeName: "string"}: "string",
{TypeName: "int"}: "number",
{TypeName: "uint"}: "number",
{TypeName: "uint32"}: "number",
{TypeName: "int32"}: "number",
{TypeName: "int64"}: "number",
{TypeName: "float64"}: "number",
{TypeName: "bool"}: "boolean",
{TypeName: "interface{}"}: "any",
{TypeName: "map[string]interface{}"}: "object",
{TypeName: "SomeObject", IsObject: true}: "object",
} {
actual, err := in.JSType()
is.NoErr(err)
if actual != expected {
t.Errorf("%s expected: %q but got %q", in.TypeName, expected, actual)
}
}
}

func TestExtractExample(t *testing.T) {
is := is.New(t)