package wasm import ( "errors" "reflect" "syscall/js" ) // ErrInvalidArgumentType is returned when a generated Go function wrapper receives invalid argument types from JS. var ErrInvalidArgumentType = errors.New("invalid argument passed into Go function") var errorType = reflect.TypeOf(error(nil)) func toJSFunc(x reflect.Value) js.Value { funcType := x.Type() var hasError bool if funcType.NumOut() != 0 { hasError = funcType.Out(funcType.NumOut()-1) == errorType } return js.FuncOf(func(this js.Value, args []js.Value) interface{} { in, err := conformJSValueToType(funcType, this, args) if err != nil { throwWrapper.Invoke(NewError(err)) return nil } out := x.Call(in) if !hasError { return ToJSValue(returnValue(out)) } lastParam := out[len(out)-1] if !lastParam.IsNil() { throwWrapper.Invoke(NewError(err)) return nil } return ToJSValue(returnValue(out[:len(out)-1])) }).JSValue() } var jsValueType = reflect.TypeOf(js.Value{}) func conformJSValueToType(funcType reflect.Type, this js.Value, values []js.Value) ([]reflect.Value, error) { if funcType.NumIn() == 0 { if len(values) != 0 { return nil, ErrInvalidArgumentType } return []reflect.Value{}, nil } if funcType.In(0) == jsValueType { values = append([]js.Value{this}, values...) } if !funcType.IsVariadic() && funcType.NumIn() != len(values) { return nil, ErrInvalidArgumentType } in := make([]reflect.Value, 0, len(values)) for i, v := range values { paramType := funcType.In(i) x := reflect.Zero(paramType).Interface() err := FromJSValue(v, &x) if err != nil { return nil, err } in = append(in, reflect.ValueOf(x)) } return in, nil } func returnValue(x []reflect.Value) js.Value { if len(x) == 1 { return ToJSValue(x[0]) } xInterface := make([]interface{}, 0, len(x)) for _, v := range x { xInterface = append(xInterface, v.Interface()) } return ToJSValue(x) }