fix: error formatting

This commit is contained in:
yusing 2025-05-13 20:11:03 +08:00
parent 44b4cff35e
commit 21724c037f
4 changed files with 31 additions and 12 deletions

View file

@ -59,6 +59,9 @@ func (b *Builder) Error() Error {
if len(b.errs) == 0 { if len(b.errs) == 0 {
return nil return nil
} }
if len(b.errs) == 1 && b.about == "" {
return wrap(b.errs[0])
}
return &nestedError{Err: New(b.about), Extras: b.errs} return &nestedError{Err: New(b.about), Extras: b.errs}
} }

View file

@ -11,9 +11,11 @@ type nestedError struct {
Extras []error `json:"extras"` Extras []error `json:"extras"`
} }
var emptyError = errStr("")
func (err nestedError) Subject(subject string) Error { func (err nestedError) Subject(subject string) Error {
if err.Err == nil { if err.Err == nil {
err.Err = PrependSubject(subject, errStr("")) err.Err = PrependSubject(subject, emptyError)
} else { } else {
err.Err = PrependSubject(subject, err.Err) err.Err = PrependSubject(subject, err.Err)
} }

View file

@ -45,6 +45,11 @@ func PrependSubject(subject string, err error) error {
switch err := err.(type) { switch err := err.(type) {
case *withSubject: case *withSubject:
return err.Prepend(subject) return err.Prepend(subject)
case *wrappedError:
return &wrappedError{
Err: PrependSubject(subject, err.Err),
Message: err.Message,
}
case Error: case Error:
return err.Subject(subject) return err.Subject(subject)
} }
@ -95,20 +100,24 @@ func (err *withSubject) Markdown() []byte {
func (err *withSubject) fmtError(highlight highlightFunc) []byte { func (err *withSubject) fmtError(highlight highlightFunc) []byte {
// subject is in reversed order // subject is in reversed order
n := len(err.Subjects)
size := 0 size := 0
errStr := err.Err.Error() errStr := err.Err.Error()
subjects := err.Subjects
if err.pendingSubject != "" {
subjects = append(subjects, err.pendingSubject)
}
var buf bytes.Buffer var buf bytes.Buffer
for _, s := range err.Subjects { for _, s := range subjects {
size += len(s) size += len(s)
} }
n := len(subjects)
buf.Grow(size + 2 + n*len(subjectSep) + len(errStr) + len(highlight(""))) buf.Grow(size + 2 + n*len(subjectSep) + len(errStr) + len(highlight("")))
for i := n - 1; i > 0; i-- { for i := n - 1; i > 0; i-- {
buf.WriteString(err.Subjects[i]) buf.WriteString(subjects[i])
buf.WriteString(subjectSep) buf.WriteString(subjectSep)
} }
buf.WriteString(highlight(err.Subjects[0])) buf.WriteString(highlight(subjects[0]))
if errStr != "" { if errStr != "" {
buf.WriteString(": ") buf.WriteString(": ")
buf.WriteString(errStr) buf.WriteString(errStr)

View file

@ -256,7 +256,7 @@ func mapUnmarshalValidate(src SerializedObject, dst any, checkValidateTag bool)
if field, ok := mapping[strutils.ToLowerNoSnake(k)]; ok { if field, ok := mapping[strutils.ToLowerNoSnake(k)]; ok {
err := Convert(reflect.ValueOf(v), field, !hasValidateTag) err := Convert(reflect.ValueOf(v), field, !hasValidateTag)
if err != nil { if err != nil {
errs.Add(err) errs.Add(err.Subject(k))
} }
} else { } else {
errs.Add(ErrUnknownField.Subject(k).With(gperr.DoYouMean(NearestField(k, mapping)))) errs.Add(ErrUnknownField.Subject(k).With(gperr.DoYouMean(NearestField(k, mapping))))
@ -330,10 +330,6 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) gperr.
srcT = src.Type() srcT = src.Type()
} }
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
if dst.Kind() == reflect.Pointer { if dst.Kind() == reflect.Pointer {
if dst.IsNil() { if dst.IsNil() {
dst.Set(New(dstT.Elem())) dst.Set(New(dstT.Elem()))
@ -346,16 +342,25 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) gperr.
switch { switch {
case srcT.AssignableTo(dstT): case srcT.AssignableTo(dstT):
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
dst.Set(src) dst.Set(src)
return nil return nil
// case srcT.ConvertibleTo(dstT): // case srcT.ConvertibleTo(dstT):
// dst.Set(src.Convert(dstT)) // dst.Set(src.Convert(dstT))
// return nil // return nil
case srcKind == reflect.String: case srcKind == reflect.String:
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
if convertible, err := ConvertString(src.String(), dst); convertible { if convertible, err := ConvertString(src.String(), dst); convertible {
return err return err
} }
case isIntFloat(srcKind): case isIntFloat(srcKind):
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
var strV string var strV string
switch { switch {
case src.CanInt(): case src.CanInt():
@ -386,7 +391,7 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) gperr.
if dstT.Kind() != reflect.Slice { if dstT.Kind() != reflect.Slice {
return ErrUnsupportedConversion.Subject(dstT.String() + " to " + srcT.String()) return ErrUnsupportedConversion.Subject(dstT.String() + " to " + srcT.String())
} }
sliceErrs := gperr.NewBuilder("slice conversion errors") sliceErrs := gperr.NewBuilder()
newSlice := reflect.MakeSlice(dstT, src.Len(), src.Len()) newSlice := reflect.MakeSlice(dstT, src.Len(), src.Len())
i := 0 i := 0
for j, v := range src.Seq2() { for j, v := range src.Seq2() {
@ -469,7 +474,7 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gpe
if !isMultiline && src[0] != '-' { if !isMultiline && src[0] != '-' {
values := strutils.CommaSeperatedList(src) values := strutils.CommaSeperatedList(src)
dst.Set(reflect.MakeSlice(dst.Type(), len(values), len(values))) dst.Set(reflect.MakeSlice(dst.Type(), len(values), len(values)))
errs := gperr.NewBuilder("invalid slice values") errs := gperr.NewBuilder()
for i, v := range values { for i, v := range values {
err := Convert(reflect.ValueOf(v), dst.Index(i), true) err := Convert(reflect.ValueOf(v), dst.Index(i), true)
if err != nil { if err != nil {