You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
4.1 KiB
Go
190 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"go/format"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type StructField interface {
|
|
GetName() string
|
|
GetType() string
|
|
GetJSONTag() string
|
|
String() string
|
|
}
|
|
|
|
type StructType struct {
|
|
JSONField string
|
|
Name string
|
|
Children []StructField
|
|
}
|
|
|
|
func (s *StructType) GetJSONTag() string {
|
|
return fmt.Sprintf("`json:\"%s\"`", s.JSONField)
|
|
}
|
|
|
|
func (s *StructType) String() string {
|
|
var children []string
|
|
for _, v := range s.Children {
|
|
children = append(children, v.String())
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
"%s struct {\n%s\n}",
|
|
s.Name,
|
|
strings.Join(children, "\n"),
|
|
)
|
|
}
|
|
|
|
func (s *StructType) GetType() string {
|
|
return "struct"
|
|
}
|
|
|
|
func (s *StructType) GetName() string {
|
|
return s.Name
|
|
}
|
|
|
|
type SimpleType struct {
|
|
JSONField string
|
|
Name string
|
|
Type string
|
|
}
|
|
|
|
func (s *SimpleType) GetJSONTag() string {
|
|
return fmt.Sprintf("`json:\"%s\"`", s.JSONField)
|
|
}
|
|
|
|
func (s *SimpleType) String() string {
|
|
return fmt.Sprintf("%s %s", s.Name, s.Type)
|
|
}
|
|
|
|
func (s *SimpleType) GetName() string {
|
|
return s.Name
|
|
}
|
|
|
|
func (s *SimpleType) GetType() string {
|
|
return s.Type
|
|
}
|
|
|
|
func (s *StructType) AddChild(name string, value json.RawMessage) {
|
|
var i interface{}
|
|
json.Unmarshal(value, &i)
|
|
switch v := i.(type) {
|
|
case float64:
|
|
s.addChild(ParseNumberField(name, value))
|
|
case string, bool:
|
|
s.addChild(ParseSimpleField(name, fmt.Sprintf("%T", v)))
|
|
case []interface{}:
|
|
// To Do: parse slices
|
|
s.addChild(ParseSliceField(name, value))
|
|
case map[string]interface{}:
|
|
s.addChild(ParseStruct(name, value))
|
|
default:
|
|
fmt.Printf("%s %s %T\n", name, "dunno", v)
|
|
}
|
|
}
|
|
|
|
func (s *StructType) addChild(field StructField) {
|
|
s.Children = append(s.Children, field)
|
|
}
|
|
|
|
func ParseSliceField(name string, value json.RawMessage) *SimpleType {
|
|
var s []interface{}
|
|
err := json.Unmarshal(value, &s)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if len(s) == 0 {
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: "[]interface{}"}
|
|
}
|
|
|
|
sliceType := fmt.Sprintf("%T", s[0])
|
|
for _, v := range s {
|
|
if sliceType != fmt.Sprintf("%T", v) {
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: "[]interface{}"}
|
|
}
|
|
}
|
|
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: fmt.Sprintf("[]%s", sliceType)}
|
|
}
|
|
|
|
func ParseNumberField(name string, value json.RawMessage) *SimpleType {
|
|
for _, b := range value {
|
|
if b == '.' {
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: "float64"}
|
|
}
|
|
}
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: "int"}
|
|
}
|
|
|
|
func ParseSimpleField(name, gotype string) *SimpleType {
|
|
return &SimpleType{JSONField: name, Name: SanitizeName(name), Type: gotype}
|
|
}
|
|
|
|
func ParseStruct(name string, data []byte) *StructType {
|
|
jsonMap := make(map[string]json.RawMessage)
|
|
err := json.Unmarshal(data, &jsonMap)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
s := &StructType{JSONField: name, Name: SanitizeName(name)}
|
|
|
|
for key, value := range jsonMap {
|
|
s.AddChild(key, value)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func SanitizeName(name string) string {
|
|
return strings.ReplaceAll(strings.Title(strings.ReplaceAll(name, "_", "-")), "-", "")
|
|
}
|
|
|
|
func FormatStructType(s *StructType, inlineTypes bool) string {
|
|
var lines []string
|
|
var types []string
|
|
lines = append(lines, fmt.Sprintf("type %s struct {", s.Name))
|
|
for _, c := range s.Children {
|
|
switch v := c.(type) {
|
|
case *SimpleType:
|
|
lines = append(lines, fmt.Sprintf("%s %s", c.String(), c.GetJSONTag()))
|
|
case *StructType:
|
|
if inlineTypes {
|
|
lines = append(lines, fmt.Sprintf("%s %s", c.String(), c.GetJSONTag()))
|
|
continue
|
|
}
|
|
lines = append(lines, fmt.Sprintf("%s %s %s", c.GetName(), c.GetName(), c.GetJSONTag()))
|
|
types = append(types, FormatStructType(v, inlineTypes))
|
|
}
|
|
}
|
|
|
|
lines = append(lines, "}")
|
|
lines = append(lines, types...)
|
|
|
|
formatted, err := format.Source([]byte(strings.Join(lines, "\n")))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
return string(formatted)
|
|
}
|
|
|
|
func main() {
|
|
log.Default().SetOutput(os.Stderr)
|
|
reader := bufio.NewReader(os.Stdin)
|
|
buf, err := io.ReadAll(reader)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
s := ParseStruct("AutoGenerated", buf)
|
|
|
|
fmt.Println(FormatStructType(s, false))
|
|
}
|