catch.go 959 B

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