types
This commit is contained in:
@@ -1,170 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -5,44 +5,47 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"reichard.io/poiesis/internal/tsconvert"
|
||||
)
|
||||
|
||||
var (
|
||||
functionRegistry = make(map[string]Function)
|
||||
registryMutex sync.RWMutex
|
||||
collector *typeCollector
|
||||
)
|
||||
|
||||
func registerFunction[A Args, R any](name string, isAsync bool, fn GoFunc[A, R]) {
|
||||
// Lock Registry
|
||||
registryMutex.Lock()
|
||||
defer registryMutex.Unlock()
|
||||
|
||||
if collector == nil {
|
||||
collector = newTypeCollector()
|
||||
}
|
||||
|
||||
// Validate Args Type
|
||||
tType := reflect.TypeFor[A]()
|
||||
if tType.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("function %s: argument must be a struct type, got %v", name, tType))
|
||||
}
|
||||
|
||||
// Collect Types and Generate Definition
|
||||
fnType := reflect.TypeOf(fn)
|
||||
types := collector.collectTypes(tType, fnType)
|
||||
paramTypes := collector.getParamTypes()
|
||||
types := tsconvert.CollectTypes(tType, fnType)
|
||||
definition := tsconvert.GenerateFunctionDecl(name, tType, fnType, isAsync)
|
||||
|
||||
// Register Function
|
||||
functionRegistry[name] = &functionImpl[A, R]{
|
||||
name: name,
|
||||
fn: fn,
|
||||
types: types,
|
||||
definition: generateTypeScriptDefinition(name, tType, fnType, isAsync, paramTypes),
|
||||
types: types.All(),
|
||||
definition: definition,
|
||||
isAsync: isAsync,
|
||||
}
|
||||
}
|
||||
|
||||
func GetFunctionDeclarations() string {
|
||||
// Lock Registry
|
||||
registryMutex.RLock()
|
||||
defer registryMutex.RUnlock()
|
||||
|
||||
// Collect Type Definitions
|
||||
typeDefinitions := make(map[string]bool)
|
||||
var typeDefs []string
|
||||
var functionDecls []string
|
||||
@@ -57,6 +60,7 @@ func GetFunctionDeclarations() string {
|
||||
functionDecls = append(functionDecls, fn.Definition())
|
||||
}
|
||||
|
||||
// Build Result
|
||||
result := strings.Join(typeDefs, "\n\n")
|
||||
if len(result) > 0 && len(functionDecls) > 0 {
|
||||
result += "\n\n"
|
||||
@@ -66,10 +70,33 @@ func GetFunctionDeclarations() string {
|
||||
return result
|
||||
}
|
||||
|
||||
func GetRegisteredFunctions() map[string]Function {
|
||||
// GetTypeDeclarations returns all type declarations from all registered functions.
|
||||
// This is used for aggregating types across multiple functions.
|
||||
func GetTypeDeclarations() map[string]string {
|
||||
// Lock Registry
|
||||
registryMutex.RLock()
|
||||
defer registryMutex.RUnlock()
|
||||
|
||||
// Collect All Types
|
||||
allTypes := make(map[string]string)
|
||||
for _, fn := range functionRegistry {
|
||||
for name, def := range fn.Types() {
|
||||
if existing, ok := allTypes[name]; ok && existing != def {
|
||||
// Type Conflict Detected - Skip
|
||||
continue
|
||||
}
|
||||
allTypes[name] = def
|
||||
}
|
||||
}
|
||||
return allTypes
|
||||
}
|
||||
|
||||
func GetRegisteredFunctions() map[string]Function {
|
||||
// Lock Registry
|
||||
registryMutex.RLock()
|
||||
defer registryMutex.RUnlock()
|
||||
|
||||
// Copy Registry
|
||||
result := make(map[string]Function, len(functionRegistry))
|
||||
for k, v := range functionRegistry {
|
||||
result[k] = v
|
||||
@@ -78,9 +105,11 @@ func GetRegisteredFunctions() map[string]Function {
|
||||
}
|
||||
|
||||
func RegisterFunction[T Args, R any](name string, fn GoFunc[T, R]) {
|
||||
// Register Sync Function
|
||||
registerFunction(name, false, fn)
|
||||
}
|
||||
|
||||
func RegisterAsyncFunction[T Args, R any](name string, fn GoFunc[T, R]) {
|
||||
// Register Async Function
|
||||
registerFunction(name, true, fn)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
type Function interface {
|
||||
Name() string
|
||||
Types() []string
|
||||
Types() map[string]string
|
||||
Definition() string
|
||||
IsAsync() bool
|
||||
Arguments() []reflect.Type
|
||||
@@ -25,7 +25,7 @@ type functionImpl[A Args, R any] struct {
|
||||
name string
|
||||
fn GoFunc[A, R]
|
||||
definition string
|
||||
types []string
|
||||
types map[string]string
|
||||
isAsync bool
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (b *functionImpl[A, R]) Name() string {
|
||||
return b.name
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) Types() []string {
|
||||
func (b *functionImpl[A, R]) Types() map[string]string {
|
||||
return b.types
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ func (b *functionImpl[A, R]) Function() any {
|
||||
}
|
||||
|
||||
func (b *functionImpl[A, R]) Arguments() []reflect.Type {
|
||||
// Collect Argument Types
|
||||
var allTypes []reflect.Type
|
||||
|
||||
rType := reflect.TypeFor[A]()
|
||||
@@ -73,17 +74,19 @@ func (b *functionImpl[A, R]) CallGeneric(ctx context.Context, allArgs []any) (ze
|
||||
for i := range min(aVal.NumField(), len(allArgs)) {
|
||||
field := aVal.Field(i)
|
||||
|
||||
// Validate Field is Settable
|
||||
if !field.CanSet() {
|
||||
return zeroR, errors.New("cannot set field")
|
||||
}
|
||||
|
||||
// Validate and Set Field Value
|
||||
argVal := reflect.ValueOf(allArgs[i])
|
||||
if !argVal.Type().AssignableTo(field.Type()) {
|
||||
return zeroR, errors.New("cannot assign field")
|
||||
}
|
||||
|
||||
field.Set(argVal)
|
||||
}
|
||||
|
||||
// Execute Function
|
||||
return b.fn(ctx, fnArgs)
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package functions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getFieldName(field reflect.StructField) string {
|
||||
jsonTag := field.Tag.Get("json")
|
||||
if jsonTag != "" && jsonTag != "-" {
|
||||
name, _, _ := strings.Cut(jsonTag, ",")
|
||||
return name
|
||||
}
|
||||
return field.Name
|
||||
}
|
||||
|
||||
func generateTypeScriptDefinition(name string, argsType reflect.Type, fnType reflect.Type, isPromise bool, paramTypes map[string]bool) string {
|
||||
if argsType.Kind() != reflect.Struct {
|
||||
return ""
|
||||
}
|
||||
|
||||
var params []string
|
||||
for i := 0; i < argsType.NumField(); i++ {
|
||||
field := argsType.Field(i)
|
||||
fieldName := getFieldName(field)
|
||||
goType := field.Type
|
||||
|
||||
var tsType string
|
||||
var isOptional bool
|
||||
isPointer := goType.Kind() == reflect.Pointer
|
||||
|
||||
if isPointer {
|
||||
isOptional = true
|
||||
tsType = goTypeToTSType(goType, true)
|
||||
if !strings.Contains(tsType, " | null") {
|
||||
tsType += " | null"
|
||||
}
|
||||
} else {
|
||||
isOptional = strings.Contains(field.Tag.Get("json"), ",omitempty")
|
||||
tsType = goTypeToTSType(goType, false)
|
||||
if isOptional && paramTypes[tsType+" | null"] {
|
||||
tsType += " | null"
|
||||
}
|
||||
}
|
||||
|
||||
if isOptional {
|
||||
fieldName += "?"
|
||||
}
|
||||
params = append(params, fmt.Sprintf("%s: %s", fieldName, tsType))
|
||||
}
|
||||
|
||||
returnSignature := "any"
|
||||
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 {
|
||||
returnType := fnType.Out(0)
|
||||
returnSignature = goTypeToTSType(returnType, returnType.Kind() == reflect.Pointer)
|
||||
}
|
||||
} else {
|
||||
returnSignature = goTypeToTSType(lastType, lastType.Kind() == reflect.Pointer)
|
||||
}
|
||||
}
|
||||
|
||||
if isPromise {
|
||||
returnSignature = fmt.Sprintf("Promise<%s>", returnSignature)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("declare function %s(%s): %s;", name, strings.Join(params, ", "), returnSignature)
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -17,19 +16,26 @@ type TestBasicArgs struct {
|
||||
func (t TestBasicArgs) Validate() error { return nil }
|
||||
|
||||
func TestBasicType(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction("basic", func(ctx context.Context, args TestBasicArgs) (string, error) {
|
||||
return args.Name, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function basic(name: string, age: number): string;")
|
||||
assert.Contains(t, defs, "interface TestBasicArgs")
|
||||
}
|
||||
|
||||
func resetRegistry() {
|
||||
// Lock Registry
|
||||
registryLock.Lock()
|
||||
defer registryLock.Unlock()
|
||||
|
||||
// Clear Registry
|
||||
functionRegistry = make(map[string]Function)
|
||||
}
|
||||
|
||||
@@ -46,11 +52,15 @@ type TestComplexArgs struct {
|
||||
func (t TestComplexArgs) Validate() error { return nil }
|
||||
|
||||
func TestComplexTypes(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction("complex", func(ctx context.Context, args TestComplexArgs) (bool, error) {
|
||||
return args.Flag, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function complex(items: number[], data: Record<string, any>, flag: boolean): boolean;")
|
||||
}
|
||||
@@ -65,11 +75,15 @@ type TestNestedArgs struct {
|
||||
func (t TestNestedArgs) Validate() error { return nil }
|
||||
|
||||
func TestNestedStruct(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction("nested", func(ctx context.Context, args TestNestedArgs) (string, error) {
|
||||
return args.User.FirstName, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function nested(user: {}): string;")
|
||||
}
|
||||
@@ -83,11 +97,15 @@ type TestOptionalArgs struct {
|
||||
func (t TestOptionalArgs) Validate() error { return nil }
|
||||
|
||||
func TestOptionalFields(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestOptionalArgs, string]("optional", func(ctx context.Context, args TestOptionalArgs) (string, error) {
|
||||
return args.Name, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function optional(name: string, age?: number | null, score?: number | null): string;")
|
||||
}
|
||||
@@ -104,11 +122,15 @@ type TestResultArgs struct {
|
||||
func (t TestResultArgs) Validate() error { return nil }
|
||||
|
||||
func TestResultStruct(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestResultArgs, TestResult]("result", func(ctx context.Context, args TestResultArgs) (TestResult, error) {
|
||||
return TestResult{ID: 1}, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function result(input: string): TestResult;")
|
||||
assert.Contains(t, defs, "interface TestResult {id: number; data: number[]}")
|
||||
@@ -125,11 +147,15 @@ type TestAsyncResult struct {
|
||||
}
|
||||
|
||||
func TestAsyncPromise(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Async Function
|
||||
RegisterAsyncFunction[TestAsyncArgs, *TestAsyncStatus]("async", func(ctx context.Context, args TestAsyncArgs) (*TestAsyncStatus, error) {
|
||||
return &TestAsyncStatus{Code: 200}, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function async(url: string): Promise<TestAsyncStatus | null>;")
|
||||
assert.Contains(t, defs, "interface TestAsyncStatus")
|
||||
@@ -150,11 +176,15 @@ type TestNestedPointerArgs struct {
|
||||
func (t TestNestedPointerArgs) Validate() error { return nil }
|
||||
|
||||
func TestNestedPointerInResult(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestNestedPointerArgs, *TestNestedPointerResult]("pointerResult", func(ctx context.Context, args TestNestedPointerArgs) (*TestNestedPointerResult, error) {
|
||||
return &TestNestedPointerResult{Value: "test"}, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function pointerResult(id: number): TestNestedPointerResult | null;")
|
||||
}
|
||||
@@ -166,11 +196,15 @@ type TestUintArgs struct {
|
||||
func (t TestUintArgs) Validate() error { return nil }
|
||||
|
||||
func TestUintType(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestUintArgs, uint]("uint", func(ctx context.Context, args TestUintArgs) (uint, error) {
|
||||
return args.Value, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function uint(value: number): number;")
|
||||
}
|
||||
@@ -182,11 +216,15 @@ type TestFloatArgs struct {
|
||||
func (t TestFloatArgs) Validate() error { return nil }
|
||||
|
||||
func TestFloatType(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestFloatArgs, float32]("float", func(ctx context.Context, args TestFloatArgs) (float32, error) {
|
||||
return float32(args.Amount), nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function float(amount: number): number;")
|
||||
}
|
||||
@@ -200,11 +238,15 @@ type TestPointerInArgs struct {
|
||||
func (t TestPointerInArgs) Validate() error { return nil }
|
||||
|
||||
func TestNestedPointerStruct(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestPointerInArgs, string]("nestedPointer", func(ctx context.Context, args TestPointerInArgs) (string, error) {
|
||||
return "test", nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function nestedPointer(user?: {} | null): string;")
|
||||
}
|
||||
@@ -216,58 +258,15 @@ type TestErrorOnlyArgs struct {
|
||||
func (t TestErrorOnlyArgs) Validate() error { return nil }
|
||||
|
||||
func TestErrorOnlyReturn(t *testing.T) {
|
||||
// Reset Registry
|
||||
resetRegistry()
|
||||
|
||||
// Register Function
|
||||
RegisterFunction[TestErrorOnlyArgs, struct{}]("errorOnly", func(ctx context.Context, args TestErrorOnlyArgs) (struct{}, error) {
|
||||
return struct{}{}, nil
|
||||
})
|
||||
|
||||
// Verify Declarations
|
||||
defs := GetFunctionDeclarations()
|
||||
assert.Contains(t, defs, "declare function errorOnly(input: string): {};")
|
||||
}
|
||||
|
||||
func TestGoTypeToTSTypeBasic(t *testing.T) {
|
||||
tests := []struct {
|
||||
input reflect.Type
|
||||
inputPtr bool
|
||||
expected string
|
||||
}{
|
||||
{reflect.TypeOf(""), false, "string"},
|
||||
{reflect.TypeOf(0), false, "number"},
|
||||
{reflect.TypeOf(int64(0)), false, "number"},
|
||||
{reflect.TypeOf(uint(0)), false, "number"},
|
||||
{reflect.TypeOf(3.14), false, "number"},
|
||||
{reflect.TypeOf(float32(0.0)), false, "number"},
|
||||
{reflect.TypeOf(true), false, "boolean"},
|
||||
{reflect.TypeOf([]string{}), false, "string[]"},
|
||||
{reflect.TypeOf([]int{}), false, "number[]"},
|
||||
{reflect.TypeOf(map[string]any{}), false, "Record<string, any>"},
|
||||
{reflect.TypeOf(map[string]int{}), false, "Record<string, any>"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.expected, func(t *testing.T) {
|
||||
result := goTypeToTSType(tt.input, tt.inputPtr)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type TestNestedStructField struct {
|
||||
Inner struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"inner"`
|
||||
}
|
||||
|
||||
func TestGoTypeToTSTypeNestedStruct(t *testing.T) {
|
||||
result := goTypeToTSType(reflect.TypeOf(TestNestedStructField{}), false)
|
||||
assert.Equal(t, "TestNestedStructField", result)
|
||||
}
|
||||
|
||||
type TestArrayField struct {
|
||||
Items []string `json:"items"`
|
||||
}
|
||||
|
||||
func TestGoTypeToTSTypeArray(t *testing.T) {
|
||||
result := goTypeToTSType(reflect.TypeOf(TestArrayField{}), false)
|
||||
assert.Equal(t, "TestArrayField", result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user