-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
02c0027
commit 320f5a5
Showing
47 changed files
with
933 additions
and
857 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package internal | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"reflect" | ||
"strings" | ||
) | ||
|
||
// RuleSetError is a container for transferring multiple errors reported by [govy.RuleSet]. | ||
// It is intentionally not exported as it is only an intermediate stage before the | ||
// aggregated errors are flattened. | ||
type RuleSetError []error | ||
|
||
func (r RuleSetError) Error() string { | ||
b := new(strings.Builder) | ||
JoinErrors(b, r, "") | ||
return b.String() | ||
} | ||
|
||
// JoinErrors joins multiple errors into a single pretty-formmated string. | ||
func JoinErrors[T error](b *strings.Builder, errs []T, indent string) { | ||
for i, err := range errs { | ||
buildErrorMessage(b, err.Error(), indent) | ||
if i < len(errs)-1 { | ||
b.WriteString("\n") | ||
} | ||
} | ||
} | ||
|
||
const listPoint = "- " | ||
|
||
func buildErrorMessage(b *strings.Builder, errMsg, indent string) { | ||
b.WriteString(indent) | ||
if !strings.HasPrefix(errMsg, listPoint) { | ||
b.WriteString(listPoint) | ||
} | ||
// Indent the whole error message. | ||
errMsg = strings.ReplaceAll(errMsg, "\n", "\n"+indent) | ||
b.WriteString(errMsg) | ||
} | ||
|
||
var newLineReplacer = strings.NewReplacer("\n", "\\n", "\r", "\\r") | ||
|
||
// PropertyValueString returns the string representation of the given value. | ||
// Structs, interfaces, maps and slices are converted to compacted JSON strings. | ||
// It tries to improve readability by: | ||
// - limiting the string to 100 characters | ||
// - removing leading and trailing whitespaces | ||
// - escaping newlines | ||
// If value is a struct implementing [fmt.Stringer] String method will be used | ||
// only if the struct does not contain any JSON tags. | ||
func PropertyValueString(v interface{}) string { | ||
if v == nil { | ||
return "" | ||
} | ||
rv := reflect.ValueOf(v) | ||
ft := reflect.Indirect(rv) | ||
var s string | ||
switch ft.Kind() { | ||
case reflect.Interface, reflect.Map, reflect.Slice: | ||
if reflect.ValueOf(v).IsZero() { | ||
break | ||
} | ||
raw, _ := json.Marshal(v) | ||
s = string(raw) | ||
case reflect.Struct: | ||
if reflect.ValueOf(v).IsZero() { | ||
break | ||
} | ||
if stringer, ok := v.(fmt.Stringer); ok && !hasJSONTags(v, rv.Kind() == reflect.Pointer) { | ||
s = stringer.String() | ||
break | ||
} | ||
raw, _ := json.Marshal(v) | ||
s = string(raw) | ||
case reflect.Invalid: | ||
return "" | ||
default: | ||
s = fmt.Sprint(ft.Interface()) | ||
} | ||
s = limitString(s, 100) | ||
s = strings.TrimSpace(s) | ||
s = newLineReplacer.Replace(s) | ||
return s | ||
} | ||
|
||
func hasJSONTags(v interface{}, isPointer bool) bool { | ||
t := reflect.TypeOf(v) | ||
if isPointer { | ||
t = t.Elem() | ||
} | ||
for i := 0; i < t.NumField(); i++ { | ||
field := t.Field(i) | ||
if _, hasTag := field.Tag.Lookup("json"); hasTag { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func limitString(s string, limit int) string { | ||
if len(s) > limit { | ||
return s[:limit] + "..." | ||
} | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package internal | ||
|
||
import "reflect" | ||
|
||
const RequiredErrorMessage = "property is required but was empty" | ||
|
||
const RequiredErrorCodeString = "required" | ||
|
||
// IsEmptyFunc verifies if the value is zero value of its type. | ||
func IsEmptyFunc(v interface{}) bool { | ||
rv := reflect.ValueOf(v) | ||
return rv.Kind() == 0 || rv.IsZero() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
// Package validation implements a functional API for consistent struct level validation. | ||
package validation | ||
// package govy implements a functional API for consistent struct level validation. | ||
package govy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package govy | ||
|
||
// ErrorCode is a unique string that represents a specific [RuleError]. | ||
// It can be used to precisely identify the error without inspecting its message. | ||
type ErrorCode = string | ||
|
||
const ( | ||
ErrorCodeTransform ErrorCode = "transform" | ||
) |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.