package validate import "fmt" // Err is the zero Error. It carries no message, so errors.Is(x, Err) is // true for any error produced by this package. var Err = Error{} // Error represents a validation error. type Error struct { Message string Data []any } // Error returns the error message. If Data is non-empty, Message is used // as an fmt.Sprintf format string and Data as its arguments (this is how // the sentinels with %d/%q verbs are filled in, e.g. via With). func (e Error) Error() string { if len(e.Data) > 0 { return fmt.Sprintf(e.Message, e.Data...) } return e.Message } // Is determines whether the Error is an instance of the target. // https://pkg.go.dev/errors#Is // // If the target is a validation error and specifies a message, this function returns true if the messages match. // If the target is an empty validation error, this function always returns true. func (e Error) Is(target error) bool { if t, ok := target.(Error); ok { return t.Message == e.Message || t.Message == "" } return false } // With returns a copy of the Error with value appended to Data, so it // lands in the message when Message contains a formatting verb: // // ErrMustBeLonger.With(4) // "must contain at least 4 characters" func (e Error) With(value any) Error { if e.Data == nil { e.Data = []any{} } e.Data = append(e.Data, value) return e } // NewError creates a new validation error. func NewError(message string) Error { return Error{ Message: message, } }