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 {
return nil
}
if len(b.errs) == 1 && b.about == "" {
return wrap(b.errs[0])
}
return &nestedError{Err: New(b.about), Extras: b.errs}
}

View file

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

View file

@ -45,6 +45,11 @@ func PrependSubject(subject string, err error) error {
switch err := err.(type) {
case *withSubject:
return err.Prepend(subject)
case *wrappedError:
return &wrappedError{
Err: PrependSubject(subject, err.Err),
Message: err.Message,
}
case Error:
return err.Subject(subject)
}
@ -95,20 +100,24 @@ func (err *withSubject) Markdown() []byte {
func (err *withSubject) fmtError(highlight highlightFunc) []byte {
// subject is in reversed order
n := len(err.Subjects)
size := 0
errStr := err.Err.Error()
subjects := err.Subjects
if err.pendingSubject != "" {
subjects = append(subjects, err.pendingSubject)
}
var buf bytes.Buffer
for _, s := range err.Subjects {
for _, s := range subjects {
size += len(s)
}
n := len(subjects)
buf.Grow(size + 2 + n*len(subjectSep) + len(errStr) + len(highlight("")))
for i := n - 1; i > 0; i-- {
buf.WriteString(err.Subjects[i])
buf.WriteString(subjects[i])
buf.WriteString(subjectSep)
}
buf.WriteString(highlight(err.Subjects[0]))
buf.WriteString(highlight(subjects[0]))
if errStr != "" {
buf.WriteString(": ")
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 {
err := Convert(reflect.ValueOf(v), field, !hasValidateTag)
if err != nil {
errs.Add(err)
errs.Add(err.Subject(k))
}
} else {
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()
}
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
if dst.Kind() == reflect.Pointer {
if dst.IsNil() {
dst.Set(New(dstT.Elem()))
@ -346,16 +342,25 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) gperr.
switch {
case srcT.AssignableTo(dstT):
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
dst.Set(src)
return nil
// case srcT.ConvertibleTo(dstT):
// dst.Set(src.Convert(dstT))
// return nil
case srcKind == reflect.String:
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
if convertible, err := ConvertString(src.String(), dst); convertible {
return err
}
case isIntFloat(srcKind):
if !dst.CanSet() {
return ErrUnsettable.Subject(dstT.String())
}
var strV string
switch {
case src.CanInt():
@ -386,7 +391,7 @@ func Convert(src reflect.Value, dst reflect.Value, checkValidateTag bool) gperr.
if dstT.Kind() != reflect.Slice {
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())
i := 0
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] != '-' {
values := strutils.CommaSeperatedList(src)
dst.Set(reflect.MakeSlice(dst.Type(), len(values), len(values)))
errs := gperr.NewBuilder("invalid slice values")
errs := gperr.NewBuilder()
for i, v := range values {
err := Convert(reflect.ValueOf(v), dst.Index(i), true)
if err != nil {