dorfylegends/analyze/df/analyze.go

236 lines
5.0 KiB
Go
Raw Normal View History

2022-04-14 18:39:18 +03:00
package df
import (
"bytes"
"encoding/json"
"fmt"
"go/format"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"github.com/iancoleman/strcase"
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
)
func Analyze(filex string) error {
fmt.Println("Search...", filex)
files, err := filepath.Glob(filex + "/*.xml")
if err != nil {
return err
}
fmt.Println(files)
a := NewAnalyzeData()
for _, file := range files {
analyze(file, a)
}
return a.Save()
}
func Generate() error {
a, err := LoadAnalyzeData()
if err != nil {
return err
}
return createMetadata(a)
}
var allowedTyped = map[string]bool{
"df_world|historical_events|historical_event": true,
"df_world|historical_event_collections|historical_event_collection": true,
}
func filterSubtypes(data *map[string]*FieldData) []string {
filtered := make(map[string]*FieldData)
for k, v := range *data {
path := strings.Split(k, PATH_SEPARATOR)
for index, seg := range path {
if strings.Contains(seg, "+") {
base := seg[:strings.Index(seg, "+")]
basePath := strings.Join(append(path[:index], base), PATH_SEPARATOR)
if allowedTyped[basePath] {
path[index] = seg
}
}
}
filtered[strings.Join(path, PATH_SEPARATOR)] = v
}
*data = filtered
list := util.Keys(filtered)
sort.Strings(list)
return list
}
func getSubtypes(objectTypes []string, k string) *[]string {
subtypes := make(map[string]bool)
for _, t := range objectTypes {
if strings.HasPrefix(t, k+"+") && !strings.Contains(t[len(k):], PATH_SEPARATOR) {
subtypes[t[strings.LastIndex(t, "+")+1:]] = true
}
}
keys := util.Keys(subtypes)
sort.Strings(keys)
if len(keys) > 0 {
return &keys
}
return nil
}
func getSubtypeOf(k string) *string {
if strings.Contains(k, PATH_SEPARATOR) {
last := k[strings.LastIndex(k, PATH_SEPARATOR)+1:]
if strings.Contains(last, "+") {
base := strcase.ToCamel(last[:strings.Index(last, "+")])
return &base
}
}
return nil
}
func createMetadata(a *AnalyzeData) error {
fs := filterSubtypes(&a.Fields)
var objectTypes []string
for k := range a.Fields {
path := strings.Split(k, PATH_SEPARATOR)
if len(path) >= 2 {
objectTypes = append(objectTypes, strings.Join(path[:len(path)-1], PATH_SEPARATOR))
}
}
objects := make(map[string]Object, 0)
for _, k := range objectTypes {
if ok, _ := isArray(k, fs); !ok {
n := k
if strings.Contains(k, PATH_SEPARATOR) {
n = k[strings.LastIndex(k, PATH_SEPARATOR)+1:]
}
if n == "" {
continue
}
objFields := make(map[string]Field, 0)
for _, f := range fs {
if strings.HasPrefix(f, k+PATH_SEPARATOR) {
fn := f[len(k)+1:]
if !strings.Contains(fn, PATH_SEPARATOR) {
legend := ""
if a.Fields[f].Base && a.Fields[f].Plus {
legend = "both"
} else if a.Fields[f].Base {
legend = "base"
} else if a.Fields[f].Plus {
legend = "plus"
}
field := Field{
Name: strcase.ToCamel(fn),
Type: "int",
Multiple: a.Fields[f].Multiple,
Legend: legend,
}
if ok, elements := isArray(f, fs); ok {
el := elements[strings.LastIndex(elements, PATH_SEPARATOR)+1:]
if _, ok := a.Fields[elements+PATH_SEPARATOR+"id"]; ok {
field.Type = "map"
} else {
field.Type = "array"
}
field.ElementType = &(el)
} else if ok, _ := isObject(f, fs); ok {
field.Type = "object"
} else if a.Fields[f].IsString {
field.Type = "string"
}
objFields[fn] = field
}
}
}
objects[n] = Object{
Name: strcase.ToCamel(n),
Id: a.Fields[k+PATH_SEPARATOR+"id"] != nil,
Named: a.Fields[k+PATH_SEPARATOR+"name"] != nil,
Typed: a.Fields[k+PATH_SEPARATOR+"type"] != nil,
SubTypes: getSubtypes(objectTypes, k),
SubTypeOf: getSubtypeOf(k),
Fields: objFields,
}
}
}
return generateCode(&objects)
}
func generateCode(objects *map[string]Object) error {
file, _ := json.MarshalIndent(objects, "", " ")
_ = ioutil.WriteFile("model.json", file, 0644)
f, err := os.Create("../backend/model/model.go")
if err != nil {
return err
}
defer f.Close()
var buf bytes.Buffer
err = packageTemplate.Execute(&buf, struct {
Objects *map[string]Object
}{
Objects: objects,
})
if err != nil {
return err
}
p, err := format.Source(buf.Bytes())
if err != nil {
return err
}
_, err = f.Write(p)
return err
}
func isArray(typ string, types []string) (bool, string) {
fc := 0
elements := ""
if !strings.Contains(typ, PATH_SEPARATOR) || strings.Contains(typ[strings.LastIndex(typ, PATH_SEPARATOR):], "+") {
return false, ""
}
for _, t := range types {
if !strings.HasPrefix(t, typ+PATH_SEPARATOR) {
continue
}
if strings.Contains(t[len(typ)+1:], PATH_SEPARATOR) {
continue
}
fc++
elements = t
}
return fc == 1, elements
}
func isObject(typ string, types []string) (bool, string) {
fc := 0
for _, t := range types {
if !strings.HasPrefix(t, typ+PATH_SEPARATOR) {
continue
}
fc++
}
return fc > 0, typ
}