Adding jflect and converted to package for generate-structs

This commit is contained in:
Steven Polley 2018-08-15 15:15:19 -06:00
parent 9a9079e42d
commit 8fec1c86c7
3 changed files with 192 additions and 18 deletions

View File

@ -1,14 +1,12 @@
package main
import (
"bytes"
"fmt"
"log"
"os"
"strconv"
"deadbeef.codes/steven/go-itg/itglue"
"github.com/ChimeraCoder/gojson"
)
var itg *itglue.ITGAPI
@ -40,21 +38,6 @@ func main() {
log.Fatalf("could get flexible asset with type ID %d: %s", id, err)
}
name := &fat.FlexibleAssetTypeData.Attributes.Name
pkg := "itglue"
subStruct := false // try changing to true?
tagList := make([]string, 0)
tagList = append(tagList, "json")
var convertFloats bool
var parser gojson.Parser
parser = gojson.ParseJson
convertFloats = true
input := bytes.NewReader(fa)
output, err := gojson.Generate(input, parser, *name, pkg, tagList, subStruct, convertFloats)
fmt.Print(string(output))
//name := &fat.FlexibleAssetTypeData.Attributes.Name
}
}

59
generate-structs/vendor/jflect/field.go vendored Normal file
View File

@ -0,0 +1,59 @@
package jflect
import (
"fmt"
"unicode"
)
// Field data type
type Field struct {
name string
gtype string
tag string
}
// Simplifies Field construction
func NewField(name, gtype string, body ...byte) Field {
if gtype == "struct" {
gtype = fmt.Sprintf("%s {%s}", gtype, body)
}
return Field{goField(name), gtype, goTag(name)}
}
// Provides Sorter interface so we can keep field order
type FieldSort []Field
func (s FieldSort) Len() int { return len(s) }
func (s FieldSort) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s FieldSort) Less(i, j int) bool {
return s[i].name < s[j].name
}
// Return lower_case json fields to camel case fields.
func goField(jf string) string {
mkUpper := true
gf := ""
for _, c := range jf {
if mkUpper {
c = unicode.ToUpper(c)
mkUpper = false
}
if c == '_' {
mkUpper = true
continue
}
if c == '-' {
mkUpper = true
continue
}
gf += string(c)
}
return fmt.Sprintf("%s", gf)
}
// Returns the json tag from a json field.
func goTag(jf string) string {
return fmt.Sprintf("`json:\"%s\"`", jf)
}

132
generate-structs/vendor/jflect/main.go vendored Normal file
View File

@ -0,0 +1,132 @@
package jflect
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"go/format"
"io"
"log"
"os"
"sort"
)
// TODO: write proper Usage and README
var (
ErrNotValidSyntax = errors.New("Json reflection is not valid Go syntax")
)
//Read accepts a structName, json io.Reader and outputs a golang struct to an io.Writer
func Read(structName string, r io.Reader, w io.Writer) error {
var v interface{}
err := json.NewDecoder(r).Decode(&v)
if err != nil {
log.Println(err)
return err
}
buf := new(bytes.Buffer)
// Open struct
b, err := xreflect(v)
if err != nil {
log.Println(err)
return err
}
field := NewField(structName, "struct", b...)
fmt.Fprintf(buf, "type %s %s", field.name, field.gtype)
// Pass through gofmt for uniform formatting, and weak syntax check.
b, err = format.Source(buf.Bytes())
if err != nil {
log.Println(err)
fmt.Println("Final Go Code")
fmt.Println()
os.Stderr.Write(buf.Bytes())
fmt.Println()
return ErrNotValidSyntax
}
w.Write(b)
return nil
}
func xreflect(v interface{}) ([]byte, error) {
var (
buf = new(bytes.Buffer)
)
fields := []Field{}
switch root := v.(type) {
case map[string]interface{}:
for key, val := range root {
switch j := val.(type) {
case nil:
// FIXME: sometimes json service will return nil even though the type is string.
// go can not convert string to nil and vs versa. Can we assume its a string?
continue
case float64:
fields = append(fields, NewField(key, "int"))
case map[string]interface{}:
// If type is map[string]interface{} then we have nested object, Recurse
o, err := xreflect(j)
if err != nil {
log.Println(err)
return nil, err
}
fields = append(fields, NewField(key, "struct", o...))
case []interface{}:
gtype, err := sliceType(j)
if err != nil {
log.Println(err)
return nil, err
}
fields = append(fields, NewField(key, gtype))
default:
fields = append(fields, NewField(key, fmt.Sprintf("%T", val)))
}
}
default:
return nil, fmt.Errorf("%T: unexpected type", root)
}
// Sort and write field buffer last to keep order and formatting.
sort.Sort(FieldSort(fields))
for _, f := range fields {
fmt.Fprintf(buf, "%s %s %s\n", f.name, f.gtype, f.tag)
}
return buf.Bytes(), nil
}
// if all entries in j are the same type, return slice of that type
func sliceType(j []interface{}) (string, error) {
dft := "[]interface{}"
if len(j) == 0 {
return dft, nil
}
var t, t2 string
for _, v := range j {
switch v.(type) {
case string:
t2 = "[]string"
case float64:
t2 = "[]int"
case map[string]interface{}:
t2 = "[]struct"
default:
// something else, just return default
return dft, nil
}
if t != "" && t != t2 {
return dft, nil
}
t = t2
}
if t == "[]struct" {
o, err := xreflect(j[0])
if err != nil {
log.Println(err)
return "", err
}
f := NewField("", "struct", o...)
t = "[]" + f.gtype
}
return t, nil
}