-
Notifications
You must be signed in to change notification settings - Fork 1
/
errors.go
124 lines (105 loc) · 2.8 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
package tex
import (
"encoding/json"
"fmt"
)
type errCategory uint8
const (
inputErr errCategory = iota + 1
compilationErr
queueErr
referenceErr
)
func (cat errCategory) String() string {
switch cat {
case inputErr:
return "input"
case compilationErr:
return "compilation"
case queueErr:
return "queue"
case referenceErr:
return "reference"
default:
return "unknown"
}
}
type KV map[string]interface{}
type ErrWithCategory struct {
cat errCategory
message string
cause error
extra KV
}
// ExtendError adds the given extra ke/value pairs to err, if err is a
// ErrWithCategory. If extra is empty or err is another type of error,
// this function does nothing.
func ExtendError(err error, extra KV) {
if len(extra) == 0 {
return
}
if catErr, ok := err.(*ErrWithCategory); ok {
if catErr.extra == nil {
catErr.extra = extra
return
}
for k, v := range extra {
catErr.extra[k] = v
}
}
}
func newCategoryError(cat errCategory, message string, cause error, extra KV) error {
return &ErrWithCategory{cat: cat, message: message, cause: cause, extra: extra}
}
func InputError(message string, cause error, extra KV) error {
return newCategoryError(inputErr, message, cause, extra)
}
func ReferenceError(references []string) error {
return newCategoryError(referenceErr, "unknown file references", nil, KV{
"references": references,
})
}
func CompilationError(message string, cause error, extra KV) error {
return newCategoryError(compilationErr, message, cause, extra)
}
func QueueError(message string, cause error, extra KV) error {
return newCategoryError(queueErr, message, cause, extra)
}
func UnknownError(message string, cause error, extra KV) error {
return newCategoryError(0, message, cause, extra)
}
func errorIs(err error, cat errCategory) bool {
if catErr, ok := err.(*ErrWithCategory); ok {
return catErr.cat == cat
}
return false
}
func IsUnknownError(err error) bool { return errorIs(err, 0) }
func IsInputError(err error) bool { return errorIs(err, inputErr) }
func IsCompilationError(err error) bool { return errorIs(err, compilationErr) }
func IsQueueError(err error) bool { return errorIs(err, queueErr) }
func IsReferenceError(err error) bool { return errorIs(err, referenceErr) }
func (err *ErrWithCategory) Error() string {
if err.cause == nil {
return err.message
}
return fmt.Sprintf("%s: %v", err.message, err.cause)
}
func (err *ErrWithCategory) Unwrap() error {
return err.cause
}
func (err *ErrWithCategory) Extra() KV {
return err.extra
}
func (err *ErrWithCategory) MarshalJSON() ([]byte, error) {
data := KV{
"error": err.message, // omit cause, could leak internal data
"category": err.cat.String(),
}
for k, v := range err.extra {
if k != "error" && k != "category" {
data[k] = v
}
}
return json.Marshal(data)
}