github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/errs/userfacing.go (about) 1 package errs 2 3 import ( 4 "errors" 5 ) 6 7 type UserFacingError interface { 8 error 9 UserError() string 10 } 11 12 type ErrOpt func(err *userFacingError) 13 14 type userFacingError struct { 15 wrapped error 16 message string 17 input bool 18 tips []string 19 } 20 21 func (e *userFacingError) Error() string { 22 return "User Facing Error: " + e.UserError() 23 } 24 25 func (e *userFacingError) UserError() string { 26 return e.message 27 } 28 29 func (e *userFacingError) ErrorTips() []string { 30 return e.tips 31 } 32 33 func (e *userFacingError) InputError() bool { 34 return e.input 35 } 36 37 func (e *userFacingError) Unwrap() error { 38 return e.wrapped 39 } 40 41 func NewUserFacing(message string, opts ...ErrOpt) *userFacingError { 42 return WrapUserFacing(nil, message, opts...) 43 } 44 45 func WrapUserFacing(wrapTarget error, message string, opts ...ErrOpt) *userFacingError { 46 err := &userFacingError{ 47 wrapTarget, 48 message, 49 false, 50 nil, 51 } 52 53 for _, opt := range opts { 54 opt(err) 55 } 56 57 return err 58 } 59 60 func IsUserFacing(err error) bool { 61 var userFacingError UserFacingError 62 return errors.As(err, &userFacingError) 63 } 64 65 // SetIf is a helper for setting options if some conditional evaluated to true. 66 // This is mainly intended for setting tips, as without this you'd have to evaluate your conditional outside of 67 // NewUserFacing/WrapUserFacing, adding to the boilerplate. 68 func SetIf(evaluated bool, opt ErrOpt) ErrOpt { 69 if evaluated { 70 return opt 71 } 72 return func(err *userFacingError) {} 73 } 74 75 func SetTips(tips ...string) ErrOpt { 76 return func(err *userFacingError) { 77 err.tips = append(err.tips, tips...) 78 } 79 } 80 81 func SetInput() ErrOpt { 82 return func(err *userFacingError) { 83 err.input = true 84 } 85 }