wip rename
This commit is contained in:
170
internal/functions/collector.go
Normal file
170
internal/functions/collector.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package functions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type typeCollector struct {
|
||||
mu sync.Mutex
|
||||
types map[string]string
|
||||
paramTypes map[string]bool
|
||||
}
|
||||
|
||||
func newTypeCollector() *typeCollector {
|
||||
return &typeCollector{
|
||||
types: make(map[string]string),
|
||||
paramTypes: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *typeCollector) collectTypes(argsType reflect.Type, fnType reflect.Type) []string {
|
||||
tc.mu.Lock()
|
||||
defer tc.mu.Unlock()
|
||||
tc.types = make(map[string]string)
|
||||
tc.paramTypes = make(map[string]bool)
|
||||
|
||||
var result []string
|
||||
|
||||
tc.collectStruct(argsType, argsType.Name())
|
||||
|
||||
for i := 0; i < argsType.NumField(); i++ {
|
||||
field := argsType.Field(i)
|
||||
if field.Type.Kind() == reflect.Pointer || strings.Contains(field.Tag.Get("json"), ",omitempty") {
|
||||
tc.collectParamType(field.Type)
|
||||
}
|
||||
}
|
||||
|
||||
if fnType.Kind() == reflect.Func && fnType.NumOut() > 0 {
|
||||
lastIndex := fnType.NumOut() - 1
|
||||
lastType := fnType.Out(lastIndex)
|
||||
|
||||
if lastType.Implements(reflect.TypeOf((*error)(nil)).Elem()) {
|
||||
if fnType.NumOut() > 1 {
|
||||
tc.collectType(fnType.Out(0))
|
||||
}
|
||||
} else {
|
||||
tc.collectType(lastType)
|
||||
}
|
||||
}
|
||||
|
||||
for _, t := range tc.types {
|
||||
result = append(result, t)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (tc *typeCollector) collectParamType(t reflect.Type) {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
tc.collectParamType(t.Elem())
|
||||
return
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Struct && t.Name() != "" {
|
||||
tc.paramTypes[t.Name()+" | null"] = true
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *typeCollector) getParamTypes() map[string]bool {
|
||||
return tc.paramTypes
|
||||
}
|
||||
|
||||
func (tc *typeCollector) collectType(t reflect.Type) {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
tc.collectType(t.Elem())
|
||||
return
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Struct {
|
||||
name := t.Name()
|
||||
if _, exists := tc.types[name]; !exists {
|
||||
tc.collectStruct(t, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *typeCollector) collectStruct(t reflect.Type, name string) {
|
||||
if t.Kind() != reflect.Struct {
|
||||
return
|
||||
}
|
||||
|
||||
var fields []string
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
|
||||
if field.Anonymous || !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := getFieldName(field)
|
||||
|
||||
var tsType string
|
||||
var isOptional bool
|
||||
isPointer := field.Type.Kind() == reflect.Pointer
|
||||
|
||||
if isPointer {
|
||||
isOptional = true
|
||||
tsType = goTypeToTSType(field.Type, false)
|
||||
} else {
|
||||
isOptional = strings.Contains(field.Tag.Get("json"), ",omitempty")
|
||||
tsType = goTypeToTSType(field.Type, false)
|
||||
}
|
||||
|
||||
if isOptional {
|
||||
fieldName += "?"
|
||||
}
|
||||
|
||||
fields = append(fields, fmt.Sprintf("%s: %s", fieldName, tsType))
|
||||
|
||||
tc.collectType(field.Type)
|
||||
}
|
||||
|
||||
tc.types[name] = fmt.Sprintf("interface %s {%s}", name, strings.Join(fields, "; "))
|
||||
}
|
||||
|
||||
func goTypeToTSType(t reflect.Type, isPointer bool) string {
|
||||
if t.Kind() == reflect.Pointer {
|
||||
return goTypeToTSType(t.Elem(), true)
|
||||
}
|
||||
|
||||
baseType := ""
|
||||
switch t.Kind() {
|
||||
case reflect.String:
|
||||
baseType = "string"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
baseType = "number"
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
baseType = "number"
|
||||
case reflect.Float32, reflect.Float64:
|
||||
baseType = "number"
|
||||
case reflect.Bool:
|
||||
baseType = "boolean"
|
||||
case reflect.Interface:
|
||||
baseType = "any"
|
||||
case reflect.Slice:
|
||||
baseType = fmt.Sprintf("%s[]", goTypeToTSType(t.Elem(), false))
|
||||
case reflect.Map:
|
||||
if t.Key().Kind() == reflect.String && t.Elem().Kind() == reflect.Interface {
|
||||
baseType = "Record<string, any>"
|
||||
} else {
|
||||
baseType = "Record<string, any>"
|
||||
}
|
||||
case reflect.Struct:
|
||||
name := t.Name()
|
||||
if name == "" {
|
||||
baseType = "{}"
|
||||
} else {
|
||||
baseType = name
|
||||
}
|
||||
default:
|
||||
baseType = "any"
|
||||
}
|
||||
|
||||
if isPointer {
|
||||
baseType += " | null"
|
||||
}
|
||||
return baseType
|
||||
}
|
||||
Reference in New Issue
Block a user