tons of code
This commit is contained in:
parent
6c396107c8
commit
12e472c8e5
17
example/golang/tsapi.gen.go
Normal file
17
example/golang/tsapi.gen.go
Normal file
@ -0,0 +1,17 @@
|
||||
// Code generated by kitcom. DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
import kittenipc "efprojects.com/kitten-ipc"
|
||||
|
||||
type TsIpcApi struct {
|
||||
Ipc *kittenipc.KittenIPC
|
||||
}
|
||||
|
||||
func (t *TsIpcApi) Div(
|
||||
a int, b int,
|
||||
) int {
|
||||
return t.Ipc.Call(
|
||||
"Div", a, b,
|
||||
)
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @kittenipc api
|
||||
*/
|
||||
class IpcApi {
|
||||
class TsIpcApi {
|
||||
Div(a: number, b: number): number {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
28
kitcom/go_gen.tmpl
Normal file
28
kitcom/go_gen.tmpl
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
{{- /*gotype: efprojects.com/kitten-ipc/kitcom.genData*/ -}}
|
||||
|
||||
// Code generated by kitcom. DO NOT EDIT.
|
||||
|
||||
package {{.PkgName}}
|
||||
|
||||
import kittenipc "efprojects.com/kitten-ipc"
|
||||
|
||||
{{range $e := .Api.Endpoints}}
|
||||
|
||||
type {{.Name}} struct {
|
||||
Ipc *kittenipc.KittenIPC
|
||||
}
|
||||
|
||||
{{range $mtd := .Methods}}
|
||||
func ({{$e.Name | receiver}} *{{$e.Name}}) {{$mtd.Name}} (
|
||||
{{range $mtd.Params}}{{.Name}} {{.Type | typedef}}, {{end}}
|
||||
) (
|
||||
{{range $mtd.Ret}}{{.Type | typedef}}, {{end}}
|
||||
) {
|
||||
return {{$e.Name | receiver}}.Ipc.Call(
|
||||
"{{$mtd.Name}}", {{range $mtd.Pars}}{{.Name}}, {{end}}
|
||||
)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
@ -1,49 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"go/format"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type GoApiGenerator struct {
|
||||
type genData struct {
|
||||
PkgName string
|
||||
Api *Api
|
||||
}
|
||||
|
||||
var tpl = template.Must(template.New("gotpl").Parse(strings.TrimSpace(`
|
||||
|
||||
|
||||
|
||||
`)))
|
||||
type GoApiGenerator struct {
|
||||
pkgName string
|
||||
}
|
||||
|
||||
func (g *GoApiGenerator) Generate(api *Api, destFile string) error {
|
||||
destFileBak := filepath.Join(destFile, ".bak")
|
||||
_, err := os.Stat(destFile)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return fmt.Errorf("stat destination file: %w", err)
|
||||
}
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
if err := os.Rename(destFile, destFileBak); err != nil {
|
||||
return fmt.Errorf("backup destination file: %w", err)
|
||||
}
|
||||
tplCtx := genData{
|
||||
PkgName: g.pkgName,
|
||||
Api: api,
|
||||
}
|
||||
|
||||
tpl := template.New("gogen")
|
||||
tpl = tpl.Funcs(map[string]any{
|
||||
"receiver": func(name string) string {
|
||||
return strings.ToLower(name)[0:1]
|
||||
},
|
||||
"typedef": func(t ValType) (string, error) {
|
||||
td, ok := map[ValType]string{
|
||||
TInt: "int",
|
||||
TString: "string",
|
||||
TBool: "bool",
|
||||
}[t]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("cannot generate type %v", t)
|
||||
}
|
||||
return td, nil
|
||||
},
|
||||
})
|
||||
tpl = template.Must(tpl.ParseFiles("./go_gen.tmpl"))
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err := tpl.ExecuteTemplate(&buf, "go_gen.tmpl", tplCtx); err != nil {
|
||||
return fmt.Errorf("execute template: %w", err)
|
||||
}
|
||||
|
||||
if err := g.writeDest(destFile, buf.Bytes()); err != nil {
|
||||
return fmt.Errorf("write file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GoApiGenerator) writeDest(destFile string, bytes []byte) error {
|
||||
f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open destination file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := tpl.Execute(f, api); err != nil {
|
||||
return fmt.Errorf("execute template: %w", err)
|
||||
formatted, err := format.Source(bytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("format source: %w", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(destFileBak); err == nil {
|
||||
if err := os.Remove(destFileBak); err != nil {
|
||||
return fmt.Errorf("remove backup file: %w", err)
|
||||
}
|
||||
if _, err := f.Write(formatted); err != nil {
|
||||
return fmt.Errorf("write formatted source: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -3,23 +3,13 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
Src string
|
||||
Dest string
|
||||
)
|
||||
|
||||
func parseFlags() {
|
||||
flag.StringVar(&Src, "src", "", "Source file")
|
||||
flag.StringVar(&Dest, "dest", "", "Dest file")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
type ValType int
|
||||
|
||||
// todo check TInt size < 64
|
||||
@ -40,13 +30,18 @@ type Val struct {
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
Name string
|
||||
Pars []Val
|
||||
Ret []Val
|
||||
Name string
|
||||
Params []Val
|
||||
Ret []Val
|
||||
}
|
||||
|
||||
type Endpoint struct {
|
||||
Name string
|
||||
Methods []Method
|
||||
}
|
||||
|
||||
type Api struct {
|
||||
Methods []Method
|
||||
Endpoints []Endpoint
|
||||
}
|
||||
|
||||
type ApiParser interface {
|
||||
@ -64,17 +59,21 @@ func main() {
|
||||
// log.Panic("GOFILE must be set")
|
||||
//}
|
||||
|
||||
parseFlags()
|
||||
if Src == "" || Dest == "" {
|
||||
src := flag.String("src", "", "Source file")
|
||||
dest := flag.String("dest", "", "Dest file")
|
||||
pkgName := flag.String("pkgname", "", "Package name (for go)")
|
||||
flag.Parse()
|
||||
|
||||
if *src == "" || *dest == "" {
|
||||
log.Panic("source and destination must be set")
|
||||
}
|
||||
|
||||
srcAbs, err := filepath.Abs(Src)
|
||||
srcAbs, err := filepath.Abs(*src)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
destAbs, err := filepath.Abs(Dest)
|
||||
destAbs, err := filepath.Abs(*dest)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
@ -93,7 +92,7 @@ func main() {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
apiGenerator, err := apiGeneratorByExt(destAbs)
|
||||
apiGenerator, err := apiGeneratorByExt(destAbs, *pkgName)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
@ -129,10 +128,18 @@ func apiParserByExt(src string) (ApiParser, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func apiGeneratorByExt(dest string) (ApiGenerator, error) {
|
||||
func apiGeneratorByExt(dest string, pkgName string) (ApiGenerator, error) {
|
||||
switch path.Ext(dest) {
|
||||
case ".go":
|
||||
return &GoApiGenerator{}, nil
|
||||
if pkgName == "" {
|
||||
return nil, fmt.Errorf("package name must be set for Go generation")
|
||||
}
|
||||
if !token.IsIdentifier(pkgName) {
|
||||
return nil, fmt.Errorf("invalid package name: %s", pkgName)
|
||||
}
|
||||
return &GoApiGenerator{
|
||||
pkgName: pkgName,
|
||||
}, nil
|
||||
case ".ts":
|
||||
return &TypescriptApiGenerator{}, nil
|
||||
case ".js":
|
||||
|
||||
@ -18,10 +18,6 @@ const TagComment = "api"
|
||||
type TypescriptApiParser struct {
|
||||
}
|
||||
|
||||
type apiClass struct {
|
||||
methods []Method
|
||||
}
|
||||
|
||||
func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
|
||||
f, err := os.Open(sourceFilePath)
|
||||
@ -44,7 +40,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
}, string(fileContents), core.ScriptKindTS)
|
||||
_ = sourceFile
|
||||
|
||||
var apiClasses []apiClass
|
||||
var api Api
|
||||
|
||||
sourceFile.ForEachChild(func(node *ast.Node) bool {
|
||||
if node.Kind != ast.KindClassDeclaration {
|
||||
@ -78,7 +74,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
return false
|
||||
}
|
||||
|
||||
var apiCls apiClass
|
||||
var endpoint Endpoint
|
||||
|
||||
endpoint.Name = cls.Name().Text()
|
||||
|
||||
for _, member := range cls.MemberList().Nodes {
|
||||
if member.Kind != ast.KindMethodDeclaration {
|
||||
@ -103,7 +101,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
err = fmt.Errorf("parameter type %s is not supported yet", par.Type.Kind)
|
||||
return false
|
||||
}
|
||||
apiMethod.Pars = append(apiMethod.Pars, apiPar)
|
||||
apiMethod.Params = append(apiMethod.Params, apiPar)
|
||||
}
|
||||
var apiRet Val
|
||||
switch method.Type.Kind {
|
||||
@ -118,10 +116,10 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
return false
|
||||
}
|
||||
apiMethod.Ret = []Val{apiRet}
|
||||
apiCls.methods = append(apiCls.methods, apiMethod)
|
||||
endpoint.Methods = append(endpoint.Methods, apiMethod)
|
||||
}
|
||||
|
||||
apiClasses = append(apiClasses, apiCls)
|
||||
api.Endpoints = append(api.Endpoints, endpoint)
|
||||
|
||||
return false
|
||||
})
|
||||
@ -130,13 +128,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(apiClasses) == 0 {
|
||||
if len(api.Endpoints) == 0 {
|
||||
return nil, fmt.Errorf("no api class found")
|
||||
}
|
||||
|
||||
if len(apiClasses) > 1 {
|
||||
return nil, fmt.Errorf("multiple api classes found")
|
||||
}
|
||||
|
||||
return &Api{Methods: apiClasses[0].methods}, nil
|
||||
return &api, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user