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
|
* @kittenipc api
|
||||||
*/
|
*/
|
||||||
class IpcApi {
|
class TsIpcApi {
|
||||||
Div(a: number, b: number): number {
|
Div(a: number, b: number): number {
|
||||||
return a / b;
|
return a / b;
|
||||||
}
|
}
|
||||||
@ -9,7 +9,7 @@ class IpcApi {
|
|||||||
|
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|||||||
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"go/format"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"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 {
|
func (g *GoApiGenerator) Generate(api *Api, destFile string) error {
|
||||||
destFileBak := filepath.Join(destFile, ".bak")
|
tplCtx := genData{
|
||||||
_, err := os.Stat(destFile)
|
PkgName: g.pkgName,
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
Api: api,
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("open destination file: %w", err)
|
return fmt.Errorf("open destination file: %w", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
if err := tpl.Execute(f, api); err != nil {
|
formatted, err := format.Source(bytes)
|
||||||
return fmt.Errorf("execute template: %w", err)
|
if err != nil {
|
||||||
|
return fmt.Errorf("format source: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(destFileBak); err == nil {
|
if _, err := f.Write(formatted); err != nil {
|
||||||
if err := os.Remove(destFileBak); err != nil {
|
return fmt.Errorf("write formatted source: %w", err)
|
||||||
return fmt.Errorf("remove backup file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,23 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/token"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"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
|
type ValType int
|
||||||
|
|
||||||
// todo check TInt size < 64
|
// todo check TInt size < 64
|
||||||
@ -40,13 +30,18 @@ type Val struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Method struct {
|
type Method struct {
|
||||||
Name string
|
Name string
|
||||||
Pars []Val
|
Params []Val
|
||||||
Ret []Val
|
Ret []Val
|
||||||
|
}
|
||||||
|
|
||||||
|
type Endpoint struct {
|
||||||
|
Name string
|
||||||
|
Methods []Method
|
||||||
}
|
}
|
||||||
|
|
||||||
type Api struct {
|
type Api struct {
|
||||||
Methods []Method
|
Endpoints []Endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiParser interface {
|
type ApiParser interface {
|
||||||
@ -64,17 +59,21 @@ func main() {
|
|||||||
// log.Panic("GOFILE must be set")
|
// log.Panic("GOFILE must be set")
|
||||||
//}
|
//}
|
||||||
|
|
||||||
parseFlags()
|
src := flag.String("src", "", "Source file")
|
||||||
if Src == "" || Dest == "" {
|
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")
|
log.Panic("source and destination must be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
srcAbs, err := filepath.Abs(Src)
|
srcAbs, err := filepath.Abs(*src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
destAbs, err := filepath.Abs(Dest)
|
destAbs, err := filepath.Abs(*dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
@ -93,7 +92,7 @@ func main() {
|
|||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
apiGenerator, err := apiGeneratorByExt(destAbs)
|
apiGenerator, err := apiGeneratorByExt(destAbs, *pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
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) {
|
switch path.Ext(dest) {
|
||||||
case ".go":
|
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":
|
case ".ts":
|
||||||
return &TypescriptApiGenerator{}, nil
|
return &TypescriptApiGenerator{}, nil
|
||||||
case ".js":
|
case ".js":
|
||||||
|
|||||||
@ -18,10 +18,6 @@ const TagComment = "api"
|
|||||||
type TypescriptApiParser struct {
|
type TypescriptApiParser struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type apiClass struct {
|
|
||||||
methods []Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
||||||
|
|
||||||
f, err := os.Open(sourceFilePath)
|
f, err := os.Open(sourceFilePath)
|
||||||
@ -44,7 +40,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
|||||||
}, string(fileContents), core.ScriptKindTS)
|
}, string(fileContents), core.ScriptKindTS)
|
||||||
_ = sourceFile
|
_ = sourceFile
|
||||||
|
|
||||||
var apiClasses []apiClass
|
var api Api
|
||||||
|
|
||||||
sourceFile.ForEachChild(func(node *ast.Node) bool {
|
sourceFile.ForEachChild(func(node *ast.Node) bool {
|
||||||
if node.Kind != ast.KindClassDeclaration {
|
if node.Kind != ast.KindClassDeclaration {
|
||||||
@ -78,7 +74,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiCls apiClass
|
var endpoint Endpoint
|
||||||
|
|
||||||
|
endpoint.Name = cls.Name().Text()
|
||||||
|
|
||||||
for _, member := range cls.MemberList().Nodes {
|
for _, member := range cls.MemberList().Nodes {
|
||||||
if member.Kind != ast.KindMethodDeclaration {
|
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)
|
err = fmt.Errorf("parameter type %s is not supported yet", par.Type.Kind)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
apiMethod.Pars = append(apiMethod.Pars, apiPar)
|
apiMethod.Params = append(apiMethod.Params, apiPar)
|
||||||
}
|
}
|
||||||
var apiRet Val
|
var apiRet Val
|
||||||
switch method.Type.Kind {
|
switch method.Type.Kind {
|
||||||
@ -118,10 +116,10 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
apiMethod.Ret = []Val{apiRet}
|
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
|
return false
|
||||||
})
|
})
|
||||||
@ -130,13 +128,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(apiClasses) == 0 {
|
if len(api.Endpoints) == 0 {
|
||||||
return nil, fmt.Errorf("no api class found")
|
return nil, fmt.Errorf("no api class found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(apiClasses) > 1 {
|
return &api, nil
|
||||||
return nil, fmt.Errorf("multiple api classes found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Api{Methods: apiClasses[0].methods}, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user