// exportable typescript generated from golang // Copyright (C) 2022 Fabio Prada package tsrpc import ( "bytes" "fmt" "strings" "text/template" ) type TSEndpoint struct { Name string Path string Method string Request string Response string RequestTs string ResponseTs string Source string File string Line int } func ParseEndpoint(source string, file string, line int) TSEndpoint { p := strings.Index(source, "TSEndpoint=") s := strings.Trim(source[p+len("TSEndpoint="):], " ") a := strings.Split(s, ";") n := 0 endpoint := TSEndpoint{} endpoint.Source = strings.Trim(source, "\t") endpoint.File = file endpoint.Line = line for _, v := range a { t := strings.Split(v, "=") if len(t) < 2 || strings.Trim(t[1], " ") == "" { exitOnError(fmt.Errorf("worong endpoint: %s", s)) } if len(t) == 2 { switch strings.Trim(t[0], " ") { case "path": n++ endpoint.Path = strings.Trim(t[1], " ") case "method": n++ endpoint.Method = strings.Trim(t[1], " ") case "name": n++ endpoint.Name = strings.Trim(t[1], " ") case "request": n++ endpoint.Request = strings.Trim(t[1], " ") case "response": n++ endpoint.Response = strings.Trim(t[1], " ") } } else { exitOnError(fmt.Errorf("wrong endpoint props: %s", s)) } } if endpoint.Method != "POST" && endpoint.Method != "GET" && endpoint.Method != "DELETE" && endpoint.Method != "PUT" { exitOnError(fmt.Errorf("wrong endpoint method: %s", s)) } if (endpoint.Method == "GET" || endpoint.Method == "DELETE") && n < 4 { exitOnError(fmt.Errorf("wrong endpoint number of props: %s", s)) } if (endpoint.Method == "POST" || endpoint.Method == "PUT") && n < 5 { exitOnError(fmt.Errorf("wrong endpoint number of props: %s", s)) } return endpoint } type tplData struct { E *TSEndpoint Path string Params []string } func (e *TSEndpoint) VerifyTypes(info TSInfo, p string) { a := strings.Split(e.Request, ".") if e.Request != "" { if len(a) == 2 { e.RequestTs = a[1] if strings.HasPrefix(a[1], "[]") { a[1] = strings.TrimPrefix(a[1], "[]") e.RequestTs = fmt.Sprintf("%s[]", a[1]) } if strings.HasPrefix(a[1], "*") { a[1] = strings.TrimPrefix(a[1], "*") e.RequestTs = fmt.Sprintf("Nullable<%s>", a[1]) } e.Request = fmt.Sprintf("%s.%s", a[0], a[1]) if !info.find(a[0], a[1]) { exitOnError(fmt.Errorf("endpoint request not found: %s AT %s Line: %d ", e.Request, e.File, e.Line)) } info.setTypescript(a[0], a[1], true) } if len(a) == 1 { e.RequestTs = a[0] if strings.HasPrefix(a[0], "[]") { a[0] = strings.TrimPrefix(a[0], "[]") e.RequestTs = fmt.Sprintf("%s[]", a[0]) } if strings.HasPrefix(a[0], "*") { a[0] = strings.TrimPrefix(a[0], "*") e.RequestTs = fmt.Sprintf("Nullable<%s>", a[0]) } e.Request = a[0] } } a = strings.Split(e.Response, ".") if len(a) == 2 { if !info.find(a[0], a[1]) { exitOnError(fmt.Errorf("endpoint response not found: %s AT %s Line: %d ", e.Request, e.File, e.Line)) } e.ResponseTs = a[1] if strings.HasPrefix(a[1], "[]") { a[1] = strings.TrimPrefix(a[1], "[]") e.ResponseTs = fmt.Sprintf("%s[]", a[1]) } if strings.HasPrefix(a[1], "*") { a[1] = strings.TrimPrefix(a[1], "*") e.ResponseTs = fmt.Sprintf("Nullable<%s>", a[1]) } e.Response = fmt.Sprintf("%s.%s", a[0], a[1]) } if len(a) == 1 { e.ResponseTs = a[0] if strings.HasPrefix(a[0], "[]") { a[0] = strings.TrimPrefix(a[0], "[]") e.ResponseTs = fmt.Sprintf("%s[]", a[0]) } if strings.HasPrefix(a[0], "*") { a[0] = strings.TrimPrefix(a[0], "*") e.ResponseTs = fmt.Sprintf("Nullable<%s>", a[0]) } e.Response = a[0] } } func (e *TSEndpoint) ToTs(pkg string) string { data := tplData{E: e, Path: e.Path, Params: []string{}} tpl := ` {{ .E.Source }} // {{ .E.File }} Line: {{ .E.Line }} {{if eq .E.Method "GET"}}export const {{ .E.Name}} = async ({{range $v := .Params}}{{$v}}{{end}}):Promise<{ data:{{.E.ResponseTs}}; error: Nullable }> => { return await api.GET({{ .Path}}) as { data: {{ .E.ResponseTs}}; error: Nullable }; }{{end}} {{if eq .E.Method "DELETE"}}export const {{ .E.Name}} = async ({{range $v := .Params}}{{$v}}{{end}}):Promise<{ data:{{.E.ResponseTs}}; error: Nullable }> => { return await api.DELETE({{ .Path}}) as { data: {{ .E.ResponseTs}}; error: Nullable }; }{{end}} {{if eq .E.Method "PUT"}}export const {{ .E.Name}} = async (data: {{ .E.RequestTs}}):Promise<{ data:{{.E.ResponseTs}}; error: Nullable }> => { return await api.PUT("{{ .Path}}", data) as { data: {{ .E.ResponseTs}}; error: Nullable }; }{{end}} {{if eq .E.Method "POST"}}export const {{ .E.Name}} = async (data: {{ .E.RequestTs}}):Promise<{ data:{{.E.ResponseTs}}; error: Nullable }> => { return await api.POST("{{ .Path}}", data) as { data: {{ .E.ResponseTs}}; error: Nullable }; }{{end}}` if e.Method == "GET" || e.Method == "DELETE" { a := strings.Split(e.Path, "/") c := "" f := false for _, v := range a { if len(v) == 0 { continue } prefix := v[0:1] if f { c = ", " } if prefix == ":" { f = true data.Params = append(data.Params, fmt.Sprintf("%s%s: string", c, v[1:])) data.Path = strings.Replace(data.Path, v, fmt.Sprintf("${%s}", v[1:]), 1) } else if prefix == "*" { f = true data.Params = append(data.Params, fmt.Sprintf("%s%s: Nullable", c, v[1:])) data.Path = strings.Replace(data.Path, v, fmt.Sprintf("${%s}", v[1:]), 1) } } if len(data.Params) > 0 { data.Path = fmt.Sprintf("`%s`", data.Path) } else { data.Path = fmt.Sprintf("\"%s\"", data.Path) } } t, err := template.New("test").Parse(tpl) if err != nil { panic(err) } var result bytes.Buffer err = t.Execute(&result, data) if err != nil { panic(err) } return result.String() }