// exportable typescript generated from golang // Copyright (C) 2022 Fabio Prada package tsrpc import ( "errors" "fmt" "strings" ) type TSModule struct { Structs map[string]string Types map[string]string Enums map[string]string Consts map[string]string GTypes map[string]string Endpoints map[string]string } type TSSouces struct { Pakages map[string]TSModule Errors []string } func (ts *TSSouces) ensurePackage(p string) { if _, ok := ts.Pakages[p]; !ok { ts.Pakages[p] = TSModule{ Structs: make(map[string]string), Types: make(map[string]string), Enums: make(map[string]string), Consts: make(map[string]string), GTypes: make(map[string]string), Endpoints: make(map[string]string), } return } pkg := ts.Pakages[p] if pkg.Structs == nil { pkg.Structs = make(map[string]string) } if pkg.Types == nil { pkg.Types = make(map[string]string) } if pkg.Enums == nil { pkg.Enums = make(map[string]string) } if pkg.Consts == nil { pkg.Consts = make(map[string]string) } if pkg.GTypes == nil { pkg.GTypes = make(map[string]string) } if pkg.Endpoints == nil { pkg.Endpoints = make(map[string]string) } ts.Pakages[p] = pkg } func (ts *TSSouces) findStruct(p string, n string) bool { if _, ok := ts.Pakages[p]; ok { if _, ok := ts.Pakages[p].Structs[n]; ok { return true } } return false } func (ts *TSSouces) findType(p string, n string) bool { if _, ok := ts.Pakages[p]; ok { if _, ok := ts.Pakages[p].Types[n]; ok { return true } } return false } func (ts *TSSouces) find(p string, n string) bool { return ts.findType(p, n) || ts.findStruct(p, n) } func emptySrtuct(info TSInfo, p string, k string) bool { s := info.Packages[p].structs[k] fields := 0 for _, v := range s.Fields { if !v.Json.Ignore { fields++ } } return fields == 0 } func structToTs(info TSInfo, p string, k string) (string, []string, error) { var result = "" var dependencies = []string{} fields := 0 s := info.Packages[p].structs[k] if s.Name == "" { return "", []string{}, errors.New("name not found") } if len(s.Fields) > 0 { result += fmt.Sprintf("\nexport interface %s {\n", k) for _, v := range info.Packages[p].structs[k].Fields { if v.Json.Ignore && !v.Ts.Expand { continue } var typeName = v.TsType if v.Ts.Type != "" { typeName = v.Ts.Type } if v.Ts.Expand { sp := strings.Split(v.Name, ".") pkg := p name := v.Name if len(sp) > 1 { pkg = sp[0] name = sp[1] } for _, v := range info.Packages[pkg].structs[name].Fields { result += fmt.Sprintf("\t%s: %s;\n", v.Name, v.TsType) fields++ } } else { omitempty := "" if v.Json.OmitEmpty { omitempty = "?" } if !v.Json.Ignore { result += fmt.Sprintf("\t%s%s: %s;\n", v.Json.Name, omitempty, typeName) fields++ } } if v.DependOn && v.Ts.Type == "" { dependencies = append(dependencies, v.TsType) } } result += "}\n" } if fields == 0 { return result, dependencies, fmt.Errorf("struct %s not export fields AT: %s", k, info.Packages[p].structs[k].SourceInfo) } return result, dependencies, nil } func typeToTs(info TSInfo, p string, k string) (string, []string) { var result = "" // var dependencies = []string{} s := info.Packages[p].types[k] result = fmt.Sprintf("export type %s = %s\n", s.Name, s.TsType) return result, []string{} } func enumToTs(info TSInfo, p string, k string) string { var result = "" s := info.Packages[p].enums[k] result += fmt.Sprintf("export const Enum%s = {\n", s.Name) for _, v := range s.Info { result += fmt.Sprintf("%s: %s,\n", v.Key, v.Value) } result += "} as const\n" return result } func constToTs(info TSInfo, p string, k string) string { var result = "" s := info.Packages[p].consts[k] result += fmt.Sprintf("export const %s = %s\n", s.Name, s.Value) return result } func (ts *TSSouces) AddDependencies(info TSInfo, p string, s string, dependencies []string) { if len(dependencies) > 0 { for _, v := range dependencies { pk := p st := string(v) if strings.Contains(st, ".") { sp := strings.Split(st, ".") if len(sp) == 2 { pk = sp[0] st = sp[1] } } if info.findStruct(pk, st) { if emptySrtuct(info, pk, st) { ts.Errors = append(ts.Errors, fmt.Sprintf("Empty struct %s.%s AT: %s", pk, st, info.Packages[p].structs[s].SourceInfo)) } s, d, err := structToTs(info, pk, st) if err != nil { ts.Errors = append(ts.Errors, err.Error()) } ts.ensurePackage(pk) ts.Pakages[pk].Structs[st] = s if len(d) > 0 { ts.AddDependencies(info, pk, st, d) } } else if info.findType(pk, st) { s, _ := typeToTs(info, pk, st) ts.ensurePackage(pk) ts.Pakages[pk].Types[st] = s } else { ts.Errors = append(ts.Errors, fmt.Sprintf("Dipendence not found %s.%s AT: %s", pk, st, info.Packages[p].structs[s].SourceInfo)) } } } } func (ts *TSSouces) Populate(info TSInfo) { ts.Pakages = make(map[string]TSModule) ts.Errors = []string{} for p, _ := range info.Packages { ts.ensurePackage(p) for _, st := range info.Packages[p].structs { if st.Typescript { if len(st.Fields) == 0 { ts.Errors = append(ts.Errors, fmt.Sprintf("Empty struct %s.%s AT: %s", p, st.Name, info.Packages[p].structs[st.Name].SourceInfo)) } s, dependencies, err := structToTs(info, p, st.Name) if err != nil { ts.Errors = append(ts.Errors, err.Error()) } ts.Pakages[p].Structs[st.Name] = s ts.AddDependencies(info, p, st.Name, dependencies) } } for _, t := range info.Packages[p].decs { ts.Pakages[p].GTypes[t.Name] = fmt.Sprintf("export type %s = %s\n", t.Name, t.Value) } for _, e := range info.Packages[p].consts { ts.Pakages[p].Consts[e.Name] = fmt.Sprint(constToTs(info, p, e.Name)) } for _, e := range info.Packages[p].enums { ts.Pakages[p].Enums[e.Name] = fmt.Sprint(enumToTs(info, p, e.Name)) } for _, t := range info.Packages[p].types { if t.Typescript { ts.Pakages[p].Types[t.Name] = fmt.Sprintf("export type %s = %s\n", t.Name, t.TsType) } } if len(info.Packages[p].endpoints) > 0 { for _, e := range info.Packages[p].endpoints { /* if e.Request != "" { a := strings.Split(e.Request, ".") if len(a) == 2 { s, d, err := structToTs(info, a[0], a[1]) if err != nil { ts.Errors = append(ts.Errors, err.Error()) } fmt.Println(s, d) } } if e.Response != "" { a := strings.Split(e.Response, ".") if len(a) == 2 { s, d, err := structToTs(info, a[0], a[1]) if err != nil { ts.Errors = append(ts.Errors, err.Error()) } fmt.Println(s, d) } } */ e.VerifyTypes(info, p) endpoint := e.ToTs(p) ts.Pakages[p].Endpoints[e.Name] = endpoint } } } }