package builtin import ( "context" "fmt" "reflect" "github.com/dop251/goja" ) func createWrapper[T Args, R any](fn Func[T, R], isAsync bool) func(*goja.Runtime) func(goja.FunctionCall) goja.Value { return func(vm *goja.Runtime) func(goja.FunctionCall) goja.Value { return func(call goja.FunctionCall) goja.Value { var args T argsValue := reflect.ValueOf(&args).Elem() for i := 0; i < argsValue.NumField() && i < len(call.Arguments); i++ { jsArg := call.Arguments[i] field := argsValue.Field(i) if goja.IsUndefined(jsArg) || goja.IsNull(jsArg) { if field.Kind() == reflect.Pointer { continue } } converted, err := convertJSValueToGo(vm, jsArg, field.Type()) if err != nil { panic(fmt.Sprintf("argument %d (%s): %v", i, getFieldName(argsValue.Type().Field(i)), err)) } if converted != nil { field.Set(reflect.ValueOf(converted)) } } if err := args.Validate(); err != nil { panic(fmt.Sprintf("argument validation failed: %v", err)) } if isAsync { return createAsyncPromise(vm, fn, args) } ctx := context.Background() result, err := fn(ctx, args) if err != nil { panic(err) } return convertGoValueToJS(vm, reflect.ValueOf(result)) } } } func createAsyncPromise[T Args, R any](vm *goja.Runtime, fn Func[T, R], args T) goja.Value { promise, resolve, reject := vm.NewPromise() go func() { ctx := context.Background() result, err := fn(ctx, args) if err != nil { _ = reject(vm.ToValue(err.Error())) } else { _ = resolve(convertGoValueToJS(vm, reflect.ValueOf(result))) } }() return vm.ToValue(promise) }