tons of code

This commit is contained in:
Egor Aristov 2025-10-25 14:28:32 +03:00
parent 3ebfa08350
commit de8c9aedf7
Signed by: egor3f
GPG Key ID: 40482A264AAEC85F
8 changed files with 115 additions and 103 deletions

35
kitcom/api/api.go Normal file
View File

@ -0,0 +1,35 @@
package api
// todo check TInt size < 64
// todo check not float
type ValType int
const (
TInt ValType = 1
TString ValType = 2
TBool ValType = 3
TBlob ValType = 4
TArray ValType = 5
)
type Val struct {
Name string
Type ValType
Children []Val
}
type Method struct {
Name string
Params []Val
Ret []Val
}
type Endpoint struct {
Name string
Methods []Method
}
type Api struct {
Endpoints []Endpoint
}

View File

@ -1,4 +1,4 @@
package main package golang
import ( import (
"bytes" "bytes"
@ -7,21 +7,23 @@ import (
"os" "os"
"strings" "strings"
"text/template" "text/template"
"efprojects.com/kitten-ipc/kitcom/api"
) )
type goGenData struct { type goGenData struct {
PkgName string PkgName string
Api *Api Api *api.Api
} }
type GoApiGenerator struct { type GoApiGenerator struct {
pkgName string PkgName string
} }
func (g *GoApiGenerator) Generate(api *Api, destFile string) error { func (g *GoApiGenerator) Generate(apis *api.Api, destFile string) error {
tplCtx := goGenData{ tplCtx := goGenData{
PkgName: g.pkgName, PkgName: g.PkgName,
Api: api, Api: apis,
} }
tpl := template.New("gogen") tpl := template.New("gogen")
@ -29,22 +31,22 @@ func (g *GoApiGenerator) Generate(api *Api, destFile string) error {
"receiver": func(name string) string { "receiver": func(name string) string {
return strings.ToLower(name)[0:1] return strings.ToLower(name)[0:1]
}, },
"typedef": func(t ValType) (string, error) { "typedef": func(t api.ValType) (string, error) {
td, ok := map[ValType]string{ td, ok := map[api.ValType]string{
TInt: "int", api.TInt: "int",
TString: "string", api.TString: "string",
TBool: "bool", api.TBool: "bool",
}[t] }[t]
if !ok { if !ok {
return "", fmt.Errorf("cannot generate type %v", t) return "", fmt.Errorf("cannot generate type %v", t)
} }
return td, nil return td, nil
}, },
"zerovalue": func(t ValType) (string, error) { "zerovalue": func(t api.ValType) (string, error) {
v, ok := map[ValType]string{ v, ok := map[api.ValType]string{
TInt: "0", api.TInt: "0",
TString: `""`, api.TString: `""`,
TBool: "false", api.TBool: "false",
}[t] }[t]
if !ok { if !ok {
return "", fmt.Errorf("cannot generate zero value for type %v", t) return "", fmt.Errorf("cannot generate zero value for type %v", t)

View File

@ -1,4 +1,4 @@
package main package golang
import ( import (
"fmt" "fmt"
@ -6,6 +6,8 @@ import (
"go/parser" "go/parser"
"go/token" "go/token"
"regexp" "regexp"
"efprojects.com/kitten-ipc/kitcom/api"
) )
var decorComment = regexp.MustCompile(`^//\s?kittenipc:api$`) var decorComment = regexp.MustCompile(`^//\s?kittenipc:api$`)
@ -13,9 +15,9 @@ var decorComment = regexp.MustCompile(`^//\s?kittenipc:api$`)
type GoApiParser struct { type GoApiParser struct {
} }
func (g *GoApiParser) Parse(sourceFile string) (*Api, error) { func (g *GoApiParser) Parse(sourceFile string) (*api.Api, error) {
var api Api var apis api.Api
fileSet := token.NewFileSet() fileSet := token.NewFileSet()
astFile, err := parser.ParseFile(fileSet, sourceFile, nil, parser.ParseComments|parser.SkipObjectResolution) astFile, err := parser.ParseFile(fileSet, sourceFile, nil, parser.ParseComments|parser.SkipObjectResolution)
@ -50,12 +52,12 @@ func (g *GoApiParser) Parse(sourceFile string) (*Api, error) {
} }
_ = structType _ = structType
api.Endpoints = append(api.Endpoints, Endpoint{ apis.Endpoints = append(apis.Endpoints, api.Endpoint{
Name: typeSpec.Name.Name, Name: typeSpec.Name.Name,
}) })
} }
if len(api.Endpoints) == 0 { if len(apis.Endpoints) == 0 {
return nil, fmt.Errorf("no api struct found") return nil, fmt.Errorf("no api struct found")
} }
@ -86,20 +88,20 @@ func (g *GoApiParser) Parse(sourceFile string) (*Api, error) {
continue continue
} }
for i, endpoint := range api.Endpoints { for i, endpoint := range apis.Endpoints {
if recvIdent.Name == endpoint.Name { if recvIdent.Name == endpoint.Name {
var apiMethod Method var apiMethod api.Method
apiMethod.Name = funcDecl.Name.Name apiMethod.Name = funcDecl.Name.Name
for _, param := range funcDecl.Type.Params.List { for _, param := range funcDecl.Type.Params.List {
var apiPar Val var apiPar api.Val
ident := param.Type.(*ast.Ident) ident := param.Type.(*ast.Ident)
switch ident.Name { switch ident.Name {
case "int": case "int":
apiPar.Type = TInt apiPar.Type = api.TInt
case "string": case "string":
apiPar.Type = TString apiPar.Type = api.TString
case "bool": case "bool":
apiPar.Type = TBool apiPar.Type = api.TBool
default: default:
return nil, fmt.Errorf("parameter type %s is not supported yet", ident.Name) return nil, fmt.Errorf("parameter type %s is not supported yet", ident.Name)
} }
@ -110,15 +112,15 @@ func (g *GoApiParser) Parse(sourceFile string) (*Api, error) {
apiMethod.Params = append(apiMethod.Params, apiPar) apiMethod.Params = append(apiMethod.Params, apiPar)
} }
for _, ret := range funcDecl.Type.Results.List { for _, ret := range funcDecl.Type.Results.List {
var apiRet Val var apiRet api.Val
ident := ret.Type.(*ast.Ident) ident := ret.Type.(*ast.Ident)
switch ident.Name { switch ident.Name {
case "int": case "int":
apiRet.Type = TInt apiRet.Type = api.TInt
case "string": case "string":
apiRet.Type = TString apiRet.Type = api.TString
case "bool": case "bool":
apiRet.Type = TBool apiRet.Type = api.TBool
case "error": case "error":
// errors are processed other way // errors are processed other way
continue continue
@ -130,10 +132,10 @@ func (g *GoApiParser) Parse(sourceFile string) (*Api, error) {
} }
apiMethod.Ret = append(apiMethod.Ret, apiRet) apiMethod.Ret = append(apiMethod.Ret, apiRet)
} }
api.Endpoints[i].Methods = append(api.Endpoints[i].Methods, apiMethod) apis.Endpoints[i].Methods = append(apis.Endpoints[i].Methods, apiMethod)
} }
} }
} }
return &api, nil return &apis, nil
} }

View File

@ -8,48 +8,18 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"efprojects.com/kitten-ipc/kitcom/api"
"efprojects.com/kitten-ipc/kitcom/golang"
"efprojects.com/kitten-ipc/kitcom/ts"
) )
type ValType int
// todo check TInt size < 64
// todo check not float
const (
TInt ValType = 1
TString ValType = 2
TBool ValType = 3
TBlob ValType = 4
TArray ValType = 5
)
type Val struct {
Name string
Type ValType
Children []Val
}
type Method struct {
Name string
Params []Val
Ret []Val
}
type Endpoint struct {
Name string
Methods []Method
}
type Api struct {
Endpoints []Endpoint
}
type ApiParser interface { type ApiParser interface {
Parse(sourceFile string) (*Api, error) Parse(sourceFile string) (*api.Api, error)
} }
type ApiGenerator interface { type ApiGenerator interface {
Generate(api *Api, destFile string) error Generate(api *api.Api, destFile string) error
} }
func main() { func main() {
@ -116,9 +86,9 @@ func checkIsFile(src string) error {
func apiParserByExt(src string) (ApiParser, error) { func apiParserByExt(src string) (ApiParser, error) {
switch path.Ext(src) { switch path.Ext(src) {
case ".go": case ".go":
return &GoApiParser{}, nil return &golang.GoApiParser{}, nil
case ".ts": case ".ts":
return &TypescriptApiParser{}, nil return &ts.TypescriptApiParser{}, nil
case ".js": case ".js":
return nil, fmt.Errorf("vanilla javascript is not supported and never will be") return nil, fmt.Errorf("vanilla javascript is not supported and never will be")
case "": case "":
@ -137,11 +107,11 @@ func apiGeneratorByExt(dest string, pkgName string) (ApiGenerator, error) {
if !token.IsIdentifier(pkgName) { if !token.IsIdentifier(pkgName) {
return nil, fmt.Errorf("invalid package name: %s", pkgName) return nil, fmt.Errorf("invalid package name: %s", pkgName)
} }
return &GoApiGenerator{ return &golang.GoApiGenerator{
pkgName: pkgName, PkgName: pkgName,
}, nil }, nil
case ".ts": case ".ts":
return &TypescriptApiGenerator{}, nil return &ts.TypescriptApiGenerator{}, nil
case ".js": case ".js":
return nil, fmt.Errorf("vanilla javascript is not supported and never will be") return nil, fmt.Errorf("vanilla javascript is not supported and never will be")
case "": case "":

View File

@ -1,7 +1,6 @@
{{- /*gotype: efprojects.com/kitten-ipc/kitcom.tsGenData*/ -}}
import {ParentIPC, ChildIPC} from 'kitten-ipc'; import {ParentIPC, ChildIPC} from 'kitten-ipc';
{{- /*gotype: efprojects.com/kitten-ipc/kitcom/ts.tsGenData*/ -}}
{{range $e := .Api.Endpoints}} {{range $e := .Api.Endpoints}}
export default class {{$e.Name}} { export default class {{$e.Name}} {
private ipc: ParentIPC | ChildIPC; private ipc: ParentIPC | ChildIPC;
@ -14,9 +13,10 @@ export default class {{$e.Name}} {
async {{ $mtd.Name }}( async {{ $mtd.Name }}(
{{ range $par := $mtd.Params }}{{$par.Name}}: {{$par.Type | typedef }}, {{end}} {{ range $par := $mtd.Params }}{{$par.Name}}: {{$par.Type | typedef }}, {{end}}
): Promise<{{if len $mtd.Ret}}{{(index $mtd.Ret 0).Type | typedef }}{{else}}void{{end}}> { ): Promise<{{if len $mtd.Ret}}{{(index $mtd.Ret 0).Type | typedef }}{{else}}void{{end}}> {
return await this.ipc.call('{{$mtd.Name}}', const results = await this.ipc.call('{{$mtd.Name}}',
{{range $par := $mtd.Params}}{{$par.Name}}, {{end}} {{range $par := $mtd.Params}}{{$par.Name}}, {{end}}
); );
return {{range $ret := $mtd.}}
} }
{{end}} {{end}}
} }

View File

@ -1,4 +1,4 @@
package main package ts
import ( import (
"bytes" "bytes"
@ -7,27 +7,29 @@ import (
"os" "os"
"os/exec" "os/exec"
"text/template" "text/template"
"efprojects.com/kitten-ipc/kitcom/api"
) )
type tsGenData struct { type tsGenData struct {
Api *Api Api *api.Api
} }
type TypescriptApiGenerator struct { type TypescriptApiGenerator struct {
} }
func (g *TypescriptApiGenerator) Generate(api *Api, destFile string) error { func (g *TypescriptApiGenerator) Generate(apis *api.Api, destFile string) error {
tplCtx := tsGenData{ tplCtx := tsGenData{
Api: api, Api: apis,
} }
tpl := template.New("tsgen") tpl := template.New("tsgen")
tpl = tpl.Funcs(map[string]any{ tpl = tpl.Funcs(map[string]any{
"typedef": func(t ValType) (string, error) { "typedef": func(t api.ValType) (string, error) {
td, ok := map[ValType]string{ td, ok := map[api.ValType]string{
TInt: "number", api.TInt: "number",
TString: "string", api.TString: "string",
TBool: "boolean", api.TBool: "boolean",
}[t] }[t]
if !ok { if !ok {
return "", fmt.Errorf("cannot generate type %v", t) return "", fmt.Errorf("cannot generate type %v", t)

View File

@ -1,4 +1,4 @@
package main package ts
import ( import (
"fmt" "fmt"
@ -6,6 +6,7 @@ import (
"os" "os"
"strings" "strings"
"efprojects.com/kitten-ipc/kitcom/api"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/parser" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/parser"
@ -18,7 +19,7 @@ const TagComment = "api"
type TypescriptApiParser struct { type TypescriptApiParser struct {
} }
func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) { func (t *TypescriptApiParser) Parse(sourceFilePath string) (*api.Api, error) {
f, err := os.Open(sourceFilePath) f, err := os.Open(sourceFilePath)
if err != nil { if err != nil {
@ -40,7 +41,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
}, string(fileContents), core.ScriptKindTS) }, string(fileContents), core.ScriptKindTS)
_ = sourceFile _ = sourceFile
var api Api var apis 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 {
@ -74,7 +75,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
return false return false
} }
var endpoint Endpoint var endpoint api.Endpoint
endpoint.Name = cls.Name().Text() endpoint.Name = cls.Name().Text()
@ -84,42 +85,42 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
} }
method := member.AsMethodDeclaration() method := member.AsMethodDeclaration()
var apiMethod Method var apiMethod api.Method
apiMethod.Name = method.Name().Text() apiMethod.Name = method.Name().Text()
for _, parNode := range method.ParameterList().Nodes { for _, parNode := range method.ParameterList().Nodes {
par := parNode.AsParameterDeclaration() par := parNode.AsParameterDeclaration()
var apiPar Val var apiPar api.Val
apiPar.Name = par.Name().Text() apiPar.Name = par.Name().Text()
switch par.Type.Kind { switch par.Type.Kind {
case ast.KindNumberKeyword: case ast.KindNumberKeyword:
apiPar.Type = TInt apiPar.Type = api.TInt
case ast.KindStringKeyword: case ast.KindStringKeyword:
apiPar.Type = TString apiPar.Type = api.TString
case ast.KindBooleanKeyword: case ast.KindBooleanKeyword:
apiPar.Type = TBool apiPar.Type = api.TBool
default: default:
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.Params = append(apiMethod.Params, apiPar) apiMethod.Params = append(apiMethod.Params, apiPar)
} }
var apiRet Val var apiRet api.Val
switch method.Type.Kind { switch method.Type.Kind {
case ast.KindNumberKeyword: case ast.KindNumberKeyword:
apiRet.Type = TInt apiRet.Type = api.TInt
case ast.KindStringKeyword: case ast.KindStringKeyword:
apiRet.Type = TString apiRet.Type = api.TString
case ast.KindBooleanKeyword: case ast.KindBooleanKeyword:
apiRet.Type = TBool apiRet.Type = api.TBool
default: default:
err = fmt.Errorf("return type %s is not supported yet", method.Type.Kind) err = fmt.Errorf("return type %s is not supported yet", method.Type.Kind)
return false return false
} }
apiMethod.Ret = []Val{apiRet} apiMethod.Ret = []api.Val{apiRet}
endpoint.Methods = append(endpoint.Methods, apiMethod) endpoint.Methods = append(endpoint.Methods, apiMethod)
} }
api.Endpoints = append(api.Endpoints, endpoint) apis.Endpoints = append(apis.Endpoints, endpoint)
return false return false
}) })
@ -128,9 +129,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
return nil, err return nil, err
} }
if len(api.Endpoints) == 0 { if len(apis.Endpoints) == 0 {
return nil, fmt.Errorf("no api class found") return nil, fmt.Errorf("no api class found")
} }
return &api, nil return &apis, nil
} }