catch.go raw
1 //go:build js && wasm
2
3 // Package catch runs functions and returns panic values as errors instead.
4 package catch
5
6 import (
7 "fmt"
8 "syscall/js"
9
10 "github.com/hack-pad/safejs/internal/stackerr"
11 )
12
13 // Try runs fn and returns the result. If fn panicked, the panic value is returned as an error instead.
14 func Try[Result any](fn func() Result) (result Result, err error) {
15 defer recoverErr(&err)
16 result = fn()
17 return
18 }
19
20 // TrySideEffect is like Try, but does not have a return value.
21 func TrySideEffect(fn func()) (err error) {
22 defer recoverErr(&err)
23 fn()
24 return
25 }
26
27 func recoverErr(err *error) {
28 value := recover()
29 valueErr := recoverValueToError(value)
30 if valueErr != nil {
31 *err = stackerr.WithStack(valueErr)
32 }
33 }
34
35 func recoverValueToError(value any) error {
36 if value == nil {
37 return nil
38 }
39 switch value := value.(type) {
40 case error:
41 return value
42 case js.Value:
43 return js.Error{Value: value}
44 default:
45 return fmt.Errorf("%+v", value)
46 }
47 }
48