-
Notifications
You must be signed in to change notification settings - Fork 0
/
error.go
139 lines (123 loc) · 2.9 KB
/
error.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
package validator
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"html/template"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
// Errors contains a slice of errors
type Errors interface {
Errors() []error
}
// FieldErrors are slice of FieldError generate by the rules
type FieldErrors []error
// Is implements errors.Is
func (es FieldErrors) Is(err error) bool {
switch err.(type) {
case FieldErrors:
return true
case *FieldErrors:
return true
}
for _, e := range es {
if errors.Is(e, err) {
return true
}
}
return false
}
// As implements errors.As
func (es FieldErrors) As(err interface{}) bool {
if ptr, ok := err.(*FieldErrors); ok {
*ptr = es
return true
} else if fes, ok := err.(FieldErrors); ok {
for i := range fes {
if len(es) == i {
return true
}
fes[i] = es[i]
}
return true
}
for _, e := range es {
if errors.As(e, err) {
return true
}
}
return false
}
// Error implements errors.Error
func (es FieldErrors) Error() string {
bs, err := json.Marshal(es)
if err != nil {
return err.Error()
}
return string(bs)
}
// Errors implements Errors
func (es FieldErrors) Errors() []error {
return es
}
// Add merges FieldErrors together
func (es *FieldErrors) Add(errs ...error) {
for _, err := range errs {
if errs, ok := err.(Errors); ok {
es.Add(errs.Errors()...)
}
*es = append(*es, err)
}
}
// FieldError is the error returned when a field rule returns an error
type FieldError struct {
Path string `json:"path,omitempty"`
Message error `json:"message,omitempty"`
}
// Is implements errors.Is
func (fe *FieldError) Is(err error) bool {
if _, ok := err.(*FieldError); ok {
return true
}
return errors.Is(fe.Message, err)
}
// Is implements errors.As
func (fe *FieldError) As(i interface{}) bool {
if e, ok := i.(*FieldError); ok {
e.Path = fe.Path
e.Message = fe.Message
return true
}
return errors.As(fe.Message, i)
}
// Error implements errors.Error
func (fe *FieldError) Error() string {
return fe.Message.Error()
}
// MarshalJSON implements the json.Marshaler interface
func (fe *FieldError) MarshalJSON() ([]byte, error) {
// TODO: after we have a clean `Path` for each error,
// add a config boolean that renders these as json objects instead
return []byte(fmt.Sprintf("\"%s\"", fe.Message)), nil
}
// errorf handles i18n errors
func errorf(tag language.Tag, str string, is ...interface{}) error {
return errors.New(message.NewPrinter(tag).Sprintf(str, is...))
}
// errorTemplate handles i18n template based errors
func errorTemplate(tag language.Tag, str string, context interface{}) error {
str = message.NewPrinter(tag).Sprint(str)
var bs bytes.Buffer
if t, err := template.New(str).Funcs(template.FuncMap{
"minus": func(a, b int) int {
return a - b
},
}).Parse(str); err != nil {
return err
} else if err := t.Execute(&bs, context); err != nil {
return err
}
return errors.New(bs.String())
}