// exportable typescript generated from golang // Copyright (C) 2022 Fabio Prada package tsrpc import ( "fmt" "go/ast" ) type TSSField struct { Name string Type string TsType string Json TSTagJson Ts TSTagTs DependOn bool SourceInfo string } type TSStruct struct { Name string Typescript bool Fields []TSSField SourceInfo string } func IsNativeType(t string) bool { switch t { case "uint8", "uint16", "uint32", "uint64", "uint", "int8", "int16", "int32", "int64", "int", "float32", "float64": return true case "bool": return true case "string": return true } return false } func toBeImported(t ast.Expr) bool { switch ft := t.(type) { case *ast.Ident: return !IsNativeType(ft.Name) case *ast.SelectorExpr: return true } return false } func typeToTypescript(k string) string { switch k { case "uint8", "uint16", "uint32", "uint64", "uint", "int8", "int16", "int32", "int64", "int", "float32", "float64": return "number" case "bool": return "boolean" case "string": return "string" } return k } func getFieldInfo(t ast.Expr) string { result := "" switch ft := t.(type) { case *ast.Ident: result = ft.Name case *ast.SelectorExpr: result = fmt.Sprintf("%s.%s", ft.X, ft.Sel) case *ast.ArrayType: result = fmt.Sprintf("[]%s", getFieldInfo(ft.Elt)) case *ast.StarExpr: result = fmt.Sprintf("*%s", (ft.X)) case *ast.MapType: result = fmt.Sprintf("map[%s]%s", ft.Key, getFieldInfo(ft.Value)) case *ast.InterfaceType: result = "interface{}" default: f := fmt.Sprintf("this go type: %T is not evaluated", ft) fmt.Println(f) //exitOnError(fmt.Errorf("this go type: %T is not evaluated", ft)) } return result } func getFieldTsInfo(t ast.Expr) string { result := "" switch ft := t.(type) { case *ast.Ident: result = typeToTypescript(ft.Name) case *ast.SelectorExpr: result = typeToTypescript(fmt.Sprintf("%s.%s", ft.X, ft.Sel)) case *ast.ArrayType: result = fmt.Sprintf("%s[]", typeToTypescript(getFieldTsInfo(ft.Elt))) case *ast.StarExpr: result = fmt.Sprintf("Nullable<%s>", typeToTypescript(getFieldTsInfo(ft.X))) case *ast.MapType: result = fmt.Sprintf("Record<%s , %s>", typeToTypescript(fmt.Sprintf("%s", ft.Key)), typeToTypescript(("ft.Value"))) case *ast.InterfaceType: result = "unknown" case *ast.FuncType: fmt.Println("*ast.FuncType found, skipping...") default: //f := fmt.Sprintf("getFieldTsInfo can't evaluate type: %T %T", t, ft) //fmt.Println(f) exitOnError(fmt.Errorf("getFieldTsInfo can't evaluate type: %T %T", t, ft)) } return result } func getSourceInfo(pos int, src []TSSourceFile) string { for _, v := range src { for _, l := range v.Lines { if pos >= l.Pos && pos <= l.End { return fmt.Sprintf("%s Line: %d", v.Name, l.Line) } } } return "" } func (s *TSStruct) getStruct(ts *ast.TypeSpec, src []TSSourceFile) { if st, ok := ts.Type.(*ast.StructType); ok { for _, field := range st.Fields.List { tag := "" if field.Tag != nil { tag = field.Tag.Value } tagJson := TSTagJson{} tagJson.parse(tag) tagTs := TSTagTs{} tagTs.parse(tag) tsType := "" if len(field.Names) > 0 { tsType = getFieldTsInfo(field.Type) var f = TSSField{ Name: field.Names[0].String(), Json: tagJson, Ts: tagTs, Type: getFieldInfo(field.Type), TsType: tsType, DependOn: toBeImported(field.Type), SourceInfo: getSourceInfo(int(field.Type.Pos()), src), } s.Fields = append(s.Fields, f) } else { if se, ok := field.Type.(*ast.SelectorExpr); ok { var f = TSSField{ Name: fmt.Sprintf("%s.%s", se.X, se.Sel), Json: tagJson, Ts: tagTs, Type: getFieldInfo(field.Type), TsType: tsType, DependOn: toBeImported(field.Type), SourceInfo: getSourceInfo(int(field.Type.Pos()), src), } s.Fields = append(s.Fields, f) } else { if se, ok := field.Type.(*ast.Ident); ok { var f = TSSField{ Name: se.Name, Json: tagJson, Ts: tagTs, Type: se.Name, TsType: tsType, DependOn: false, SourceInfo: getSourceInfo(int(field.Type.Pos()), src), } s.Fields = append(s.Fields, f) fmt.Println(f) } else { exitOnError(fmt.Errorf("this typescript type: %T is not evaluated", field.Type)) } } } } } }