-
Notifications
You must be signed in to change notification settings - Fork 3
/
errors.go
151 lines (122 loc) · 4.82 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package goval
import (
"context"
"encoding/json"
"fmt"
"sync"
)
// jsonErrorStringer is an interface that combines error, json.Marshaler and fmt.Stringer.
type jsonErrorStringer interface {
error
json.Marshaler
fmt.Stringer
}
// auxRuleError is an auxiliary type for marshaling RuleError.
// It is used to avoid infinite recursion when marshaling RuleError.
type auxRuleError RuleError
// RuleError is an error type for validation errors.
type RuleError struct {
Code RuleCoder `json:"code"` // the error code that identifies which rule failed.
Args []any `json:"args,omitempty"` // additional arguments for the error.
}
// ensure RuleError implements jsonErrorStringer.
var _ jsonErrorStringer = (*RuleError)(nil)
// NewRuleError creates a new RuleError.
func NewRuleError(code RuleCoder, args ...any) *RuleError {
return &RuleError{
Code: code,
Args: args,
}
}
func (r *RuleError) Error() string { return r.String() }
func (r *RuleError) String() string { return stringifyJSON(r) }
func (r *RuleError) MarshalJSON() ([]byte, error) { return json.Marshal(auxRuleError(*r)) }
// TextError is an error type for turning an ordinary string to an error.
// This error type is intended to be used for creating an error that can be marshaled to JSON.
// For example, when overriding th ErrorTranslator, the implementation requires to return an error,
// you can use TextError to create an error message from a string literal.
type TextError string
var _ jsonErrorStringer = TextError("")
func (t TextError) Error() string { return t.String() }
func (t TextError) String() string { return string(t) }
func (t TextError) MarshalJSON() ([]byte, error) { return json.Marshal(t.String()) }
// ErrorTranslator is an interface for translating RuleError to a readable error.
type ErrorTranslator interface {
// Translate translates a RuleError to a readable error.
Translate(ctx context.Context, err *RuleError) error
}
// errorTranslatorImpl is an implementation of ErrorTranslator.
type errorTranslatorImpl int
// Translate implements ErrorTranslator.
func (t errorTranslatorImpl) Translate(_ context.Context, err *RuleError) error { return err }
// DefaultErrorTranslator is the default ErrorTranslator that never translates the error.
// In other words, it always returns the original error.
const DefaultErrorTranslator = errorTranslatorImpl(1)
var globalErrorTranslator ErrorTranslator = DefaultErrorTranslator
var globalErrorTranslatorLock sync.RWMutex
// SetErrorTranslator sets the global ErrorTranslator.
func SetErrorTranslator(translator ErrorTranslator) {
globalErrorTranslatorLock.Lock()
defer globalErrorTranslatorLock.Unlock()
globalErrorTranslator = translator
}
// KeyError is an error with a key to give more context to the error.
type KeyError struct {
Key string `json:"key"`
Err error `json:"err"`
}
// auxKeyError is an auxiliary type for marshaling KeyError.
type auxKeyError KeyError
// ensure KeyError implements jsonErrorStringer.
var _ jsonErrorStringer = (*KeyError)(nil)
// NewKeyError creates a new KeyError.
func NewKeyError(key string, err error) *KeyError {
return &KeyError{
Key: key,
Err: err,
}
}
func (k *KeyError) Error() string { return k.String() }
func (k *KeyError) String() string { return stringifyJSON(k) }
func (k *KeyError) MarshalJSON() ([]byte, error) {
// if the error is not a json.Marshaler, we convert it to a TextError.
if _, ok := k.Err.(json.Marshaler); !ok {
k.Err = TextError(k.Err.Error())
}
aux := auxKeyError(*k)
return json.Marshal(aux)
}
// Errors is a type for collecting multiple errors and bundling them into a single error.
type Errors []error
// ensure Errors implements jsonErrorStringer.
var _ jsonErrorStringer = make(Errors, 0)
func (e Errors) Error() string { return e.String() }
func (e Errors) String() string { return stringifyJSON(e) }
func (e Errors) MarshalJSON() ([]byte, error) { return json.Marshal([]error(e)) }
func (e Errors) NilIfEmpty() error {
if len(e) > 0 {
return e
}
return nil
}
// stringifyJSON converts a json.Marshaler to a string.
// If the json.Marshaler returns an error, the error is returned as a string.
func stringifyJSON(m json.Marshaler) string {
b, err := m.MarshalJSON()
if err != nil {
return err.Error()
}
return string(b)
}
// InternalError is an error wrapper to indicate an internal error.
// If goval got this type of error, it will not include in Errors and KeyError.
type InternalError struct {
Err error
}
// NewInternalError creates a new InternalError.
func NewInternalError(err error) *InternalError {
return &InternalError{Err: err}
}
func (e *InternalError) Error() string { return e.String() }
func (e *InternalError) Unwrap() error { return e.Err }
func (e *InternalError) String() string { return "goval.InternalError: " + e.Err.Error() }