Skip to content

Commit

Permalink
Merge pull request #19 from aaharu/clean-description
Browse files Browse the repository at this point in the history
fix description
  • Loading branch information
aaharu authored Aug 15, 2017
2 parents c4adf16 + ab10686 commit cbd492e
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 127 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## [1.1.1] - 2017-08-16
### Fixed
- fix comments bugs

### Changed
- refactoring


## [1.1.0] - 2017-08-15
### Added
- add description comments
Expand Down Expand Up @@ -152,7 +160,8 @@
- pre-release


[1.0.2]: https://github.com/aaharu/schemarshal/compare/1.0.2...1.1.0
[1.1.1]: https://github.com/aaharu/schemarshal/compare/1.1.0...1.1.1
[1.1.0]: https://github.com/aaharu/schemarshal/compare/1.0.2...1.1.0
[1.0.2]: https://github.com/aaharu/schemarshal/compare/1.0.1...1.0.2
[1.0.1]: https://github.com/aaharu/schemarshal/compare/1.0.0...1.0.1
[1.0.0]: https://github.com/aaharu/schemarshal/compare/0.9.0...1.0.0
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ curl -s "https://raw.githubusercontent.com/aaharu/schemarshal/master/test_data/d

## [Examples](examples.md)

- [example a.json](examples.md#a.json)
- [example a.json](examples.md#ajson)
- [example qiita schema](examples.md#qiita-v2-schema)

## Dependencies
Expand Down
241 changes: 124 additions & 117 deletions codegen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,32 @@ import (
)

// Generator of Go source code from JSON Schema
type Generator struct {
type Generator interface {
ReadSchema(input io.Reader, name string) error
Generate() ([]byte, error)
}

type generator struct {
name string // package nage
command string
imports ImportSpec
imports importSpec
decls []*typeSpec
enumList EnumSpec
enumList enumSpec
}

// NewGenerator create Generator struct
func NewGenerator(packageName string, command string) *Generator {
return &Generator{
func NewGenerator(packageName string, command string) Generator {
return &generator{
name: packageName,
command: command,
imports: ImportSpec{},
imports: importSpec{},
decls: []*typeSpec{},
enumList: EnumSpec{},
enumList: enumSpec{},
}
}

// ReadSchema : read and parse JSON Schema
func (g *Generator) ReadSchema(input io.Reader, name string) error {
func (g *generator) ReadSchema(input io.Reader, name string) error {
js, err := schema.Read(input)
if err != nil {
return err
Expand All @@ -58,8 +63,8 @@ func (g *Generator) ReadSchema(input io.Reader, name string) error {
}

// parse returns JSON Schema type
func (g *Generator) parse(js *schema.Schema, fieldName string) (JSONType, error) {
jt := JSONType{}
func (g *generator) parse(js *schema.Schema, fieldName string) (jsonType, error) {
jt := jsonType{}
if inPrimitiveTypes(schema.IntegerType, js.Type) ||
inPrimitiveTypes(schema.BooleanType, js.Type) ||
inPrimitiveTypes(schema.NumberType, js.Type) {
Expand Down Expand Up @@ -147,7 +152,7 @@ func (g *Generator) parse(js *schema.Schema, fieldName string) (JSONType, error)
if propType.format == formatObject {
objectTypeName := fieldName + utils.UpperCamelCase(key) + "Object"
g.addType(objectTypeName, &propType)
copyType := &JSONType{
copyType := jsonType{
format: propType.format,
nullable: propType.nullable,
fields: propType.fields,
Expand All @@ -159,7 +164,7 @@ func (g *Generator) parse(js *schema.Schema, fieldName string) (JSONType, error)
name: utils.UpperCamelCase(key),
description: propSchema.Description,
jsontype: copyType,
jsontag: &jsonTag{
jsontag: jsonTag{
name: key,
omitEmpty: !js.IsPropRequired(key),
},
Expand All @@ -168,8 +173,8 @@ func (g *Generator) parse(js *schema.Schema, fieldName string) (JSONType, error)
jt.addField(&field{
name: utils.UpperCamelCase(key),
description: propSchema.Description,
jsontype: &propType,
jsontag: &jsonTag{
jsontype: propType,
jsontag: jsonTag{
name: key,
omitEmpty: !js.IsPropRequired(key),
},
Expand All @@ -188,17 +193,16 @@ func (g *Generator) parse(js *schema.Schema, fieldName string) (JSONType, error)
}

// addType add a type statement
func (g *Generator) addType(name string, jsonType *JSONType) {
func (g *generator) addType(name string, jsonType *jsonType) {
g.decls = append(g.decls, &typeSpec{
name: name,
jsontype: jsonType,
})
}

// Generate gofmt-ed Go source code
func (g *Generator) Generate() ([]byte, error) {
func (g *generator) Generate() ([]byte, error) {
var buf bytes.Buffer

buf.WriteString(fmt.Sprintf("// Code generated by %s `%s`\n", version.String(), g.command))
buf.WriteString("// DO NOT RECOMMEND EDITING THIS FILE.\n\n")
buf.WriteString(fmt.Sprintf("package %s\n\n", g.name))
Expand All @@ -225,7 +229,7 @@ func (g *Generator) Generate() ([]byte, error) {
if g.decls != nil {
for i := range g.decls {
if g.decls[i].jsontype.description != "" {
buf.WriteString(fmt.Sprintf("// %s : %s\n", g.decls[i].name, g.decls[i].jsontype.description))
buf.WriteString(fmt.Sprintf("// %s : %s\n", g.decls[i].name, utils.CleanDescription(g.decls[i].jsontype.description)))
}
buf.WriteString("type " + g.decls[i].name + " ")
g.decls[i].jsontype.nullable = false
Expand All @@ -234,106 +238,109 @@ func (g *Generator) Generate() ([]byte, error) {
}
}

if g.enumList != nil && len(g.enumList) > 0 {
buf.WriteString("\n")
// sort map
var keys []string
for k := range g.enumList {
keys = append(keys, k)
}
sort.Strings(keys)
for _, typeName := range keys {
enum := g.enumList[typeName]
buf.WriteString("type " + typeName + " int\n")
buf.WriteString("const (\n")
for i := range enum {
buf.WriteString(utils.UpperCamelCase(fmt.Sprintf("%s %v", typeName, enum[i])))
if i == 0 {
buf.WriteString(" " + typeName + " = iota\n")
} else {
buf.WriteString("\n")
}
}
buf.WriteString(")\n\n")

var enumMapName = "_" + strings.ToLower(typeName[:1])
if len(typeName) > 1 {
enumMapName += typeName[1:]
}
buf.WriteString("var " + enumMapName + " = map[" + typeName + "]interface{}{\n")
for i := range enum {
buf.WriteString(utils.UpperCamelCase(fmt.Sprintf("%s %v", typeName, enum[i])) + ": ")
switch v := enum[i].(type) {
case string:
buf.WriteString(strconv.Quote(v))
default:
buf.WriteString(fmt.Sprintf("%v", v))
}
buf.WriteString(",\n")
}
buf.WriteString("}\n\n")

buf.WriteString("func (enum " + typeName + ") MarshalJSON() ([]byte, error) {\n")
buf.WriteString("switch v:= " + enumMapName + "[enum].(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("return []byte(strconv.Quote(v)), nil\n")
buf.WriteString("default:\n")
buf.WriteString("return []byte(fmt.Sprintf(\"%v\", v)), nil\n")
buf.WriteString("}\n")
buf.WriteString("}\n\n")

buf.WriteString("func (enum *" + typeName + ") UnmarshalJSON(data []byte) error {\n")
buf.WriteString("for i, v := range " + enumMapName + " {\n")
buf.WriteString("switch vv := v.(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("if strconv.Quote(vv) == string(data) {\n")
buf.WriteString("*enum = " + typeName + "(i)\n")
buf.WriteString("return nil\n")
buf.WriteString("}\n")
buf.WriteString("default:\n")
buf.WriteString("if fmt.Sprintf(\"%v\", v) == string(data) {\n")
buf.WriteString("*enum = " + typeName + "(i)\n")
buf.WriteString("return nil\n")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("return fmt.Errorf(\"Error: miss-matched " + typeName + " (%s)\", data)\n")
buf.WriteString("}\n\n")

buf.WriteString("func (enum " + typeName + ") String() string {\n")
buf.WriteString("switch v:= " + enumMapName + "[enum].(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("return v\n")
buf.WriteString("default:\n")
buf.WriteString("return fmt.Sprintf(\"%v\", v)\n")
buf.WriteString("}\n")
buf.WriteString("}\n\n")

buf.WriteString("func To" + typeName + "(val interface{}) *" + typeName + " {\n")
buf.WriteString("for i, v := range " + enumMapName + " {\n")
buf.WriteString("if val == v {")
buf.WriteString("return &i")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("return nil")
buf.WriteString("}\n\n")
}
}
buf.Write(g.enumList.generate())

//return buf.Bytes(), nil
return format.Source(buf.Bytes())
}

// ImportSpec has `import` information
type ImportSpec map[string]string
// importSpec has `import` information
type importSpec map[string]string

type typeSpec struct {
name string // type name
jsontype *JSONType
jsontype *jsonType
}

// EnumSpec has enum information
type EnumSpec map[string][]interface{}
// enumSpec has enum information
type enumSpec map[string][]interface{}

func (e enumSpec) generate() []byte {
var buf bytes.Buffer
// sort map
var keys []string
for k := range e {
keys = append(keys, k)
}
sort.Strings(keys)
for _, typeName := range keys {
enum := e[typeName]
buf.WriteString("\ntype " + typeName + " int\n")
buf.WriteString("const (\n")
for i := range enum {
buf.WriteString(utils.UpperCamelCase(fmt.Sprintf("%s %v", typeName, enum[i])))
if i == 0 {
buf.WriteString(" " + typeName + " = iota\n")
} else {
buf.WriteString("\n")
}
}
buf.WriteString(")\n\n")

var enumMapName = "_" + strings.ToLower(typeName[:1])
if len(typeName) > 1 {
enumMapName += typeName[1:]
}
buf.WriteString("var " + enumMapName + " = map[" + typeName + "]interface{}{\n")
for i := range enum {
buf.WriteString(utils.UpperCamelCase(fmt.Sprintf("%s %v", typeName, enum[i])) + ": ")
switch v := enum[i].(type) {
case string:
buf.WriteString(strconv.Quote(v))
default:
buf.WriteString(fmt.Sprintf("%v", v))
}
buf.WriteString(",\n")
}
buf.WriteString("}\n\n")

buf.WriteString("func (enum " + typeName + ") MarshalJSON() ([]byte, error) {\n")
buf.WriteString("switch v:= " + enumMapName + "[enum].(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("return []byte(strconv.Quote(v)), nil\n")
buf.WriteString("default:\n")
buf.WriteString("return []byte(fmt.Sprintf(\"%v\", v)), nil\n")
buf.WriteString("}\n")
buf.WriteString("}\n\n")

buf.WriteString("func (enum *" + typeName + ") UnmarshalJSON(data []byte) error {\n")
buf.WriteString("for i, v := range " + enumMapName + " {\n")
buf.WriteString("switch vv := v.(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("if strconv.Quote(vv) == string(data) {\n")
buf.WriteString("*enum = " + typeName + "(i)\n")
buf.WriteString("return nil\n")
buf.WriteString("}\n")
buf.WriteString("default:\n")
buf.WriteString("if fmt.Sprintf(\"%v\", v) == string(data) {\n")
buf.WriteString("*enum = " + typeName + "(i)\n")
buf.WriteString("return nil\n")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("return fmt.Errorf(\"Error: miss-matched " + typeName + " (%s)\", data)\n")
buf.WriteString("}\n\n")

buf.WriteString("func (enum " + typeName + ") String() string {\n")
buf.WriteString("switch v:= " + enumMapName + "[enum].(type) {\n")
buf.WriteString("case string:\n")
buf.WriteString("return v\n")
buf.WriteString("default:\n")
buf.WriteString("return fmt.Sprintf(\"%v\", v)\n")
buf.WriteString("}\n")
buf.WriteString("}\n\n")

buf.WriteString("func To" + typeName + "(val interface{}) *" + typeName + " {\n")
buf.WriteString("for i, v := range " + enumMapName + " {\n")
buf.WriteString("if val == v {")
buf.WriteString("return &i")
buf.WriteString("}\n")
buf.WriteString("}\n")
buf.WriteString("return nil")
buf.WriteString("}\n")
}
return buf.Bytes()
}

type jsonFormat int

Expand All @@ -347,22 +354,22 @@ const (
formatDatetime
)

// JSONType is type of json
type JSONType struct {
// jsonType is type of json
type jsonType struct {
format jsonFormat
nullable bool
fields []*field // object has
itemType *JSONType // array has
itemType *jsonType // array has
typeName string // object's array and object has
enumType string // enum has
description string // for comment
}

func (t *JSONType) addField(f *field) {
func (t *jsonType) addField(f *field) {
t.fields = append(t.fields, f)
}

func (t *JSONType) generate() []byte {
func (t *jsonType) generate() []byte {
var buf bytes.Buffer
if t.nullable {
buf.WriteString("*")
Expand All @@ -379,7 +386,7 @@ func (t *JSONType) generate() []byte {
buf.WriteString("struct {\n")
for i := range t.fields {
if t.fields[i].description != "" {
buf.WriteString(fmt.Sprintf("// %s : %s\n", t.fields[i].name, t.fields[i].description))
buf.WriteString(fmt.Sprintf("// %s : %s\n", t.fields[i].name, utils.CleanDescription(t.fields[i].description)))
}
buf.WriteString(t.fields[i].name)
buf.WriteString(" ")
Expand Down Expand Up @@ -414,9 +421,9 @@ func (t *JSONType) generate() []byte {

type field struct {
name string
description string // comment
jsontype *JSONType // go type
jsontag *jsonTag // `json:""`
description string // comment
jsontype jsonType // go type
jsontag jsonTag // `json:""`
}

type jsonTag struct {
Expand Down
Loading

0 comments on commit cbd492e

Please sign in to comment.