package functions import ( "fmt" "reflect" "strings" "sync" ) 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]) { registryMutex.Lock() defer registryMutex.Unlock() if collector == nil { collector = newTypeCollector() } tType := reflect.TypeFor[A]() if tType.Kind() != reflect.Struct { panic(fmt.Sprintf("function %s: argument must be a struct type, got %v", name, tType)) } fnType := reflect.TypeOf(fn) types := collector.collectTypes(tType, fnType) paramTypes := collector.getParamTypes() functionRegistry[name] = &functionImpl[A, R]{ name: name, fn: fn, types: types, definition: generateTypeScriptDefinition(name, tType, fnType, isAsync, paramTypes), isAsync: isAsync, } } func GetFunctionDeclarations() string { registryMutex.RLock() defer registryMutex.RUnlock() typeDefinitions := make(map[string]bool) var typeDefs []string var functionDecls []string for _, fn := range functionRegistry { for _, t := range fn.Types() { if !typeDefinitions[t] { typeDefinitions[t] = true typeDefs = append(typeDefs, t) } } functionDecls = append(functionDecls, fn.Definition()) } result := strings.Join(typeDefs, "\n\n") if len(result) > 0 && len(functionDecls) > 0 { result += "\n\n" } result += strings.Join(functionDecls, "\n") return result } func GetRegisteredFunctions() map[string]Function { registryMutex.RLock() defer registryMutex.RUnlock() result := make(map[string]Function, len(functionRegistry)) for k, v := range functionRegistry { result[k] = v } return result } func RegisterFunction[T Args, R any](name string, fn GoFunc[T, R]) { registerFunction(name, false, fn) } func RegisterAsyncFunction[T Args, R any](name string, fn GoFunc[T, R]) { registerFunction(name, true, fn) }