-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror.go
More file actions
254 lines (213 loc) · 6.65 KB
/
error.go
File metadata and controls
254 lines (213 loc) · 6.65 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
package applause
import (
"fmt"
"strings"
)
// ApplauseError is the base interface for all applause errors
type ApplauseError interface {
error
Code() string
Context() map[string]interface{}
}
// ParseError represents an error that occurred during value parsing
type ParseError struct {
Type string // The expected type (e.g., "int", "bool")
Value string // The value that failed to parse
Original error // The underlying error from the parser
}
func (e *ParseError) Error() string {
if e.Original != nil {
return fmt.Sprintf("failed to parse '%s' as %s: %v", e.Value, e.Type, e.Original)
}
return fmt.Sprintf("failed to parse '%s' as %s", e.Value, e.Type)
}
func (e *ParseError) Code() string {
return "PARSE_ERROR"
}
func (e *ParseError) Context() map[string]interface{} {
return map[string]interface{}{
"type": e.Type,
"value": e.Value,
"original": e.Original,
}
}
// TypeMismatchError represents an error when a value is accessed with the wrong type
type TypeMismatchError struct {
Expected ValueType
Actual ValueType
Value string
}
func (e *TypeMismatchError) Error() string {
return fmt.Sprintf("type mismatch: expected %s but value was parsed as %s (value: '%s')",
e.Expected, e.Actual, e.Value)
}
func (e *TypeMismatchError) Code() string {
return "TYPE_MISMATCH"
}
func (e *TypeMismatchError) Context() map[string]interface{} {
return map[string]interface{}{
"expected": e.Expected.String(),
"actual": e.Actual.String(),
"value": e.Value,
}
}
// ValidationError represents an error that occurred during argument validation
type ValidationError struct {
Argument string // The name of the argument that failed validation
Value string // The value that failed validation
Message string // Human-readable validation error message
Rule string // The validation rule that was violated
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed for argument '%s': %s (value: '%s')",
e.Argument, e.Message, e.Value)
}
func (e *ValidationError) Code() string {
return "VALIDATION_ERROR"
}
func (e *ValidationError) Context() map[string]interface{} {
return map[string]interface{}{
"argument": e.Argument,
"value": e.Value,
"rule": e.Rule,
}
}
// RequiredError represents an error when a required argument is missing
type RequiredError struct {
Argument string // The name of the required argument that is missing
Type string // "positional" or "flag"
}
func (e *RequiredError) Error() string {
return fmt.Sprintf("required %s argument '%s' is missing", e.Type, e.Argument)
}
func (e *RequiredError) Code() string {
return "REQUIRED_ERROR"
}
func (e *RequiredError) Context() map[string]interface{} {
return map[string]interface{}{
"argument": e.Argument,
"type": e.Type,
}
}
// UnknownArgumentError represents an error when an unknown argument is provided
type UnknownArgumentError struct {
Argument string // The unknown argument
Type string // "flag" or "subcommand"
Suggestion string // Suggested similar argument (optional)
Available []string // List of available arguments
}
func (e *UnknownArgumentError) Error() string {
msg := fmt.Sprintf("unknown %s '%s'", e.Type, e.Argument)
if e.Suggestion != "" {
msg += fmt.Sprintf(", did you mean '%s'?", e.Suggestion)
}
return msg
}
func (e *UnknownArgumentError) Code() string {
return "UNKNOWN_ARGUMENT"
}
func (e *UnknownArgumentError) Context() map[string]interface{} {
return map[string]interface{}{
"argument": e.Argument,
"type": e.Type,
"suggestion": e.Suggestion,
"available": e.Available,
}
}
// ConflictError represents an error when conflicting arguments are provided
type ConflictError struct {
Arguments []string // The conflicting arguments
Message string // Human-readable conflict description
}
func (e *ConflictError) Error() string {
args := strings.Join(e.Arguments, "', '")
return fmt.Sprintf("conflicting arguments: '%s' - %s", args, e.Message)
}
func (e *ConflictError) Code() string {
return "CONFLICT_ERROR"
}
func (e *ConflictError) Context() map[string]interface{} {
return map[string]interface{}{
"arguments": e.Arguments,
"message": e.Message,
}
}
// GroupError represents an error related to argument groups
type GroupError struct {
Group string // The name of the group
Type string // The type of group error ("mutually_exclusive" or "required_group")
Message string // Human-readable error message
Args []string // The arguments involved
}
func (e *GroupError) Error() string {
return fmt.Sprintf("group '%s' error: %s", e.Group, e.Message)
}
func (e *GroupError) Code() string {
return "GROUP_ERROR"
}
func (e *GroupError) Context() map[string]interface{} {
return map[string]interface{}{
"group": e.Group,
"type": e.Type,
"message": e.Message,
"args": e.Args,
}
}
// ErrorFormatter provides methods to format errors for display
type ErrorFormatter struct {
UseColors bool
}
// NewErrorFormatter creates a new error formatter
func NewErrorFormatter() *ErrorFormatter {
return &ErrorFormatter{
UseColors: true, // TODO: Detect terminal capability
}
}
// Format formats an error for display to the user
func (ef *ErrorFormatter) Format(err error) string {
if applauseErr, ok := err.(ApplauseError); ok {
return ef.formatApplauseError(applauseErr)
}
return err.Error()
}
func (ef *ErrorFormatter) formatApplauseError(err ApplauseError) string {
var result strings.Builder
// Error prefix with color
if ef.UseColors {
result.WriteString("\033[31mError:\033[0m ") // Red "Error:"
} else {
result.WriteString("Error: ")
}
result.WriteString(err.Error())
// Add context-specific suggestions
switch e := err.(type) {
case *ParseError:
if e.Type == "bool" {
result.WriteString("\n Valid boolean values: true, false, yes, no, 1, 0, on, off")
} else if e.Type == "int" {
result.WriteString("\n Please provide a valid integer")
} else if e.Type == "duration" {
result.WriteString("\n Valid duration format: 1h30m, 5s, 100ms, etc.")
}
case *UnknownArgumentError:
if len(e.Available) > 0 {
result.WriteString(fmt.Sprintf("\n Available %ss: %s",
e.Type, strings.Join(e.Available, ", ")))
}
case *RequiredError:
result.WriteString("\n This argument must be provided")
}
return result.String()
}
// FormatHelp formats multiple errors with help suggestions
func (ef *ErrorFormatter) FormatHelp(errs []error, commandName string) string {
var result strings.Builder
for i, err := range errs {
if i > 0 {
result.WriteString("\n")
}
result.WriteString(ef.Format(err))
}
result.WriteString(fmt.Sprintf("\n\nFor more information try '%s --help'", commandName))
return result.String()
}